Procházet zdrojové kódy

Merge pull request #1 from assimp/master

Update
Madrich před 10 roky
rodič
revize
45988cd238
100 změnil soubory, kde provedl 4390 přidání a 895 odebrání
  1. 19 0
      .gitignore
  2. 25 7
      .travis.yml
  3. 23 0
      CHANGES
  4. 148 143
      CMakeLists.txt
  5. 3 0
      CREDITS
  6. 8 2
      Readme.md
  7. 11 11
      assimp-config.cmake.in
  8. 1 0
      assimp.pc.in
  9. 64 0
      cmake-modules/AddGTest.cmake
  10. 560 0
      code/3DSExporter.cpp
  11. 94 0
      code/3DSExporter.h
  12. 1 1
      code/3DSHelper.h
  13. 2 2
      code/3DSLoader.h
  14. 2 2
      code/ASEParser.cpp
  15. 765 0
      code/AssbinExporter.cpp
  16. 49 0
      code/AssbinExporter.h
  17. 672 0
      code/AssbinLoader.cpp
  18. 94 0
      code/AssbinLoader.h
  19. 24 1
      code/Assimp.cpp
  20. 2 0
      code/AssimpCExport.cpp
  21. 638 0
      code/AssxmlExporter.cpp
  22. 49 0
      code/AssxmlExporter.h
  23. 1 1
      code/B3DImporter.cpp
  24. 5 0
      code/BaseImporter.h
  25. 28 1
      code/BlenderBMesh.cpp
  26. 1 0
      code/BlenderBMesh.h
  27. 6 2
      code/BlenderLoader.cpp
  28. 2 2
      code/BlenderTessellator.cpp
  29. 3 3
      code/BoostWorkaround/boost/tuple/tuple.hpp
  30. 33 1
      code/CMakeLists.txt
  31. 3 3
      code/CalcTangentsProcess.cpp
  32. 39 31
      code/ColladaExporter.cpp
  33. 0 1
      code/ColladaHelper.h
  34. 7 8
      code/ColladaLoader.cpp
  35. 4 1
      code/ColladaLoader.h
  36. 87 37
      code/ColladaParser.cpp
  37. 10 1
      code/ColladaParser.h
  38. 3 3
      code/ComputeUVMappingProcess.cpp
  39. 19 9
      code/ConvertToLHProcess.cpp
  40. 2 2
      code/DeboneProcess.cpp
  41. 18 11
      code/DefaultIOStream.h
  42. 25 5
      code/Exporter.cpp
  43. 1 1
      code/FBXAnimation.cpp
  44. 6 5
      code/FBXBinaryTokenizer.cpp
  45. 11 14
      code/FBXConverter.cpp
  46. 10 5
      code/FBXDocument.cpp
  47. 2 2
      code/FBXDocument.h
  48. 3 1
      code/FBXImporter.cpp
  49. 1 1
      code/FBXMaterial.cpp
  50. 4 2
      code/FBXMeshGeometry.cpp
  51. 24 34
      code/FBXParser.cpp
  52. 2 2
      code/FBXProperties.cpp
  53. 2 4
      code/FBXProperties.h
  54. 5 4
      code/FBXTokenizer.cpp
  55. 2 4
      code/FindInstancesProcess.cpp
  56. 1 1
      code/FindInvalidDataProcess.cpp
  57. 2 2
      code/FixNormalsStep.cpp
  58. 2 2
      code/GenVertexNormalsProcess.cpp
  59. 1 1
      code/GenVertexNormalsProcess.h
  60. 6 6
      code/IFCBoolean.cpp
  61. 12 12
      code/IFCCurve.cpp
  62. 4 4
      code/IFCGeometry.cpp
  63. 39 39
      code/IFCOpenings.cpp
  64. 2 2
      code/IFCProfile.cpp
  65. 3 3
      code/IFCReaderGen.cpp
  66. 1 1
      code/IFCUtil.cpp
  67. 1 1
      code/IFCUtil.h
  68. 24 22
      code/IFF.h
  69. 3 3
      code/IRRLoader.cpp
  70. 13 4
      code/Importer.cpp
  71. 6 0
      code/ImporterRegistry.cpp
  72. 1 3
      code/JoinVerticesProcess.h
  73. 58 40
      code/LWOBLoader.cpp
  74. 57 45
      code/LWOLoader.cpp
  75. 9 3
      code/LWOLoader.h
  76. 37 37
      code/LWOMaterial.cpp
  77. 3 3
      code/LWSLoader.cpp
  78. 10 17
      code/LimitBoneWeightsProcess.cpp
  79. 3 3
      code/MD3FileData.h
  80. 1 1
      code/MD5Parser.h
  81. 36 32
      code/ObjExporter.cpp
  82. 38 29
      code/ObjFileImporter.cpp
  83. 2 2
      code/ObjFileImporter.h
  84. 24 28
      code/ObjFileMtlImporter.cpp
  85. 42 32
      code/ObjFileParser.cpp
  86. 15 35
      code/ObjTools.h
  87. 5 6
      code/OgreBinarySerializer.cpp
  88. 6 2
      code/OgreBinarySerializer.h
  89. 4 4
      code/OgreImporter.cpp
  90. 14 12
      code/OgreStructs.cpp
  91. 45 32
      code/OptimizeMeshes.cpp
  92. 60 27
      code/ParsingUtils.h
  93. 103 6
      code/PlyExporter.cpp
  94. 4 1
      code/PlyExporter.h
  95. 1 1
      code/PlyParser.cpp
  96. 6 6
      code/PolyTools.h
  97. 10 8
      code/Q3BSPFileImporter.cpp
  98. 5 5
      code/Q3BSPZipArchive.cpp
  99. 2 2
      code/STLLoader.cpp
  100. 46 0
      code/SceneCombiner.cpp

+ 19 - 0
.gitignore

@@ -32,3 +32,22 @@ test/results
 
 
 # Python
 # Python
 __pycache__
 __pycache__
+*.log
+*.vcxproj
+*.filters
+*.tlog
+Assimp.sdf
+test/gtest/tmp/gtest-gitupdate.cmake
+test/gtest/tmp/gtest-gitclone.cmake
+test/gtest/tmp/gtest-cfgcmd.txt.in
+test/gtest/tmp/gtest-cfgcmd.txt
+test/gtest/src/gtest-stamp/gtest-download.cmake
+test/gtest/src/gtest-stamp/gtest-configure.cmake
+test/gtest/src/gtest-stamp/gtest-build.cmake
+test/gtest/src/gtest-stamp/Debug/gtest-patch
+*.cache
+test/gtest/src/gtest-stamp/Debug/gtest-build
+*.suo
+*.lib
+test/gtest/src/gtest-stamp/Debug/
+tools/assimp_view/assimp_viewer.vcxproj.user

+ 25 - 7
.travis.yml

@@ -1,11 +1,16 @@
 before_install:
 before_install:
-  - sudo apt-get install cmake
+  - sudo apt-get install cmake python3
 
 
 env:
 env:
-  - TRAVIS_NO_EXPORT=YES
-  - TRAVIS_NO_EXPORT=NO
-  - TRAVIS_STATIC_BUILD=ON
-  - TRAVIS_STATIC_BUILD=OFF
+    matrix:
+    - LINUX=1 TRAVIS_NO_EXPORT=YES
+    - LINUX=1 TRAVIS_NO_EXPORT=NO
+    - LINUX=1 TRAVIS_STATIC_BUILD=ON
+    - LINUX=1 TRAVIS_STATIC_BUILD=OFF
+    - WINDOWS=1 TRAVIS_NO_EXPORT=YES
+    - WINDOWS=1 TRAVIS_NO_EXPORT=NO
+    - WINDOWS=1 TRAVIS_STATIC_BUILD=ON
+    - WINDOWS=1 TRAVIS_STATIC_BUILD=OFF
 
 
 language: cpp
 language: cpp
 
 
@@ -13,7 +18,20 @@ compiler:
   - gcc
   - gcc
   - clang
   - clang
 
 
-script: cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -STATIC_BUILD=$TRAVIS_STATIC_BUILD && make
-
+install:
+  - if [ $WINDOWS ]; then travis_retry sudo apt-get install -q -y gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64; fi 
 
 
+script:
+  - cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -STATIC_BUILD=$TRAVIS_STATIC_BUILD
+  - make
+  - sudo make install
+  - sudo ldconfig
+  - cd test/unit
+  - ../../bin/unit
+  - cd ../regression
+  - chmod 755 run.py
+  - ./run.py
+  - echo "=========================================================="
+  - echo "REGRESSION TEST FAILS (results/run_regression_suite_failures.csv)"
+  - cat ../results/run_regression_suite_failures.csv
 
 

+ 23 - 0
CHANGES

@@ -2,6 +2,29 @@
 CHANGELOG
 CHANGELOG
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
+3.1.1 (2014-06-15)
+
+FEATURES:
+   - Support for FBX 2013 and newer, binary and ASCII (this is partly
+     work from Google Summer of Code 2012)
+   - Support for OGRE binary mesh and skeleton format
+   - Updated BLEND support for newer Blender versions
+   - Support for arbitrary meta data, used to hold FBX and DAE metadata
+   - OBJ Export now produces smaller files
+   - Meshes can now have names, this is supported by the major importers
+   - Improved IFC geometry generation
+   - M3 support has been removed
+
+FIXES/HOUSEKEEPING:
+    - Hundreds of bugfixes in all parts of the library
+    - CMake is now the primary build system
+    
+API COMPATIBILITY:
+    - 3.1.1 is not binary compatible to 3.0 due to aiNode::mMetaData
+      and aiMesh::mName
+    - Export interface has been cleaned up and unified
+    - Other than that no relevant changes
+   
 
 
 3.0 (2012-07-07)
 3.0 (2012-07-07)
 
 

+ 148 - 143
CMakeLists.txt

@@ -3,7 +3,7 @@ PROJECT( Assimp )
 
 
 # Define here the needed parameters
 # Define here the needed parameters
 set (ASSIMP_VERSION_MAJOR 3)
 set (ASSIMP_VERSION_MAJOR 3)
-set (ASSIMP_VERSION_MINOR 0)
+set (ASSIMP_VERSION_MINOR 1)
 set (ASSIMP_VERSION_PATCH 1) # subversion revision?
 set (ASSIMP_VERSION_PATCH 1) # subversion revision?
 set (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
 set (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
 set (ASSIMP_SOVERSION 3)
 set (ASSIMP_SOVERSION 3)
@@ -13,30 +13,30 @@ set(ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used f
 
 
 # Get the current working branch
 # Get the current working branch
 execute_process(
 execute_process(
-  COMMAND git rev-parse --abbrev-ref HEAD
-  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-  OUTPUT_VARIABLE GIT_BRANCH
-  OUTPUT_STRIP_TRAILING_WHITESPACE
+    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
 # Get the latest abbreviated commit hash of the working branch
 execute_process(
 execute_process(
-  COMMAND git log -1 --format=%h
-  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-  OUTPUT_VARIABLE GIT_COMMIT_HASH
-  OUTPUT_STRIP_TRAILING_WHITESPACE
+    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)
 if(NOT GIT_COMMIT_HASH)
-  set(GIT_COMMIT_HASH 0)
+    set(GIT_COMMIT_HASH 0)
 endif(NOT GIT_COMMIT_HASH)
 endif(NOT GIT_COMMIT_HASH)
 
 
 configure_file(
 configure_file(
-  ${CMAKE_SOURCE_DIR}/revision.h.in
-  ${CMAKE_BINARY_DIR}/revision.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/revision.h.in
+    ${CMAKE_CURRENT_BINARY_DIR}/revision.h
 )
 )
 
 
-include_directories(${CMAKE_BINARY_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
 
 option(ASSIMP_OPT_BUILD_PACKAGES "Set to ON to generate CPack configuration files and packaging targets" OFF)
 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(CMAKE_MODULE_PATH       "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
@@ -45,14 +45,16 @@ set(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_M
 set(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-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")
 set(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 
 
+option(ASSIMP_ANDROID_JNIIOSYSTEM "Android JNI IOSystem support is active" OFF)
+
 if((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW)
 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 )
+    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)
 elseif(MSVC)
-  # enable multi-core compilation with MSVC
-  add_definitions(/MP)
-endif()
+    # enable multi-core compilation with MSVC
+    add_definitions(/MP)
+    endif()
 
 
 INCLUDE (FindPkgConfig)
 INCLUDE (FindPkgConfig)
 INCLUDE_DIRECTORIES( include )
 INCLUDE_DIRECTORIES( include )
@@ -64,57 +66,54 @@ INCLUDE (PrecompiledHeader)
 # source tree. During an out-of-source build, however, do not litter this
 # source tree. During an out-of-source build, however, do not litter this
 # directory, since that is probably what the user wanted to avoid.
 # directory, since that is probably what the user wanted to avoid.
 IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
 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" )
+    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 )
 ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
 
 
 # Cache these to allow the user to override them manually.
 # Cache these to allow the user to override them manually.
 SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE PATH
 SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE PATH
-	"Path the built library files are installed to." )
+    "Path the built library files are installed to." )
 SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE PATH
 SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE PATH
-	"Path the header files are installed to." )
+    "Path the header files are installed to." )
 SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE PATH
 SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE PATH
-	"Path the tool executables are installed to." )
+    "Path the tool executables are installed to." )
 
 
 SET(ASSIMP_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfitx for lib, samples and tools")
 SET(ASSIMP_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfitx for lib, samples and tools")
 
 
-# Allow the user to build a static library
+# Allow the user to build a shared or static library
 option ( BUILD_SHARED_LIBS "Build a shared version of the library" ON )
 option ( BUILD_SHARED_LIBS "Build a shared version of the library" ON )
 
 
-# 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
 # Only generate this target if no higher-level project already has
 IF (NOT TARGET uninstall)
 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")
+    # 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()
 ENDIF()
 
 
 # Globally enable Boost resp. the Boost workaround – it is also needed by the
 # Globally enable Boost resp. the Boost workaround – it is also needed by the
 # tools which include the Assimp headers.
 # 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."
+option ( ASSIMP_ENABLE_BOOST_WORKAROUND
+    "If a simple implementation of the used Boost functions is used. Slightly reduces functionality, but enables builds without Boost available."
+    ON
 )
 )
 IF ( ASSIMP_ENABLE_BOOST_WORKAROUND )
 IF ( ASSIMP_ENABLE_BOOST_WORKAROUND )
-	INCLUDE_DIRECTORIES( code/BoostWorkaround )
-	ADD_DEFINITIONS( -DASSIMP_BUILD_BOOST_WORKAROUND )
-	MESSAGE( STATUS "Building a non-boost version of Assimp." )
+    INCLUDE_DIRECTORIES( code/BoostWorkaround )
+    ADD_DEFINITIONS( -DASSIMP_BUILD_BOOST_WORKAROUND )
+    MESSAGE( STATUS "Building a non-boost version of Assimp." )
 ELSE ( ASSIMP_ENABLE_BOOST_WORKAROUND )
 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")	
-	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 "
+    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" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" )	
+    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."
       "functionality by specifying -DASSIMP_ENABLE_BOOST_WORKAROUND=ON."
-		)
-	ENDIF ( NOT Boost_FOUND )
+        )
+    ENDIF ( NOT Boost_FOUND )
 
 
-	INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIRS} )
+    INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIRS} )
 ENDIF ( ASSIMP_ENABLE_BOOST_WORKAROUND )
 ENDIF ( ASSIMP_ENABLE_BOOST_WORKAROUND )
 
 
 # cmake configuration files
 # cmake configuration files
@@ -122,146 +121,152 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in"         "${C
 configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
 configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-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})
 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." 
+option ( ASSIMP_NO_EXPORT
+    "Disable Assimp's export functionality."
+    OFF
 )
 )
 
 
+if( CMAKE_COMPILER_IS_GNUCXX )
+  set(LIBSTDC++_LIBRARIES -lstdc++)
+endif( CMAKE_COMPILER_IS_GNUCXX )
+
 # Search for external dependencies, and build them from source if not found
 # Search for external dependencies, and build them from source if not found
 # Search for zlib
 # Search for zlib
 find_package(ZLIB)
 find_package(ZLIB)
 if( NOT ZLIB_FOUND )
 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)
+    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)
 else(NOT ZLIB_FOUND)
-  ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
+    ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
+    set(ZLIB_LIBRARIES_LINKED -lz)
 endif(NOT ZLIB_FOUND)
 endif(NOT ZLIB_FOUND)
 INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
 INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
 
 
 # Search for unzip
 # Search for unzip
 if (PKG_CONFIG_FOUND)
 if (PKG_CONFIG_FOUND)
-	PKG_CHECK_MODULES(UNZIP minizip)
+    PKG_CHECK_MODULES(UNZIP minizip)
 endif (PKG_CONFIG_FOUND)
 endif (PKG_CONFIG_FOUND)
 
 
 IF ( ASSIMP_NO_EXPORT )
 IF ( ASSIMP_NO_EXPORT )
-	ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
-	MESSAGE( STATUS "Build an import-only version of Assimp." )
+    ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
+    MESSAGE( STATUS "Build an import-only version of Assimp." )
 ENDIF( ASSIMP_NO_EXPORT )
 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 
 SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING 
-	"describe the current architecture."
+    "describe the current architecture."
 )
 )
 IF    ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
 IF    ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
 ELSE  ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
 ELSE  ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
-	ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
+    ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
 ENDIF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
 ENDIF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
 
 
 # ${CMAKE_GENERATOR}
 # ${CMAKE_GENERATOR}
 SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING 
 SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING 
-	"describe the current compiler."
+    "describe the current compiler."
 )
 )
 IF    ( ASSIMP_BUILD_COMPILER STREQUAL "")
 IF    ( ASSIMP_BUILD_COMPILER STREQUAL "")
 ELSE  ( ASSIMP_BUILD_COMPILER STREQUAL "")
 ELSE  ( ASSIMP_BUILD_COMPILER STREQUAL "")
-	ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
+    ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
 ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "")
 ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "")
 
 
 MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
 MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
 
 
 ADD_SUBDIRECTORY( code/ )
 ADD_SUBDIRECTORY( code/ )
-SET ( ASSIMP_BUILD_ASSIMP_TOOLS ON CACHE BOOL
-	"If the supplementary tools for Assimp are built in addition to the library."
+option ( ASSIMP_BUILD_ASSIMP_TOOLS
+    "If the supplementary tools for Assimp are built in addition to the library."
+    ON
 )
 )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
-	IF ( WIN32 )
-		ADD_SUBDIRECTORY( tools/assimp_view/ )
-	ENDIF ( WIN32 )
-	ADD_SUBDIRECTORY( tools/assimp_cmd/ )
+    IF ( WIN32 )
+        ADD_SUBDIRECTORY( tools/assimp_view/ )
+    ENDIF ( WIN32 )
+    ADD_SUBDIRECTORY( tools/assimp_cmd/ )
 ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
 ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
 
 
-SET ( ASSIMP_BUILD_SAMPLES OFF CACHE BOOL
-	"If the official samples are built as well (needs Glut)."
+option ( ASSIMP_BUILD_SAMPLES
+    "If the official samples are built as well (needs Glut)."
+    OFF
 )
 )
 
 
 IF ( ASSIMP_BUILD_SAMPLES)
 IF ( ASSIMP_BUILD_SAMPLES)
-	IF ( WIN32 )
-		ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
-	ENDIF ( WIN32 )
-	ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
+    IF ( WIN32 )
+        ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
+    ENDIF ( WIN32 )
+    ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
 ENDIF ( ASSIMP_BUILD_SAMPLES )
 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 )
+option ( ASSIMP_BUILD_TESTS
+    "If the test suite for Assimp is built in addition to the library."
+    ON
+)
+    
+IF ( ASSIMP_BUILD_TESTS )
+    ADD_SUBDIRECTORY( test/ )
+ENDIF ( ASSIMP_BUILD_TESTS )
 
 
 IF(MSVC)
 IF(MSVC)
-	SET ( ASSIMP_INSTALL_PDB ON CACHE BOOL
-		"Install MSVC debug files."
-	)
+    option ( ASSIMP_INSTALL_PDB
+        "Install MSVC debug files."
+        ON
+    )
 ENDIF(MSVC)
 ENDIF(MSVC)
 
 
+# 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})
+
 if(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
 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)
+    # 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_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()
 endif()

+ 3 - 0
CREDITS

@@ -148,3 +148,6 @@ Bugfixes for uv-tanget calculation.
 
 
 - Jonne Nauha
 - Jonne Nauha
 Ogre Binary format support
 Ogre Binary format support
+
+- Filip Wasil, Tieto Poland Sp. z o.o.
+Android JNI asset extraction support

+ 8 - 2
Readme.md

@@ -1,10 +1,12 @@
 Open Asset Import Library (assimp) 
 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.
+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 __40 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)
 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)
 
 
+[open3mod](https://github.com/acgessler/open3mod) is an Open Source 3D model viewer based off Assimp's import and export abilities.
+
 #### Supported file formats ####
 #### Supported file formats ####
 
 
 The library provides importers for a lot of file formats, including:
 The library provides importers for a lot of file formats, including:
@@ -44,6 +46,7 @@ The library provides importers for a lot of file formats, including:
 - Ogre Binary
 - Ogre Binary
 - Ogre XML
 - Ogre XML
 - Q3D
 - Q3D
+- ASSBIN (Assimp scene serialization)
  
  
 Additionally, the following formats are also supported, but not part of the core library as they depend on proprietary libraries.
 Additionally, the following formats are also supported, but not part of the core library as they depend on proprietary libraries.
 
 
@@ -55,7 +58,10 @@ Exporters include:
 - STL
 - STL
 - OBJ
 - OBJ
 - PLY
 - PLY
+- X
+- 3DS
 - JSON (for WebGl, via https://github.com/acgessler/assimp2json)
 - JSON (for WebGl, via https://github.com/acgessler/assimp2json)
+- ASSBIN
 	
 	
 See [the full list here](http://assimp.sourceforge.net/main_features_formats.html).
 See [the full list here](http://assimp.sourceforge.net/main_features_formats.html).
 
 
@@ -77,7 +83,7 @@ C++ish interface). The directory structure is:
 	/scripts 	Scripts used to generate the loading code for some formats
 	/scripts 	Scripts used to generate the loading code for some formats
 	/port		Ports to other languages and scripts to maintain those.
 	/port		Ports to other languages and scripts to maintain those.
 	/test		Unit- and regression tests, test suite of models
 	/test		Unit- and regression tests, test suite of models
-	/tools		Tools (viewer, command line `assimp`)
+	/tools		Tools (old assimp viewer, command line `assimp`)
 	/samples	A small number of samples to illustrate possible 
 	/samples	A small number of samples to illustrate possible 
                         use cases for Assimp
                         use cases for Assimp
 	/workspaces	Build enviroments for vc,xcode,... (deprecated,
 	/workspaces	Build enviroments for vc,xcode,... (deprecated,

+ 11 - 11
assimp-config.cmake.in

@@ -44,20 +44,20 @@ if (CMAKE_BUILD_TYPE EQUAL "DEBUG")
 	set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}D)
 	set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}D)
 endif (CMAKE_BUILD_TYPE EQUAL "DEBUG")
 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
 # the boost version assimp was compiled with
 set( ASSIMP_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@")
 set( ASSIMP_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@")
 
 
-# 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")
-
 # for compatibility wiht pkg-config
 # for compatibility wiht pkg-config
 set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
 set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
 set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
 set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")

+ 1 - 0
assimp.pc.in

@@ -7,4 +7,5 @@ Name: @CMAKE_PROJECT_NAME@
 Description: Import various well-known 3D model formats in an uniform manner.
 Description: Import various well-known 3D model formats in an uniform manner.
 Version: @PROJECT_VERSION@
 Version: @PROJECT_VERSION@
 Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@
 Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@
+Libs.private: @LIBSTDC++_LIBRARIES@ @ZLIB_LIBRARIES_LINKED@
 Cflags: -I${includedir}
 Cflags: -I${includedir}

+ 64 - 0
cmake-modules/AddGTest.cmake

@@ -0,0 +1,64 @@
+find_package(Threads REQUIRED)
+include(ExternalProject)
+
+if(MSYS OR MINGW)
+	set(DISABLE_PTHREADS ON)
+else()
+	set(DISABLE_PTHREADS OFF)
+endif()
+
+if (MSVC)
+	set(RELEASE_LIB_DIR ReleaseLibs)
+	set(DEBUG_LIB_DIR DebugLibs)
+else()
+	set(RELEASE_LIB_DIR "")
+	set(DEBUG_LIB_DIR "")
+endif()
+
+set(GTEST_CMAKE_ARGS
+	"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
+	"-Dgtest_force_shared_crt=ON"
+	"-Dgtest_disable_pthreads:BOOL=${DISABLE_PTHREADS}")
+set(GTEST_RELEASE_LIB_DIR "")
+set(GTEST_DEBUGLIB_DIR "")
+if (MSVC)
+	set(GTEST_CMAKE_ARGS ${GTEST_CMAKE_ARGS}
+		"-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=${DEBUG_LIB_DIR}"
+		"-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=${RELEASE_LIB_DIR}")
+	set(GTEST_LIB_DIR)
+endif()
+
+set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gtest")
+
+ExternalProject_Add(gtest
+	GIT_REPOSITORY https://chromium.googlesource.com/external/googletest
+	TIMEOUT 10
+	PREFIX "${GTEST_PREFIX}"
+	CMAKE_ARGS "${GTEST_CMAKE_ARGS}"
+	LOG_DOWNLOAD ON
+	LOG_CONFIGURE ON
+	LOG_BUILD ON
+	# Disable install
+	INSTALL_COMMAND ""
+)
+
+set(LIB_PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")
+set(LIB_SUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set(GTEST_LOCATION "${GTEST_PREFIX}/src/gtest-build")
+set(GTEST_DEBUG_LIBRARIES
+	"${GTEST_LOCATION}/${DEBUG_LIB_DIR}/${LIB_PREFIX}gtest${LIB_SUFFIX}"
+	"${CMAKE_THREAD_LIBS_INIT}")
+SET(GTEST_RELEASE_LIBRARIES
+	"${GTEST_LOCATION}/${RELEASE_LIB_DIR}/${LIB_PREFIX}gtest${LIB_SUFFIX}"
+	"${CMAKE_THREAD_LIBS_INIT}")
+
+if(MSVC_VERSION EQUAL 1700)
+  add_definitions(-D_VARIADIC_MAX=10)
+endif()
+
+ExternalProject_Get_Property(gtest source_dir)
+include_directories(${source_dir}/include)
+include_directories(${source_dir}/gtest/include)
+
+ExternalProject_Get_Property(gtest binary_dir)
+link_directories(${binary_dir})

+ 560 - 0
code/3DSExporter.cpp

@@ -0,0 +1,560 @@
+/*
+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_3DS_EXPORTER
+
+#include "3DSExporter.h"
+#include "3DSLoader.h"
+#include "SceneCombiner.h"
+#include "SplitLargeMeshes.h"
+
+using namespace Assimp;
+namespace Assimp	{
+
+namespace {
+
+	//////////////////////////////////////////////////////////////////////////////////////
+	// Scope utility to write a 3DS file chunk.
+	//
+	// Upon construction, the chunk header is written with the chunk type (flags)
+	// filled out, but the chunk size left empty. Upon destruction, the correct chunk
+	// size based on the then-position of the output stream cursor is filled in.
+	class ChunkWriter {
+		enum {
+			  CHUNK_SIZE_NOT_SET = 0xdeadbeef
+			, SIZE_OFFSET        = 2
+		};
+	public:
+
+		ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
+			: writer(writer)
+		{
+			chunk_start_pos = writer.GetCurrentPos();
+			writer.PutU2(chunk_type);
+			writer.PutU4(CHUNK_SIZE_NOT_SET);
+		}
+
+		~ChunkWriter() {
+			std::size_t head_pos = writer.GetCurrentPos();
+
+			ai_assert(head_pos > chunk_start_pos);
+			const std::size_t chunk_size = head_pos - chunk_start_pos;
+
+			writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
+			writer.PutU4(chunk_size);
+			writer.SetCurrentPos(head_pos);
+		}
+		
+	private:
+		StreamWriterLE& writer;
+		std::size_t chunk_start_pos;
+	};
+
+
+	// Return an unique name for a given |mesh| attached to |node| that
+	// preserves the mesh's given name if it has one. |index| is the index
+	// of the mesh in |aiScene::mMeshes|.
+	std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
+		static const std::string underscore = "_";
+		char postfix[10] = {0};
+		ASSIMP_itoa10(postfix, index);
+
+		std::string result = node.mName.C_Str();
+		if (mesh.mName.length > 0) {
+			result += underscore + mesh.mName.C_Str();
+		}
+		return result + underscore + postfix;
+	}
+
+	// Return an unique name for a given |mat| with original position |index|
+	// in |aiScene::mMaterials|. The name preserves the original material
+	// name if possible.
+	std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
+		static const std::string underscore = "_";
+		char postfix[10] = {0};
+		ASSIMP_itoa10(postfix, index);
+
+		aiString mat_name;
+		if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
+			return mat_name.C_Str() + underscore + postfix;
+		}
+
+		return "Material" + underscore + postfix;
+	}
+
+	// Collect world transformations for each node
+	void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
+		const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
+		trafos[node] = parent * node->mTransformation;
+		for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+			CollectTrafos(node->mChildren[i], trafos);
+		}
+	}
+
+	// Generate a flat list of the meshes (by index) assigned to each node
+	void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
+		for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
+			meshes.insert(std::make_pair(node, node->mMeshes[i]));
+		}
+		for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+			CollectMeshes(node->mChildren[i], meshes);
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
+void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+{
+	boost::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
+	if(!outfile) {
+		throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
+	} 
+
+	// TODO: This extra copy should be avoided and all of this made a preprocess
+	// requirement of the 3DS exporter.
+	//
+	// 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively.
+	// SplitLargeMeshes can do this, but it requires the correct limit to be set
+	// which is not possible with the current way of specifying preprocess steps
+	// in |Exporter::ExportFormatEntry|.
+	aiScene* scenecopy_tmp;
+	SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
+	std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
+
+	SplitLargeMeshesProcess_Triangle tri_splitter;
+	tri_splitter.SetLimit(0xffff);
+	tri_splitter.Execute(scenecopy.get());
+
+	SplitLargeMeshesProcess_Vertex vert_splitter;
+	vert_splitter.SetLimit(0xffff);
+	vert_splitter.Execute(scenecopy.get());
+
+	// Invoke the actual exporter 
+	Discreet3DSExporter exporter(outfile, scenecopy.get());
+}
+
+} // end of namespace Assimp
+
+// ------------------------------------------------------------------------------------------------
+Discreet3DSExporter:: Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, const aiScene* scene)
+: scene(scene)
+, writer(outfile)
+{
+	CollectTrafos(scene->mRootNode, trafos);
+	CollectMeshes(scene->mRootNode, meshes);
+
+	ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
+
+	{
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
+		WriteMeshes();
+		WriteMaterials();
+
+		{
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
+			writer.PutF4(1.0f);
+		}
+	}
+
+	{
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
+		WriteHierarchy(*scene->mRootNode, -1, -1);
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
+{
+	// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
+	{
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
+		{
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
+
+			// Assimp node names are unique and distinct from all mesh-node
+			// names we generate; thus we can use them as-is
+			WriteString(node.mName);
+
+			// Two unknown int16 values - it is even unclear if 0 is a safe value
+			// but luckily importers do not know better either.
+			writer.PutI4(0);
+
+			int16_t hierarchy_pos = static_cast<int16_t>(seq);
+			if (sibling_level != -1) {
+				hierarchy_pos = sibling_level;
+			}
+
+			// Write the hierarchy position
+			writer.PutI2(hierarchy_pos);
+		}
+	}
+
+	// TODO: write transformation chunks
+
+	++seq;
+	sibling_level = seq;
+
+	// Write all children
+	for (unsigned int i = 0; i < node.mNumChildren; ++i) {
+		seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level);
+	}
+
+	// Write all meshes as separate nodes to be able to reference the meshes by name
+	for (unsigned int i = 0; i < node.mNumMeshes; ++i) {
+		const bool first_child = node.mNumChildren == 0 && i == 0;
+
+		const unsigned int mesh_idx = node.mMeshes[i];
+		const aiMesh& mesh = *scene->mMeshes[mesh_idx];
+
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
+		{
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
+			WriteString(GetMeshName(mesh, mesh_idx, node));
+
+			writer.PutI4(0);
+			writer.PutI2(static_cast<int16_t>(first_child ? seq : sibling_level));
+			++seq;
+		}
+	}
+	return seq;
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WriteMaterials()
+{
+	for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
+		const aiMaterial& mat = *scene->mMaterials[i];
+
+		{
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
+			const std::string& name = GetMaterialName(mat, i);
+			WriteString(name);
+		}
+
+		aiColor3D color;
+		if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
+			WriteColor(color);
+		}
+
+		if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
+			WriteColor(color);
+		}
+
+		if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
+			WriteColor(color);
+		}
+
+		if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
+			WriteColor(color);
+		}
+
+		aiShadingMode shading_mode;
+		if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
+
+			Discreet3DS::shadetype3ds shading_mode_out;
+			switch(shading_mode) {
+			case aiShadingMode_Flat:
+			case aiShadingMode_NoShading:
+				shading_mode_out = Discreet3DS::Flat;
+				break;
+
+			case aiShadingMode_Gouraud:
+			case aiShadingMode_Toon:
+			case aiShadingMode_OrenNayar:
+			case aiShadingMode_Minnaert:
+				shading_mode_out = Discreet3DS::Gouraud;
+				break;
+
+			case aiShadingMode_Phong:
+			case aiShadingMode_Blinn:
+			case aiShadingMode_CookTorrance:
+			case aiShadingMode_Fresnel:
+				shading_mode_out = Discreet3DS::Phong;
+				break;
+
+			default:
+				ai_assert(false);
+			};
+			writer.PutU2(static_cast<uint16_t>(shading_mode_out));
+		}
+
+
+		float f;
+		if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
+			WritePercentChunk(f);
+		}
+
+		if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT);
+			WritePercentChunk(f);
+		}
+
+		int twosided;
+		if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE);
+			writer.PutI2(1);
+		}
+		
+		WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
+		WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
+		WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
+		WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
+		WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP);
+		WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP);
+		WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP);
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags) 
+{
+	aiString path;
+	aiTextureMapMode map_mode[2] = {
+		aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
+	};
+	float blend = 1.0f;
+	if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
+		return;
+	}
+
+	// TODO: handle embedded textures properly
+	if (path.data[0] == '*') {
+		DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str()));
+		return;
+	}
+
+	ChunkWriter chunk(writer, chunk_flags);
+	{
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
+		WriteString(path);
+	}
+
+	WritePercentChunk(blend);
+
+	{
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
+		uint16_t val = 0; // WRAP
+		if (map_mode[0] == aiTextureMapMode_Mirror) {
+			val = 0x2;
+		}
+		else if (map_mode[0] == aiTextureMapMode_Decal) {
+			val = 0x10;
+		}
+		writer.PutU2(val);
+	}
+	// TODO: export texture transformation (i.e. UV offset, scale, rotation)
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WriteMeshes()
+{
+	// NOTE: 3DS allows for instances. However:
+	//   i)  not all importers support reading them
+	//   ii) instances are not as flexible as they are in assimp, in particular,
+	//        nodes can carry (and instance) only one mesh.
+	//
+	// This exporter currently deep clones all instanced meshes, i.e. for each mesh
+	// attached to a node a full TRIMESH chunk is written to the file.
+	//
+	// Furthermore, the TRIMESH is transformed into world space so that it will
+	// appear correctly if importers don't read the scene hierarchy at all.
+	for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
+		const aiNode& node = *(*it).first;
+		const unsigned int mesh_idx = (*it).second;
+
+		const aiMesh& mesh = *scene->mMeshes[mesh_idx];
+
+		// This should not happen if the SLM step is correctly executed
+		// before the scene is handed to the exporter
+		ai_assert(mesh.mNumVertices <= 0xffff);
+		ai_assert(mesh.mNumFaces <= 0xffff);
+
+		const aiMatrix4x4& trafo = trafos[&node];
+
+		ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
+
+		// Mesh name is tied to the node it is attached to so it can later be referenced
+		const std::string& name = GetMeshName(mesh, mesh_idx, node);
+		WriteString(name);
+
+
+		// TRIMESH chunk
+		ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
+
+		// Vertices in world space
+		{
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
+
+			const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
+			writer.PutU2(count);
+			for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
+				const aiVector3D& v = trafo * mesh.mVertices[i];
+				writer.PutF4(v.x);
+				writer.PutF4(v.y);
+				writer.PutF4(v.z);
+			}
+		}
+
+		// UV coordinates
+		if (mesh.HasTextureCoords(0)) {
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
+			const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
+			writer.PutU2(count);
+
+			for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
+				const aiVector3D& v = mesh.mTextureCoords[0][i];
+				writer.PutF4(v.x);
+				writer.PutF4(v.y);
+			}
+		}
+
+		// Faces (indices)
+		{
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
+
+			ai_assert(mesh.mNumFaces <= 0xffff);
+
+			// Count triangles, discard lines and points
+			uint16_t count = 0;
+			for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
+				const aiFace& f = mesh.mFaces[i];
+				if (f.mNumIndices < 3) {
+					continue;
+				}
+				// TRIANGULATE step is a pre-requisite so we should not see polys here
+				ai_assert(f.mNumIndices == 3);
+				++count;
+			}
+
+			writer.PutU2(count);
+			for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
+				const aiFace& f = mesh.mFaces[i];
+				if (f.mNumIndices < 3) {
+					continue;
+				}
+
+				for (unsigned int j = 0; j < 3; ++j) {
+					ai_assert(f.mIndices[j] <= 0xffff);
+					writer.PutI2(static_cast<uint16_t>(f.mIndices[j]));
+				}
+
+				// Edge visibility flag
+				writer.PutI2(0x0);
+			}
+
+			// TODO: write smoothing groups (CHUNK_SMOOLIST)
+
+			WriteFaceMaterialChunk(mesh);
+		}
+
+		// Transformation matrix by which the mesh vertices have been pre-transformed with.
+		{
+			ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
+			for (unsigned int r = 0; r < 4; ++r) {
+				for (unsigned int c = 0; c < 3; ++c) {
+					writer.PutF4(trafo[r][c]);
+				}
+			}
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
+{
+	ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
+	const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
+	WriteString(name);
+
+	// Because assimp splits meshes by material, only a single
+	// FACEMAT chunk needs to be written
+	ai_assert(mesh.mNumFaces <= 0xffff);
+	const uint16_t count = static_cast<uint16_t>(mesh.mNumFaces);
+	writer.PutU2(count);
+
+	for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
+		writer.PutU2(static_cast<uint16_t>(i));
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WriteString(const std::string& s) {
+	for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
+		writer.PutI1(*it);
+	}
+	writer.PutI1('\0');
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WriteString(const aiString& s) {
+	for (std::size_t i = 0; i < s.length; ++i) {
+		writer.PutI1(s.data[i]);
+	}
+	writer.PutI1('\0');
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
+	ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
+	writer.PutF4(color.r);
+	writer.PutF4(color.g);
+	writer.PutF4(color.b);
+}
+
+// ------------------------------------------------------------------------------------------------
+void Discreet3DSExporter::WritePercentChunk(float f) {
+	ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
+	writer.PutF4(f);
+}
+
+
+#endif // ASSIMP_BUILD_NO_3DS_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 94 - 0
code/3DSExporter.h

@@ -0,0 +1,94 @@
+/*
+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 3DSExporter.h
+ * 3DS Exporter Main Header
+ */
+#ifndef AI_3DSEXPORTER_H_INC
+#define AI_3DSEXPORTER_H_INC
+
+#include <map>
+
+#include "StreamWriter.h"
+
+struct aiScene;
+struct aiNode;
+
+namespace Assimp	
+{
+
+// ------------------------------------------------------------------------------------------------
+/** Helper class to export a given scene to a 3DS file. */
+// ------------------------------------------------------------------------------------------------
+class Discreet3DSExporter
+{
+public:
+	Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, const aiScene* pScene);
+
+private:
+
+	void WriteMeshes();
+	void WriteMaterials();
+	void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
+
+	void WriteFaceMaterialChunk(const aiMesh& mesh);
+
+	int WriteHierarchy(const aiNode& node, int level, int sibling_level);
+
+	void WriteString(const std::string& s);
+	void WriteString(const aiString& s);
+	void WriteColor(const aiColor3D& color);
+	void WritePercentChunk(float f);
+
+private:
+
+	const aiScene* const scene;
+	StreamWriterLE writer;
+
+	std::map<const aiNode*, aiMatrix4x4> trafos;
+
+	typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap;
+	MeshesByNodeMap meshes;
+
+};
+
+}
+
+#endif

+ 1 - 1
code/3DSHelper.h

@@ -468,7 +468,7 @@ struct aiFloatKey
 		{return mTime < o.mTime;}
 		{return mTime < o.mTime;}
 
 
 	bool operator > (const aiFloatKey& o) const
 	bool operator > (const aiFloatKey& o) const
-		{return mTime < o.mTime;}
+		{return mTime > o.mTime;}
 
 
 #endif
 #endif
 };
 };

+ 2 - 2
code/3DSLoader.h

@@ -273,8 +273,8 @@ protected:
 	bool bIsPrj;
 	bool bIsPrj;
 };
 };
 
 
-#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER
-
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 
+#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER
+
 #endif // AI_3DSIMPORTER_H_INC
 #endif // AI_3DSIMPORTER_H_INC

+ 2 - 2
code/ASEParser.cpp

@@ -1525,7 +1525,7 @@ void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh& mesh)
 				continue;
 				continue;
 			}
 			}
 			// Number of bones
 			// Number of bones
-			if (TokenMatch(filePtr,"MESH_NUMBONE" ,11))
+			if (TokenMatch(filePtr,"MESH_NUMBONE" ,12))
 			{
 			{
 				ParseLV4MeshLong(iNumBones);
 				ParseLV4MeshLong(iNumBones);
 				continue;
 				continue;
@@ -1559,7 +1559,7 @@ void Parser::ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh& mesh)
 			++filePtr;
 			++filePtr;
 
 
 			// Mesh bone with name ...
 			// Mesh bone with name ...
-			if (TokenMatch(filePtr,"MESH_BONE_NAME" ,16))
+			if (TokenMatch(filePtr,"MESH_BONE_NAME" ,14))
 			{
 			{
 				// parse an index ...
 				// parse an index ...
 				if(SkipSpaces(&filePtr))
 				if(SkipSpaces(&filePtr))

+ 765 - 0
code/AssbinExporter.cpp

@@ -0,0 +1,765 @@
+/*
+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  AssbinExporter.cpp
+ *  ASSBIN exporter main code
+ */
+#include "AssimpPCH.h"
+#include "assbin_chunks.h"
+#include "./../include/assimp/version.h"
+#include "ProcessHelper.h"
+
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#	include <zlib.h>
+#else
+#	include "../contrib/zlib/zlib.h"
+#endif
+
+#include <time.h>
+
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
+
+using namespace Assimp;
+
+namespace Assimp	{
+
+template <typename T> 
+size_t Write(IOStream * stream, const T& v)
+{
+	return stream->Write( &v, sizeof(T), 1 );
+}
+
+
+// -----------------------------------------------------------------------------------
+// Serialize an aiString
+template <>
+inline size_t Write<aiString>(IOStream * stream, const aiString& s)
+{
+	const size_t s2 = (uint32_t)s.length;
+	stream->Write(&s,4,1);
+	stream->Write(s.data,s2,1);
+	return s2+4;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an unsigned int as uint32_t
+template <>
+inline size_t Write<unsigned int>(IOStream * stream, const unsigned int& w)
+{
+	const uint32_t t = (uint32_t)w;
+	if (w > t) {
+		// this shouldn't happen, integers in Assimp data structures never exceed 2^32
+		throw new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
+	}
+
+	stream->Write(&t,4,1);
+	return 4;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an unsigned int as uint16_t
+template <>
+inline size_t Write<uint16_t>(IOStream * stream, const uint16_t& w)
+{
+	BOOST_STATIC_ASSERT(sizeof(uint16_t)==2);
+	stream->Write(&w,2,1);
+	return 2;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a float
+template <>
+inline size_t Write<float>(IOStream * stream, const float& f)
+{
+	BOOST_STATIC_ASSERT(sizeof(float)==4);
+	stream->Write(&f,4,1);
+	return 4;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a double
+template <>
+inline size_t Write<double>(IOStream * stream, const double& f)
+{
+	BOOST_STATIC_ASSERT(sizeof(double)==8);
+	stream->Write(&f,8,1);
+	return 8;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a vec3
+template <>
+inline size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v)
+{
+	size_t t = Write<float>(stream,v.x);
+	t += Write<float>(stream,v.y);
+	t += Write<float>(stream,v.z);
+	return t;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a color value
+template <>
+inline size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v)
+{
+	size_t t = Write<float>(stream,v.r);
+	t += Write<float>(stream,v.g);
+	t += Write<float>(stream,v.b);
+	t += Write<float>(stream,v.a);
+	return t;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a quaternion
+template <>
+inline size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v)
+{
+	size_t t = Write<float>(stream,v.w);
+	t += Write<float>(stream,v.x);
+	t += Write<float>(stream,v.y);
+	t += Write<float>(stream,v.z);
+	return 16;
+}
+
+
+// -----------------------------------------------------------------------------------
+// Serialize a vertex weight
+template <>
+inline size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v)
+{
+	size_t t = Write<unsigned int>(stream,v.mVertexId);
+	return t+Write<float>(stream,v.mWeight);
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a mat4x4
+template <>
+inline size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m)
+{
+	for (unsigned int i = 0; i < 4;++i) {
+		for (unsigned int i2 = 0; i2 < 4;++i2) {
+			Write<float>(stream,m[i][i2]);
+		}
+	}
+	return 64;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an aiVectorKey
+template <>
+inline size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v)
+{
+	const size_t t = Write<double>(stream,v.mTime);
+	return t + Write<aiVector3D>(stream,v.mValue);
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an aiQuatKey
+template <>
+inline size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v)
+{
+	const size_t t = Write<double>(stream,v.mTime);
+	return t + Write<aiQuaternion>(stream,v.mValue);
+}
+
+template <typename T>
+inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size)
+{
+	T minc,maxc;
+	ArrayBounds(in,size,minc,maxc);
+
+	const size_t t = Write<T>(stream,minc);
+	return t + Write<T>(stream,maxc);
+}
+
+// We use this to write out non-byte arrays so that we write using the specializations.
+// This way we avoid writing out extra bytes that potentially come from struct alignment.
+template <typename T>
+inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
+{
+	size_t n = 0;
+	for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
+	return n;
+}
+
+	// ----------------------------------------------------------------------------------
+	/**	@class	AssbinChunkWriter
+	 *	@brief	Chunk writer mechanism for the .assbin file structure
+	 *
+	 *  This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
+	 *  the difference being that this takes another IOStream as a "container" in the
+	 *  constructor, and when it is destroyed, it appends the magic number, the chunk size,
+	 *  and the chunk contents to the container stream. This allows relatively easy chunk
+	 *  chunk construction, even recursively.
+	 */
+	class AssbinChunkWriter : public IOStream
+	{
+	private:
+
+		uint8_t* buffer;
+		uint32_t magic;
+		IOStream * container;
+		size_t cur_size, cursor, initial;
+
+	private:
+		// -------------------------------------------------------------------
+		void Grow(size_t need = 0) 
+		{
+			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;
+		}
+
+	public:
+
+		AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) 
+			: buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
+		{
+		}
+
+		virtual ~AssbinChunkWriter() 
+		{
+			if (container) {
+				container->Write( &magic, sizeof(uint32_t), 1 );
+				container->Write( &cursor, sizeof(uint32_t), 1 );
+				container->Write( buffer, 1, cursor );
+			}
+			if (buffer) delete[] buffer;
+		}
+
+		void * GetBufferPointer() { return buffer; };
+
+		// -------------------------------------------------------------------
+		virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; };
+		virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; };
+		virtual size_t Tell() const { return cursor; };
+		virtual void Flush() { };
+
+		virtual size_t FileSize() const
+		{
+			return cursor;
+		}
+
+		// -------------------------------------------------------------------
+		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;
+
+			return pCount; 
+		}
+
+	};
+
+	// ----------------------------------------------------------------------------------
+	/**	@class	AssbinExport
+	 *	@brief	Assbin exporter class
+	 *
+	 *  This class performs the .assbin exporting, and is responsible for the file layout.
+	 */
+	class AssbinExport
+	{
+	private:
+		bool shortened;
+		bool compressed;
+
+	protected:
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryNode( IOStream * container, const aiNode* node)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
+
+			Write<aiString>(&chunk,node->mName);
+			Write<aiMatrix4x4>(&chunk,node->mTransformation);
+			Write<unsigned int>(&chunk,node->mNumChildren);
+			Write<unsigned int>(&chunk,node->mNumMeshes);
+
+			for (unsigned int i = 0; i < node->mNumMeshes;++i) {
+				Write<unsigned int>(&chunk,node->mMeshes[i]);
+			}
+
+			for (unsigned int i = 0; i < node->mNumChildren;++i) {
+				WriteBinaryNode( &chunk, node->mChildren[i] );
+			}
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
+
+			Write<unsigned int>(&chunk,tex->mWidth);
+			Write<unsigned int>(&chunk,tex->mHeight);
+			chunk.Write( tex->achFormatHint, sizeof(char), 4 );
+
+			if(!shortened) {
+				if (!tex->mHeight) {
+					chunk.Write(tex->pcData,1,tex->mWidth);
+				}
+				else {
+					chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
+				}
+			}
+
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryBone(IOStream * container, const aiBone* b)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
+
+			Write<aiString>(&chunk,b->mName);
+			Write<unsigned int>(&chunk,b->mNumWeights);
+			Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
+
+			// for the moment we write dumb min/max values for the bones, too.
+			// maybe I'll add a better, hash-like solution later
+			if (shortened) {
+				WriteBounds(&chunk,b->mWeights,b->mNumWeights);
+			} // else write as usual
+			else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
+
+			Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
+			Write<unsigned int>(&chunk,mesh->mNumVertices);
+			Write<unsigned int>(&chunk,mesh->mNumFaces);
+			Write<unsigned int>(&chunk,mesh->mNumBones);
+			Write<unsigned int>(&chunk,mesh->mMaterialIndex);
+
+			// first of all, write bits for all existent vertex components
+			unsigned int c = 0;
+			if (mesh->mVertices) {
+				c |= ASSBIN_MESH_HAS_POSITIONS;
+			}
+			if (mesh->mNormals) {
+				c |= ASSBIN_MESH_HAS_NORMALS;
+			}
+			if (mesh->mTangents && mesh->mBitangents) {
+				c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
+			}
+			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+				if (!mesh->mTextureCoords[n]) {
+					break;
+				}
+				c |= ASSBIN_MESH_HAS_TEXCOORD(n);
+			}
+			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+				if (!mesh->mColors[n]) {
+					break;
+				}
+				c |= ASSBIN_MESH_HAS_COLOR(n);
+			}
+			Write<unsigned int>(&chunk,c);
+
+			aiVector3D minVec, maxVec;
+			if (mesh->mVertices) {
+				if (shortened) {
+					WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
+				} // else write as usual
+				else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
+			}
+			if (mesh->mNormals) {
+				if (shortened) {
+					WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
+				} // else write as usual
+				else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
+			}
+			if (mesh->mTangents && mesh->mBitangents) {
+				if (shortened) {
+					WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
+					WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
+				} // else write as usual
+				else {
+					WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
+					WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
+				}
+			}
+			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+				if (!mesh->mColors[n])
+					break;
+
+				if (shortened) {
+					WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
+				} // else write as usual
+				else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
+			}
+			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+				if (!mesh->mTextureCoords[n])
+					break;
+
+				// write number of UV components
+				Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
+
+				if (shortened) {
+					WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+				} // else write as usual
+				else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+			}
+
+			// write faces. There are no floating-point calculations involved
+			// in these, so we can write a simple hash over the face data
+			// to the dump file. We generate a single 32 Bit hash for 512 faces
+			// using Assimp's standard hashing function.
+			if (shortened) {
+				unsigned int processed = 0;
+				for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
+
+					uint32_t hash = 0;
+					for (unsigned int a = 0; a < job;++a) {
+
+						const aiFace& f = mesh->mFaces[processed+a];
+						uint32_t tmp = f.mNumIndices;
+						hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
+						for (unsigned int i = 0; i < f.mNumIndices; ++i) {
+							BOOST_STATIC_ASSERT(AI_MAX_VERTICES <= 0xffffffff);
+							tmp = static_cast<uint32_t>( f.mIndices[i] );
+							hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
+						}
+					}
+					Write<unsigned int>(&chunk,hash);
+				}
+			}
+			else // else write as usual
+			{
+				// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
+				for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
+					const aiFace& f = mesh->mFaces[i];
+
+					BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff);
+					Write<uint16_t>(&chunk,f.mNumIndices);
+
+					for (unsigned int a = 0; a < f.mNumIndices;++a) {
+						if (mesh->mNumVertices < (1u<<16)) {
+							Write<uint16_t>(&chunk,f.mIndices[a]);
+						}
+						else Write<unsigned int>(&chunk,f.mIndices[a]);
+					}
+				}
+			}
+
+			// write bones
+			if (mesh->mNumBones) {
+				for (unsigned int a = 0; a < mesh->mNumBones;++a) {
+					const aiBone* b = mesh->mBones[a];
+					WriteBinaryBone(&chunk,b);
+				}
+			}
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
+
+			Write<aiString>(&chunk,prop->mKey);
+			Write<unsigned int>(&chunk,prop->mSemantic);
+			Write<unsigned int>(&chunk,prop->mIndex);
+
+			Write<unsigned int>(&chunk,prop->mDataLength);
+			Write<unsigned int>(&chunk,(unsigned int)prop->mType);
+			chunk.Write(prop->mData,1,prop->mDataLength);
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
+
+			Write<unsigned int>(&chunk,mat->mNumProperties);
+			for (unsigned int i = 0; i < mat->mNumProperties;++i) {
+				WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
+			}
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
+
+			Write<aiString>(&chunk,nd->mNodeName);
+			Write<unsigned int>(&chunk,nd->mNumPositionKeys);
+			Write<unsigned int>(&chunk,nd->mNumRotationKeys);
+			Write<unsigned int>(&chunk,nd->mNumScalingKeys);
+			Write<unsigned int>(&chunk,nd->mPreState);
+			Write<unsigned int>(&chunk,nd->mPostState);
+
+			if (nd->mPositionKeys) {
+				if (shortened) {
+					WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
+
+				} // else write as usual
+				else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
+			}
+			if (nd->mRotationKeys) {
+				if (shortened) {
+					WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
+
+				} // else write as usual
+				else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
+			}
+			if (nd->mScalingKeys) {
+				if (shortened) {
+					WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
+
+				} // else write as usual
+				else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
+			}
+		}
+
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
+
+			Write<aiString>(&chunk,anim->mName);
+			Write<double>(&chunk,anim->mDuration);
+			Write<double>(&chunk,anim->mTicksPerSecond);
+			Write<unsigned int>(&chunk,anim->mNumChannels);
+
+			for (unsigned int a = 0; a < anim->mNumChannels;++a) {
+				const aiNodeAnim* nd = anim->mChannels[a];
+				WriteBinaryNodeAnim(&chunk,nd);	
+			}
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryLight( IOStream * container, const aiLight* l )
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
+
+			Write<aiString>(&chunk,l->mName);
+			Write<unsigned int>(&chunk,l->mType);
+
+			if (l->mType != aiLightSource_DIRECTIONAL) { 
+				Write<float>(&chunk,l->mAttenuationConstant);
+				Write<float>(&chunk,l->mAttenuationLinear);
+				Write<float>(&chunk,l->mAttenuationQuadratic);
+			}
+
+			Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorDiffuse);
+			Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorSpecular);
+			Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorAmbient);
+
+			if (l->mType == aiLightSource_SPOT) {
+				Write<float>(&chunk,l->mAngleInnerCone);
+				Write<float>(&chunk,l->mAngleOuterCone);
+			}
+
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
+
+			Write<aiString>(&chunk,cam->mName);
+			Write<aiVector3D>(&chunk,cam->mPosition);
+			Write<aiVector3D>(&chunk,cam->mLookAt);
+			Write<aiVector3D>(&chunk,cam->mUp);
+			Write<float>(&chunk,cam->mHorizontalFOV);
+			Write<float>(&chunk,cam->mClipPlaneNear);
+			Write<float>(&chunk,cam->mClipPlaneFar);
+			Write<float>(&chunk,cam->mAspect);
+		}
+
+		// -----------------------------------------------------------------------------------
+		void WriteBinaryScene( IOStream * container, const aiScene* scene)
+		{
+			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
+
+			// basic scene information
+			Write<unsigned int>(&chunk,scene->mFlags);
+			Write<unsigned int>(&chunk,scene->mNumMeshes);
+			Write<unsigned int>(&chunk,scene->mNumMaterials);
+			Write<unsigned int>(&chunk,scene->mNumAnimations);
+			Write<unsigned int>(&chunk,scene->mNumTextures);
+			Write<unsigned int>(&chunk,scene->mNumLights);
+			Write<unsigned int>(&chunk,scene->mNumCameras);
+
+			// write node graph
+			WriteBinaryNode( &chunk, scene->mRootNode );
+
+			// write all meshes
+			for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
+				const aiMesh* mesh = scene->mMeshes[i];
+				WriteBinaryMesh( &chunk,mesh);
+			}
+
+			// write materials
+			for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
+				const aiMaterial* mat = scene->mMaterials[i];
+				WriteBinaryMaterial(&chunk,mat);
+			}
+
+			// write all animations
+			for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+				const aiAnimation* anim = scene->mAnimations[i];
+				WriteBinaryAnim(&chunk,anim);
+			}
+
+
+			// write all textures
+			for (unsigned int i = 0; i < scene->mNumTextures;++i) {
+				const aiTexture* mesh = scene->mTextures[i];
+				WriteBinaryTexture(&chunk,mesh);
+			}
+
+			// write lights
+			for (unsigned int i = 0; i < scene->mNumLights;++i) {
+				const aiLight* l = scene->mLights[i];
+				WriteBinaryLight(&chunk,l);
+			}
+
+			// write cameras
+			for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+				const aiCamera* cam = scene->mCameras[i];
+				WriteBinaryCamera(&chunk,cam);
+			}
+
+		}
+
+	public:
+		AssbinExport() 
+			: shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
+		{
+		}
+
+		// -----------------------------------------------------------------------------------
+		// Write a binary model dump
+		void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+		{
+			IOStream * out = pIOSystem->Open( pFile, "wb" );
+			if (!out) return;
+
+			time_t tt = time(NULL);
+			tm* p     = gmtime(&tt);
+
+			// header
+			char s[64];
+			memset( s, 0, 64 );
+#if _MSC_VER >= 1400
+			sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
+#else
+			snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
+#endif
+			out->Write( s, 44, 1 );
+			// == 44 bytes
+
+			Write<unsigned int>( out, ASSBIN_VERSION_MAJOR );
+			Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
+			Write<unsigned int>( out, aiGetVersionRevision() );
+			Write<unsigned int>( out, aiGetCompileFlags() );
+			Write<uint16_t>( out, shortened );
+			Write<uint16_t>( out, compressed );
+			// ==  20 bytes
+
+			char buff[256]; 
+			strncpy(buff,pFile,256);
+			out->Write(buff,sizeof(char),256);
+
+			char cmd[] = "\0";
+			strncpy(buff,cmd,128);
+			out->Write(buff,sizeof(char),128);
+
+			// leave 64 bytes free for future extensions
+			memset(buff,0xcd,64);
+			out->Write(buff,sizeof(char),64);
+			// == 435 bytes
+
+			// ==== total header size: 512 bytes
+			ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH );
+
+			// Up to here the data is uncompressed. For compressed files, the rest
+			// is compressed using standard DEFLATE from zlib.
+			if (compressed)
+			{
+				AssbinChunkWriter uncompressedStream( NULL, 0 );
+				WriteBinaryScene( &uncompressedStream, pScene );
+
+				uLongf uncompressedSize = uncompressedStream.Tell();
+				uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.);
+				uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
+
+				compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
+
+				out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
+				out->Write( compressedBuffer, sizeof(char), compressedSize );
+
+				delete[] compressedBuffer;
+			}
+			else
+			{
+				WriteBinaryScene( out, pScene );
+			}
+
+			pIOSystem->Close( out );
+		}
+	};
+
+void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+{
+	AssbinExport exporter;
+	exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
+}
+} // end of namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_ASSBIN_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 49 - 0
code/AssbinExporter.h

@@ -0,0 +1,49 @@
+/*
+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 AssbinExporter.h
+ * ASSBIN Exporter Main Header
+ */
+#ifndef AI_ASSBINEXPORTER_H_INC
+#define AI_ASSBINEXPORTER_H_INC
+
+// nothing really needed here - reserved for future use like properties
+
+#endif

+ 672 - 0
code/AssbinLoader.cpp

@@ -0,0 +1,672 @@
+/*
+---------------------------------------------------------------------------
+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  AssbinLoader.cpp
+ *  @brief Implementation of the .assbin importer class
+ *
+ *  see assbin_chunks.h
+ */
+
+#include "AssimpPCH.h"
+#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
+
+// internal headers
+#include "AssbinLoader.h"
+#include "assbin_chunks.h"
+#include "MemoryIOWrapper.h"
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#	include <zlib.h>
+#else
+#	include "../contrib/zlib/zlib.h"
+#endif
+
+using namespace Assimp;
+
+static const aiImporterDesc desc = {
+	".assbin Importer",
+	"Gargaj / Conspiracy",
+	"",
+	"",
+	aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
+	0,
+	0,
+	0,
+	0,
+	"assbin" 
+};
+
+const aiImporterDesc* AssbinImporter::GetInfo() const
+{
+	return &desc;
+}
+
+bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const
+{
+	IOStream * in = pIOHandler->Open(pFile);
+	if (!in)
+		return false;
+
+	char s[32];
+	in->Read( s, sizeof(char), 32 );
+
+	pIOHandler->Close(in);
+
+	return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
+}
+
+template <typename T>
+T Read(IOStream * stream)
+{
+	T t;
+	stream->Read( &t, sizeof(T), 1 );
+	return t;
+}
+
+template <>
+aiVector3D Read<aiVector3D>(IOStream * stream)
+{
+	aiVector3D v;
+	v.x = Read<float>(stream);
+	v.y = Read<float>(stream);
+	v.z = Read<float>(stream);
+	return v;
+}
+
+template <>
+aiColor4D Read<aiColor4D>(IOStream * stream)
+{
+	aiColor4D c;
+	c.r = Read<float>(stream);
+	c.g = Read<float>(stream);
+	c.b = Read<float>(stream);
+	c.a = Read<float>(stream);
+	return c;
+}
+
+template <>
+aiQuaternion Read<aiQuaternion>(IOStream * stream)
+{
+	aiQuaternion v;
+	v.w = Read<float>(stream);
+	v.x = Read<float>(stream);
+	v.y = Read<float>(stream);
+	v.z = Read<float>(stream);
+	return v;
+}
+
+template <>
+aiString Read<aiString>(IOStream * stream)
+{
+	aiString s;
+	stream->Read(&s.length,4,1);
+	stream->Read(s.data,s.length,1);
+	s.data[s.length] = 0;
+	return s;
+}
+
+template <>
+aiVertexWeight Read<aiVertexWeight>(IOStream * stream)
+{
+	aiVertexWeight w;
+	w.mVertexId = Read<unsigned int>(stream);
+	w.mWeight = Read<float>(stream);
+	return w;
+}
+
+template <>
+aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream)
+{
+	aiMatrix4x4 m;
+	for (unsigned int i = 0; i < 4;++i) {
+		for (unsigned int i2 = 0; i2 < 4;++i2) {
+			m[i][i2] = Read<float>(stream);
+		}
+	}
+	return m;
+}
+
+template <>
+aiVectorKey Read<aiVectorKey>(IOStream * stream)
+{
+	aiVectorKey v;
+	v.mTime = Read<double>(stream);
+	v.mValue = Read<aiVector3D>(stream);
+	return v;
+}
+
+template <>
+aiQuatKey Read<aiQuatKey>(IOStream * stream)
+{
+	aiQuatKey v;
+	v.mTime = Read<double>(stream);
+	v.mValue = Read<aiQuaternion>(stream);
+	return v;
+}
+
+template <typename T>
+void ReadArray(IOStream * stream, T * out, unsigned int size)
+{ 
+	for (unsigned int i=0; i<size; i++) out[i] = Read<T>(stream);
+}
+
+template <typename T> void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n )
+{
+	// not sure what to do here, the data isn't really useful.
+	stream->Seek( sizeof(T) * n, aiOrigin_CUR );
+}
+
+void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node )
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AINODE);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	*node = new aiNode();
+
+	(*node)->mName = Read<aiString>(stream);
+	(*node)->mTransformation = Read<aiMatrix4x4>(stream);
+	(*node)->mNumChildren = Read<unsigned int>(stream);
+	(*node)->mNumMeshes = Read<unsigned int>(stream);
+
+	if ((*node)->mNumMeshes)
+	{
+		(*node)->mMeshes = new unsigned int[(*node)->mNumMeshes];
+		for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) {
+			(*node)->mMeshes[i] = Read<unsigned int>(stream);
+		}
+	}
+
+	if ((*node)->mNumChildren)
+	{
+		(*node)->mChildren = new aiNode*[(*node)->mNumChildren];
+		for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) {
+			ReadBinaryNode( stream, &(*node)->mChildren[i] );
+		}
+	}
+
+}
+
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AIBONE );
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	b->mName = Read<aiString>(stream);
+	b->mNumWeights = Read<unsigned int>(stream);
+	b->mOffsetMatrix = Read<aiMatrix4x4>(stream);
+
+	// for the moment we write dumb min/max values for the bones, too.
+	// maybe I'll add a better, hash-like solution later
+	if (shortened) 
+	{
+		ReadBounds(stream,b->mWeights,b->mNumWeights);
+	} // else write as usual
+	else 
+	{
+		b->mWeights = new aiVertexWeight[b->mNumWeights];
+		ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
+	}
+}
+
+
+void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AIMESH);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	mesh->mPrimitiveTypes = Read<unsigned int>(stream);
+	mesh->mNumVertices = Read<unsigned int>(stream);
+	mesh->mNumFaces = Read<unsigned int>(stream);
+	mesh->mNumBones = Read<unsigned int>(stream);
+	mesh->mMaterialIndex = Read<unsigned int>(stream);
+
+	// first of all, write bits for all existent vertex components
+	unsigned int c = Read<unsigned int>(stream);
+
+	if (c & ASSBIN_MESH_HAS_POSITIONS) 
+	{
+		if (shortened) {
+			ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
+		} // else write as usual
+		else 
+		{
+			mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+			ReadArray<aiVector3D>(stream,mesh->mVertices,mesh->mNumVertices);
+		}
+	}
+	if (c & ASSBIN_MESH_HAS_NORMALS) 
+	{
+		if (shortened) {
+			ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
+		} // else write as usual
+		else 
+		{
+			mesh->mNormals = new aiVector3D[mesh->mNumVertices];
+			ReadArray<aiVector3D>(stream,mesh->mNormals,mesh->mNumVertices);
+		}
+	}
+	if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) 
+	{
+		if (shortened) {
+			ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
+			ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
+		} // else write as usual
+		else 
+		{
+			mesh->mTangents = new aiVector3D[mesh->mNumVertices];
+			ReadArray<aiVector3D>(stream,mesh->mTangents,mesh->mNumVertices);
+			mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
+			ReadArray<aiVector3D>(stream,mesh->mBitangents,mesh->mNumVertices);
+		}
+	}
+	for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) 
+	{
+		if (!(c & ASSBIN_MESH_HAS_COLOR(n)))
+			break;
+
+		if (shortened) 
+		{
+			ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
+		} // else write as usual
+		else 
+		{
+			mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
+			ReadArray<aiColor4D>(stream,mesh->mColors[n],mesh->mNumVertices);
+		}
+	}
+	for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) 
+	{
+		if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n)))
+			break;
+
+		// write number of UV components
+		mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
+
+		if (shortened) {
+			ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
+		} // else write as usual
+		else 
+		{
+			mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
+			ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
+		}
+	}
+
+	// write faces. There are no floating-point calculations involved
+	// in these, so we can write a simple hash over the face data
+	// to the dump file. We generate a single 32 Bit hash for 512 faces
+	// using Assimp's standard hashing function.
+	if (shortened) {
+		Read<unsigned int>(stream);
+	}
+	else // else write as usual
+	{
+		// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
+		mesh->mFaces = new aiFace[mesh->mNumFaces];
+		for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
+			aiFace& f = mesh->mFaces[i];
+
+			BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff);
+			f.mNumIndices = Read<uint16_t>(stream);
+			f.mIndices = new unsigned int[f.mNumIndices];
+
+			for (unsigned int a = 0; a < f.mNumIndices;++a) {
+				if (mesh->mNumVertices < (1u<<16)) 
+				{
+					f.mIndices[a] = Read<uint16_t>(stream);
+				}
+				else 
+				{
+					f.mIndices[a] = Read<unsigned int>(stream);
+				}
+			}
+		}
+	}
+
+	// write bones
+	if (mesh->mNumBones) {
+		mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones];
+		for (unsigned int a = 0; a < mesh->mNumBones;++a) {
+			mesh->mBones[a] = new aiBone();
+			ReadBinaryBone(stream,mesh->mBones[a]);
+		}
+	}
+}
+
+void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop)
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AIMATERIALPROPERTY);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	prop->mKey = Read<aiString>(stream);
+	prop->mSemantic = Read<unsigned int>(stream);
+	prop->mIndex = Read<unsigned int>(stream);
+
+	prop->mDataLength = Read<unsigned int>(stream);
+	prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
+	prop->mData = new char [ prop->mDataLength ];
+	stream->Read(prop->mData,1,prop->mDataLength);
+}
+
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AIMATERIAL);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
+	if (mat->mNumProperties)
+	{
+		if (mat->mProperties) 
+		{
+			delete[] mat->mProperties;
+		}
+		mat->mProperties = new aiMaterialProperty*[mat->mNumProperties];
+		for (unsigned int i = 0; i < mat->mNumProperties;++i) {
+			mat->mProperties[i] = new aiMaterialProperty();
+			ReadBinaryMaterialProperty( stream, mat->mProperties[i]);
+		}
+	}
+}
+
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AINODEANIM);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	nd->mNodeName = Read<aiString>(stream);
+	nd->mNumPositionKeys = Read<unsigned int>(stream);
+	nd->mNumRotationKeys = Read<unsigned int>(stream);
+	nd->mNumScalingKeys = Read<unsigned int>(stream);
+	nd->mPreState = (aiAnimBehaviour)Read<unsigned int>(stream);
+	nd->mPostState = (aiAnimBehaviour)Read<unsigned int>(stream);
+
+	if (nd->mNumPositionKeys) {
+		if (shortened) {
+			ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys);
+
+		} // else write as usual
+		else {
+			nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
+			ReadArray<aiVectorKey>(stream,nd->mPositionKeys,nd->mNumPositionKeys);
+		}
+	}
+	if (nd->mNumRotationKeys) {
+		if (shortened) {
+			ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
+
+		} // else write as usual
+		else 
+		{
+			nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
+			ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
+		}
+	}
+	if (nd->mNumScalingKeys) {
+		if (shortened) {
+			ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
+
+		} // else write as usual
+		else 
+		{
+			nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
+			ReadArray<aiVectorKey>(stream,nd->mScalingKeys,nd->mNumScalingKeys);
+		}
+	}
+}
+
+
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AIANIMATION);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	anim->mName = Read<aiString> (stream);
+	anim->mDuration = Read<double> (stream);
+	anim->mTicksPerSecond = Read<double> (stream);
+	anim->mNumChannels = Read<unsigned int>(stream);
+
+	if (anim->mNumChannels)
+	{
+		anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
+		for (unsigned int a = 0; a < anim->mNumChannels;++a) {
+			anim->mChannels[a] = new aiNodeAnim();
+			ReadBinaryNodeAnim(stream,anim->mChannels[a]);
+		}
+	}
+}
+
+void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AITEXTURE);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	tex->mWidth = Read<unsigned int>(stream);
+	tex->mHeight = Read<unsigned int>(stream);
+	stream->Read( tex->achFormatHint, sizeof(char), 4 );
+
+	if(!shortened) {
+		if (!tex->mHeight) {
+			tex->pcData = new aiTexel[ tex->mWidth ];
+			stream->Read(tex->pcData,1,tex->mWidth);
+		}
+		else {
+			tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
+			stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
+		}
+	}
+
+}
+
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AILIGHT);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	l->mName = Read<aiString>(stream);
+	l->mType = (aiLightSourceType)Read<unsigned int>(stream);
+
+	if (l->mType != aiLightSource_DIRECTIONAL) { 
+		l->mAttenuationConstant = Read<float>(stream);
+		l->mAttenuationLinear = Read<float>(stream);
+		l->mAttenuationQuadratic = Read<float>(stream);
+	}
+
+	l->mColorDiffuse = Read<aiColor3D>(stream);
+	l->mColorSpecular = Read<aiColor3D>(stream);
+	l->mColorAmbient = Read<aiColor3D>(stream);
+
+	if (l->mType == aiLightSource_SPOT) {
+		l->mAngleInnerCone = Read<float>(stream);
+		l->mAngleOuterCone = Read<float>(stream);
+	}
+
+}
+
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AICAMERA);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	cam->mName = Read<aiString>(stream);
+	cam->mPosition = Read<aiVector3D>(stream);
+	cam->mLookAt = Read<aiVector3D>(stream);
+	cam->mUp = Read<aiVector3D>(stream);
+	cam->mHorizontalFOV = Read<float>(stream);
+	cam->mClipPlaneNear = Read<float>(stream);
+	cam->mClipPlaneFar = Read<float>(stream);
+	cam->mAspect = Read<float>(stream);
+}
+
+void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
+{
+	ai_assert( Read<uint32_t>(stream) == ASSBIN_CHUNK_AISCENE);
+	/*uint32_t size =*/ Read<uint32_t>(stream);
+
+	scene->mFlags         = Read<unsigned int>(stream);
+	scene->mNumMeshes     = Read<unsigned int>(stream);
+	scene->mNumMaterials  = Read<unsigned int>(stream);
+	scene->mNumAnimations = Read<unsigned int>(stream);
+	scene->mNumTextures   = Read<unsigned int>(stream);
+	scene->mNumLights     = Read<unsigned int>(stream);
+	scene->mNumCameras    = Read<unsigned int>(stream);
+
+	// Read node graph
+	scene->mRootNode = new aiNode[1];
+	ReadBinaryNode( stream, &scene->mRootNode );
+
+	// Read all meshes
+	if (scene->mNumMeshes)
+	{
+		scene->mMeshes = new aiMesh*[scene->mNumMeshes];
+		for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
+			scene->mMeshes[i] = new aiMesh();
+			ReadBinaryMesh( stream,scene->mMeshes[i]);
+		}
+	}
+
+	// Read materials
+	if (scene->mNumMaterials)
+	{
+		scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
+		for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
+			scene->mMaterials[i] = new aiMaterial();
+			ReadBinaryMaterial(stream,scene->mMaterials[i]);
+		}
+	}
+
+	// Read all animations
+	if (scene->mNumAnimations)
+	{
+		scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
+		for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+			scene->mAnimations[i] = new aiAnimation();
+			ReadBinaryAnim(stream,scene->mAnimations[i]);
+		}
+	}
+
+	// Read all textures
+	if (scene->mNumTextures)
+	{
+		scene->mTextures = new aiTexture*[scene->mNumTextures];
+		for (unsigned int i = 0; i < scene->mNumTextures;++i) {
+			scene->mTextures[i] = new aiTexture();
+			ReadBinaryTexture(stream,scene->mTextures[i]);
+		}
+	}
+
+	// Read lights
+	if (scene->mNumLights)
+	{
+		scene->mLights = new aiLight*[scene->mNumLights];
+		for (unsigned int i = 0; i < scene->mNumLights;++i) {
+			scene->mLights[i] = new aiLight();
+			ReadBinaryLight(stream,scene->mLights[i]);
+		}
+	}
+
+	// Read cameras
+	if (scene->mNumCameras)
+	{
+		scene->mCameras = new aiCamera*[scene->mNumCameras];
+		for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+			scene->mCameras[i] = new aiCamera();
+			ReadBinaryCamera(stream,scene->mCameras[i]);
+		}
+	}
+
+}
+
+void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler )
+{
+	IOStream * stream = pIOHandler->Open(pFile,"rb");
+	if (!stream)
+		return;
+
+	stream->Seek( 44, aiOrigin_CUR ); // signature
+
+	/*unsigned int versionMajor =*/ Read<unsigned int>(stream);
+	/*unsigned int versionMinor =*/ Read<unsigned int>(stream);
+	/*unsigned int versionRevision =*/ Read<unsigned int>(stream);
+	/*unsigned int compileFlags =*/ Read<unsigned int>(stream);
+
+	shortened = Read<uint16_t>(stream) > 0;
+	compressed = Read<uint16_t>(stream) > 0;
+
+	if (shortened)
+		throw DeadlyImportError( "Shortened binaries are not supported!" );
+
+	stream->Seek( 256, aiOrigin_CUR ); // original filename
+	stream->Seek( 128, aiOrigin_CUR ); // options
+	stream->Seek( 64, aiOrigin_CUR ); // padding
+
+	if (compressed)
+	{
+		uLongf uncompressedSize = Read<uint32_t>(stream);
+		uLongf compressedSize = stream->FileSize() - stream->Tell();
+
+		unsigned char * compressedData = new unsigned char[ compressedSize ];
+		stream->Read( compressedData, 1, compressedSize );
+
+		unsigned char * uncompressedData = new unsigned char[ uncompressedSize ];
+
+		uncompress( uncompressedData, &uncompressedSize, compressedData, compressedSize );
+
+		MemoryIOStream io( uncompressedData, uncompressedSize );
+
+		ReadBinaryScene(&io,pScene);
+
+		delete[] uncompressedData;
+		delete[] compressedData;
+	}
+	else
+	{
+		ReadBinaryScene(stream,pScene);
+	}
+	
+	pIOHandler->Close(stream);
+}
+
+#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER

+ 94 - 0
code/AssbinLoader.h

@@ -0,0 +1,94 @@
+
+/*
+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  AssbinLoader.h
+ *  @brief .assbin File format loader
+ */
+#ifndef AI_ASSBINIMPORTER_H_INC
+#define AI_ASSBINIMPORTER_H_INC
+
+#include "BaseImporter.h"
+#include "../include/assimp/types.h"
+
+#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
+
+namespace Assimp	{
+
+// ---------------------------------------------------------------------------------
+/** Importer class for 3D Studio r3 and r4 3DS files
+ */
+class AssbinImporter : public BaseImporter
+{
+private:
+  bool shortened;
+  bool compressed;
+protected:
+
+public:
+  virtual bool CanRead( 
+    const std::string& pFile, 
+    IOSystem* pIOHandler, 
+    bool checkSig
+    ) const;
+  virtual const aiImporterDesc* GetInfo() const;
+  virtual void InternReadFile( 
+    const std::string& pFile, 
+    aiScene* pScene, 
+    IOSystem* pIOHandler
+    );
+  void ReadBinaryScene( IOStream * stream, aiScene* pScene );
+  void ReadBinaryNode( IOStream * stream, aiNode** mRootNode );
+  void ReadBinaryMesh( IOStream * stream, aiMesh* mesh );
+  void ReadBinaryBone( IOStream * stream, aiBone* bone );
+  void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat);
+  void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop);
+  void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd);
+  void ReadBinaryAnim( IOStream * stream, aiAnimation* anim );
+  void ReadBinaryTexture(IOStream * stream, aiTexture* tex);
+  void ReadBinaryLight( IOStream * stream, aiLight* l );
+  void ReadBinaryCamera( IOStream * stream, aiCamera* cam );
+};
+
+} // end of namespace Assimp
+
+#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER
+
+#endif // AI_ASSBINIMPORTER_H_INC

+ 24 - 1
code/Assimp.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "GenericProperty.h"
 #include "GenericProperty.h"
 #include "CInterfaceIOWrapper.h"
 #include "CInterfaceIOWrapper.h"
+#include "../include/assimp/importerdesc.h"
 #include "Importer.h"
 #include "Importer.h"
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -84,7 +85,11 @@ namespace Assimp
 
 
 	/** Verbose logging active or not? */
 	/** Verbose logging active or not? */
 	static aiBool gVerboseLogging = false;
 	static aiBool gVerboseLogging = false;
-}
+
+    /** will return all registered importers. */
+    void GetImporterInstanceList(std::vector< BaseImporter* >& out);
+
+} // namespace assimp
 
 
 
 
 #ifndef ASSIMP_BUILD_SINGLETHREADED
 #ifndef ASSIMP_BUILD_SINGLETHREADED
@@ -606,4 +611,22 @@ ASSIMP_API void aiIdentityMatrix4(
 	*mat = aiMatrix4x4();
 	*mat = aiMatrix4x4();
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) {
+    if( NULL == extension ) {
+        return NULL;
+    }
+    const aiImporterDesc *desc( NULL );
+    std::vector< BaseImporter* > out;
+    GetImporterInstanceList( out );
+    for( size_t i = 0; i < out.size(); ++i ) {
+        if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) {
+            desc = out[ i ]->GetInfo();
+            break;
+        }
+    }
 
 
+    return desc;
+}
+
+// ------------------------------------------------------------------------------------------------

+ 2 - 0
code/AssimpCExport.cpp

@@ -61,6 +61,8 @@ ASSIMP_API size_t aiGetExportFormatCount(void)
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
 ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
 {
 {
+	// Note: this is valid as the index always pertains to a builtin exporter,
+	// for which the returned structure is guaranteed to be of static storage duration.
 	return Exporter().GetExportFormatDescription(pIndex);
 	return Exporter().GetExportFormatDescription(pIndex);
 }
 }
 
 

+ 638 - 0
code/AssxmlExporter.cpp

@@ -0,0 +1,638 @@
+/*
+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  AssxmlExporter.cpp
+ *  ASSXML exporter main code
+ */
+#include <stdarg.h>
+#include "AssimpPCH.h"
+#include "./../include/assimp/version.h"
+#include "ProcessHelper.h"
+
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#	include <zlib.h>
+#else
+#	include "../contrib/zlib/zlib.h"
+#endif
+
+#include <time.h>
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
+
+using namespace Assimp;
+
+namespace Assimp	{
+
+namespace AssxmlExport	{
+
+int ioprintf( IOStream * io, const char * format, ... )
+{
+	char sz[4096];
+	va_list va;
+	va_start( va, format );
+	int nSize = vsnprintf( sz, 4096, format, va );
+  ai_assert( nSize < 4096 );
+	va_end( va );
+
+	io->Write( sz, sizeof(char), nSize );
+
+	return nSize;
+}
+
+// -----------------------------------------------------------------------------------
+// Convert a name to standard XML format
+void ConvertName(aiString& out, const aiString& in)
+{
+	out.length = 0;
+	for (unsigned int i = 0; i < in.length; ++i)  {
+		switch (in.data[i]) {
+			case '<':
+				out.Append("&lt;");break;
+			case '>':
+				out.Append("&gt;");break;
+			case '&':
+				out.Append("&amp;");break;
+			case '\"':
+				out.Append("&quot;");break;
+			case '\'':
+				out.Append("&apos;");break;
+			default:
+				out.data[out.length++] = in.data[i];
+		}
+	}
+	out.data[out.length] = 0;
+}
+
+// -----------------------------------------------------------------------------------
+// Write a single node as text dump
+void WriteNode(const aiNode* node, IOStream * io, unsigned int depth)
+{
+	char prefix[512];
+	for (unsigned int i = 0; i < depth;++i)
+		prefix[i] = '\t';
+	prefix[depth] = '\0';
+
+	const aiMatrix4x4& m = node->mTransformation;
+
+	aiString name;
+	ConvertName(name,node->mName);
+	ioprintf(io,"%s<Node name=\"%s\"> \n"
+		"%s\t<Matrix4> \n"
+		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+		"%s\t</Matrix4> \n",
+		prefix,name.data,prefix,
+		prefix,m.a1,m.a2,m.a3,m.a4,
+		prefix,m.b1,m.b2,m.b3,m.b4,
+		prefix,m.c1,m.c2,m.c3,m.c4,
+		prefix,m.d1,m.d2,m.d3,m.d4,prefix);
+
+	if (node->mNumMeshes) {
+		ioprintf(io, "%s\t<MeshRefs num=\"%i\">\n%s\t",
+			prefix,node->mNumMeshes,prefix);
+
+		for (unsigned int i = 0; i < node->mNumMeshes;++i) {
+			ioprintf(io,"%i ",node->mMeshes[i]);
+		}
+		ioprintf(io,"\n%s\t</MeshRefs>\n",prefix);
+	}
+
+	if (node->mNumChildren) {
+		ioprintf(io,"%s\t<NodeList num=\"%i\">\n",
+			prefix,node->mNumChildren);
+
+		for (unsigned int i = 0; i < node->mNumChildren;++i) {
+			WriteNode(node->mChildren[i],io,depth+2);
+		}
+		ioprintf(io,"%s\t</NodeList>\n",prefix);
+	}
+	ioprintf(io,"%s</Node>\n",prefix);
+}
+
+
+// -----------------------------------------------------------------------------------
+// Some chuncks of text will need to be encoded for XML
+// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377
+static std::string encodeXML(const std::string& data) {
+		std::string buffer;
+		buffer.reserve(data.size());
+		for(size_t pos = 0; pos != data.size(); ++pos) {
+				switch(data[pos]) {
+						case '&':  buffer.append("&amp;");				break;
+						case '\"': buffer.append("&quot;");				break;
+						case '\'': buffer.append("&apos;");				break;
+						case '<':  buffer.append("&lt;");					break;
+						case '>':  buffer.append("&gt;");					break;
+						default:   buffer.append(&data[pos], 1);	break;
+				}
+		}
+		return buffer;
+}
+
+
+
+// -----------------------------------------------------------------------------------
+// Write a text model dump
+void WriteDump(const aiScene* scene, IOStream* io, bool shortened)
+{
+	time_t tt = ::time(NULL);
+	tm* p     = ::gmtime(&tt);
+
+	aiString name;
+
+	// write header
+	ioprintf(io,
+		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+		"<ASSIMP format_id=\"1\">\n\n"
+
+		"<!-- XML Model dump produced by assimp dump\n"
+		"  Library version: %i.%i.%i\n"
+		"  %s\n"
+		"-->"
+		" \n\n"
+		"<Scene flags=\"%i\" postprocessing=\"%i\">\n",
+		
+		aiGetVersionMajor(),aiGetVersionMinor(),aiGetVersionRevision(),asctime(p),
+		scene->mFlags,
+		0 /*globalImporter->GetEffectivePostProcessing()*/);
+
+	// write the node graph
+	WriteNode(scene->mRootNode, io, 0);
+
+#if 0
+		// write cameras
+	for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+		aiCamera* cam  = scene->mCameras[i];
+		ConvertName(name,cam->mName);
+
+		// camera header
+		ioprintf(io,"\t<Camera parent=\"%s\">\n"
+			"\t\t<Vector3 name=\"up\"        > %0 8f %0 8f %0 8f </Vector3>\n"
+			"\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n"
+			"\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
+			"\t\t<Float   name=\"fov\"       > %f </Float>\n"
+			"\t\t<Float   name=\"aspect\"    > %f </Float>\n"
+			"\t\t<Float   name=\"near_clip\" > %f </Float>\n"
+			"\t\t<Float   name=\"far_clip\"  > %f </Float>\n"
+			"\t</Camera>\n",
+			name.data,
+			cam->mUp.x,cam->mUp.y,cam->mUp.z,
+			cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
+			cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
+			cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
+	}
+
+	// write lights
+	for (unsigned int i = 0; i < scene->mNumLights;++i) {
+		aiLight* l  = scene->mLights[i];
+		ConvertName(name,l->mName);
+
+		// light header
+		ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
+			"\t\t<Vector3 name=\"diffuse\"   > %0 8f %0 8f %0 8f </Vector3>\n"
+			"\t\t<Vector3 name=\"specular\"  > %0 8f %0 8f %0 8f </Vector3>\n"
+			"\t\t<Vector3 name=\"ambient\"   > %0 8f %0 8f %0 8f </Vector3>\n",
+			name.data,
+			(l->mType == aiLightSource_DIRECTIONAL ? "directional" :
+			(l->mType == aiLightSource_POINT ? "point" : "spot" )),
+			l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
+			l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
+			l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
+
+		if (l->mType != aiLightSource_DIRECTIONAL) {
+			ioprintf(io,
+				"\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
+				"\t\t<Float   name=\"atten_cst\" > %f </Float>\n"
+				"\t\t<Float   name=\"atten_lin\" > %f </Float>\n"
+				"\t\t<Float   name=\"atten_sqr\" > %f </Float>\n",
+				l->mPosition.x,l->mPosition.y,l->mPosition.z,
+				l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
+		}
+
+		if (l->mType != aiLightSource_POINT) {
+			ioprintf(io,
+				"\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n",
+				l->mDirection.x,l->mDirection.y,l->mDirection.z);
+		}
+
+		if (l->mType == aiLightSource_SPOT) {
+			ioprintf(io,
+				"\t\t<Float   name=\"cone_out\" > %f </Float>\n"
+				"\t\t<Float   name=\"cone_inn\" > %f </Float>\n",
+				l->mAngleOuterCone,l->mAngleInnerCone);
+		}
+		ioprintf(io,"\t</Light>\n");
+	}
+#endif
+
+	// write textures
+	if (scene->mNumTextures) {
+		ioprintf(io,"<TextureList num=\"%i\">\n",scene->mNumTextures);
+		for (unsigned int i = 0; i < scene->mNumTextures;++i) {
+			aiTexture* tex  = scene->mTextures[i];
+			bool compressed = (tex->mHeight == 0);
+
+			// mesh header
+			ioprintf(io,"\t<Texture width=\"%i\" height=\"%i\" compressed=\"%s\"> \n",
+				(compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight),
+				(compressed ? "true" : "false"));
+
+			if (compressed) {
+				ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth);
+
+				if (!shortened) {
+					for (unsigned int n = 0; n < tex->mWidth;++n) {
+						ioprintf(io,"\t\t\t%2x",reinterpret_cast<uint8_t*>(tex->pcData)[n]);
+						if (n && !(n % 50)) {
+							ioprintf(io,"\n");
+						}
+					}
+				}
+			}
+			else if (!shortened){
+				ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth*tex->mHeight*4);
+
+				// const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1;
+				for (unsigned int y = 0; y < tex->mHeight;++y) {
+					for (unsigned int x = 0; x < tex->mWidth;++x) {
+						aiTexel* tx = tex->pcData + y*tex->mWidth+x;
+						unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a;
+						ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a);
+
+						// group by four for readibility
+						if (0 == (x+y*tex->mWidth) % 4)
+							ioprintf(io,"\n");
+					}
+				}
+			}
+			ioprintf(io,"\t\t</Data>\n\t</Texture>\n");
+		}
+		ioprintf(io,"</TextureList>\n");
+	}
+
+	// write materials
+	if (scene->mNumMaterials) {
+		ioprintf(io,"<MaterialList num=\"%i\">\n",scene->mNumMaterials);
+		for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
+			const aiMaterial* mat = scene->mMaterials[i];
+
+			ioprintf(io,"\t<Material>\n");
+			ioprintf(io,"\t\t<MatPropertyList  num=\"%i\">\n",mat->mNumProperties);
+			for (unsigned int n = 0; n < mat->mNumProperties;++n) {
+
+				const aiMaterialProperty* prop = mat->mProperties[n];
+				const char* sz = "";
+				if (prop->mType == aiPTI_Float) {
+					sz = "float";
+				}
+				else if (prop->mType == aiPTI_Integer) {
+					sz = "integer";
+				}
+				else if (prop->mType == aiPTI_String) {
+					sz = "string";
+				}
+				else if (prop->mType == aiPTI_Buffer) {
+					sz = "binary_buffer";
+				}
+
+				ioprintf(io,"\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%i\"",
+					prop->mKey.data, sz,
+					::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex);
+
+				if (prop->mType == aiPTI_Float) {
+					ioprintf(io," size=\"%i\">\n\t\t\t\t",
+						static_cast<int>(prop->mDataLength/sizeof(float)));
+
+					for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) {
+						ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float))));
+					}
+				}
+				else if (prop->mType == aiPTI_Integer) {
+					ioprintf(io," size=\"%i\">\n\t\t\t\t",
+						static_cast<int>(prop->mDataLength/sizeof(int)));
+
+					for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) {
+						ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int))));
+					}
+				}
+				else if (prop->mType == aiPTI_Buffer) {
+					ioprintf(io," size=\"%i\">\n\t\t\t\t",
+						static_cast<int>(prop->mDataLength));
+
+					for (unsigned int p = 0; p < prop->mDataLength;++p) {
+						ioprintf(io,"%2x ",prop->mData[p]);
+						if (p && 0 == p%30) {
+							ioprintf(io,"\n\t\t\t\t");
+						}
+					}
+				}
+				else if (prop->mType == aiPTI_String) {
+					ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */);
+				}
+				ioprintf(io,"\n\t\t\t</MatProperty>\n");
+			}
+			ioprintf(io,"\t\t</MatPropertyList>\n");
+			ioprintf(io,"\t</Material>\n");
+		}
+		ioprintf(io,"</MaterialList>\n");
+	}
+
+	// write animations
+	if (scene->mNumAnimations) {
+		ioprintf(io,"<AnimationList num=\"%i\">\n",scene->mNumAnimations);
+		for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+			aiAnimation* anim = scene->mAnimations[i];
+
+			// anim header
+			ConvertName(name,anim->mName);
+			ioprintf(io,"\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
+				name.data, anim->mDuration, anim->mTicksPerSecond);
+
+			// write bone animation channels
+			if (anim->mNumChannels) {
+				ioprintf(io,"\t\t<NodeAnimList num=\"%i\">\n",anim->mNumChannels);
+				for (unsigned int n = 0; n < anim->mNumChannels;++n) {
+					aiNodeAnim* nd = anim->mChannels[n];
+
+					// node anim header
+					ConvertName(name,nd->mNodeName);
+					ioprintf(io,"\t\t\t<NodeAnim node=\"%s\">\n",name.data);
+
+					if (!shortened) {
+						// write position keys
+						if (nd->mNumPositionKeys) {
+							ioprintf(io,"\t\t\t\t<PositionKeyList num=\"%i\">\n",nd->mNumPositionKeys);
+							for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) {
+								aiVectorKey* vc = nd->mPositionKeys+a;
+								ioprintf(io,"\t\t\t\t\t<PositionKey time=\"%e\">\n"
+									"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
+									vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
+							}
+							ioprintf(io,"\t\t\t\t</PositionKeyList>\n");
+						}
+
+						// write scaling keys
+						if (nd->mNumScalingKeys) {
+							ioprintf(io,"\t\t\t\t<ScalingKeyList num=\"%i\">\n",nd->mNumScalingKeys);
+							for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) {
+								aiVectorKey* vc = nd->mScalingKeys+a;
+								ioprintf(io,"\t\t\t\t\t<ScalingKey time=\"%e\">\n"
+									"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
+									vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
+							}
+							ioprintf(io,"\t\t\t\t</ScalingKeyList>\n");
+						}
+
+						// write rotation keys
+						if (nd->mNumRotationKeys) {
+							ioprintf(io,"\t\t\t\t<RotationKeyList num=\"%i\">\n",nd->mNumRotationKeys);
+							for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) {
+								aiQuatKey* vc = nd->mRotationKeys+a;
+								ioprintf(io,"\t\t\t\t\t<RotationKey time=\"%e\">\n"
+									"\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
+									vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w);
+							}
+							ioprintf(io,"\t\t\t\t</RotationKeyList>\n");
+						}
+					}
+					ioprintf(io,"\t\t\t</NodeAnim>\n");
+				}
+				ioprintf(io,"\t\t</NodeAnimList>\n");
+			}
+			ioprintf(io,"\t</Animation>\n");
+		}
+		ioprintf(io,"</AnimationList>\n");
+	}
+
+	// write meshes
+	if (scene->mNumMeshes) {
+		ioprintf(io,"<MeshList num=\"%i\">\n",scene->mNumMeshes);
+		for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
+			aiMesh* mesh = scene->mMeshes[i];
+			// const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1;
+
+			// mesh header
+			ioprintf(io,"\t<Mesh types=\"%s %s %s %s\" material_index=\"%i\">\n",
+				(mesh->mPrimitiveTypes & aiPrimitiveType_POINT    ? "points"    : ""),
+				(mesh->mPrimitiveTypes & aiPrimitiveType_LINE     ? "lines"     : ""),
+				(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
+				(mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON  ? "polygons"  : ""),
+				mesh->mMaterialIndex);
+
+			// bones
+			if (mesh->mNumBones) {
+				ioprintf(io,"\t\t<BoneList num=\"%i\">\n",mesh->mNumBones);
+
+				for (unsigned int n = 0; n < mesh->mNumBones;++n) {
+					aiBone* bone = mesh->mBones[n];
+
+					ConvertName(name,bone->mName);
+					// bone header
+					ioprintf(io,"\t\t\t<Bone name=\"%s\">\n"
+						"\t\t\t\t<Matrix4> \n"
+						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+						"\t\t\t\t</Matrix4> \n",
+						name.data,
+						bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4,
+						bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4,
+						bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4,
+						bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4);
+
+					if (!shortened && bone->mNumWeights) {
+						ioprintf(io,"\t\t\t\t<WeightList num=\"%i\">\n",bone->mNumWeights);
+
+						// bone weights
+						for (unsigned int a = 0; a < bone->mNumWeights;++a) {
+							aiVertexWeight* wght = bone->mWeights+a;
+
+							ioprintf(io,"\t\t\t\t\t<Weight index=\"%i\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
+								wght->mVertexId,wght->mWeight);
+						}
+						ioprintf(io,"\t\t\t\t</WeightList>\n");
+					}
+					ioprintf(io,"\t\t\t</Bone>\n");
+				}
+				ioprintf(io,"\t\t</BoneList>\n");
+			}
+
+			// faces
+			if (!shortened && mesh->mNumFaces) {
+				ioprintf(io,"\t\t<FaceList num=\"%i\">\n",mesh->mNumFaces);
+				for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
+					aiFace& f = mesh->mFaces[n];
+					ioprintf(io,"\t\t\t<Face num=\"%i\">\n"
+						"\t\t\t\t",f.mNumIndices);
+
+					for (unsigned int j = 0; j < f.mNumIndices;++j)
+						ioprintf(io,"%i ",f.mIndices[j]);
+
+					ioprintf(io,"\n\t\t\t</Face>\n");
+				}
+				ioprintf(io,"\t\t</FaceList>\n");
+			}
+
+			// vertex positions
+			if (mesh->HasPositions()) {
+				ioprintf(io,"\t\t<Positions num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+				if (!shortened) {
+					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+							mesh->mVertices[n].x,
+							mesh->mVertices[n].y,
+							mesh->mVertices[n].z);
+					}
+				}
+				ioprintf(io,"\t\t</Positions>\n");
+			}
+
+			// vertex normals
+			if (mesh->HasNormals()) {
+				ioprintf(io,"\t\t<Normals num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+				if (!shortened) {
+					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+							mesh->mNormals[n].x,
+							mesh->mNormals[n].y,
+							mesh->mNormals[n].z);
+					}
+				}
+				else {
+				}
+				ioprintf(io,"\t\t</Normals>\n");
+			}
+
+			// vertex tangents and bitangents
+			if (mesh->HasTangentsAndBitangents()) {
+				ioprintf(io,"\t\t<Tangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+				if (!shortened) {
+					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+							mesh->mTangents[n].x,
+							mesh->mTangents[n].y,
+							mesh->mTangents[n].z);
+					}
+				}
+				ioprintf(io,"\t\t</Tangents>\n");
+
+				ioprintf(io,"\t\t<Bitangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+				if (!shortened) {
+					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+							mesh->mBitangents[n].x,
+							mesh->mBitangents[n].y,
+							mesh->mBitangents[n].z);
+					}
+				}
+				ioprintf(io,"\t\t</Bitangents>\n");
+			}
+
+			// texture coordinates
+			for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+				if (!mesh->mTextureCoords[a])
+					break;
+
+				ioprintf(io,"\t\t<TextureCoords num=\"%i\" set=\"%i\" num_components=\"%i\"> \n",mesh->mNumVertices,
+					a,mesh->mNumUVComponents[a]);
+				
+				if (!shortened) {
+					if (mesh->mNumUVComponents[a] == 3) {
+						for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+							ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+								mesh->mTextureCoords[a][n].x,
+								mesh->mTextureCoords[a][n].y,
+								mesh->mTextureCoords[a][n].z);
+						}
+					}
+					else {
+						for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+							ioprintf(io,"\t\t%0 8f %0 8f\n",
+								mesh->mTextureCoords[a][n].x,
+								mesh->mTextureCoords[a][n].y);
+						}
+					}
+				}
+				ioprintf(io,"\t\t</TextureCoords>\n");
+			}
+
+			// vertex colors
+			for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
+				if (!mesh->mColors[a])
+					break;
+				ioprintf(io,"\t\t<Colors num=\"%i\" set=\"%i\" num_components=\"4\"> \n",mesh->mNumVertices,a);
+				if (!shortened) {
+					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+						ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n",
+							mesh->mColors[a][n].r,
+							mesh->mColors[a][n].g,
+							mesh->mColors[a][n].b,
+							mesh->mColors[a][n].a);
+					}
+				}
+				ioprintf(io,"\t\t</Colors>\n");
+			}
+			ioprintf(io,"\t</Mesh>\n");
+		}
+		ioprintf(io,"</MeshList>\n");
+	}
+	ioprintf(io,"</Scene>\n</ASSIMP>");
+}
+
+} // end of namespace AssxmlExport
+
+void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+{
+	IOStream * out = pIOSystem->Open( pFile, "wt" );
+	if (!out) return;
+
+	bool shortened = false;
+	AssxmlExport::WriteDump( pScene, out, shortened );
+
+	pIOSystem->Close( out );
+}
+
+} // end of namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_ASSXML_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 49 - 0
code/AssxmlExporter.h

@@ -0,0 +1,49 @@
+/*
+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 AssxmlExporter.h
+ * ASSXML Exporter Main Header
+ */
+#ifndef AI_ASSXMLEXPORTER_H_INC
+#define AI_ASSXMLEXPORTER_H_INC
+
+// nothing really needed here - reserved for future use like properties
+
+#endif

+ 1 - 1
code/B3DImporter.cpp

@@ -548,7 +548,7 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
 void B3DImporter::ReadBB3D( aiScene *scene ){
 void B3DImporter::ReadBB3D( aiScene *scene ){
 
 
 	_textures.clear();
 	_textures.clear();
-	_materials.size();
+	_materials.clear();
 
 
 	_vertices.clear();
 	_vertices.clear();
 	_meshes.clear();
 	_meshes.clear();

+ 5 - 0
code/BaseImporter.h

@@ -90,6 +90,11 @@ struct ScopeGuard
 	}
 	}
 
 
 private:
 private:
+    // no copying allowed.
+    ScopeGuard();
+    ScopeGuard( const ScopeGuard & );
+    ScopeGuard &operator = ( const ScopeGuard & );
+
 	T* obj;
 	T* obj;
 	bool mdismiss;
 	bool mdismiss;
 };
 };

+ 28 - 1
code/BlenderBMesh.cpp

@@ -65,7 +65,6 @@ BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
 	BMesh( mesh ),
 	BMesh( mesh ),
 	triMesh( NULL )
 	triMesh( NULL )
 {
 {
-	AssertValidMesh( );
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -143,9 +142,21 @@ void BlenderBMeshConverter::DestroyTriMesh( )
 void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
 void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
 {
 {
 	const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
 	const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
+
 	if ( poly.totloop == 3 || poly.totloop == 4 )
 	if ( poly.totloop == 3 || poly.totloop == 4 )
 	{
 	{
 		AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
 		AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
+
+		// UVs are optional, so only convert when present.
+		if ( BMesh->mloopuv.size() )
+		{
+			if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
+			{
+				ThrowException( "BMesh uv loop array has incorrect size" );
+			}
+			const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
+			AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
+		}
 	}
 	}
 	else if ( poly.totloop > 4 )
 	else if ( poly.totloop > 4 )
 	{
 	{
@@ -173,4 +184,20 @@ void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
 	triMesh->totface = triMesh->mface.size( );
 	triMesh->totface = triMesh->mface.size( );
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
+{
+	MTFace mtface;
+	memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
+	memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
+	memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
+	
+	if ( uv4 )
+	{
+		memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
+	}
+	
+	triMesh->mtface.push_back( mtface );
+}
+
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 1 - 0
code/BlenderBMesh.h

@@ -80,6 +80,7 @@ namespace Assimp
 		void DestroyTriMesh( );
 		void DestroyTriMesh( );
 		void ConvertPolyToFaces( const Blender::MPoly& poly );
 		void ConvertPolyToFaces( const Blender::MPoly& poly );
 		void AddFace( int v1, int v2, int v3, int v4 = 0 );
 		void AddFace( int v1, int v2, int v3, int v4 = 0 );
+		void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 );
 
 
 		const Blender::Mesh* BMesh;
 		const Blender::Mesh* BMesh;
 		Blender::Mesh* triMesh;
 		Blender::Mesh* triMesh;

+ 6 - 2
code/BlenderLoader.cpp

@@ -659,11 +659,15 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
 	ConversionData& conv_data, TempArray<std::vector,aiMesh>&  temp
 	ConversionData& conv_data, TempArray<std::vector,aiMesh>&  temp
 	) 
 	) 
 {
 {
+	// TODO: Resolve various problems with BMesh triangluation before re-enabling.
+	//       See issues #400, #373, #318  #315 and #132.
+#if defined(TODO_FIX_BMESH_CONVERSION)
 	BlenderBMeshConverter BMeshConverter( mesh );
 	BlenderBMeshConverter BMeshConverter( mesh );
 	if ( BMeshConverter.ContainsBMesh( ) )
 	if ( BMeshConverter.ContainsBMesh( ) )
 	{
 	{
 		mesh = BMeshConverter.TriangulateBMesh( );
 		mesh = BMeshConverter.TriangulateBMesh( );
 	}
 	}
+#endif
 
 
 	typedef std::pair<const int,size_t> MyPair;
 	typedef std::pair<const int,size_t> MyPair;
 	if ((!mesh->totface && !mesh->totloop) || !mesh->totvert) {
 	if ((!mesh->totface && !mesh->totloop) || !mesh->totvert) {
@@ -999,7 +1003,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* camera, ConversionData& /*conv_data*/)
+aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* /*camera*/, ConversionData& /*conv_data*/)
 {
 {
 	ScopeGuard<aiCamera> out(new aiCamera());
 	ScopeGuard<aiCamera> out(new aiCamera());
 	out->mName = obj->id.name+2;
 	out->mName = obj->id.name+2;
@@ -1010,7 +1014,7 @@ aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj,
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-aiLight* BlenderImporter::ConvertLight(const Scene& in, const Object* obj, const Lamp* lamp, ConversionData& conv_data)
+aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, const Lamp* lamp, ConversionData& /*conv_data*/)
 {
 {
 	ScopeGuard<aiLight> out(new aiLight());
 	ScopeGuard<aiLight> out(new aiLight());
 	out->mName = obj->id.name+2;
 	out->mName = obj->id.name+2;

+ 2 - 2
code/BlenderTessellator.cpp

@@ -324,7 +324,7 @@ void BlenderTessellatorP2T::Copy3DVertices( const MLoop* polyLoop, int vertexCou
 aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const
 aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const
 {
 {
 	aiVector3D sideA( 1.0f, 0.0f, 0.0f );
 	aiVector3D sideA( 1.0f, 0.0f, 0.0f );
-	if ( fabs( plane.normal * sideA ) > 0.999f )
+	if ( std::fabs( plane.normal * sideA ) > 0.999f )
 	{
 	{
 		sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
 		sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
 	}
 	}
@@ -420,7 +420,7 @@ float BlenderTessellatorP2T::FindLargestMatrixElem( const aiMatrix3x3& mtx ) con
 	{
 	{
 		for ( int y = 0; y < 3; ++y )
 		for ( int y = 0; y < 3; ++y )
 		{
 		{
-			result = p2tMax( fabs( mtx[ x ][ y ] ), result );
+			result = p2tMax( std::fabs( mtx[ x ][ y ] ), result );
 		}
 		}
 	}
 	}
 
 

+ 3 - 3
code/BoostWorkaround/boost/tuple/tuple.hpp

@@ -100,7 +100,7 @@ namespace boost	{
 			};
 			};
 
 
 			// dummy
 			// dummy
-			list_elem& operator = (const list_elem& other)	{
+			list_elem& operator = (const list_elem& /*other*/)	{
 				return *this;
 				return *this;
 			}
 			}
 
 
@@ -142,7 +142,7 @@ namespace boost	{
 				return me.me;
 				return me.me;
 			}
 			}
 		};
 		};
-	};
+	}
 
 
 	// A very minimal implementation for up to 5 elements
 	// A very minimal implementation for up to 5 elements
 	template <typename T0  = detail::nulltype,
 	template <typename T0  = detail::nulltype,
@@ -278,6 +278,6 @@ namespace boost	{
 		tuple <> t;
 		tuple <> t;
 		return t;
 		return t;
 	}
 	}
-};
+}
 
 
 #endif // !! BOOST_TUPLE_INCLUDED
 #endif // !! BOOST_TUPLE_INCLUDED

+ 33 - 1
code/CMakeLists.txt

@@ -111,6 +111,7 @@ SET( Common_SRCS
 	MemoryIOWrapper.h
 	MemoryIOWrapper.h
 	ParsingUtils.h
 	ParsingUtils.h
 	StreamReader.h
 	StreamReader.h
+	StreamWriter.h
 	StringComparison.h
 	StringComparison.h
 	SGSpatialSort.cpp
 	SGSpatialSort.cpp
 	SGSpatialSort.h
 	SGSpatialSort.h
@@ -143,6 +144,7 @@ SET( Common_SRCS
 	LogAux.h
 	LogAux.h
 	Bitmap.cpp
 	Bitmap.cpp
 	Bitmap.h
 	Bitmap.h
+	XMLTools.h
 )
 )
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 
 
@@ -151,6 +153,8 @@ SET( 3DS_SRCS
 	3DSHelper.h
 	3DSHelper.h
 	3DSLoader.cpp
 	3DSLoader.cpp
 	3DSLoader.h
 	3DSLoader.h
+	3DSExporter.h
+	3DSExporter.cpp
 )
 )
 SOURCE_GROUP(3DS FILES ${3DS_SRCS})
 SOURCE_GROUP(3DS FILES ${3DS_SRCS})
 
 
@@ -168,6 +172,20 @@ SET( ASE_SRCS
 )
 )
 SOURCE_GROUP( ASE FILES ${ASE_SRCS})
 SOURCE_GROUP( ASE FILES ${ASE_SRCS})
 
 
+SET( ASSBIN_SRCS
+	AssbinExporter.h
+	AssbinExporter.cpp
+	AssbinLoader.h
+	AssbinLoader.cpp
+)
+SOURCE_GROUP( Assbin FILES ${ASSBIN_SRCS})
+
+SET( ASSXML_SRCS
+	AssxmlExporter.h
+	AssxmlExporter.cpp
+)
+SOURCE_GROUP( Assxml FILES ${ASSXML_SRCS})
+
 SET( B3D_SRCS
 SET( B3D_SRCS
 	B3DImporter.cpp
 	B3DImporter.cpp
 	B3DImporter.h
 	B3DImporter.h
@@ -612,7 +630,7 @@ SOURCE_GROUP( unzip FILES ${unzip_SRCS})
 
 
 # VC2010 fixes
 # VC2010 fixes
 if(MSVC10)
 if(MSVC10)
-	OPTION( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
+	option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
 	if( VC10_STDINT_FIX )
 	if( VC10_STDINT_FIX )
 		ADD_DEFINITIONS( -D_STDINT )
 		ADD_DEFINITIONS( -D_STDINT )
 	endif( VC10_STDINT_FIX )
 	endif( VC10_STDINT_FIX )
@@ -643,6 +661,8 @@ SET( assimp_src
 	${3DS_SRCS}
 	${3DS_SRCS}
 	${AC_SRCS}
 	${AC_SRCS}
 	${ASE_SRCS}
 	${ASE_SRCS}
+	${ASSBIN_SRCS}
+	${ASSXML_SRCS}
 	${B3D_SRCS}
 	${B3D_SRCS}
 	${BVH_SRCS}
 	${BVH_SRCS}
 	${Collada_SRCS}
 	${Collada_SRCS}
@@ -705,6 +725,13 @@ ADD_LIBRARY( assimp ${assimp_src} )
 SET_PROPERTY(TARGET assimp PROPERTY DEBUG_POSTFIX ${ASSIMP_DEBUG_POSTFIX})
 SET_PROPERTY(TARGET assimp PROPERTY DEBUG_POSTFIX ${ASSIMP_DEBUG_POSTFIX})
 
 
 TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES})
 TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES})
+
+if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
+	set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI)
+	add_subdirectory(../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/ ../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/)
+	target_link_libraries(assimp android_jniiosystem)
+endif(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
+
 SET_TARGET_PROPERTIES( assimp PROPERTIES
 SET_TARGET_PROPERTIES( assimp PROPERTIES
 	VERSION ${ASSIMP_VERSION}
 	VERSION ${ASSIMP_VERSION}
 	SOVERSION ${ASSIMP_SOVERSION} # use full version 
 	SOVERSION ${ASSIMP_SOVERSION} # use full version 
@@ -731,6 +758,11 @@ INSTALL( TARGETS assimp
          COMPONENT ${LIBASSIMP_COMPONENT})
          COMPONENT ${LIBASSIMP_COMPONENT})
 INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)
 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)
 INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev)
+if (ASSIMP_ANDROID_JNIIOSYSTEM)
+	INSTALL(FILES ${HEADER_PATH}/../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
+			DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
+			COMPONENT assimp-dev)
+endif(ASSIMP_ANDROID_JNIIOSYSTEM)
 
 
 if(MSVC AND ASSIMP_INSTALL_PDB)
 if(MSVC AND ASSIMP_INSTALL_PDB)
 	install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${ASSIMP_DEBUG_POSTFIX}.pdb
 	install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${ASSIMP_DEBUG_POSTFIX}.pdb

+ 3 - 3
code/CalcTangentsProcess.cpp

@@ -115,9 +115,9 @@ 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
 	// 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 
 	// of vertices and no vertices are shared between faces. Sadly I don't know any quick test to 
 	// assert() it here.
 	// assert() it here.
-    //assert( must be verbose, dammit);
+    // assert( must be verbose, dammit);
 
 
-	if (pMesh->mTangents) // thisimplies that mBitangents is also there
+	if (pMesh->mTangents) // this implies that mBitangents is also there
 		return false;
 		return false;
 
 
 	// If the mesh consists of lines and/or points but not of
 	// If the mesh consists of lines and/or points but not of
@@ -271,7 +271,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
 		const aiVector3D& origNorm = pMesh->mNormals[a];
 		const aiVector3D& origNorm = pMesh->mNormals[a];
 		const aiVector3D& origTang = pMesh->mTangents[a];
 		const aiVector3D& origTang = pMesh->mTangents[a];
 		const aiVector3D& origBitang = pMesh->mBitangents[a];
 		const aiVector3D& origBitang = pMesh->mBitangents[a];
-		closeVertices.clear();
+		closeVertices.resize( 0 );
 
 
 		// find all vertices close to that position
 		// find all vertices close to that position
 		vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
 		vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);

+ 39 - 31
code/ColladaExporter.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "Bitmap.h"
 #include "Bitmap.h"
 #include "fast_atof.h"
 #include "fast_atof.h"
 #include "SceneCombiner.h" 
 #include "SceneCombiner.h" 
+#include "XMLTools.h"
 
 
 #include <ctime>
 #include <ctime>
 #include <set>
 #include <set>
@@ -93,6 +94,7 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 
 
 
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor for a specific scene to export
 // 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)
 ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file)
@@ -140,7 +142,7 @@ void ColladaExporter::WriteFile()
 	// useless Collada fu at the end, just in case we haven't had enough indirections, yet. 
 	// useless Collada fu at the end, just in case we haven't had enough indirections, yet. 
 	mOutput << startstr << "<scene>" << endstr;
 	mOutput << startstr << "<scene>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<instance_visual_scene url=\"#" + std::string(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
+	mOutput << startstr << "<instance_visual_scene url=\"#" + XMLEscape(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
 	PopTag();
 	PopTag();
 	mOutput << startstr << "</scene>" << endstr;
 	mOutput << startstr << "</scene>" << endstr;
 	PopTag();
 	PopTag();
@@ -236,12 +238,12 @@ void ColladaExporter::WriteHeader()
 	if (!meta || !meta->Get("Author", value))		
 	if (!meta || !meta->Get("Author", value))		
 		mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
 		mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
 	else		
 	else		
-		mOutput << startstr << "<author>" << value.C_Str() << "</author>" << endstr;
+		mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
 
 
 	if (!meta || !meta->Get("AuthoringTool", value))
 	if (!meta || !meta->Get("AuthoringTool", value))
 		mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
 		mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
 	else		
 	else		
-		mOutput << startstr << "<authoring_tool>" << value.C_Str() << "</authoring_tool>" << endstr;
+		mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
 
 
 	//mOutput << startstr << "<author>" << mScene->author.C_Str() << "</author>" << endstr;
 	//mOutput << startstr << "<author>" << mScene->author.C_Str() << "</author>" << endstr;
 	//mOutput << startstr << "<authoring_tool>" << mScene->authoringTool.C_Str() << "</authoring_tool>" << endstr;
 	//mOutput << startstr << "<authoring_tool>" << mScene->authoringTool.C_Str() << "</authoring_tool>" << endstr;
@@ -342,16 +344,20 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin
 {
 {
   if( !pSurface.texture.empty() )
   if( !pSurface.texture.empty() )
   {
   {
-    mOutput << startstr << "<image id=\"" << pNameAdd << "\">" << endstr;
+    mOutput << startstr << "<image id=\"" << XMLEscape(pNameAdd) << "\">" << endstr;
     PushTag(); 
     PushTag(); 
     mOutput << startstr << "<init_from>";
     mOutput << startstr << "<init_from>";
+	
+	// URL encode image file name first, then XML encode on top
+	std::stringstream imageUrlEncoded;
     for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it )
     for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it )
     {
     {
       if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' )
       if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' )
-        mOutput << *it;
+        imageUrlEncoded << *it;
       else
       else
-        mOutput << '%' << std::hex << size_t( (unsigned char) *it) << std::dec;
+        imageUrlEncoded << '%' << std::hex << size_t( (unsigned char) *it) << std::dec;
     }
     }
+	mOutput << XMLEscape(imageUrlEncoded.str());
     mOutput << "</init_from>" << endstr;
     mOutput << "</init_from>" << endstr;
     PopTag();
     PopTag();
     mOutput << startstr << "</image>" << endstr;
     mOutput << startstr << "</image>" << endstr;
@@ -371,7 +377,7 @@ void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std
     }
     }
 	else
 	else
     {
     {
-      mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
+      mOutput << startstr << "<texture texture=\"" << XMLEscape(pImageName) << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
     }
     }
     PopTag();
     PopTag();
     mOutput << startstr << "</" << pTypeName << ">" << endstr;
     mOutput << startstr << "</" << pTypeName << ">" << endstr;
@@ -385,21 +391,21 @@ void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std
   // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
   // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
   if( !pSurface.texture.empty() )
   if( !pSurface.texture.empty() )
   {
   {
-    mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-surface\">" << endstr;
+    mOutput << startstr << "<newparam sid=\"" << XMLEscape(pMatName) << "-" << pTypeName << "-surface\">" << endstr;
     PushTag();
     PushTag();
     mOutput << startstr << "<surface type=\"2D\">" << endstr;
     mOutput << startstr << "<surface type=\"2D\">" << endstr;
     PushTag();
     PushTag();
-    mOutput << startstr << "<init_from>" << pMatName << "-" << pTypeName << "-image</init_from>" << endstr;
+    mOutput << startstr << "<init_from>" << XMLEscape(pMatName) << "-" << pTypeName << "-image</init_from>" << endstr;
     PopTag();
     PopTag();
     mOutput << startstr << "</surface>" << endstr;
     mOutput << startstr << "</surface>" << endstr;
     PopTag();
     PopTag();
     mOutput << startstr << "</newparam>" << endstr;
     mOutput << startstr << "</newparam>" << endstr;
 
 
-    mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-sampler\">" << endstr;
+    mOutput << startstr << "<newparam sid=\"" << XMLEscape(pMatName) << "-" << pTypeName << "-sampler\">" << endstr;
     PushTag();
     PushTag();
     mOutput << startstr << "<sampler2D>" << endstr;
     mOutput << startstr << "<sampler2D>" << endstr;
     PushTag();
     PushTag();
-    mOutput << startstr << "<source>" << pMatName << "-" << pTypeName << "-surface</source>" << endstr;
+    mOutput << startstr << "<source>" << XMLEscape(pMatName) << "-" << pTypeName << "-surface</source>" << endstr;
     PopTag();
     PopTag();
     mOutput << startstr << "</sampler2D>" << endstr;
     mOutput << startstr << "</sampler2D>" << endstr;
     PopTag();
     PopTag();
@@ -439,7 +445,7 @@ void ColladaExporter::WriteMaterials()
       name = "mat";
       name = "mat";
     materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
     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 ) {
     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
+		// isalnum on MSVC asserts for code points outside [0,255]. Thus prevent unwanted promotion
 		// of char to signed int and take the unsigned char value.
 		// of char to signed int and take the unsigned char value.
       if( !isalnum( static_cast<uint8_t>(*it) ) ) {
       if( !isalnum( static_cast<uint8_t>(*it) ) ) {
         *it = '_';
         *it = '_';
@@ -510,7 +516,7 @@ void ColladaExporter::WriteMaterials()
     {
     {
       const Material& mat = *it;
       const Material& mat = *it;
       // this is so ridiculous it must be right
       // this is so ridiculous it must be right
-      mOutput << startstr << "<effect id=\"" << mat.name << "-fx\" name=\"" << mat.name << "\">" << endstr;
+      mOutput << startstr << "<effect id=\"" << XMLEscape(mat.name) << "-fx\" name=\"" << XMLEscape(mat.name) << "\">" << endstr;
       PushTag();
       PushTag();
       mOutput << startstr << "<profile_COMMON>" << endstr;
       mOutput << startstr << "<profile_COMMON>" << endstr;
       PushTag();
       PushTag();
@@ -561,9 +567,9 @@ void ColladaExporter::WriteMaterials()
     for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
     for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
     {
     {
       const Material& mat = *it;
       const Material& mat = *it;
-      mOutput << startstr << "<material id=\"" << mat.name << "\" name=\"" << mat.name << "\">" << endstr;
+      mOutput << startstr << "<material id=\"" << XMLEscape(mat.name) << "\" name=\"" << mat.name << "\">" << endstr;
       PushTag();
       PushTag();
-      mOutput << startstr << "<instance_effect url=\"#" << mat.name << "-fx\"/>" << endstr;
+      mOutput << startstr << "<instance_effect url=\"#" << XMLEscape(mat.name) << "-fx\"/>" << endstr;
       PopTag();
       PopTag();
       mOutput << startstr << "</material>" << endstr;
       mOutput << startstr << "</material>" << endstr;
     }
     }
@@ -591,13 +597,14 @@ void ColladaExporter::WriteGeometryLibrary()
 void ColladaExporter::WriteGeometry( size_t pIndex)
 void ColladaExporter::WriteGeometry( size_t pIndex)
 {
 {
 	const aiMesh* mesh = mScene->mMeshes[pIndex];
 	const aiMesh* mesh = mScene->mMeshes[pIndex];
-	std::string idstr = GetMeshId( pIndex);
+	const std::string idstr = GetMeshId( pIndex);
+	const std::string idstrEscaped = XMLEscape(idstr);
 
 
   if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
   if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
     return;
     return;
 
 
 	// opening tag
 	// opening tag
-	mOutput << startstr << "<geometry id=\"" << idstr << "\" name=\"" << idstr << "_name\" >" << endstr;
+	mOutput << startstr << "<geometry id=\"" << idstrEscaped << "\" name=\"" << idstrEscaped << "_name\" >" << endstr;
 	PushTag();
 	PushTag();
 
 
 	mOutput << startstr << "<mesh>" << endstr;
 	mOutput << startstr << "<mesh>" << endstr;
@@ -627,20 +634,20 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
 	}
 	}
 
 
 	// assemble vertex structure
 	// assemble vertex structure
-	mOutput << startstr << "<vertices id=\"" << idstr << "-vertices" << "\">" << endstr;
+	mOutput << startstr << "<vertices id=\"" << idstrEscaped << "-vertices" << "\">" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstr << "-positions\" />" << endstr;
+	mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstrEscaped << "-positions\" />" << endstr;
 	if( mesh->HasNormals() )
 	if( mesh->HasNormals() )
-		mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstr << "-normals\" />" << endstr;
+		mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstrEscaped << "-normals\" />" << endstr;
 	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
 	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
 	{
 	{
 		if( mesh->HasTextureCoords( a) )
 		if( mesh->HasTextureCoords( a) )
-			mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstr << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr;
+			mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstrEscaped << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr;
 	}
 	}
 	for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
 	for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
 	{
 	{
 		if( mesh->HasVertexColors( a) )
 		if( mesh->HasVertexColors( a) )
-			mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstr << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr;
+			mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstrEscaped << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr;
 	}
 	}
 	
 	
 	PopTag();
 	PopTag();
@@ -660,7 +667,7 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
 	{
 	{
 		mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
 		mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
 		PushTag();
 		PushTag();
-		mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;
+		mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr;
 		mOutput << startstr << "<p>";
 		mOutput << startstr << "<p>";
 		for( size_t a = 0; a < mesh->mNumFaces; ++a )
 		for( size_t a = 0; a < mesh->mNumFaces; ++a )
 		{
 		{
@@ -681,7 +688,7 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
 	{		
 	{		
 		mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
 		mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
 		PushTag();
 		PushTag();
-		mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr;
+		mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr;
 	
 	
 		mOutput << startstr << "<vcount>";
 		mOutput << startstr << "<vcount>";
 		for( size_t a = 0; a < mesh->mNumFaces; ++a )
 		for( size_t a = 0; a < mesh->mNumFaces; ++a )
@@ -728,11 +735,11 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
 
 
 	std::string arrayId = pIdString + "-array";
 	std::string arrayId = pIdString + "-array";
 
 
-	mOutput << startstr << "<source id=\"" << pIdString << "\" name=\"" << pIdString << "\">" << endstr;
+	mOutput << startstr << "<source id=\"" << XMLEscape(pIdString) << "\" name=\"" << XMLEscape(pIdString) << "\">" << endstr;
 	PushTag();
 	PushTag();
 
 
 	// source array
 	// source array
-	mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
+	mOutput << startstr << "<float_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
 	PushTag();
 	PushTag();
 
 
 	if( pType == FloatType_TexCoord2 )
 	if( pType == FloatType_TexCoord2 )
@@ -804,11 +811,11 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
 // Writes the scene library
 // Writes the scene library
 void ColladaExporter::WriteSceneLibrary()
 void ColladaExporter::WriteSceneLibrary()
 {
 {
-	std::string scene_name = mScene->mRootNode->mName.C_Str();
+	const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str());
 
 
 	mOutput << startstr << "<library_visual_scenes>" << endstr;
 	mOutput << startstr << "<library_visual_scenes>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<visual_scene id=\"" + scene_name + "\" name=\"" + scene_name + "\">" << endstr;
+	mOutput << startstr << "<visual_scene id=\"" + scene_name_escaped + "\" name=\"" + scene_name_escaped + "\">" << endstr;
 	PushTag();
 	PushTag();
 
 
 	// start recursive write at the root node
 	// start recursive write at the root node
@@ -833,7 +840,8 @@ void ColladaExporter::WriteNode(aiNode* pNode)
 		pNode->mName.Set(ss.str());
 		pNode->mName.Set(ss.str());
 	}
 	}
 
 
-	mOutput << startstr << "<node id=\"" << pNode->mName.data << "\" name=\"" << pNode->mName.data << "\">" << endstr;
+	const std::string node_name_escaped = XMLEscape(pNode->mName.data);
+	mOutput << startstr << "<node id=\"" << node_name_escaped << "\" name=\"" << node_name_escaped << "\">" << endstr;
 	PushTag();
 	PushTag();
 
 
 	// write transformation - we can directly put the matrix there
 	// write transformation - we can directly put the matrix there
@@ -854,13 +862,13 @@ void ColladaExporter::WriteNode(aiNode* pNode)
 	if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
 	if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
 		continue;
 		continue;
 
 
-		mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
+		mOutput << startstr << "<instance_geometry url=\"#" << XMLEscape(GetMeshId( pNode->mMeshes[a])) << "\">" << endstr;
 		PushTag();
 		PushTag();
 	mOutput << startstr << "<bind_material>" << endstr;
 	mOutput << startstr << "<bind_material>" << endstr;
 	PushTag();
 	PushTag();
 	mOutput << startstr << "<technique_common>" << endstr;
 	mOutput << startstr << "<technique_common>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
+	mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << XMLEscape(materials[mesh->mMaterialIndex].name) << "\" />" << endstr;
 		PopTag();
 		PopTag();
 	mOutput << startstr << "</technique_common>" << endstr;
 	mOutput << startstr << "</technique_common>" << endstr;
 	PopTag();
 	PopTag();

+ 0 - 1
code/ColladaHelper.h

@@ -118,7 +118,6 @@ struct Camera
 	float mZNear, mZFar;
 	float mZNear, mZFar;
 };
 };
 
 
-#define aiLightSource_AMBIENT 0xdeaddead
 #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
 #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
 
 
 /** A collada light source. */
 /** A collada light source. */

+ 7 - 8
code/ColladaLoader.cpp

@@ -73,7 +73,7 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 ColladaLoader::ColladaLoader()
 ColladaLoader::ColladaLoader()
-: noSkeletonMesh(), ignoreUpDirection(false)
+: noSkeletonMesh(), ignoreUpDirection(false), mNodeNameCounter()
 {}
 {}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -133,6 +133,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
 	mLights.clear();
 	mLights.clear();
 	mCameras.clear();
 	mCameras.clear();
 	mTextures.clear();
 	mTextures.clear();
+	mAnims.clear();
 
 
 	// parse the input file
 	// parse the input file
 	ColladaParser parser( pIOHandler, pFile);
 	ColladaParser parser( pIOHandler, pFile);
@@ -307,10 +308,6 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
 			continue;
 			continue;
 		}
 		}
 		const Collada::Light* srcLight = &srcLightIt->second;
 		const Collada::Light* srcLight = &srcLightIt->second;
-		if (srcLight->mType == aiLightSource_AMBIENT) {
-			DefaultLogger::get()->error("Collada: Skipping ambient light for the moment");
-			continue;
-		}
 		
 		
 		// now fill our ai data structure
 		// now fill our ai data structure
 		aiLight* out = new aiLight();
 		aiLight* out = new aiLight();
@@ -340,7 +337,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
 				{
 				{
 					// Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
 					// Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
 					// epsilon chosen to be 0.1
 					// epsilon chosen to be 0.1
-					out->mAngleOuterCone = AI_DEG_TO_RAD (acos(pow(0.1f,1.f/srcLight->mFalloffExponent))+
+					out->mAngleOuterCone = AI_DEG_TO_RAD (std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+
 						srcLight->mFalloffAngle);
 						srcLight->mFalloffAngle);
 				}
 				}
 				else {
 				else {
@@ -904,6 +901,8 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
 		pScene->mAnimations = new aiAnimation*[mAnims.size()];
 		pScene->mAnimations = new aiAnimation*[mAnims.size()];
 		std::copy( mAnims.begin(), mAnims.end(), pScene->mAnimations);
 		std::copy( mAnims.begin(), mAnims.end(), pScene->mAnimations);
 	}
 	}
+
+	mAnims.clear();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -1544,7 +1543,7 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Finds a proper name for a node derived from the collada-node's properties
 // Finds a proper name for a node derived from the collada-node's properties
-std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode) const
+std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
 {
 {
 	// now setup the name of the node. We take the name if not empty, otherwise the collada ID
 	// now setup the name of the node. We take the name if not empty, otherwise the collada ID
 	// FIX: Workaround for XSI calling the instanced visual scene 'untitled' by default.
 	// FIX: Workaround for XSI calling the instanced visual scene 'untitled' by default.
@@ -1558,7 +1557,7 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode) const
 	{
 	{
 		// No need to worry. Unnamed nodes are no problem at all, except
 		// No need to worry. Unnamed nodes are no problem at all, except
 		// if cameras or lights need to be assigned to them.
 		// if cameras or lights need to be assigned to them.
-    return boost::str( boost::format( "$ColladaAutoName$_%d") % clock());
+    return boost::str( boost::format( "$ColladaAutoName$_%d") % mNodeNameCounter++);
 	}
 	}
 }
 }
 
 

+ 4 - 1
code/ColladaLoader.h

@@ -203,7 +203,7 @@ protected:
 	const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
 	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 */
 	/** Finds a proper name for a node derived from the collada-node's properties */
-	std::string FindNameForNode( const Collada::Node* pNode) const;
+	std::string FindNameForNode( const Collada::Node* pNode);
 
 
 protected:
 protected:
 	/** Filename, for a verbose error message */
 	/** Filename, for a verbose error message */
@@ -235,6 +235,9 @@ protected:
 
 
 	bool noSkeletonMesh;
 	bool noSkeletonMesh;
 	bool ignoreUpDirection;
 	bool ignoreUpDirection;
+
+	/** Used by FindNameForNode() to generate unique node names */
+	unsigned int mNodeNameCounter;
 };
 };
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp

+ 87 - 37
code/ColladaParser.cpp

@@ -1163,6 +1163,19 @@ void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect)
 				// just syntactic sugar
 				// just syntactic sugar
 			}
 			}
 
 
+			else if( mFormat == FV_1_4_n && IsElement( "image"))
+			{
+				// read ID. Another entry which is "optional" by design but obligatory in reality
+				int attrID = GetAttribute( "id");
+				std::string id = mReader->getAttributeValue( attrID);
+
+				// create an entry and store it in the library under its ID
+				mImageLibrary[id] = Image();
+
+				// read on from there
+				ReadImage( mImageLibrary[id]);
+			}
+
 			/* Shading modes */
 			/* Shading modes */
 			else if( IsElement( "phong"))
 			else if( IsElement( "phong"))
 				pEffect.mShadeType = Shade_Phong;
 				pEffect.mShadeType = Shade_Phong;
@@ -1854,14 +1867,15 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 	// read primitive count from the attribute
 	// read primitive count from the attribute
 	int attrCount = GetAttribute( "count");
 	int attrCount = GetAttribute( "count");
 	size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
 	size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
+	// some mesh types (e.g. tristrips) don't specify primitive count upfront,
+	// so we need to sum up the actual number of primitives while we read the <p>-tags
+	size_t actualPrimitives = 0;
 
 
-	// material subgroup 
+	// material subgroup
 	int attrMaterial = TestAttribute( "material");
 	int attrMaterial = TestAttribute( "material");
 	SubMesh subgroup;
 	SubMesh subgroup;
 	if( attrMaterial > -1)
 	if( attrMaterial > -1)
 		subgroup.mMaterial = mReader->getAttributeValue( attrMaterial);
 		subgroup.mMaterial = mReader->getAttributeValue( attrMaterial);
-	subgroup.mNumFaces = numPrimitives;
-	pMesh->mSubMeshes.push_back( subgroup);
 
 
 	// distinguish between polys and triangles
 	// distinguish between polys and triangles
 	std::string elementName = mReader->getNodeName();
 	std::string elementName = mReader->getNodeName();
@@ -1920,7 +1934,7 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 				if( !mReader->isEmptyElement())
 				if( !mReader->isEmptyElement())
 				{
 				{
 					// now here the actual fun starts - these are the indices to construct the mesh data from
 					// now here the actual fun starts - these are the indices to construct the mesh data from
-					ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, primType);
+					actualPrimitives += ReadPrimitives(pMesh, perIndexData, numPrimitives, vcount, primType);
 				}
 				}
 			} else
 			} else
 			{
 			{
@@ -1935,6 +1949,14 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 			break;
 			break;
 		}
 		}
 	}
 	}
+
+	// small sanity check
+	if (primType != Prim_TriFans && primType != Prim_TriStrips)
+		ai_assert(actualPrimitives == numPrimitives);
+
+	// only when we're done reading all <p> tags (and thus know the final vertex count) can we commit the submesh
+	subgroup.mNumFaces = actualPrimitives;
+	pMesh->mSubMeshes.push_back(subgroup);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -1982,7 +2004,7 @@ void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads a <p> primitive index list and assembles the mesh data into the given mesh
 // Reads a <p> primitive index list and assembles the mesh data into the given mesh
-void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, 
+size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
 	size_t pNumPrimitives, const std::vector<size_t>& pVCount, PrimitiveType pPrimType)
 	size_t pNumPrimitives, const std::vector<size_t>& pVCount, PrimitiveType pPrimType)
 {
 {
 	// determine number of indices coming per vertex 
 	// determine number of indices coming per vertex 
@@ -2080,70 +2102,98 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPer
 			acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
 			acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
 	}
 	}
 
 
-
-	// now assemble vertex data according to those indices
-	std::vector<size_t>::const_iterator idx = indices.begin();
-
 	// For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
 	// For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
 	size_t numPrimitives = pNumPrimitives;
 	size_t numPrimitives = pNumPrimitives;
 	if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
 	if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
 		numPrimitives = 1;
 		numPrimitives = 1;
+	// For continued primitives, the given count is actually the number of <p>'s inside the parent tag
+	if ( pPrimType == Prim_TriStrips){
+		size_t numberOfVertices = indices.size() / numOffsets;
+		numPrimitives = numberOfVertices - 2;
+	}
 
 
 	pMesh->mFaceSize.reserve( numPrimitives);
 	pMesh->mFaceSize.reserve( numPrimitives);
 	pMesh->mFacePosIndices.reserve( indices.size() / numOffsets);
 	pMesh->mFacePosIndices.reserve( indices.size() / numOffsets);
 
 
-	for( size_t a = 0; a < numPrimitives; a++)
+	size_t polylistStartVertex = 0;
+	for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++)
 	{
 	{
 		// determine number of points for this primitive
 		// determine number of points for this primitive
 		size_t numPoints = 0;
 		size_t numPoints = 0;
 		switch( pPrimType)
 		switch( pPrimType)
 		{
 		{
 			case Prim_Lines:
 			case Prim_Lines:
-				numPoints = 2; 
+				numPoints = 2;
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+				break;
+			case Prim_Triangles:
+				numPoints = 3;
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 				break;
 				break;
-			case Prim_Triangles: 
-				numPoints = 3; 
+			case Prim_TriStrips:
+				numPoints = 3;
+				ReadPrimTriStrips(numOffsets, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 				break;
 				break;
 			case Prim_Polylist: 
 			case Prim_Polylist: 
-				numPoints = pVCount[a];
+				numPoints = pVCount[currentPrimitive];
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(polylistStartVertex + currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, 0, indices);
+				polylistStartVertex += numPoints;
 				break;
 				break;
 			case Prim_TriFans: 
 			case Prim_TriFans: 
 			case Prim_Polygon:
 			case Prim_Polygon:
-				numPoints = indices.size() / numOffsets; 
+				numPoints = indices.size() / numOffsets;
+				for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+					CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
 				break;
 				break;
 			default:
 			default:
-				// LineStrip and TriStrip not supported due to expected index unmangling
+				// LineStrip is not supported due to expected index unmangling
 				ThrowException( "Unsupported primitive type.");
 				ThrowException( "Unsupported primitive type.");
 				break;
 				break;
 		}
 		}
 
 
 		// store the face size to later reconstruct the face from
 		// store the face size to later reconstruct the face from
 		pMesh->mFaceSize.push_back( numPoints);
 		pMesh->mFaceSize.push_back( numPoints);
-
-		// gather that number of vertices
-		for( size_t b = 0; b < numPoints; b++)
-		{
-			// read all indices for this vertex. Yes, in a hacky local array
-			ai_assert( numOffsets < 20 && perVertexOffset < 20);
-			size_t vindex[20];
-			for( size_t offsets = 0; offsets < numOffsets; ++offsets)
-				vindex[offsets] = *idx++;
-
-			// extract per-vertex channels using the global per-vertex offset
-      for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
-        ExtractDataObjectFromChannel( *it, vindex[perVertexOffset], pMesh);
-			// and extract per-index channels using there specified offset
-      for( std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
-				ExtractDataObjectFromChannel( *it, vindex[it->mOffset], pMesh);
-
-			// store the vertex-data index for later assignment of bone vertex weights
-			pMesh->mFacePosIndices.push_back( vindex[perVertexOffset]);
-		}
 	}
 	}
 
 
-
 	// if I ever get my hands on that guy who invented this steaming pile of indirection...
 	// if I ever get my hands on that guy who invented this steaming pile of indirection...
 	TestClosing( "p");
 	TestClosing( "p");
+	return numPrimitives;
+}
+
+void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices){
+	// calculate the base offset of the vertex whose attributes we ant to copy
+	size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets;
+
+	// don't overrun the boundaries of the index list
+	size_t maxIndexRequested = baseOffset + numOffsets - 1;
+	ai_assert(maxIndexRequested < indices.size());
+
+	// extract per-vertex channels using the global per-vertex offset
+	for (std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
+		ExtractDataObjectFromChannel(*it, indices[baseOffset + perVertexOffset], pMesh);
+	// and extract per-index channels using there specified offset
+	for (std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
+		ExtractDataObjectFromChannel(*it, indices[baseOffset + it->mOffset], pMesh);
+
+	// store the vertex-data index for later assignment of bone vertex weights
+	pMesh->mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]);
+}
+
+void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices){
+	if (currentPrimitive % 2 != 0){
+		//odd tristrip triangles need their indices mangled, to preserve winding direction
+		CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(0, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(2, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+	}
+	else {//for non tristrips or even tristrip triangles
+		CopyVertex(0, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+		CopyVertex(2, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 10 - 1
code/ColladaParser.h

@@ -177,9 +177,18 @@ protected:
 	void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
 	void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
 
 
 	/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
 	/** 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 ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
 		size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
 		size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
 
 
+	/** Copies the data for a single primitive into the mesh, based on the InputChannels */
+	void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
+		Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
+		size_t currentPrimitive, const std::vector<size_t>& indices);
+
+	/** Reads one triangle of a tristrip into the mesh */
+	void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh,
+		std::vector<Collada::InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices);
+
 	/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
 	/** 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);
 	void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
 
 

+ 3 - 3
code/ComputeUVMappingProcess.cpp

@@ -207,7 +207,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
 		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
 		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
 			const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
 			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,
 			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);
+				(std::asin  (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
 		}
 		}
 	}
 	}
 	else if (axis * base_axis_y >= angle_epsilon)	{
 	else if (axis * base_axis_y >= angle_epsilon)	{
@@ -215,7 +215,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
 		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
 		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
 			const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
 			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,
 			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);
+				(std::asin  (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
 		}
 		}
 	}
 	}
 	else if (axis * base_axis_z >= angle_epsilon)	{
 	else if (axis * base_axis_z >= angle_epsilon)	{
@@ -223,7 +223,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
 		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
 		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
 			const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
 			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,
 			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);
+				(std::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
 	// slower code path in case the mapping axis is not one of the coordinate system axes

+ 19 - 9
code/ConvertToLHProcess.cpp

@@ -57,12 +57,15 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 MakeLeftHandedProcess::MakeLeftHandedProcess()
 MakeLeftHandedProcess::MakeLeftHandedProcess()
-{}
+: BaseProcess() {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
-MakeLeftHandedProcess::~MakeLeftHandedProcess()
-{}
+MakeLeftHandedProcess::~MakeLeftHandedProcess() {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 // Returns whether the processing step is present in the given flag field.
@@ -121,8 +124,9 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
 	pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
 	pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
 
 
 	// continue for all children
 	// continue for all children
-	for( size_t a = 0; a < pNode->mNumChildren; ++a)
-		ProcessNode( pNode->mChildren[a], pParentGlobalRotation * pNode->mTransformation);
+    for( size_t a = 0; a < pNode->mNumChildren; ++a ) {
+        ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation );
+    }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -244,6 +248,10 @@ void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
 	aiMaterial* mat = (aiMaterial*)_mat;
 	aiMaterial* mat = (aiMaterial*)_mat;
 	for (unsigned int a = 0; a < mat->mNumProperties;++a)	{
 	for (unsigned int a = 0; a < mat->mNumProperties;++a)	{
 		aiMaterialProperty* prop = mat->mProperties[a];
 		aiMaterialProperty* prop = mat->mProperties[a];
+        if( !prop ) {
+            DefaultLogger::get()->debug( "Property is null" );
+            continue;
+        }
 
 
 		// UV transformation key?
 		// UV transformation key?
 		if (!::strcmp( prop->mKey.data, "$tex.uvtrafo"))	{
 		if (!::strcmp( prop->mKey.data, "$tex.uvtrafo"))	{
@@ -263,11 +271,13 @@ void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
 {
 {
 	// mirror texture y coordinate
 	// mirror texture y coordinate
 	for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)	{
 	for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)	{
-		if( !pMesh->HasTextureCoords( a))
-			break;
+        if( !pMesh->HasTextureCoords( a ) ) {
+            break;
+        }
 
 
-		for( unsigned int b = 0; b < pMesh->mNumVertices; b++)
-			pMesh->mTextureCoords[a][b].y = 1.0f - pMesh->mTextureCoords[a][b].y;
+        for( unsigned int b = 0; b < pMesh->mNumVertices; b++ ) {
+            pMesh->mTextureCoords[ a ][ b ].y = 1.0f - pMesh->mTextureCoords[ a ][ b ].y;
+        }
 	}
 	}
 }
 }
 
 

+ 2 - 2
code/DeboneProcess.cpp

@@ -111,8 +111,8 @@ void DeboneProcess::Execute( aiScene* pScene)
 
 
 	if(numSplits)	{
 	if(numSplits)	{
 		// we need to do something. Let's go.
 		// we need to do something. Let's go.
-		mSubMeshIndices.clear();
-		mSubMeshIndices.resize(pScene->mNumMeshes);
+		//mSubMeshIndices.clear();                  // really needed?
+		mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway
 
 
 		// build a new array of meshes for the scene
 		// build a new array of meshes for the scene
 		std::vector<aiMesh*> meshes;
 		std::vector<aiMesh*> meshes;

+ 18 - 11
code/DefaultIOStream.h

@@ -56,52 +56,59 @@ namespace Assimp	{
 class DefaultIOStream : public IOStream
 class DefaultIOStream : public IOStream
 {
 {
 	friend class DefaultIOSystem;
 	friend class DefaultIOSystem;
+#if __ANDROID__ 
+#if __ANDROID_API__ > 9
+#if defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
+    friend class AndroidJNIIOSystem;
+#endif // defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
+#endif // __ANDROID_API__ > 9
+#endif // __ANDROID__ 
 
 
 protected:
 protected:
-	DefaultIOStream ();
-	DefaultIOStream (FILE* pFile, const std::string &strFilename);
+	DefaultIOStream();
+	DefaultIOStream(FILE* pFile, const std::string &strFilename);
 
 
 public:
 public:
 	/** Destructor public to allow simple deletion to close the file. */
 	/** Destructor public to allow simple deletion to close the file. */
 	~DefaultIOStream ();
 	~DefaultIOStream ();
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	// Read from stream
+	/// Read from stream
     size_t Read(void* pvBuffer, 
     size_t Read(void* pvBuffer, 
 		size_t pSize, 
 		size_t pSize, 
 		size_t pCount);
 		size_t pCount);
 
 
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	// Write to stream
+	/// Write to stream
     size_t Write(const void* pvBuffer, 
     size_t Write(const void* pvBuffer, 
 		size_t pSize,
 		size_t pSize,
 		size_t pCount);
 		size_t pCount);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	// Seek specific position
+	/// Seek specific position
 	aiReturn Seek(size_t pOffset,
 	aiReturn Seek(size_t pOffset,
 		aiOrigin pOrigin);
 		aiOrigin pOrigin);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	// Get current seek position
+	/// Get current seek position
     size_t Tell() const;
     size_t Tell() const;
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	// Get size of file
+	/// Get size of file
 	size_t FileSize() const;
 	size_t FileSize() const;
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	// Flush file contents
+	/// Flush file contents
 	void Flush();
 	void Flush();
 
 
 private:
 private:
-	//!	File datastructure, using clib
+	//	File datastructure, using clib
 	FILE* mFile;
 	FILE* mFile;
-	//!	Filename
+	//	Filename
 	std::string	mFilename;
 	std::string	mFilename;
 
 
-	//! Cached file size
+	// Cached file size
 	mutable size_t cachedSize;
 	mutable size_t cachedSize;
 };
 };
 
 

+ 25 - 5
code/Exporter.cpp

@@ -78,7 +78,10 @@ void ExportSceneObj(const char*,IOSystem*, const aiScene*);
 void ExportSceneSTL(const char*,IOSystem*, const aiScene*);
 void ExportSceneSTL(const char*,IOSystem*, const aiScene*);
 void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*);
 void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*);
 void ExportScenePly(const char*,IOSystem*, const aiScene*);
 void ExportScenePly(const char*,IOSystem*, const aiScene*);
-void ExportScene3DS(const char*, IOSystem*, const aiScene*) {}
+void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*);
+void ExportScene3DS(const char*, IOSystem*, const aiScene*);
+void ExportSceneAssbin(const char*, IOSystem*, const aiScene*);
+void ExportSceneAssxml(const char*, IOSystem*, const aiScene*);
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // global array of all export formats which Assimp supports in its current build
 // global array of all export formats which Assimp supports in its current build
@@ -90,7 +93,7 @@ Exporter::ExportFormatEntry gExporters[] =
 
 
 #ifndef ASSIMP_BUILD_NO_FXILE_EXPORTER
 #ifndef ASSIMP_BUILD_NO_FXILE_EXPORTER
 	Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
 	Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
-	aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
+		aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
@@ -111,11 +114,23 @@ Exporter::ExportFormatEntry gExporters[] =
 	Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly, 
 	Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly, 
 		aiProcess_PreTransformVertices
 		aiProcess_PreTransformVertices
 	),
 	),
+	Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
+		aiProcess_PreTransformVertices
+	),
+#endif
+
+#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
+	Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
+		aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
 #endif
 #endif
 
 
-//#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
-//	ExportFormatEntry( "3ds", "Autodesk 3DS (legacy format)", "3ds" , &ExportScene3DS),
-//#endif
+#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
+	Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
+#endif
+
+#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
+	Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0),
+#endif
 };
 };
 
 
 #define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
 #define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
@@ -443,6 +458,11 @@ const aiExportFormatDesc* Exporter :: GetExportFormatDescription( size_t pIndex
 	if (pIndex >= GetExportFormatCount()) {
 	if (pIndex >= GetExportFormatCount()) {
 		return NULL;
 		return NULL;
 	}
 	}
+	
+	// Return from static storage if the requested index is built-in.
+	if (pIndex < sizeof(gExporters) / sizeof(gExporters[0])) {
+		return &gExporters[pIndex].mDescription;
+	}
 
 
 	return &pimpl->mExporters[pIndex].mDescription;
 	return &pimpl->mExporters[pIndex].mDescription;
 }
 }

+ 1 - 1
code/FBXAnimation.cpp

@@ -59,7 +59,7 @@ namespace FBX {
 	using namespace Util;
 	using namespace Util;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc)
+AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
 : Object(id, element, name)
 : Object(id, element, name)
 {
 {
 	const Scope& sc = GetRequiredScope(element);
 	const Scope& sc = GetRequiredScope(element);

+ 6 - 5
code/FBXBinaryTokenizer.cpp

@@ -55,14 +55,15 @@ namespace FBX {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset)
 Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset)
-	: sbegin(sbegin)
+	: 
+	#ifdef DEBUG
+	contents(sbegin, static_cast<size_t>(send-sbegin)),
+	#endif
+	sbegin(sbegin)
 	, send(send)
 	, send(send)
 	, type(type)
 	, type(type)
 	, line(offset)
 	, line(offset)
 	, column(BINARY_MARKER)
 	, column(BINARY_MARKER)
-#ifdef DEBUG
-	, contents(sbegin, static_cast<size_t>(send-sbegin))
-#endif
 {
 {
 	ai_assert(sbegin);
 	ai_assert(sbegin);
 	ai_assert(send);
 	ai_assert(send);
@@ -395,4 +396,4 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le
 } // !FBX
 } // !FBX
 } // !Assimp
 } // !Assimp
 
 
-#endif
+#endif

+ 11 - 14
code/FBXConverter.cpp

@@ -381,8 +381,6 @@ private:
 		out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
 		out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
 		out_camera->mPosition = cam.Position();
 		out_camera->mPosition = cam.Position();
 		out_camera->mLookAt = cam.InterestPosition() - out_camera->mPosition;
 		out_camera->mLookAt = cam.InterestPosition() - out_camera->mPosition;
-
-		// BUG HERE cam.FieldOfView() returns 1.0f every time.  1.0f is default value.
 		out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
 		out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
 	}
 	}
 
 
@@ -499,15 +497,15 @@ private:
 		bool is_id[3] = { true, true, true };
 		bool is_id[3] = { true, true, true };
 
 
 		aiMatrix4x4 temp[3];
 		aiMatrix4x4 temp[3];
-		if(fabs(rotation.z) > angle_epsilon) {
+		if(std::fabs(rotation.z) > angle_epsilon) {
 			aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z),temp[2]);
 			aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z),temp[2]);
 			is_id[2] = false;
 			is_id[2] = false;
 		}
 		}
-		if(fabs(rotation.y) > angle_epsilon) {
+		if(std::fabs(rotation.y) > angle_epsilon) {
 			aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y),temp[1]);
 			aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y),temp[1]);
 			is_id[1] = false;
 			is_id[1] = false;
 		}
 		}
-		if(fabs(rotation.x) > angle_epsilon) {
+		if(std::fabs(rotation.x) > angle_epsilon) {
 			aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x),temp[0]);
 			aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x),temp[0]);
 			is_id[0] = false;
 			is_id[0] = false;
 		}
 		}
@@ -676,7 +674,7 @@ private:
 		}
 		}
 
 
 		const aiVector3D& Scaling = PropertyGet<aiVector3D>(props,"Lcl Scaling",ok);
 		const aiVector3D& Scaling = PropertyGet<aiVector3D>(props,"Lcl Scaling",ok);
-		if(ok && fabs(Scaling.SquareLength()-1.0f) > zero_epsilon) {
+		if(ok && std::fabs(Scaling.SquareLength()-1.0f) > zero_epsilon) {
 			aiMatrix4x4::Scaling(Scaling,chain[TransformationComp_Scaling]);
 			aiMatrix4x4::Scaling(Scaling,chain[TransformationComp_Scaling]);
 		}
 		}
 
 
@@ -686,7 +684,7 @@ private:
 		}
 		}
 		
 		
 		const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
 		const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
-		if (ok && fabs(GeometricScaling.SquareLength() - 1.0f) > zero_epsilon) {
+		if (ok && std::fabs(GeometricScaling.SquareLength() - 1.0f) > zero_epsilon) {
 			aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
 			aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
 		}
 		}
 		
 		
@@ -767,7 +765,6 @@ private:
 
 
 		// find user defined properties (3ds Max)
 		// find user defined properties (3ds Max)
 		data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", "")));
 		data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", "")));
-		unparsedProperties.erase("UDP3DSMAX");
 		// preserve the info that a node was marked as Null node in the original file.
 		// preserve the info that a node was marked as Null node in the original file.
 		data->Set(index++, "IsNull", model.IsNull() ? true : false);
 		data->Set(index++, "IsNull", model.IsNull() ? true : false);
 
 
@@ -1320,7 +1317,7 @@ private:
 
 
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
-	void ConvertCluster(std::vector<aiBone*>& bones, const Model& model, const Cluster& cl, 		
+	void ConvertCluster(std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl,
 		std::vector<size_t>& out_indices,
 		std::vector<size_t>& out_indices,
 		std::vector<size_t>& index_out_indices,
 		std::vector<size_t>& index_out_indices,
 		std::vector<size_t>& count_out_indices,
 		std::vector<size_t>& count_out_indices,
@@ -2348,7 +2345,7 @@ private:
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, 
 	aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, 
-		const Model& target, 
+		const Model& /*target*/,
 		const std::vector<const AnimationCurveNode*>& curves,
 		const std::vector<const AnimationCurveNode*>& curves,
 		const LayerMap& layer_map,
 		const LayerMap& layer_map,
 		double& max_time,
 		double& max_time,
@@ -2379,7 +2376,7 @@ private:
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, 
 	aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, 
-		const Model& target, 
+		const Model& /*target*/,
 		const std::vector<const AnimationCurveNode*>& curves,
 		const std::vector<const AnimationCurveNode*>& curves,
 		const LayerMap& layer_map,
 		const LayerMap& layer_map,
 		double& max_time,
 		double& max_time,
@@ -2831,7 +2828,7 @@ private:
 
 
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
-	void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& layers,
+	void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
 		double& maxTime,
 		double& maxTime,
 		double& minTime)
 		double& minTime)
 	{
 	{
@@ -2852,7 +2849,7 @@ private:
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 
 	void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 
-		const LayerMap& layers,
+		const LayerMap& /*layers*/,
 		double& maxTime,
 		double& maxTime,
 		double& minTime)
 		double& minTime)
 	{
 	{
@@ -2870,7 +2867,7 @@ private:
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 
 	void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 
-		const LayerMap& layers, 
+		const LayerMap& /*layers*/,
 		double& maxTime,
 		double& maxTime,
 		double& minTime,
 		double& minTime,
 		Model::RotOrder order)
 		Model::RotOrder order)

+ 10 - 5
code/FBXDocument.cpp

@@ -253,8 +253,8 @@ Document::Document(const Parser& parser, const ImportSettings& settings)
 : settings(settings)
 : settings(settings)
 , parser(parser)
 , parser(parser)
 {
 {
-	// cannot use array default initialization syntax because vc8 fails on it
-	for (unsigned int i = 0; i < 7; ++i) {
+	// Cannot use array default initialization syntax because vc8 fails on it
+	for (unsigned int i = 0; i < sizeof(creationTimeStamp) / sizeof(creationTimeStamp[0]); ++i) {
 		creationTimeStamp[i] = 0;
 		creationTimeStamp[i] = 0;
 	}
 	}
 
 
@@ -263,7 +263,7 @@ Document::Document(const Parser& parser, const ImportSettings& settings)
 
 
 	ReadGlobalSettings();
 	ReadGlobalSettings();
 
 
-	// this order is important, connections need parsed objects to check
+	// This order is important, connections need parsed objects to check
 	// whether connections are ok or not. Objects may not be evaluated yet,
 	// whether connections are ok or not. Objects may not be evaluated yet,
 	// though, since this may require valid connections.
 	// though, since this may require valid connections.
 	ReadObjects();
 	ReadObjects();
@@ -277,13 +277,18 @@ Document::~Document()
 	BOOST_FOREACH(ObjectMap::value_type& v, objects) {
 	BOOST_FOREACH(ObjectMap::value_type& v, objects) {
 		delete v.second;
 		delete v.second;
 	}
 	}
+
+	BOOST_FOREACH(ConnectionMap::value_type& v, src_connections) {
+		delete v.second;
+	}
+	// |dest_connections| contain the same Connection objects as the |src_connections|
 }
 }
 
 
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void Document::ReadHeader()
 void Document::ReadHeader()
 {
 {
-	// read ID objects from "Objects" section
+	// Read ID objects from "Objects" section
 	const Scope& sc = parser.GetRootScope();
 	const Scope& sc = parser.GetRootScope();
 	const Element* const ehead = sc["FBXHeaderExtension"];
 	const Element* const ehead = sc["FBXHeaderExtension"];
 	if(!ehead || !ehead->Compound()) {
 	if(!ehead || !ehead->Compound()) {
@@ -293,7 +298,7 @@ void Document::ReadHeader()
 	const Scope& shead = *ehead->Compound();
 	const Scope& shead = *ehead->Compound();
 	fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
 	fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
 
 
-	// while we maye have some success with newer files, we don't support
+	// While we maye have some success with newer files, we don't support
 	// the older 6.n fbx format
 	// the older 6.n fbx format
 	if(fbxVersion < 7100) {
 	if(fbxVersion < 7100) {
 		DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
 		DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");

+ 2 - 2
code/FBXDocument.h

@@ -696,7 +696,7 @@ public:
 public:
 public:
 
 
 	/** Get the Skin attached to this geometry or NULL */
 	/** Get the Skin attached to this geometry or NULL */
-	const Skin* const DeformerSkin() const {
+	const Skin* DeformerSkin() const {
 		return skin;
 		return skin;
 	}
 	}
 
 
@@ -1096,7 +1096,7 @@ public:
 		return transformLink;
 		return transformLink;
 	}
 	}
 
 
-	const Model* const TargetNode() const {
+	const Model* TargetNode() const {
 		return node;
 		return node;
 	}
 	}
 
 

+ 3 - 1
code/FBXImporter.cpp

@@ -105,7 +105,7 @@ bool FBXImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
 
 
 	else if ((!extension.length() || checkSig) && pIOHandler)	{
 	else if ((!extension.length() || checkSig) && pIOHandler)	{
 		// at least ascii FBX files usually have a 'FBX' somewhere in their head
 		// at least ascii FBX files usually have a 'FBX' somewhere in their head
-		const char* tokens[] = {"FBX"};
+		const char* tokens[] = {"fbx"};
 		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
 		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
 	}
 	}
 	return false;
 	return false;
@@ -179,6 +179,8 @@ void FBXImporter::InternReadFile( const std::string& pFile,
 
 
 		// convert the FBX DOM to aiScene
 		// convert the FBX DOM to aiScene
 		ConvertToAssimpScene(pScene,doc);
 		ConvertToAssimpScene(pScene,doc);
+
+		std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
 	}
 	}
 	catch(std::exception&) {
 	catch(std::exception&) {
 		std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
 		std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());

+ 1 - 1
code/FBXMaterial.cpp

@@ -207,7 +207,7 @@ Texture::~Texture()
 
 
 }
 }
 
 
-LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
+LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name)
 : Object(id,element,name)
 : Object(id,element,name)
 ,texture(0)
 ,texture(0)
 ,blendMode(BlendMode_Modulate)
 ,blendMode(BlendMode_Modulate)

+ 4 - 2
code/FBXMeshGeometry.cpp

@@ -466,8 +466,9 @@ void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out,
 	const std::string& MappingInformationType,
 	const std::string& MappingInformationType,
 	const std::string& ReferenceInformationType)
 	const std::string& ReferenceInformationType)
 {
 {
+	const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
 	ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
 	ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
-		"Tangent",
+		str,
 		"TangentIndex",
 		"TangentIndex",
 		vertices.size(),
 		vertices.size(),
 		mapping_counts,
 		mapping_counts,
@@ -481,8 +482,9 @@ void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_ou
 	const std::string& MappingInformationType,
 	const std::string& MappingInformationType,
 	const std::string& ReferenceInformationType)
 	const std::string& ReferenceInformationType)
 {
 {
+	const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
 	ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
 	ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
-		"Binormal",
+		str,
 		"BinormalIndex",
 		"BinormalIndex",
 		vertices.size(),
 		vertices.size(),
 		mapping_counts,
 		mapping_counts,

+ 24 - 34
code/FBXParser.cpp

@@ -93,7 +93,7 @@ namespace {
 	}
 	}
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
-	void ParseWarning(const std::string& message, const Element* element = NULL)
+/*	void ParseWarning(const std::string& message, const Element* element = NULL)
 	{
 	{
 		if(element) {
 		if(element) {
 			ParseWarning(message,element->KeyToken());
 			ParseWarning(message,element->KeyToken());
@@ -103,7 +103,7 @@ namespace {
 			DefaultLogger::get()->warn("FBX-Parser: " + message);
 			DefaultLogger::get()->warn("FBX-Parser: " + message);
 		}
 		}
 	}
 	}
-
+*/
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	void ParseError(const std::string& message, TokenPtr token)
 	void ParseError(const std::string& message, TokenPtr token)
 	{
 	{
@@ -113,6 +113,18 @@ namespace {
 		ParseError(message);
 		ParseError(message);
 	}
 	}
 
 
+	// Initially, we did reinterpret_cast, breaking strict aliasing rules.
+	// This actually caused trouble on Android, so let's be safe this time.
+	// https://github.com/assimp/assimp/issues/24
+	template <typename T>
+	T SafeParse(const char* data, const char* end) {
+		// Actual size validation happens during Tokenization so
+		// this is valid as an assertion.
+		ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
+		T result = static_cast<T>(0);
+		::memcpy(&result, data, sizeof(T));
+		return result;
+	}
 }
 }
 
 
 namespace Assimp {
 namespace Assimp {
@@ -275,9 +287,7 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
 			return 0L;
 			return 0L;
 		}
 		}
 
 
-		ai_assert(t.end() - data == 9);
-
-		BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1);
+		BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
 		AI_SWAP8(id);
 		AI_SWAP8(id);
 		return id;
 		return id;
 	}
 	}
@@ -316,8 +326,7 @@ size_t ParseTokenAsDim(const Token& t, const char*& err_out)
 			return 0;
 			return 0;
 		}
 		}
 
 
-		ai_assert(t.end() - data == 9);
-		BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1);
+		BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
 		AI_SWAP8(id);
 		AI_SWAP8(id);
 		return static_cast<size_t>(id);
 		return static_cast<size_t>(id);
 	}
 	}
@@ -364,24 +373,10 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
 		}
 		}
 
 
 		if (data[0] == 'F') {
 		if (data[0] == 'F') {
-			// Actual size validation happens during Tokenization so
-			// this is valid as an assertion.
-			ai_assert(t.end() - data == sizeof(float) + 1);
-			// Initially, we did reinterpret_cast, breaking strict aliasing rules.
-			// This actually caused trouble on Android, so let's be safe this time.
-			// https://github.com/assimp/assimp/issues/24
-			
-			float out_float;
-			::memcpy(&out_float, data+1, sizeof(float));
-			return out_float;
+			return SafeParse<float>(data+1, t.end());
 		}
 		}
 		else {
 		else {
-			ai_assert(t.end() - data == sizeof(double) + 1);
-			
-			// Same
-			double out_double;
-			::memcpy(&out_double, data+1, sizeof(double));
-			return out_double;
+			return static_cast<float>( SafeParse<double>(data+1, t.end()) );
 		}
 		}
 	}
 	}
 
 
@@ -416,8 +411,7 @@ int ParseTokenAsInt(const Token& t, const char*& err_out)
 			return 0;
 			return 0;
 		}
 		}
 
 
-		ai_assert(t.end() - data == 5);
-		BE_NCONST int32_t ival = *reinterpret_cast<const int32_t*>(data+1);
+		BE_NCONST int32_t ival = SafeParse<int32_t>(data+1, t.end());
 		AI_SWAP4(ival);
 		AI_SWAP4(ival);
 		return static_cast<int>(ival);
 		return static_cast<int>(ival);
 	}
 	}
@@ -453,10 +447,8 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out)
 			return "";
 			return "";
 		}
 		}
 
 
-		ai_assert(t.end() - data >= 5);
-
 		// read string length
 		// read string length
-		BE_NCONST int32_t len = *reinterpret_cast<const int32_t*>(data+1);
+		BE_NCONST int32_t len = SafeParse<int32_t>(data+1, t.end());
 		AI_SWAP4(len);
 		AI_SWAP4(len);
 
 
 		ai_assert(t.end() - data == 5 + len);
 		ai_assert(t.end() - data == 5 + len);
@@ -494,7 +486,7 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin
 	type = *data;
 	type = *data;
 
 
 	// read number of elements
 	// read number of elements
-	BE_NCONST uint32_t len = *reinterpret_cast<const uint32_t*>(data+1);
+	BE_NCONST uint32_t len = SafeParse<uint32_t>(data+1, end);
 	AI_SWAP4(len);
 	AI_SWAP4(len);
 
 
 	count = len;
 	count = len;
@@ -506,16 +498,14 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin
 // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
 // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
 void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, 
 void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, 
 	std::vector<char>& buff, 
 	std::vector<char>& buff, 
-	const Element& el)
+	const Element& /*el*/)
 {
 {
-	ai_assert(static_cast<size_t>(end-data) >= 4); // runtime check for this happens at tokenization stage
-
-	BE_NCONST uint32_t encmode = *reinterpret_cast<const uint32_t*>(data);
+	BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
 	AI_SWAP4(encmode);
 	AI_SWAP4(encmode);
 	data += 4;
 	data += 4;
 
 
 	// next comes the compressed length
 	// next comes the compressed length
-	BE_NCONST uint32_t comp_len = *reinterpret_cast<const uint32_t*>(data);
+	BE_NCONST uint32_t comp_len = SafeParse<uint32_t>(data, end);
 	AI_SWAP4(comp_len);
 	AI_SWAP4(comp_len);
 	data += 4;
 	data += 4;
 
 

+ 2 - 2
code/FBXProperties.cpp

@@ -85,7 +85,7 @@ Property* ReadTypedProperty(const Element& element)
 	else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
 	else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
 		return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
 		return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
 	}
 	}
-	else if (!strcmp(cs,"int") || !strcmp(cs,"enum")) {
+	else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
 		return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
 		return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
 	}
 	}
 	else if (!strcmp(cs,"ULongLong")) {
 	else if (!strcmp(cs,"ULongLong")) {
@@ -105,7 +105,7 @@ Property* ReadTypedProperty(const Element& element)
 			ParseTokenAsFloat(*tok[6]))
 			ParseTokenAsFloat(*tok[6]))
 		);
 		);
 	}
 	}
-	else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"KTime") || !strcmp(cs,"Float")) {
+	else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"KTime") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) {
 		return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
 		return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
 	}
 	}
 	return NULL;
 	return NULL;

+ 2 - 4
code/FBXProperties.h

@@ -143,8 +143,7 @@ private:
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
 inline T PropertyGet(const PropertyTable& in, const std::string& name, 
 inline T PropertyGet(const PropertyTable& in, const std::string& name, 
-	const T& defaultValue, 
-	bool ignoreTemplate = false)
+	const T& defaultValue)
 {
 {
 	const Property* const prop = in.Get(name);
 	const Property* const prop = in.Get(name);
 	if(!prop) {
 	if(!prop) {
@@ -164,8 +163,7 @@ inline T PropertyGet(const PropertyTable& in, const std::string& name,
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
 inline T PropertyGet(const PropertyTable& in, const std::string& name, 
 inline T PropertyGet(const PropertyTable& in, const std::string& name, 
-	bool& result, 
-	bool ignoreTemplate = false)
+	bool& result)
 {
 {
 	const Property* const prop = in.Get(name);
 	const Property* const prop = in.Get(name);
 	if(!prop) {
 	if(!prop) {

+ 5 - 4
code/FBXTokenizer.cpp

@@ -58,14 +58,15 @@ namespace FBX {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column)
 Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column)
-	: sbegin(sbegin)
+	:
+#ifdef DEBUG
+	contents(sbegin, static_cast<size_t>(send-sbegin)),
+#endif
+	sbegin(sbegin)
 	, send(send)
 	, send(send)
 	, type(type)
 	, type(type)
 	, line(line)
 	, line(line)
 	, column(column)
 	, column(column)
-#ifdef DEBUG
-	, contents(sbegin, static_cast<size_t>(send-sbegin))
-#endif
 {
 {
 	ai_assert(sbegin);
 	ai_assert(sbegin);
 	ai_assert(send);
 	ai_assert(send);

+ 2 - 4
code/FindInstancesProcess.cpp

@@ -85,8 +85,7 @@ bool CompareBones(const aiMesh* orig, const aiMesh* inst)
 		aiBone* oha = inst->mBones[i];
 		aiBone* oha = inst->mBones[i];
 
 
 		if (aha->mNumWeights   != oha->mNumWeights   ||
 		if (aha->mNumWeights   != oha->mNumWeights   ||
-			aha->mOffsetMatrix != oha->mOffsetMatrix ||
-			aha->mNumWeights   != oha->mNumWeights) {
+			aha->mOffsetMatrix != oha->mOffsetMatrix) {
 			return false;
 			return false;
 		}
 		}
 
 
@@ -174,7 +173,6 @@ void FindInstancesProcess::Execute( aiScene* pScene)
 
 
 					// use a constant epsilon for colors and UV coordinates
 					// use a constant epsilon for colors and UV coordinates
 					static const float uvEpsilon = 10e-4f;
 					static const float uvEpsilon = 10e-4f;
-
 					{
 					{
 						unsigned int i, end = orig->GetNumUVChannels();
 						unsigned int i, end = orig->GetNumUVChannels();
 						for(i = 0; i < end; ++i) {
 						for(i = 0; i < end; ++i) {
@@ -260,7 +258,7 @@ void FindInstancesProcess::Execute( aiScene* pScene)
 					pScene->mMeshes[real++] = pScene->mMeshes[i];
 					pScene->mMeshes[real++] = pScene->mMeshes[i];
 			}
 			}
 
 
-			// And update the nodegraph with our nice lookup table
+			// And update the node graph with our nice lookup table
 			UpdateMeshIndices(pScene->mRootNode,remapping.get());
 			UpdateMeshIndices(pScene->mRootNode,remapping.get());
 
 
 			// write to log
 			// write to log

+ 1 - 1
code/FindInvalidDataProcess.cpp

@@ -221,7 +221,7 @@ AI_FORCE_INLINE bool EpsilonCompare(const T& n, const T& s, float epsilon);
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 AI_FORCE_INLINE bool EpsilonCompare(float n, float s, float epsilon) {
 AI_FORCE_INLINE bool EpsilonCompare(float n, float s, float epsilon) {
-	return fabs(n-s)>epsilon;
+	return std::fabs(n-s)>epsilon;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/FixNormalsStep.cpp

@@ -149,8 +149,8 @@ bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index)
 	if (fDelta1_z < 0.05f * sqrtf( fDelta1_y * fDelta1_x ))return false;
 	if (fDelta1_z < 0.05f * sqrtf( fDelta1_y * fDelta1_x ))return false;
 
 
 	// now compare the volumes of the bounding boxes
 	// now compare the volumes of the bounding boxes
-	if (::fabsf(fDelta0_x * fDelta1_yz) <
-		::fabsf(fDelta1_x * fDelta1_y * fDelta1_z))
+	if (std::fabs(fDelta0_x * fDelta1_yz) <
+		std::fabs(fDelta1_x * fDelta1_y * fDelta1_z))
 	{
 	{
 		if (!DefaultLogger::isNullLogger())
 		if (!DefaultLogger::isNullLogger())
 		{
 		{

+ 2 - 2
code/GenVertexNormalsProcess.cpp

@@ -93,7 +93,7 @@ void GenVertexNormalsProcess::Execute( aiScene* pScene)
 	bool bHas = false;
 	bool bHas = false;
 	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
 	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
 	{
 	{
-		if(GenMeshVertexNormals( pScene->mMeshes[a],a))
+        if(GenMeshVertexNormals( pScene->mMeshes[a],a))
 			bHas = true;
 			bHas = true;
 	}
 	}
 
 
@@ -204,7 +204,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
 	// Slower code path if a smooth angle is set. There are many ways to achieve
 	// Slower code path if a smooth angle is set. There are many ways to achieve
 	// the effect, this one is the most straightforward one.
 	// the effect, this one is the most straightforward one.
 	else	{
 	else	{
-		const float fLimit = ::cos(configMaxAngle); 
+		const float fLimit = std::cos(configMaxAngle);
 		for (unsigned int i = 0; i < pMesh->mNumVertices;++i)	{
 		for (unsigned int i = 0; i < pMesh->mNumVertices;++i)	{
 			// Get all vertices that share this one ...
 			// Get all vertices that share this one ...
 			vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);
 			vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);

+ 1 - 1
code/GenVertexNormalsProcess.h

@@ -53,7 +53,7 @@ namespace Assimp {
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** The GenFaceNormalsProcess computes vertex normals for all vertizes
 /** The GenFaceNormalsProcess computes vertex normals for all vertizes
 */
 */
-class ASSIMP_API_WINONLY GenVertexNormalsProcess : public BaseProcess
+class ASSIMP_API GenVertexNormalsProcess : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 6 - 6
code/IFCBoolean.cpp

@@ -69,8 +69,8 @@ Intersect IntersectSegmentPlane(const IfcVector3& p,const IfcVector3& n, const I
 	const IfcVector3 pdelta = e0 - p, seg = e1-e0;
 	const IfcVector3 pdelta = e0 - p, seg = e1-e0;
 	const IfcFloat dotOne = n*seg, dotTwo = -(n*pdelta);
 	const IfcFloat dotOne = n*seg, dotTwo = -(n*pdelta);
 
 
-	if (fabs(dotOne) < 1e-6) {
-		return fabs(dotTwo) < 1e-6f ? Intersect_LiesOnPlane : Intersect_No;
+	if (std::fabs(dotOne) < 1e-6) {
+		return std::fabs(dotTwo) < 1e-6f ? Intersect_LiesOnPlane : Intersect_No;
 	}
 	}
 
 
 	const IfcFloat t = dotTwo/dotOne;
 	const IfcFloat t = dotTwo/dotOne;
@@ -85,7 +85,7 @@ Intersect IntersectSegmentPlane(const IfcVector3& p,const IfcVector3& n, const I
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& result, 
 void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& result, 
 									   const TempMesh& first_operand, 
 									   const TempMesh& first_operand, 
-									   ConversionData& conv)
+									   ConversionData& /*conv*/)
 {
 {
 	ai_assert(hs != NULL);
 	ai_assert(hs != NULL);
 
 
@@ -210,7 +210,7 @@ bool IntersectsBoundaryProfile( const IfcVector3& e0, const IfcVector3& e1, cons
 		// segment-segment intersection
 		// segment-segment intersection
 		// solve b0 + b*s = e0 + e*t for (s,t)
 		// solve b0 + b*s = e0 + e*t for (s,t)
 		const IfcFloat det = (-b.x * e.y + e.x * b.y);
 		const IfcFloat det = (-b.x * e.y + e.x * b.y);
-		if(fabs(det) < 1e-6) {
+		if(std::fabs(det) < 1e-6) {
 			// no solutions (parallel lines)
 			// no solutions (parallel lines)
 			continue;
 			continue;
 		}
 		}
@@ -234,7 +234,7 @@ bool IntersectsBoundaryProfile( const IfcVector3& e0, const IfcVector3& e1, cons
 		if (t >= -epsilon && (t <= 1.0+epsilon || half_open) && s >= -epsilon && s <= 1.0) {
 		if (t >= -epsilon && (t <= 1.0+epsilon || half_open) && s >= -epsilon && s <= 1.0) {
 
 
 			if (e0_hits_border && !*e0_hits_border) {
 			if (e0_hits_border && !*e0_hits_border) {
-				*e0_hits_border = fabs(t) < 1e-5f;
+				*e0_hits_border = std::fabs(t) < 1e-5f;
 			}
 			}
 	
 	
 			const IfcVector3& p = e0 + e*t;
 			const IfcVector3& p = e0 + e*t;
@@ -419,7 +419,7 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
 
 
 #ifdef ASSIMP_BUILD_DEBUG
 #ifdef ASSIMP_BUILD_DEBUG
 			if (isect == Intersect_Yes) {
 			if (isect == Intersect_Yes) {
-				const IfcFloat f = fabs((isectpos - p)*n);
+				const IfcFloat f = std::fabs((isectpos - p)*n);
 				ai_assert(f < 1e-5);
 				ai_assert(f < 1e-5);
 			}
 			}
 #endif
 #endif

+ 12 - 12
code/IFCCurve.cpp

@@ -88,10 +88,10 @@ public:
 		a *= conv.angle_scale;
 		a *= conv.angle_scale;
 		b *= conv.angle_scale;
 		b *= conv.angle_scale;
 
 
-		a = fmod(a,static_cast<IfcFloat>( AI_MATH_TWO_PI ));
-		b = fmod(b,static_cast<IfcFloat>( AI_MATH_TWO_PI ));
+		a = std::fmod(a,static_cast<IfcFloat>( AI_MATH_TWO_PI ));
+		b = std::fmod(b,static_cast<IfcFloat>( AI_MATH_TWO_PI ));
 		const IfcFloat setting = static_cast<IfcFloat>( AI_MATH_PI * conv.settings.conicSamplingAngle / 180.0 );
 		const IfcFloat setting = static_cast<IfcFloat>( AI_MATH_PI * conv.settings.conicSamplingAngle / 180.0 );
-		return static_cast<size_t>( ceil(abs( b-a)) / setting);
+		return static_cast<size_t>( std::ceil(abs( b-a)) / setting);
 	}
 	}
 
 
 	// --------------------------------------------------
 	// --------------------------------------------------
@@ -124,8 +124,8 @@ public:
 	// --------------------------------------------------
 	// --------------------------------------------------
 	IfcVector3 Eval(IfcFloat u) const {
 	IfcVector3 Eval(IfcFloat u) const {
 		u = -conv.angle_scale * u;
 		u = -conv.angle_scale * u;
-		return location + static_cast<IfcFloat>(entity.Radius)*(static_cast<IfcFloat>(::cos(u))*p[0] + 
-			static_cast<IfcFloat>(::sin(u))*p[1]);
+		return location + static_cast<IfcFloat>(entity.Radius)*(static_cast<IfcFloat>(std::cos(u))*p[0] +
+			static_cast<IfcFloat>(std::sin(u))*p[1]);
 	}
 	}
 
 
 private:
 private:
@@ -153,8 +153,8 @@ public:
 	// --------------------------------------------------
 	// --------------------------------------------------
 	IfcVector3 Eval(IfcFloat u) const {
 	IfcVector3 Eval(IfcFloat u) const {
 		u = -conv.angle_scale * u;
 		u = -conv.angle_scale * u;
-		return location + static_cast<IfcFloat>(entity.SemiAxis1)*static_cast<IfcFloat>(::cos(u))*p[0] +
-			static_cast<IfcFloat>(entity.SemiAxis2)*static_cast<IfcFloat>(::sin(u))*p[1];
+		return location + static_cast<IfcFloat>(entity.SemiAxis1)*static_cast<IfcFloat>(std::cos(u))*p[0] +
+			static_cast<IfcFloat>(entity.SemiAxis2)*static_cast<IfcFloat>(std::sin(u))*p[1];
 	}
 	}
 
 
 private:
 private:
@@ -486,7 +486,7 @@ public:
 	IfcVector3 Eval(IfcFloat p) const {
 	IfcVector3 Eval(IfcFloat p) const {
 		ai_assert(InRange(p));
 		ai_assert(InRange(p));
 		
 		
-		const size_t b = static_cast<size_t>(floor(p));  
+		const size_t b = static_cast<size_t>(std::floor(p));
 		if (b == points.size()-1) {
 		if (b == points.size()-1) {
 			return points.back();
 			return points.back();
 		}
 		}
@@ -498,7 +498,7 @@ public:
 	// --------------------------------------------------
 	// --------------------------------------------------
 	size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
 	size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
 		ai_assert(InRange(a) && InRange(b));
 		ai_assert(InRange(a) && InRange(b));
-		return static_cast<size_t>( ceil(b) - floor(a) );
+		return static_cast<size_t>( std::ceil(b) - std::floor(a) );
 	}
 	}
 
 
 	// --------------------------------------------------
 	// --------------------------------------------------
@@ -558,7 +558,7 @@ bool Curve :: InRange(IfcFloat u) const
 	if (IsClosed()) {
 	if (IsClosed()) {
 		return true;
 		return true;
 		//ai_assert(range.first != std::numeric_limits<IfcFloat>::infinity() && range.second != std::numeric_limits<IfcFloat>::infinity());
 		//ai_assert(range.first != std::numeric_limits<IfcFloat>::infinity() && range.second != std::numeric_limits<IfcFloat>::infinity());
-		//u = range.first + fmod(u-range.first,range.second-range.first);
+		//u = range.first + std::fmod(u-range.first,range.second-range.first);
 	}
 	}
 	const IfcFloat epsilon = 1e-5;
 	const IfcFloat epsilon = 1e-5;
 	return u - range.first > -epsilon && range.second - u > -epsilon;
 	return u - range.first > -epsilon && range.second - u > -epsilon;
@@ -606,12 +606,12 @@ IfcFloat RecursiveSearch(const Curve* cv, const IfcVector3& val, IfcFloat a, Ifc
 	}
 	}
 
 
 	ai_assert(min_diff[0] != inf && min_diff[1] != inf);
 	ai_assert(min_diff[0] != inf && min_diff[1] != inf);
-	if ( fabs(a-min_point[0]) < threshold || recurse >= max_recurse) {
+	if ( std::fabs(a-min_point[0]) < threshold || recurse >= max_recurse) {
 		return min_point[0];
 		return min_point[0];
 	}
 	}
 
 
 	// fix for closed curves to take their wrap-over into account
 	// fix for closed curves to take their wrap-over into account
-	if (cv->IsClosed() && fabs(min_point[0]-min_point[1]) > cv->GetParametricRangeDelta()*0.5  ) {
+	if (cv->IsClosed() && std::fabs(min_point[0]-min_point[1]) > cv->GetParametricRangeDelta()*0.5  ) {
 		const Curve::ParamRange& range = cv->GetParametricRange();
 		const Curve::ParamRange& range = cv->GetParametricRange();
 		const IfcFloat wrapdiff = (cv->Eval(range.first)-val).SquareLength();
 		const IfcFloat wrapdiff = (cv->Eval(range.first)-val).SquareLength();
 
 

+ 4 - 4
code/IFCGeometry.cpp

@@ -250,17 +250,17 @@ void ProcessRevolvedAreaSolid(const IfcRevolvedAreaSolid& solid, TempMesh& resul
 	
 	
 	bool has_area = solid.SweptArea->ProfileType == "AREA" && size>2;
 	bool has_area = solid.SweptArea->ProfileType == "AREA" && size>2;
 	const IfcFloat max_angle = solid.Angle*conv.angle_scale;
 	const IfcFloat max_angle = solid.Angle*conv.angle_scale;
-	if(fabs(max_angle) < 1e-3) {
+	if(std::fabs(max_angle) < 1e-3) {
 		if(has_area) {
 		if(has_area) {
 			result = meshout;
 			result = meshout;
 		}
 		}
 		return;
 		return;
 	}
 	}
 
 
-	const unsigned int cnt_segments = std::max(2u,static_cast<unsigned int>(16 * fabs(max_angle)/AI_MATH_HALF_PI_F));
+	const unsigned int cnt_segments = std::max(2u,static_cast<unsigned int>(16 * std::fabs(max_angle)/AI_MATH_HALF_PI_F));
 	const IfcFloat delta = max_angle/cnt_segments;
 	const IfcFloat delta = max_angle/cnt_segments;
 
 
-	has_area = has_area && fabs(max_angle) < AI_MATH_TWO_PI_F*0.99;
+	has_area = has_area && std::fabs(max_angle) < AI_MATH_TWO_PI_F*0.99;
 	
 	
 	result.verts.reserve(size*((cnt_segments+1)*4+(has_area?2:0)));
 	result.verts.reserve(size*((cnt_segments+1)*4+(has_area?2:0)));
 	result.vertcnt.reserve(size*cnt_segments+2);
 	result.vertcnt.reserve(size*cnt_segments+2);
@@ -480,7 +480,7 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
 	for (i = 0; !done && i < s-2; done || ++i) {
 	for (i = 0; !done && i < s-2; done || ++i) {
 		for (j = i+1; j < s-1; ++j) {
 		for (j = i+1; j < s-1; ++j) {
 			nor = -((out[i]-any_point)^(out[j]-any_point));
 			nor = -((out[i]-any_point)^(out[j]-any_point));
-			if(fabs(nor.Length()) > 1e-8f) {
+			if(std::fabs(nor.Length()) > 1e-8f) {
 				done = true;
 				done = true;
 				break;
 				break;
 			}
 			}

+ 39 - 39
code/IFCOpenings.cpp

@@ -259,7 +259,7 @@ BoundingBox GetBoundingBox(const ClipperLib::Polygon& poly)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void InsertWindowContours(const ContourVector& contours,
 void InsertWindowContours(const ContourVector& contours,
-	const std::vector<TempOpening>& openings,
+	const std::vector<TempOpening>& /*openings*/,
 	TempMesh& curmesh)
 	TempMesh& curmesh)
 {
 {
 	// fix windows - we need to insert the real, polygonal shapes into the quadratic holes that we have now
 	// fix windows - we need to insert the real, polygonal shapes into the quadratic holes that we have now
@@ -303,20 +303,20 @@ void InsertWindowContours(const ContourVector& contours,
 			const IfcVector2& v = contour[n];
 			const IfcVector2& v = contour[n];
 
 
 			bool hit = false;
 			bool hit = false;
-			if (fabs(v.x-bb.first.x)<epsilon) {
+			if (std::fabs(v.x-bb.first.x)<epsilon) {
 				edge.x = bb.first.x;
 				edge.x = bb.first.x;
 				hit = true;
 				hit = true;
 			}
 			}
-			else if (fabs(v.x-bb.second.x)<epsilon) {
+			else if (std::fabs(v.x-bb.second.x)<epsilon) {
 				edge.x = bb.second.x;
 				edge.x = bb.second.x;
 				hit = true;
 				hit = true;
 			}
 			}
 
 
-			if (fabs(v.y-bb.first.y)<epsilon) {
+			if (std::fabs(v.y-bb.first.y)<epsilon) {
 				edge.y = bb.first.y;
 				edge.y = bb.first.y;
 				hit = true;
 				hit = true;
 			}
 			}
-			else if (fabs(v.y-bb.second.y)<epsilon) {
+			else if (std::fabs(v.y-bb.second.y)<epsilon) {
 				edge.y = bb.second.y;
 				edge.y = bb.second.y;
 				hit = true;
 				hit = true;
 			}
 			}
@@ -343,17 +343,17 @@ void InsertWindowContours(const ContourVector& contours,
 
 
 						IfcVector2 corner = edge;
 						IfcVector2 corner = edge;
 
 
-						if (fabs(contour[last_hit].x-bb.first.x)<epsilon) {
+						if (std::fabs(contour[last_hit].x-bb.first.x)<epsilon) {
 							corner.x = bb.first.x;
 							corner.x = bb.first.x;
 						}
 						}
-						else if (fabs(contour[last_hit].x-bb.second.x)<epsilon) {
+						else if (std::fabs(contour[last_hit].x-bb.second.x)<epsilon) {
 							corner.x = bb.second.x;
 							corner.x = bb.second.x;
 						}
 						}
 
 
-						if (fabs(contour[last_hit].y-bb.first.y)<epsilon) {
+						if (std::fabs(contour[last_hit].y-bb.first.y)<epsilon) {
 							corner.y = bb.first.y;
 							corner.y = bb.first.y;
 						}
 						}
-						else if (fabs(contour[last_hit].y-bb.second.y)<epsilon) {
+						else if (std::fabs(contour[last_hit].y-bb.second.y)<epsilon) {
 							corner.y = bb.second.y;
 							corner.y = bb.second.y;
 						}
 						}
 
 
@@ -590,10 +590,10 @@ bool BoundingBoxesAdjacent(const BoundingBox& bb, const BoundingBox& ibb)
 {
 {
 	// TODO: I'm pretty sure there is a much more compact way to check this
 	// TODO: I'm pretty sure there is a much more compact way to check this
 	const IfcFloat epsilon = 1e-5f;
 	const IfcFloat epsilon = 1e-5f;
-	return	(fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) ||
-		(fabs(bb.first.x - ibb.second.x) < epsilon && ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) || 
-		(fabs(bb.second.y - ibb.first.y) < epsilon && bb.first.x <= ibb.second.x && bb.second.x >= ibb.first.x) ||
-		(fabs(bb.first.y - ibb.second.y) < epsilon && ibb.first.x <= bb.second.x && ibb.second.x >= bb.first.x);
+	return	(std::fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) ||
+		(std::fabs(bb.first.x - ibb.second.x) < epsilon && ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) || 
+		(std::fabs(bb.second.y - ibb.first.y) < epsilon && bb.first.x <= ibb.second.x && bb.second.x >= ibb.first.x) ||
+		(std::fabs(bb.first.y - ibb.second.y) < epsilon && ibb.first.x <= bb.second.x && ibb.second.x >= bb.first.x);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -615,11 +615,11 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
 
 
 	static const IfcFloat inf = std::numeric_limits<IfcFloat>::infinity();
 	static const IfcFloat inf = std::numeric_limits<IfcFloat>::infinity();
 
 
-	if (!(n0_to_m0.SquareLength() < e*e || fabs(n0_to_m0 * n0_to_n1) / (n0_to_m0.Length() * n0_to_n1.Length()) > 1-1e-5 )) {
+	if (!(n0_to_m0.SquareLength() < e*e || std::fabs(n0_to_m0 * n0_to_n1) / (n0_to_m0.Length() * n0_to_n1.Length()) > 1-1e-5 )) {
 		return false;
 		return false;
 	}
 	}
 
 
-	if (!(n1_to_m1.SquareLength() < e*e || fabs(n1_to_m1 * n0_to_n1) / (n1_to_m1.Length() * n0_to_n1.Length()) > 1-1e-5 )) {
+	if (!(n1_to_m1.SquareLength() < e*e || std::fabs(n1_to_m1 * n0_to_n1) / (n1_to_m1.Length() * n0_to_n1.Length()) > 1-1e-5 )) {
 		return false;
 		return false;
 	}
 	}
 
 
@@ -631,14 +631,14 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
 	// the higher absolute difference is big enough as to avoid
 	// the higher absolute difference is big enough as to avoid
 	// divisions by zero, the case 0/0 ~ infinity is detected and
 	// divisions by zero, the case 0/0 ~ infinity is detected and
 	// handled separately.
 	// handled separately.
-	if(fabs(n0_to_n1.x) > fabs(n0_to_n1.y)) {
+	if(std::fabs(n0_to_n1.x) > std::fabs(n0_to_n1.y)) {
 		s0 = n0_to_m0.x / n0_to_n1.x;
 		s0 = n0_to_m0.x / n0_to_n1.x;
 		s1 = n0_to_m1.x / n0_to_n1.x;
 		s1 = n0_to_m1.x / n0_to_n1.x;
 
 
-		if (fabs(s0) == inf && fabs(n0_to_m0.x) < smalle) {
+		if (std::fabs(s0) == inf && std::fabs(n0_to_m0.x) < smalle) {
 			s0 = 0.;
 			s0 = 0.;
 		}
 		}
-		if (fabs(s1) == inf && fabs(n0_to_m1.x) < smalle) {
+		if (std::fabs(s1) == inf && std::fabs(n0_to_m1.x) < smalle) {
 			s1 = 0.;
 			s1 = 0.;
 		}
 		}
 	}
 	}
@@ -646,10 +646,10 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
 		s0 = n0_to_m0.y / n0_to_n1.y;
 		s0 = n0_to_m0.y / n0_to_n1.y;
 		s1 = n0_to_m1.y / n0_to_n1.y;
 		s1 = n0_to_m1.y / n0_to_n1.y;
 
 
-		if (fabs(s0) == inf && fabs(n0_to_m0.y) < smalle) {
+		if (std::fabs(s0) == inf && std::fabs(n0_to_m0.y) < smalle) {
 			s0 = 0.;
 			s0 = 0.;
 		}
 		}
-		if (fabs(s1) == inf && fabs(n0_to_m1.y) < smalle) {
+		if (std::fabs(s1) == inf && std::fabs(n0_to_m1.y) < smalle) {
 			s1 = 0.;
 			s1 = 0.;
 		}
 		}
 	}
 	}
@@ -664,7 +664,7 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
 	s0 = std::min(1.0,s0);
 	s0 = std::min(1.0,s0);
 	s1 = std::min(1.0,s1);
 	s1 = std::min(1.0,s1);
 
 
-	if (fabs(s1-s0) < e) {
+	if (std::fabs(s1-s0) < e) {
 		return false;
 		return false;
 	}
 	}
 
 
@@ -755,7 +755,7 @@ void FindAdjacentContours(ContourVector::iterator current, const ContourVector&
 AI_FORCE_INLINE bool LikelyBorder(const IfcVector2& vdelta)
 AI_FORCE_INLINE bool LikelyBorder(const IfcVector2& vdelta)
 {
 {
 	const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(1e-5);
 	const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(1e-5);
-	return fabs(vdelta.x * vdelta.y) < dot_point_epsilon;
+	return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -812,9 +812,9 @@ void FindBorderContours(ContourVector::iterator current)
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 AI_FORCE_INLINE bool LikelyDiagonal(IfcVector2 vdelta)
 AI_FORCE_INLINE bool LikelyDiagonal(IfcVector2 vdelta)
 {
 {
-	vdelta.x = fabs(vdelta.x);
-	vdelta.y = fabs(vdelta.y);
-	return (fabs(vdelta.x-vdelta.y) < 0.8 * std::max(vdelta.x, vdelta.y));
+	vdelta.x = std::fabs(vdelta.x);
+	vdelta.y = std::fabs(vdelta.y);
+	return (std::fabs(vdelta.x-vdelta.y) < 0.8 * std::max(vdelta.x, vdelta.y));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -926,7 +926,7 @@ size_t CloseWindows(ContourVector& contours,
 				/* debug code to check for unwanted diagonal lines in window contours
 				/* debug code to check for unwanted diagonal lines in window contours
 				if (cit != cbegin) {
 				if (cit != cbegin) {
 					const IfcVector2& vdelta = proj_point - last_proj;
 					const IfcVector2& vdelta = proj_point - last_proj;
-					if (fabs(vdelta.x-vdelta.y) < 0.5 * std::max(vdelta.x, vdelta.y)) {
+					if (std::fabs(vdelta.x-vdelta.y) < 0.5 * std::max(vdelta.x, vdelta.y)) {
 						//continue;
 						//continue;
 					}
 					}
 				} */
 				} */
@@ -1065,7 +1065,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 	}
 	}
 #ifdef ASSIMP_BUILD_DEBUG
 #ifdef ASSIMP_BUILD_DEBUG
 	const IfcFloat det = m.Determinant();
 	const IfcFloat det = m.Determinant();
-	ai_assert(fabs(det-1) < 1e-5);
+	ai_assert(std::fabs(det-1) < 1e-5);
 #endif
 #endif
 
 
 	IfcFloat zcoord = 0;
 	IfcFloat zcoord = 0;
@@ -1085,7 +1085,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 		// XXX this should be guarded, but we somehow need to pick a suitable
 		// XXX this should be guarded, but we somehow need to pick a suitable
 		// epsilon
 		// epsilon
 		// if(coord != -1.0f) {
 		// if(coord != -1.0f) {
-		//	assert(fabs(coord - vv.z) < 1e-3f);
+		//	assert(std::fabs(coord - vv.z) < 1e-3f);
 		// }
 		// }
 		zcoord += vv.z;
 		zcoord += vv.z;
 		vmin = std::min(vv, vmin);
 		vmin = std::min(vv, vmin);
@@ -1125,7 +1125,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 		const IfcVector3& vv = m * x;
 		const IfcVector3& vv = m * x;
 
 
 		out_contour2.push_back(IfcVector2(vv.x,vv.y));
 		out_contour2.push_back(IfcVector2(vv.x,vv.y));
-		ai_assert(fabs(vv.z) < vmax.z + 1e-8);
+		ai_assert(std::fabs(vv.z) < vmax.z + 1e-8);
 	} 
 	} 
 
 
 	for(size_t i = 0; i < out_contour.size(); ++i) {
 	for(size_t i = 0; i < out_contour.size(); ++i) {
@@ -1188,9 +1188,9 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 		bool is_2d_source = false;
 		bool is_2d_source = false;
 		if (opening.profileMesh2D && norm_extrusion_dir.SquareLength() > 0) {
 		if (opening.profileMesh2D && norm_extrusion_dir.SquareLength() > 0) {
 			
 			
-			if(fabs(norm_extrusion_dir * wall_extrusion_axis_norm) < 0.1) {
+			if(std::fabs(norm_extrusion_dir * wall_extrusion_axis_norm) < 0.1) {
 				// horizontal extrusion
 				// horizontal extrusion
-				if (fabs(norm_extrusion_dir * nor) > 0.9) {
+				if (std::fabs(norm_extrusion_dir * nor) > 0.9) {
 					profile_data = opening.profileMesh2D.get();
 					profile_data = opening.profileMesh2D.get();
 					is_2d_source = true;
 					is_2d_source = true;
 				}
 				}
@@ -1200,7 +1200,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 			}
 			}
 			else {
 			else {
 				// vertical extrusion
 				// vertical extrusion
-				if (fabs(norm_extrusion_dir * nor) > 0.9) {
+				if (std::fabs(norm_extrusion_dir * nor) > 0.9) {
 					continue;
 					continue;
 				}
 				}
 				continue;
 				continue;
@@ -1289,7 +1289,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 			ai_assert(!is_2d_source);
 			ai_assert(!is_2d_source);
 			const IfcVector2 area = vpmax-vpmin;
 			const IfcVector2 area = vpmax-vpmin;
 			const IfcVector2 area2 = vpmax2-vpmin2;
 			const IfcVector2 area2 = vpmax2-vpmin2;
-			if (temp_contour.size() <= 2 || fabs(area2.x * area2.y) > fabs(area.x * area.y)) {
+			if (temp_contour.size() <= 2 || std::fabs(area2.x * area2.y) > std::fabs(area.x * area.y)) {
 				temp_contour.swap(temp_contour2);
 				temp_contour.swap(temp_contour2);
 
 
 				vpmax = vpmax2;
 				vpmax = vpmax2;
@@ -1301,7 +1301,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 		}
 		}
 
 
 		// TODO: This epsilon may be too large
 		// TODO: This epsilon may be too large
-		const IfcFloat epsilon = fabs(dmax-dmin) * 0.0001;
+		const IfcFloat epsilon = std::fabs(dmax-dmin) * 0.0001;
 		if (!is_2d_source && check_intersection && (0 < dmin-epsilon || 0 > dmax+epsilon)) {
 		if (!is_2d_source && check_intersection && (0 < dmin-epsilon || 0 > dmax+epsilon)) {
 			continue;
 			continue;
 		}
 		}
@@ -1310,7 +1310,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 
 
 		// Skip over very small openings - these are likely projection errors
 		// Skip over very small openings - these are likely projection errors
 		// (i.e. they don't belong to this side of the wall)
 		// (i.e. they don't belong to this side of the wall)
-		if(fabs(vpmax.x - vpmin.x) * fabs(vpmax.y - vpmin.y) < static_cast<IfcFloat>(1e-10)) {
+		if(std::fabs(vpmax.x - vpmin.x) * std::fabs(vpmax.y - vpmin.y) < static_cast<IfcFloat>(1e-10)) {
 			continue;
 			continue;
 		}
 		}
 		std::vector<TempOpening*> joined_openings(1, &opening);
 		std::vector<TempOpening*> joined_openings(1, &opening);
@@ -1480,7 +1480,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
 		// XXX this should be guarded, but we somehow need to pick a suitable
 		// XXX this should be guarded, but we somehow need to pick a suitable
 		// epsilon
 		// epsilon
 		// if(coord != -1.0f) {
 		// if(coord != -1.0f) {
-		//	assert(fabs(coord - vv.z) < 1e-3f);
+		//	assert(std::fabs(coord - vv.z) < 1e-3f);
 		// }
 		// }
 
 
 		coord = vv.z;
 		coord = vv.z;
@@ -1515,7 +1515,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
 		BOOST_FOREACH(const TempOpening& t,openings) {
 		BOOST_FOREACH(const TempOpening& t,openings) {
 			const IfcVector3& outernor = nors[c++];
 			const IfcVector3& outernor = nors[c++];
 			const IfcFloat dot = nor * outernor;
 			const IfcFloat dot = nor * outernor;
-			if (fabs(dot)<1.f-1e-6f) {
+			if (std::fabs(dot)<1.f-1e-6f) {
 				continue;
 				continue;
 			}
 			}
 
 
@@ -1529,7 +1529,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
 			BOOST_FOREACH(const IfcVector3& xx, t.profileMesh->verts) {
 			BOOST_FOREACH(const IfcVector3& xx, t.profileMesh->verts) {
 				IfcVector3 vv = m *  xx, vv_extr = m * (xx + t.extrusionDir);
 				IfcVector3 vv = m *  xx, vv_extr = m * (xx + t.extrusionDir);
 				
 				
-				const bool is_extruded_side = fabs(vv.z - coord) > fabs(vv_extr.z - coord);
+				const bool is_extruded_side = std::fabs(vv.z - coord) > std::fabs(vv_extr.z - coord);
 				if (first) {
 				if (first) {
 					first = false;
 					first = false;
 					if (dot > 0.f) {
 					if (dot > 0.f) {
@@ -1741,4 +1741,4 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
 #undef from_int64
 #undef from_int64
 #undef one_vec
 #undef one_vec
 
 
-#endif 
+#endif 

+ 2 - 2
code/IFCProfile.cpp

@@ -101,7 +101,7 @@ void ProcessOpenProfile(const IfcArbitraryOpenProfileDef& def, TempMesh& meshout
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout, ConversionData& conv)
+void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout, ConversionData& /*conv*/)
 {
 {
 	if(const IfcRectangleProfileDef* const cprofile = def.ToPtr<IfcRectangleProfileDef>()) {
 	if(const IfcRectangleProfileDef* const cprofile = def.ToPtr<IfcRectangleProfileDef>()) {
 		const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f;
 		const IfcFloat x = cprofile->XDim*0.5f, y = cprofile->YDim*0.5f;
@@ -124,7 +124,7 @@ void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh&
 
 
 		IfcFloat angle = 0.f;
 		IfcFloat angle = 0.f;
 		for(size_t i = 0; i < segments; ++i, angle += delta) {
 		for(size_t i = 0; i < segments; ++i, angle += delta) {
-			meshout.verts.push_back( IfcVector3( cos(angle)*radius, sin(angle)*radius, 0.f ));
+			meshout.verts.push_back( IfcVector3( std::cos(angle)*radius, std::sin(angle)*radius, 0.f ));
 		}
 		}
 
 
 		meshout.vertcnt.push_back(segments);
 		meshout.vertcnt.push_back(segments);

+ 3 - 3
code/IFCReaderGen.cpp

@@ -1045,7 +1045,7 @@ void IFC::GetSchema(EXPRESS::ConversionSchema& out)
 namespace STEP {
 namespace STEP {
 
 
 // -----------------------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------
-template <> size_t GenericFill<NotImplemented>(const STEP::DB& db, const LIST& params, NotImplemented* in)
+template <> size_t GenericFill<NotImplemented>(const STEP::DB& /*db*/, const LIST& /*params*/, NotImplemented* /*in*/)
 {
 {
 	return 0;
 	return 0;
 }
 }
@@ -1253,7 +1253,7 @@ template <> size_t GenericFill<IfcPerformanceHistory>(const DB& db, const LIST&
 	return base;
 	return base;
 }
 }
 // -----------------------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------
-template <> size_t GenericFill<IfcRepresentationItem>(const DB& db, const LIST& params, IfcRepresentationItem* in)
+template <> size_t GenericFill<IfcRepresentationItem>(const DB& /*db*/, const LIST& /*params*/, IfcRepresentationItem* /*in*/)
 {
 {
 	size_t base = 0;
 	size_t base = 0;
 	return base;
 	return base;
@@ -1715,7 +1715,7 @@ template <> size_t GenericFill<IfcPlateType>(const DB& db, const LIST& params, I
 	return base;
 	return base;
 }
 }
 // -----------------------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------
-template <> size_t GenericFill<IfcObjectPlacement>(const DB& db, const LIST& params, IfcObjectPlacement* in)
+template <> size_t GenericFill<IfcObjectPlacement>(const DB& /*db*/, const LIST& /*params*/, IfcObjectPlacement* /*in*/)
 {
 {
 	size_t base = 0;
 	size_t base = 0;
 	return base;
 	return base;

+ 1 - 1
code/IFCUtil.cpp

@@ -278,7 +278,7 @@ void TempMesh::RemoveAdjacentDuplicates()
 		//		continue;
 		//		continue;
 		//	}
 		//	}
 
 
-		//	const IfcFloat d = (d0/sqrt(l0))*(d1/sqrt(l1));
+		//	const IfcFloat d = (d0/std::sqrt(l0))*(d1/std::sqrt(l1));
 
 
 		//	if ( d >= 1.f-dotepsilon ) {
 		//	if ( d >= 1.f-dotepsilon ) {
 		//		v1 = v0;
 		//		v1 = v0;

+ 1 - 1
code/IFCUtil.h

@@ -220,7 +220,7 @@ struct FuzzyVectorCompare {
 
 
 	FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {}
 	FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {}
 	bool operator()(const IfcVector3& a, const IfcVector3& b) {
 	bool operator()(const IfcVector3& a, const IfcVector3& b) {
-		return fabs((a-b).SquareLength()) < epsilon;
+		return std::fabs((a-b).SquareLength()) < epsilon;
 	}
 	}
 
 
 	const IfcFloat epsilon;
 	const IfcFloat epsilon;

+ 24 - 22
code/IFF.h

@@ -12,8 +12,6 @@
 namespace Assimp	{
 namespace Assimp	{
 namespace IFF		{
 namespace IFF		{
 
 
-#include "./../include/assimp/Compiler/pushpack1.h"
-
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 //! Describes an IFF chunk header
 //! Describes an IFF chunk header
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
@@ -24,7 +22,7 @@ struct ChunkHeader
 
 
 	//! Length of the chunk data, in bytes
 	//! Length of the chunk data, in bytes
 	uint32_t length;
 	uint32_t length;
-} PACK_STRUCT;
+};
 
 
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
@@ -37,9 +35,7 @@ struct SubChunkHeader
 
 
 	//! Length of the chunk data, in bytes
 	//! Length of the chunk data, in bytes
 	uint16_t length;
 	uint16_t length;
-} PACK_STRUCT;
-
-#include "./../include/assimp/Compiler/poppack1.h"
+};
 
 
 
 
 #define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
 #define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
@@ -52,28 +48,34 @@ struct SubChunkHeader
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 //! Load a chunk header
 //! Load a chunk header
 //! @param outFile Pointer to the file data - points to the chunk data afterwards
 //! @param outFile Pointer to the file data - points to the chunk data afterwards
-//! @return Pointer to the chunk header
+//! @return Copy of the chunk header
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
-inline ChunkHeader* LoadChunk(uint8_t*& outFile)
+inline ChunkHeader LoadChunk(uint8_t*& outFile)
 {
 {
-	ChunkHeader* head = (ChunkHeader*) outFile;
-	AI_LSWAP4(head->length);
-	AI_LSWAP4(head->type);
-	outFile += sizeof(ChunkHeader);
+	ChunkHeader head;
+	::memcpy(&head.type, outFile, 4);
+	outFile += 4;
+	::memcpy(&head.length, outFile, 4);
+	outFile += 4;
+	AI_LSWAP4(head.length);
+	AI_LSWAP4(head.type);
 	return head;
 	return head;
 }
 }
 
 
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 //! Load a sub chunk header
 //! Load a sub chunk header
 //! @param outFile Pointer to the file data - points to the chunk data afterwards
 //! @param outFile Pointer to the file data - points to the chunk data afterwards
-//! @return Pointer to the sub chunk header
+//! @return Copy of the sub chunk header
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
-inline SubChunkHeader* LoadSubChunk(uint8_t*& outFile)
+inline SubChunkHeader LoadSubChunk(uint8_t*& outFile)
 {
 {
-	SubChunkHeader* head = (SubChunkHeader*) outFile;
-	AI_LSWAP2(head->length);
-	AI_LSWAP4(head->type);
-	outFile += sizeof(SubChunkHeader);
+	SubChunkHeader head;
+	::memcpy(&head.type, outFile, 4);
+	outFile += 4;
+	::memcpy(&head.length, outFile, 2);
+	outFile += 2;
+	AI_LSWAP2(head.length);
+	AI_LSWAP4(head.type);
 	return head;
 	return head;
 }
 }
 
 
@@ -84,14 +86,14 @@ inline SubChunkHeader* LoadSubChunk(uint8_t*& outFile)
 //! @param fileType Receives the type of the file
 //! @param fileType Receives the type of the file
 //! @return 0 if everything was OK, otherwise an error message
 //! @return 0 if everything was OK, otherwise an error message
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
-inline const char* ReadHeader(uint8_t* outFile,uint32_t& fileType) 
+inline const char* ReadHeader(uint8_t* outFile, uint32_t& fileType) 
 {
 {
-	ChunkHeader* head = LoadChunk(outFile);
-	if(AI_IFF_FOURCC_FORM != head->type)
+	ChunkHeader head = LoadChunk(outFile);
+	if(AI_IFF_FOURCC_FORM != head.type)
 	{
 	{
 		return "The file is not an IFF file: FORM chunk is missing";
 		return "The file is not an IFF file: FORM chunk is missing";
 	}
 	}
-	fileType = *((uint32_t*)(head+1));
+	::memcpy(&fileType, outFile, 4);
 	AI_LSWAP4(fileType);
 	AI_LSWAP4(fileType);
 	return 0;
 	return 0;
 }
 }

+ 3 - 3
code/IRRLoader.cpp

@@ -470,7 +470,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
 					key.mTime = i * tdelta;
 					key.mTime = i * tdelta;
 
 
 					const float t = (float) ( in.speed * key.mTime );
 					const float t = (float) ( in.speed * key.mTime );
-					key.mValue = in.circleCenter  + in.circleRadius * ((vecU*::cosf(t)) + (vecV*::sinf(t)));
+					key.mValue = in.circleCenter  + in.circleRadius * ((vecU * std::cos(t)) + (vecV * std::sin(t)));
 				}
 				}
 
 
 				// This animation is repeated and repeated ...
 				// This animation is repeated and repeated ...
@@ -533,8 +533,8 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
 					aiVectorKey& key = anim->mPositionKeys[i];
 					aiVectorKey& key = anim->mPositionKeys[i];
 
 
 					const float dt = (i * in.speed * 0.001f );
 					const float dt = (i * in.speed * 0.001f );
-					const float u = dt - floor(dt);
-					const int idx = (int)floor(dt) % size;
+					const float u = dt - std::floor(dt);
+					const int idx = (int)std::floor(dt) % size;
 
 
 					// get the 4 current points to evaluate the spline
 					// get the 4 current points to evaluate the spline
 					const aiVector3D& p0 = in.splineKeys[ ClampSpline( idx - 1, size ) ].mValue;
 					const aiVector3D& p0 = in.splineKeys[ ClampSpline( idx - 1, size ) ].mValue;

+ 13 - 4
code/Importer.cpp

@@ -640,16 +640,25 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 			}
 			}
 		}
 		}
 
 
+		// Get file size for progress handler
+		IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
+		uint32_t fileSize = 0;
+		if (fileIO)
+		{
+			fileSize = fileIO->FileSize();
+			pimpl->mIOHandler->Close( fileIO );
+		}
+
 		// Dispatch the reading to the worker class for this format
 		// Dispatch the reading to the worker class for this format
 		DefaultLogger::get()->info("Found a matching importer for this file format");
 		DefaultLogger::get()->info("Found a matching importer for this file format");
-		pimpl->mProgressHandler->Update();
+		pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
 
 
 		if (profiler) {
 		if (profiler) {
 			profiler->BeginRegion("import");
 			profiler->BeginRegion("import");
 		}
 		}
 
 
 		pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
 		pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
-		pimpl->mProgressHandler->Update();
+		pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
 
 
 		if (profiler) {
 		if (profiler) {
 			profiler->EndRegion("import");
 			profiler->EndRegion("import");
@@ -678,7 +687,6 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 			ScenePreprocessor pre(pimpl->mScene);
 			ScenePreprocessor pre(pimpl->mScene);
 			pre.ProcessScene();
 			pre.ProcessScene();
 
 
-			pimpl->mProgressHandler->Update();
 			if (profiler) {
 			if (profiler) {
 				profiler->EndRegion("preprocess");
 				profiler->EndRegion("preprocess");
 			}
 			}
@@ -768,6 +776,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 	for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)	{
 	for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)	{
 
 
 		BaseProcess* process = pimpl->mPostProcessingSteps[a];
 		BaseProcess* process = pimpl->mPostProcessingSteps[a];
+		pimpl->mProgressHandler->UpdatePostProcess( a, pimpl->mPostProcessingSteps.size() );
 		if( process->IsActive( pFlags))	{
 		if( process->IsActive( pFlags))	{
 
 
 			if (profiler) {
 			if (profiler) {
@@ -775,7 +784,6 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 			}
 			}
 
 
 			process->ExecuteOnScene	( this );
 			process->ExecuteOnScene	( this );
-			pimpl->mProgressHandler->Update();
 
 
 			if (profiler) {
 			if (profiler) {
 				profiler->EndRegion("postprocess");
 				profiler->EndRegion("postprocess");
@@ -803,6 +811,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		}
 		}
 #endif // ! DEBUG
 #endif // ! DEBUG
 	}
 	}
+	pimpl->mProgressHandler->UpdatePostProcess( pimpl->mPostProcessingSteps.size(), pimpl->mPostProcessingSteps.size() );
 
 
 	// update private scene flags
 	// update private scene flags
   if( pimpl->mScene )
   if( pimpl->mScene )

+ 6 - 0
code/ImporterRegistry.cpp

@@ -166,6 +166,9 @@ corresponding preprocessor flag to selectively disable formats.
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
 #   include "FBXImporter.h"
 #   include "FBXImporter.h"
 #endif 
 #endif 
+#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
+#   include "AssbinLoader.h"
+#endif 
 
 
 namespace Assimp {
 namespace Assimp {
 
 
@@ -291,6 +294,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
 #if ( !defined ASSIMP_BUILD_NO_FBX_IMPORTER )
 #if ( !defined ASSIMP_BUILD_NO_FBX_IMPORTER )
 	out.push_back( new FBXImporter() );
 	out.push_back( new FBXImporter() );
 #endif
 #endif
+#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER )
+	out.push_back( new AssbinImporter() );
+#endif
 }
 }
 
 
 }
 }

+ 1 - 3
code/JoinVerticesProcess.h

@@ -49,8 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp
 namespace Assimp
 {
 {
 
 
-class JoinVerticesTest;
-
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** The JoinVerticesProcess unites identical vertices in all imported meshes. 
 /** The JoinVerticesProcess unites identical vertices in all imported meshes. 
  * By default the importer returns meshes where each face addressed its own 
  * By default the importer returns meshes where each face addressed its own 
@@ -59,7 +57,7 @@ class JoinVerticesTest;
  * erases all but one of the copies. This usually reduces the number of vertices
  * erases all but one of the copies. This usually reduces the number of vertices
  * in a mesh by a serious amount and is the standard form to render a mesh.
  * in a mesh by a serious amount and is the standard form to render a mesh.
  */
  */
-class ASSIMP_API_WINONLY JoinVerticesProcess : public BaseProcess
+class ASSIMP_API JoinVerticesProcess : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 58 - 40
code/LWOBLoader.cpp

@@ -58,30 +58,31 @@ void LWOImporter::LoadLWOBFile()
 	while (running)
 	while (running)
 	{
 	{
 		if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
 		if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
-		LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
+		const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
 
 
-		if (mFileBuffer + head->length > end)
+		if (mFileBuffer + head.length > end)
 		{
 		{
 			throw DeadlyImportError("LWOB: Invalid chunk length");
 			throw DeadlyImportError("LWOB: Invalid chunk length");
 			break;
 			break;
 		}
 		}
-		uint8_t* const next = mFileBuffer+head->length;
-		switch (head->type)
+		uint8_t* const next = mFileBuffer+head.length;
+		switch (head.type)
 		{
 		{
 			// vertex list
 			// vertex list
 		case AI_LWO_PNTS:
 		case AI_LWO_PNTS:
 			{
 			{
 				if (!mCurLayer->mTempPoints.empty())
 				if (!mCurLayer->mTempPoints.empty())
 					DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice");
 					DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice");
-				else LoadLWOPoints(head->length);
+				else LoadLWOPoints(head.length);
 				break;
 				break;
 			}
 			}
 			// face list
 			// face list
 		case AI_LWO_POLS:
 		case AI_LWO_POLS:
 			{
 			{
+
 				if (!mCurLayer->mFaces.empty())
 				if (!mCurLayer->mFaces.empty())
 					DefaultLogger::get()->warn("LWO: POLS chunk encountered twice");
 					DefaultLogger::get()->warn("LWO: POLS chunk encountered twice");
-				else LoadLWOBPolygons(head->length);
+				else LoadLWOBPolygons(head.length);
 				break;
 				break;
 			}
 			}
 			// list of tags
 			// list of tags
@@ -89,14 +90,14 @@ void LWOImporter::LoadLWOBFile()
 			{
 			{
 				if (!mTags->empty())
 				if (!mTags->empty())
 					DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice");
 					DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice");
-				else LoadLWOTags(head->length);
+				else LoadLWOTags(head.length);
 				break;
 				break;
 			}
 			}
 
 
 			// surface chunk
 			// surface chunk
 		case AI_LWO_SURF:
 		case AI_LWO_SURF:
 			{
 			{
-				LoadLWOBSurface(head->length);
+				LoadLWOBSurface(head.length);
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -137,14 +138,17 @@ void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& face
 {
 {
 	while (cursor < end && max--)
 	while (cursor < end && max--)
 	{
 	{
-		uint16_t numIndices = *cursor++;
-		verts += numIndices;faces++;
+		uint16_t numIndices;
+		::memcpy(&numIndices, cursor++, 2);
+		verts += numIndices;
+		faces++;
 		cursor += numIndices;
 		cursor += numIndices;
-		int16_t surface = *cursor++;
+		int16_t surface;
+		::memcpy(&surface, cursor++, 2);
 		if (surface < 0)
 		if (surface < 0)
 		{
 		{
 			// there are detail polygons
 			// there are detail polygons
-			numIndices = *cursor++;
+			::memcpy(&numIndices, cursor++, 2);
 			CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices);
 			CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices);
 		}
 		}
 	}
 	}
@@ -159,13 +163,22 @@ void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
 	while (cursor < end && max--)
 	while (cursor < end && max--)
 	{
 	{
 		LWO::Face& face = *it;++it;
 		LWO::Face& face = *it;++it;
-		if((face.mNumIndices = *cursor++))
+		uint16_t numIndices;
+		::memcpy(&numIndices, cursor++, 2);
+		face.mNumIndices = numIndices;
+		if(face.mNumIndices)
 		{
 		{
-			if (cursor + face.mNumIndices >= end)break;
+			if (cursor + face.mNumIndices >= end)
+			{
+				break;
+			}
 			face.mIndices = new unsigned int[face.mNumIndices];
 			face.mIndices = new unsigned int[face.mNumIndices];
 			for (unsigned int i = 0; i < face.mNumIndices;++i)
 			for (unsigned int i = 0; i < face.mNumIndices;++i)
 			{
 			{
-				unsigned int & mi = face.mIndices[i] = *cursor++;
+				unsigned int & mi = face.mIndices[i];
+				uint16_t index;
+				::memcpy(&index, cursor++, 2);
+				mi = index;
 				if (mi > mCurLayer->mTempPoints.size())
 				if (mi > mCurLayer->mTempPoints.size())
 				{
 				{
 					DefaultLogger::get()->warn("LWOB: face index is out of range");
 					DefaultLogger::get()->warn("LWOB: face index is out of range");
@@ -174,14 +187,19 @@ void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
 			}
 			}
 		}
 		}
 		else DefaultLogger::get()->warn("LWOB: Face has 0 indices");
 		else DefaultLogger::get()->warn("LWOB: Face has 0 indices");
-		int16_t surface = *cursor++;
+		int16_t surface;
+		::memcpy(&surface, cursor++, 2);
 		if (surface < 0)
 		if (surface < 0)
 		{
 		{
 			surface = -surface;
 			surface = -surface;
 
 
 			// there are detail polygons. 
 			// there are detail polygons. 
-			const uint16_t numPolygons = *cursor++;
-			if (cursor < end)CopyFaceIndicesLWOB(it,cursor,end,numPolygons);
+			uint16_t numPolygons;
+			::memcpy(&numPolygons, cursor++, 2);
+			if (cursor < end)
+			{
+				CopyFaceIndicesLWOB(it,cursor,end,numPolygons);
+			}
 		}
 		}
 		face.surfaceIndex = surface-1;
 		face.surfaceIndex = surface-1;
 	}
 	}
@@ -235,7 +253,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
 		if (mFileBuffer + 6 >= end)
 		if (mFileBuffer + 6 >= end)
 			break;
 			break;
 
 
-		IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
+		IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
 
 
 		/*  A single test file (sonycam.lwo) seems to have invalid surface chunks.
 		/*  A single test file (sonycam.lwo) seems to have invalid surface chunks.
 		 *  I'm assuming it's the fault of a single, unknown exporter so there are
 		 *  I'm assuming it's the fault of a single, unknown exporter so there are
@@ -244,18 +262,18 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
 		 *  We don't break if the chunk limit is exceeded. Instead, we're computing 
 		 *  We don't break if the chunk limit is exceeded. Instead, we're computing 
 		 *  how much storage is actually left and work with this value from now on.
 		 *  how much storage is actually left and work with this value from now on.
 		 */
 		 */
-		if (mFileBuffer + head->length > end) {
+		if (mFileBuffer + head.length > end) {
 			DefaultLogger::get()->error("LWOB: Invalid surface chunk length. Trying to continue.");
 			DefaultLogger::get()->error("LWOB: Invalid surface chunk length. Trying to continue.");
-			head->length = (uint16_t) (end - mFileBuffer);
+			head.length = (uint16_t) (end - mFileBuffer);
 		}
 		}
 
 
-		uint8_t* const next = mFileBuffer+head->length;
-		switch (head->type)
+		uint8_t* const next = mFileBuffer+head.length;
+		switch (head.type)
 		{
 		{
 		// diffuse color
 		// diffuse color
 		case AI_LWO_COLR:
 		case AI_LWO_COLR:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,3);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,3);
 				surf.mColor.r = GetU1() / 255.0f;
 				surf.mColor.r = GetU1() / 255.0f;
 				surf.mColor.g = GetU1() / 255.0f;
 				surf.mColor.g = GetU1() / 255.0f;
 				surf.mColor.b = GetU1() / 255.0f;
 				surf.mColor.b = GetU1() / 255.0f;
@@ -264,35 +282,35 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
 		// diffuse strength ...
 		// diffuse strength ...
 		case AI_LWO_DIFF:
 		case AI_LWO_DIFF:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,2);
 				surf.mDiffuseValue = GetU2() / 255.0f;
 				surf.mDiffuseValue = GetU2() / 255.0f;
 				break;
 				break;
 			}
 			}
 		// specular strength ... 
 		// specular strength ... 
 		case AI_LWO_SPEC:
 		case AI_LWO_SPEC:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,2);
 				surf.mSpecularValue = GetU2() / 255.0f;
 				surf.mSpecularValue = GetU2() / 255.0f;
 				break;
 				break;
 			}
 			}
 		// luminosity ... 
 		// luminosity ... 
 		case AI_LWO_LUMI:
 		case AI_LWO_LUMI:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LUMI,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LUMI,2);
 				surf.mLuminosity = GetU2() / 255.0f;
 				surf.mLuminosity = GetU2() / 255.0f;
 				break;
 				break;
 			}
 			}
 		// transparency
 		// transparency
 		case AI_LWO_TRAN:
 		case AI_LWO_TRAN:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,2);
 				surf.mTransparency = GetU2() / 255.0f;
 				surf.mTransparency = GetU2() / 255.0f;
 				break;
 				break;
 			}
 			}
 		// surface flags
 		// surface flags
 		case AI_LWO_FLAG:
 		case AI_LWO_FLAG:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,FLAG,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,FLAG,2);
 				uint16_t flag = GetU2();
 				uint16_t flag = GetU2();
 				if (flag & 0x4 )   surf.mMaximumSmoothAngle = 1.56207f;
 				if (flag & 0x4 )   surf.mMaximumSmoothAngle = 1.56207f;
 				if (flag & 0x8 )   surf.mColorHighlights = 1.f;
 				if (flag & 0x8 )   surf.mColorHighlights = 1.f;
@@ -302,14 +320,14 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
 		// maximum smoothing angle
 		// maximum smoothing angle
 		case AI_LWO_SMAN:
 		case AI_LWO_SMAN:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4);
-				surf.mMaximumSmoothAngle = fabs( GetF4() );
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4);
+				surf.mMaximumSmoothAngle = std::fabs( GetF4() );
 				break;
 				break;
 			}
 			}
 		// glossiness
 		// glossiness
 		case AI_LWO_GLOS:
 		case AI_LWO_GLOS:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,2);
 				surf.mGlossiness = (float)GetU2();
 				surf.mGlossiness = (float)GetU2();
 				break;
 				break;
 			}
 			}
@@ -317,42 +335,42 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
 		case AI_LWO_CTEX:
 		case AI_LWO_CTEX:
 			{
 			{
 				pTex = SetupNewTextureLWOB(surf.mColorTextures,
 				pTex = SetupNewTextureLWOB(surf.mColorTextures,
-					head->length);
+					head.length);
 				break;
 				break;
 			}
 			}
 		// diffuse texture
 		// diffuse texture
 		case AI_LWO_DTEX:
 		case AI_LWO_DTEX:
 			{
 			{
 				pTex = SetupNewTextureLWOB(surf.mDiffuseTextures,
 				pTex = SetupNewTextureLWOB(surf.mDiffuseTextures,
-					head->length);
+					head.length);
 				break;
 				break;
 			}
 			}
 		// specular texture
 		// specular texture
 		case AI_LWO_STEX:
 		case AI_LWO_STEX:
 			{
 			{
 				pTex = SetupNewTextureLWOB(surf.mSpecularTextures,
 				pTex = SetupNewTextureLWOB(surf.mSpecularTextures,
-					head->length);
+					head.length);
 				break;
 				break;
 			}
 			}
 		// bump texture
 		// bump texture
 		case AI_LWO_BTEX:
 		case AI_LWO_BTEX:
 			{
 			{
 				pTex = SetupNewTextureLWOB(surf.mBumpTextures,
 				pTex = SetupNewTextureLWOB(surf.mBumpTextures,
-					head->length);
+					head.length);
 				break;
 				break;
 			}
 			}
 		// transparency texture
 		// transparency texture
 		case AI_LWO_TTEX:
 		case AI_LWO_TTEX:
 			{
 			{
 				pTex = SetupNewTextureLWOB(surf.mOpacityTextures,
 				pTex = SetupNewTextureLWOB(surf.mOpacityTextures,
-					head->length);
+					head.length);
 				break;
 				break;
 			}
 			}
 		// texture path
 		// texture path
 		case AI_LWO_TIMG:
 		case AI_LWO_TIMG:
 			{
 			{
 				if (pTex)	{
 				if (pTex)	{
-					GetS0(pTex->mFileName,head->length);	
+					GetS0(pTex->mFileName,head.length);	
 				}
 				}
 				else DefaultLogger::get()->warn("LWOB: Unexpected TIMG chunk");
 				else DefaultLogger::get()->warn("LWOB: Unexpected TIMG chunk");
 				break;
 				break;
@@ -360,7 +378,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
 		// texture strength
 		// texture strength
 		case AI_LWO_TVAL:
 		case AI_LWO_TVAL:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TVAL,1);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TVAL,1);
 				if (pTex)	{
 				if (pTex)	{
 					pTex->mStrength = (float)GetU1()/ 255.f;
 					pTex->mStrength = (float)GetU1()/ 255.f;
 				}
 				}
@@ -370,7 +388,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
 		// texture flags
 		// texture flags
 		case AI_LWO_TFLG:
 		case AI_LWO_TFLG:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TFLG,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TFLG,2);
 
 
 				if (pTex) 
 				if (pTex) 
 				{
 				{

+ 57 - 45
code/LWOLoader.cpp

@@ -503,7 +503,7 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>&
 	// Generate vertex normals. We have O(logn) for the binary lookup, which we need
 	// Generate vertex normals. We have O(logn) for the binary lookup, which we need
 	// for n elements, thus the EXPECTED complexity is O(nlogn)
 	// for n elements, thus the EXPECTED complexity is O(nlogn)
 	if (surface.mMaximumSmoothAngle < 3.f && !configSpeedFlag)	{
 	if (surface.mMaximumSmoothAngle < 3.f && !configSpeedFlag)	{
-		const float fLimit = cos(surface.mMaximumSmoothAngle);
+		const float fLimit = std::cos(surface.mMaximumSmoothAngle);
 
 
 		for( begin =  mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it)	{
 		for( begin =  mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it)	{
 			const aiFace& face = *begin;
 			const aiFace& face = *begin;
@@ -787,7 +787,8 @@ void LWOImporter::LoadLWO2Polygons(unsigned int length)
 	CountVertsAndFacesLWO2(iNumVertices,iNumFaces,cursor,end);
 	CountVertsAndFacesLWO2(iNumVertices,iNumFaces,cursor,end);
 
 
 	// allocate the output array and copy face indices
 	// allocate the output array and copy face indices
-	if (iNumFaces)	{
+	if (iNumFaces)
+	{
 		cursor = (uint16_t*)mFileBuffer;
 		cursor = (uint16_t*)mFileBuffer;
 
 
 		mCurLayer->mFaces.resize(iNumFaces,LWO::Face(type));
 		mCurLayer->mFaces.resize(iNumFaces,LWO::Face(type));
@@ -802,13 +803,18 @@ void LWOImporter::CountVertsAndFacesLWO2(unsigned int& verts, unsigned int& face
 {
 {
 	while (cursor < end && max--)
 	while (cursor < end && max--)
 	{
 	{
-		AI_LSWAP2P(cursor);
-		uint16_t numIndices = *cursor++;
+		uint16_t numIndices;
+		::memcpy(&numIndices, cursor++, 2);
+		AI_LSWAP2(numIndices);
 		numIndices &= 0x03FF;
 		numIndices &= 0x03FF;
-		verts += numIndices;++faces;
+
+		verts += numIndices;
+		++faces;
 
 
 		for(uint16_t i = 0; i < numIndices; i++)
 		for(uint16_t i = 0; i < numIndices; i++)
+		{
 			ReadVSizedIntLWO2((uint8_t*&)cursor);
 			ReadVSizedIntLWO2((uint8_t*&)cursor);
+		}
 	}
 	}
 }
 }
 
 
@@ -817,10 +823,16 @@ void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it,
 	uint16_t*& cursor, 
 	uint16_t*& cursor, 
 	const uint16_t* const end)
 	const uint16_t* const end)
 {
 {
-	while (cursor < end)	{
-
-		LWO::Face& face = *it++;;
-		if((face.mNumIndices = (*cursor++) & 0x03FF)) /* byte swapping has already been done */ {
+	while (cursor < end)
+	{
+		LWO::Face& face = *it++;
+		uint16_t numIndices;
+		::memcpy(&numIndices, cursor++, 2);
+		AI_LSWAP2(numIndices);
+		face.mNumIndices = numIndices & 0x03FF;
+		
+		if(face.mNumIndices) /* byte swapping has already been done */
+		{
 			face.mIndices = new unsigned int[face.mNumIndices];
 			face.mIndices = new unsigned int[face.mNumIndices];
 			for(unsigned int i = 0; i < face.mNumIndices; i++)
 			for(unsigned int i = 0; i < face.mNumIndices; i++)
 			{
 			{
@@ -848,8 +860,8 @@ void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
 	if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
 	if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
 		return;
 		return;
 
 
-	while (mFileBuffer < end)	{
-
+	while (mFileBuffer < end)
+	{
 		unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
 		unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
 		unsigned int j = GetU2();
 		unsigned int j = GetU2();
 
 
@@ -1106,19 +1118,19 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
 	// first - get the index of the clip
 	// first - get the index of the clip
 	clip.idx = GetU4();
 	clip.idx = GetU4();
 
 
-	IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
-	switch (head->type)
+	IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
+	switch (head.type)
 	{
 	{
 	case AI_LWO_STIL:
 	case AI_LWO_STIL:
-		AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,STIL,1);
+		AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,STIL,1);
 
 
 		// "Normal" texture
 		// "Normal" texture
-		GetS0(clip.path,head->length);
+		GetS0(clip.path,head.length);
 		clip.type = Clip::STILL;
 		clip.type = Clip::STILL;
 		break;
 		break;
 
 
 	case AI_LWO_ISEQ:
 	case AI_LWO_ISEQ:
-		AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ISEQ,16);
+		AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,ISEQ,16);
 		// Image sequence. We'll later take the first.
 		// Image sequence. We'll later take the first.
 		{
 		{
 			uint8_t digits = GetU1();  mFileBuffer++;
 			uint8_t digits = GetU1();  mFileBuffer++;
@@ -1127,12 +1139,12 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
 
 
 			std::string s;
 			std::string s;
 			std::ostringstream ss;
 			std::ostringstream ss;
-			GetS0(s,head->length);
+			GetS0(s,head.length);
 
 
-			head->length -= (unsigned int)s.length()+1;
+			head.length -= (unsigned int)s.length()+1;
 			ss << s;
 			ss << s;
 			ss << std::setw(digits) << offset + start;
 			ss << std::setw(digits) << offset + start;
-			GetS0(s,head->length);
+			GetS0(s,head.length);
 			ss << s;
 			ss << s;
 			clip.path = ss.str();
 			clip.path = ss.str();
 			clip.type = Clip::SEQ;
 			clip.type = Clip::SEQ;
@@ -1148,7 +1160,7 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
 		break;
 		break;
 
 
 	case AI_LWO_XREF:
 	case AI_LWO_XREF:
-		AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,XREF,4);
+		AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,XREF,4);
 
 
 		// Just a cross-reference to another CLIp
 		// Just a cross-reference to another CLIp
 		clip.type = Clip::REF;
 		clip.type = Clip::REF;
@@ -1156,7 +1168,7 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
 		break;
 		break;
 
 
 	case AI_LWO_NEGA:
 	case AI_LWO_NEGA:
-		AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,NEGA,2);
+		AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,NEGA,2);
 		clip.negate = (0 != GetU2());
 		clip.negate = (0 != GetU2());
 		break;
 		break;
 
 
@@ -1194,17 +1206,17 @@ void LWOImporter::LoadLWO2Envelope(unsigned int length)
 	while (true)
 	while (true)
 	{
 	{
 		if (mFileBuffer + 6 >= end)break;
 		if (mFileBuffer + 6 >= end)break;
-		LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
+		LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
 
 
-		if (mFileBuffer + head->length > end)
+		if (mFileBuffer + head.length > end)
 			throw DeadlyImportError("LWO2: Invalid envelope chunk length");
 			throw DeadlyImportError("LWO2: Invalid envelope chunk length");
 
 
-		uint8_t* const next = mFileBuffer+head->length;
-		switch (head->type)
+		uint8_t* const next = mFileBuffer+head.length;
+		switch (head.type)
 		{
 		{
 			// Type & representation of the envelope
 			// Type & representation of the envelope
 		case AI_LWO_TYPE:
 		case AI_LWO_TYPE:
-			AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TYPE,2);
+			AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TYPE,2);
 			mFileBuffer++; // skip user format
 			mFileBuffer++; // skip user format
 
 
 			// Determine type of envelope
 			// Determine type of envelope
@@ -1214,20 +1226,20 @@ void LWOImporter::LoadLWO2Envelope(unsigned int length)
 
 
 			// precondition
 			// precondition
 		case AI_LWO_PRE:
 		case AI_LWO_PRE:
-			AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,PRE,2);
+			AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,PRE,2);
 			envelope.pre = (LWO::PrePostBehaviour)GetU2();
 			envelope.pre = (LWO::PrePostBehaviour)GetU2();
 			break;
 			break;
 		
 		
 			// postcondition
 			// postcondition
 		case AI_LWO_POST:
 		case AI_LWO_POST:
-			AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,POST,2);
+			AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,POST,2);
 			envelope.post = (LWO::PrePostBehaviour)GetU2();
 			envelope.post = (LWO::PrePostBehaviour)GetU2();
 			break;
 			break;
 
 
 			// keyframe
 			// keyframe
 		case AI_LWO_KEY: 
 		case AI_LWO_KEY: 
 			{
 			{
-			AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,KEY,8);
+			AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,KEY,8);
 			
 			
 			envelope.keys.push_back(LWO::Key());
 			envelope.keys.push_back(LWO::Key());
 			LWO::Key& key = envelope.keys.back();
 			LWO::Key& key = envelope.keys.back();
@@ -1240,7 +1252,7 @@ void LWOImporter::LoadLWO2Envelope(unsigned int length)
 			// interval interpolation
 			// interval interpolation
 		case AI_LWO_SPAN: 
 		case AI_LWO_SPAN: 
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPAN,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPAN,4);
 				if (envelope.keys.size()<2)
 				if (envelope.keys.size()<2)
 					DefaultLogger::get()->warn("LWO2: Unexpected SPAN chunk");
 					DefaultLogger::get()->warn("LWO2: Unexpected SPAN chunk");
 				else {
 				else {
@@ -1286,22 +1298,22 @@ void LWOImporter::LoadLWO2File()
 	while (true)
 	while (true)
 	{
 	{
 		if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
 		if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
-		IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
+		const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
 
 
-		if (mFileBuffer + head->length > end)
+		if (mFileBuffer + head.length > end)
 		{
 		{
 			throw DeadlyImportError("LWO2: Chunk length points behind the file");
 			throw DeadlyImportError("LWO2: Chunk length points behind the file");
 			break;
 			break;
 		}
 		}
-		uint8_t* const next = mFileBuffer+head->length;
+		uint8_t* const next = mFileBuffer+head.length;
 		unsigned int iUnnamed = 0;
 		unsigned int iUnnamed = 0;
 
 
-		if(!head->length) {
+		if(!head.length) {
 			mFileBuffer = next;
 			mFileBuffer = next;
 			continue;
 			continue;
 		}
 		}
 
 
-		switch (head->type)
+		switch (head.type)
 		{
 		{
 			// new layer
 			// new layer
 		case AI_LWO_LAYR:
 		case AI_LWO_LAYR:
@@ -1311,7 +1323,7 @@ void LWOImporter::LoadLWO2File()
 				LWO::Layer& layer = mLayers->back();
 				LWO::Layer& layer = mLayers->back();
 				mCurLayer = &layer;
 				mCurLayer = &layer;
 
 
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LAYR,16);
 
 
 				// layer index.
 				// layer index.
 				layer.mIndex = GetU2();
 				layer.mIndex = GetU2();
@@ -1327,7 +1339,7 @@ void LWOImporter::LoadLWO2File()
 				mCurLayer->mPivot.x = GetF4();
 				mCurLayer->mPivot.x = GetF4();
 				mCurLayer->mPivot.y = GetF4();
 				mCurLayer->mPivot.y = GetF4();
 				mCurLayer->mPivot.z = GetF4();
 				mCurLayer->mPivot.z = GetF4();
-				GetS0(layer.mName,head->length-16);
+				GetS0(layer.mName,head.length-16);
 
 
 				// if the name is empty, generate a default name
 				// if the name is empty, generate a default name
 				if (layer.mName.empty())	{
 				if (layer.mName.empty())	{
@@ -1360,7 +1372,7 @@ void LWOImporter::LoadLWO2File()
 					break;
 					break;
 
 
 				unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
 				unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
-				LoadLWOPoints(head->length);
+				LoadLWOPoints(head.length);
 				mCurLayer->mPointIDXOfs = old;
 				mCurLayer->mPointIDXOfs = old;
 				break;
 				break;
 			}
 			}
@@ -1379,7 +1391,7 @@ void LWOImporter::LoadLWO2File()
 
 
 				if (mCurLayer->mTempPoints.empty())
 				if (mCurLayer->mTempPoints.empty())
 					DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
 					DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
-				else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
+				else LoadLWO2VertexMap(head.length,head.type == AI_LWO_VMAD);
 				break;
 				break;
 			}
 			}
 			// face list
 			// face list
@@ -1389,7 +1401,7 @@ void LWOImporter::LoadLWO2File()
 					break;
 					break;
 
 
 				unsigned int old = (unsigned int)mCurLayer->mFaces.size();
 				unsigned int old = (unsigned int)mCurLayer->mFaces.size();
-				LoadLWO2Polygons(head->length);
+				LoadLWO2Polygons(head.length);
 				mCurLayer->mFaceIDXOfs = old;
 				mCurLayer->mFaceIDXOfs = old;
 				break;
 				break;
 			}
 			}
@@ -1401,7 +1413,7 @@ void LWOImporter::LoadLWO2File()
 
 
 				if (mCurLayer->mFaces.empty())
 				if (mCurLayer->mFaces.empty())
 					DefaultLogger::get()->warn("LWO2: Unexpected PTAG");
 					DefaultLogger::get()->warn("LWO2: Unexpected PTAG");
-				else LoadLWO2PolygonTags(head->length);
+				else LoadLWO2PolygonTags(head.length);
 				break;
 				break;
 			}
 			}
 			// list of tags
 			// list of tags
@@ -1409,28 +1421,28 @@ void LWOImporter::LoadLWO2File()
 			{
 			{
 				if (!mTags->empty())
 				if (!mTags->empty())
 					DefaultLogger::get()->warn("LWO2: SRFS chunk encountered twice");
 					DefaultLogger::get()->warn("LWO2: SRFS chunk encountered twice");
-				else LoadLWOTags(head->length);
+				else LoadLWOTags(head.length);
 				break;
 				break;
 			}
 			}
 
 
 			// surface chunk
 			// surface chunk
 		case AI_LWO_SURF:
 		case AI_LWO_SURF:
 			{
 			{
-				LoadLWO2Surface(head->length);
+				LoadLWO2Surface(head.length);
 				break;
 				break;
 			}
 			}
 
 
 			// clip chunk
 			// clip chunk
 		case AI_LWO_CLIP:
 		case AI_LWO_CLIP:
 			{
 			{
-				LoadLWO2Clip(head->length);
+				LoadLWO2Clip(head.length);
 				break;
 				break;
 			}
 			}
 
 
 			// envelope chunk
 			// envelope chunk
 		case AI_LWO_ENVL:
 		case AI_LWO_ENVL:
 			{
 			{
-				LoadLWO2Envelope(head->length);
+				LoadLWO2Envelope(head.length);
 				break;
 				break;
 			}
 			}
 		}
 		}

+ 9 - 3
code/LWOLoader.h

@@ -402,7 +402,9 @@ protected:
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 inline float LWOImporter::GetF4()
 inline float LWOImporter::GetF4()
 {
 {
-	float f = *((float*)mFileBuffer);mFileBuffer += 4;
+	float f;
+	::memcpy(&f, mFileBuffer, 4);
+	mFileBuffer += 4;
 	AI_LSWAP4(f);
 	AI_LSWAP4(f);
 	return f;
 	return f;
 }
 }
@@ -410,7 +412,9 @@ inline float LWOImporter::GetF4()
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 inline uint32_t LWOImporter::GetU4()
 inline uint32_t LWOImporter::GetU4()
 {
 {
-	uint32_t f = *((uint32_t*)mFileBuffer);mFileBuffer += 4;
+	uint32_t f;
+	::memcpy(&f, mFileBuffer, 4);
+	mFileBuffer += 4;
 	AI_LSWAP4(f);
 	AI_LSWAP4(f);
 	return f;
 	return f;
 }
 }
@@ -418,7 +422,9 @@ inline uint32_t LWOImporter::GetU4()
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 inline uint16_t LWOImporter::GetU2()
 inline uint16_t LWOImporter::GetU2()
 {
 {
-	uint16_t f = *((uint16_t*)mFileBuffer);mFileBuffer += 2;
+	uint16_t f;
+	::memcpy(&f, mFileBuffer, 2);
+	mFileBuffer += 2;
 	AI_LSWAP2(f);
 	AI_LSWAP2(f);
 	return f;
 	return f;
 }
 }

+ 37 - 37
code/LWOMaterial.cpp

@@ -285,7 +285,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
 	{
 	{
 		float fGloss;
 		float fGloss;
 		if (mIsLWO2)	{
 		if (mIsLWO2)	{
-			fGloss = pow( surf.mGlossiness*10.0f+2.0f, 2.0f);
+			fGloss = std::pow( surf.mGlossiness*10.0f+2.0f, 2.0f);
 		}
 		}
 		else
 		else
 		{
 		{
@@ -527,13 +527,13 @@ void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
 	while (true)
 	while (true)
 	{
 	{
 		if (mFileBuffer + 6 >= end)break;
 		if (mFileBuffer + 6 >= end)break;
-		LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
+		LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
 
 
-		if (mFileBuffer + head->length > end)
+		if (mFileBuffer + head.length > end)
 			throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length");
 			throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length");
 
 
-		uint8_t* const next = mFileBuffer+head->length;
-		switch (head->type)
+		uint8_t* const next = mFileBuffer+head.length;
+		switch (head.type)
 		{
 		{
 		case AI_LWO_PROJ:
 		case AI_LWO_PROJ:
 			tex.mapMode = (Texture::MappingMode)GetU2();
 			tex.mapMode = (Texture::MappingMode)GetU2();
@@ -549,7 +549,7 @@ void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
 			tex.mClipIdx = GetU2();
 			tex.mClipIdx = GetU2();
 			break;
 			break;
 		case AI_LWO_VMAP:
 		case AI_LWO_VMAP:
-			GetS0(tex.mUVChannelIndex,head->length);
+			GetS0(tex.mUVChannelIndex,head.length);
 			break;
 			break;
 		case AI_LWO_WRPH:
 		case AI_LWO_WRPH:
 			tex.wrapAmountH = GetF4();
 			tex.wrapAmountH = GetF4();
@@ -595,13 +595,13 @@ void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture& tex )
 	while (true)
 	while (true)
 	{
 	{
 		if (mFileBuffer + 6 >= end)break;
 		if (mFileBuffer + 6 >= end)break;
-		LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
+		const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
 
 
-		if (mFileBuffer + head->length > end)
+		if (mFileBuffer + head.length > end)
 			throw DeadlyImportError("LWO2: Invalid texture header chunk length");
 			throw DeadlyImportError("LWO2: Invalid texture header chunk length");
 
 
-		uint8_t* const next = mFileBuffer+head->length;
-		switch (head->type)
+		uint8_t* const next = mFileBuffer+head.length;
+		switch (head.type)
 		{
 		{
 		case AI_LWO_CHAN:
 		case AI_LWO_CHAN:
 			tex.type = GetU4();
 			tex.type = GetU4();
@@ -698,20 +698,20 @@ void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* /*head*/, u
 	while (true)
 	while (true)
 	{
 	{
 		if (mFileBuffer + 6 >= end)break;
 		if (mFileBuffer + 6 >= end)break;
-		LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
+		const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
 
 
-		if (mFileBuffer + head->length > end)
+		if (mFileBuffer + head.length > end)
 			throw DeadlyImportError("LWO2: Invalid shader header chunk length");
 			throw DeadlyImportError("LWO2: Invalid shader header chunk length");
 
 
-		uint8_t* const next = mFileBuffer+head->length;
-		switch (head->type)
+		uint8_t* const next = mFileBuffer+head.length;
+		switch (head.type)
 		{
 		{
 		case AI_LWO_ENAB:
 		case AI_LWO_ENAB:
 			shader.enabled = GetU2() ? true : false;
 			shader.enabled = GetU2() ? true : false;
 			break;
 			break;
 
 
 		case AI_LWO_FUNC:
 		case AI_LWO_FUNC:
-			GetS0( shader.functionName, head->length );
+			GetS0( shader.functionName, head.length );
 		}
 		}
 		mFileBuffer = next;
 		mFileBuffer = next;
 	}
 	}
@@ -756,18 +756,18 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
 	{
 	{
 		if (mFileBuffer + 6 >= end)
 		if (mFileBuffer + 6 >= end)
 			break;
 			break;
-		LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
+		const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
 
 
-		if (mFileBuffer + head->length > end)
+		if (mFileBuffer + head.length > end)
 			throw DeadlyImportError("LWO2: Invalid surface chunk length");
 			throw DeadlyImportError("LWO2: Invalid surface chunk length");
 
 
-		uint8_t* const next = mFileBuffer+head->length;
-		switch (head->type)
+		uint8_t* const next = mFileBuffer+head.length;
+		switch (head.type)
 		{
 		{
 			// diffuse color
 			// diffuse color
 		case AI_LWO_COLR:
 		case AI_LWO_COLR:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,12);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,12);
 				surf.mColor.r = GetF4();
 				surf.mColor.r = GetF4();
 				surf.mColor.g = GetF4();
 				surf.mColor.g = GetF4();
 				surf.mColor.b = GetF4();
 				surf.mColor.b = GetF4();
@@ -776,14 +776,14 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
 			// diffuse strength ... hopefully
 			// diffuse strength ... hopefully
 		case AI_LWO_DIFF:
 		case AI_LWO_DIFF:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,4);
 				surf.mDiffuseValue = GetF4();
 				surf.mDiffuseValue = GetF4();
 				break;
 				break;
 			}
 			}
 			// specular strength ... hopefully
 			// specular strength ... hopefully
 		case AI_LWO_SPEC:
 		case AI_LWO_SPEC:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,4);
 				surf.mSpecularValue = GetF4();
 				surf.mSpecularValue = GetF4();
 				break;
 				break;
 			}
 			}
@@ -794,21 +794,21 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
 				if (surf.mTransparency == 10e10f)
 				if (surf.mTransparency == 10e10f)
 					break;
 					break;
 
 
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,4);
 				surf.mTransparency = GetF4();
 				surf.mTransparency = GetF4();
 				break;
 				break;
 			}
 			}
 			// additive transparency
 			// additive transparency
 		case AI_LWO_ADTR:
 		case AI_LWO_ADTR:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ADTR,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,ADTR,4);
 				surf.mAdditiveTransparency = GetF4();
 				surf.mAdditiveTransparency = GetF4();
 				break;
 				break;
 			}
 			}
 			// wireframe mode
 			// wireframe mode
 		case AI_LWO_LINE:
 		case AI_LWO_LINE:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LINE,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LINE,2);
 				if (GetU2() & 0x1)
 				if (GetU2() & 0x1)
 					surf.mWireframe = true;
 					surf.mWireframe = true;
 				break;
 				break;
@@ -816,49 +816,49 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
 			// glossiness
 			// glossiness
 		case AI_LWO_GLOS:
 		case AI_LWO_GLOS:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,4);
 				surf.mGlossiness = GetF4();
 				surf.mGlossiness = GetF4();
 				break;
 				break;
 			}
 			}
 			// bump intensity
 			// bump intensity
 		case AI_LWO_BUMP:
 		case AI_LWO_BUMP:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,BUMP,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,BUMP,4);
 				surf.mBumpIntensity = GetF4();
 				surf.mBumpIntensity = GetF4();
 				break;
 				break;
 			}
 			}
 			// color highlights
 			// color highlights
 		case AI_LWO_CLRH:
 		case AI_LWO_CLRH:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,CLRH,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,CLRH,4);
 				surf.mColorHighlights = GetF4();
 				surf.mColorHighlights = GetF4();
 				break;
 				break;
 			}
 			}
 			// index of refraction
 			// index of refraction
 		case AI_LWO_RIND:
 		case AI_LWO_RIND:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,RIND,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,RIND,4);
 				surf.mIOR = GetF4();
 				surf.mIOR = GetF4();
 				break;
 				break;
 			}
 			}
 			// polygon sidedness
 			// polygon sidedness
 		case AI_LWO_SIDE:
 		case AI_LWO_SIDE:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SIDE,2);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SIDE,2);
 				surf.bDoubleSided = (3 == GetU2());
 				surf.bDoubleSided = (3 == GetU2());
 				break;
 				break;
 			}
 			}
 			// maximum smoothing angle
 			// maximum smoothing angle
 		case AI_LWO_SMAN:
 		case AI_LWO_SMAN:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4);
 				surf.mMaximumSmoothAngle = fabs( GetF4() );
 				surf.mMaximumSmoothAngle = fabs( GetF4() );
 				break;
 				break;
 			}
 			}
 			// vertex color channel to be applied to the surface
 			// vertex color channel to be applied to the surface
 		case AI_LWO_VCOL:
 		case AI_LWO_VCOL:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,VCOL,12);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,VCOL,12);
 				surf.mDiffuseValue *= GetF4();				// strength
 				surf.mDiffuseValue *= GetF4();				// strength
 				ReadVSizedIntLWO2(mFileBuffer);             // skip envelope
 				ReadVSizedIntLWO2(mFileBuffer);             // skip envelope
 				surf.mVCMapType = GetU4();					// type of the channel
 				surf.mVCMapType = GetU4();					// type of the channel
@@ -870,18 +870,18 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
 			// surface bock entry
 			// surface bock entry
 		case AI_LWO_BLOK:
 		case AI_LWO_BLOK:
 			{
 			{
-				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,BLOK,4);
-				LE_NCONST IFF::SubChunkHeader* head2 = IFF::LoadSubChunk(mFileBuffer);
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,BLOK,4);
+				IFF::SubChunkHeader head2 = IFF::LoadSubChunk(mFileBuffer);
 
 
-				switch (head2->type)
+				switch (head2.type)
 				{
 				{
 				case AI_LWO_PROC:
 				case AI_LWO_PROC:
 				case AI_LWO_GRAD:
 				case AI_LWO_GRAD:
 				case AI_LWO_IMAP:
 				case AI_LWO_IMAP:
-					LoadLWO2TextureBlock(head2, head->length);
+					LoadLWO2TextureBlock(&head2, head.length);
 					break;
 					break;
 				case AI_LWO_SHDR:
 				case AI_LWO_SHDR:
-					LoadLWO2ShaderBlock(head2, head->length);
+					LoadLWO2ShaderBlock(&head2, head.length);
 					break;
 					break;
 
 
 				default:
 				default:

+ 3 - 3
code/LWSLoader.cpp

@@ -464,7 +464,7 @@ std::string LWSImporter::FindLWOFile(const std::string& in)
 	std::string tmp;
 	std::string tmp;
 	if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/')
 	if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/')
 	{
 	{
-		tmp = in[0] + (":\\" + in.substr(2));
+		tmp = in[0] + (std::string(":\\") + in.substr(2));
 	}
 	}
 	else tmp = in;
 	else tmp = in;
 
 
@@ -480,12 +480,12 @@ std::string LWSImporter::FindLWOFile(const std::string& in)
 	// <folder>\Scenes\<hh>\<*>.lws
 	// <folder>\Scenes\<hh>\<*>.lws
 	// where <hh> is optional.
 	// where <hh> is optional.
 
 
-	std::string test = ".." + (io->getOsSeparator() + tmp); 
+	std::string test = std::string("..") + (io->getOsSeparator() + tmp);
 	if (io->Exists(test)) {
 	if (io->Exists(test)) {
 		return test;
 		return test;
 	}
 	}
 
 
-	test = ".." + (io->getOsSeparator() + test); 
+	test = std::string("..") + (io->getOsSeparator() + test);
 	if (io->Exists(test)) {
 	if (io->Exists(test)) {
 		return test;
 		return test;
 	}
 	}

+ 10 - 17
code/LimitBoneWeightsProcess.cpp

@@ -131,10 +131,15 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
 
 
 		// and renormalize the weights
 		// and renormalize the weights
 		float sum = 0.0f;
 		float sum = 0.0f;
-		for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it)
-			sum += it->mWeight;
-		for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it)
-			it->mWeight /= sum;
+        for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it ) {
+            sum += it->mWeight;
+        }
+        if( 0.0f != sum ) {
+            const float invSum = 1.0f / sum;
+            for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it ) {
+                it->mWeight *= invSum;
+            }
+        }
 	}
 	}
 
 
 	if (bChanged)	{
 	if (bChanged)	{
@@ -157,18 +162,6 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
 			const std::vector<aiVertexWeight>& bw = boneWeights[a];
 			const std::vector<aiVertexWeight>& bw = boneWeights[a];
 			aiBone* bone = pMesh->mBones[a];
 			aiBone* bone = pMesh->mBones[a];
 
 
-			// ignore the bone if no vertex weights were removed there
-
-			// FIX (Aramis, 07|22|08)
-			// NO! we can't ignore it in this case ... it is possible that
-			// the number of weights did not change, but the weight values did.
-
-			// if( bw.size() == bone->mNumWeights)
-			//	continue;
-
-			// FIX (Aramis, 07|21|08)
-			// It is possible that all weights of a bone have been removed.
-			// This would naturally cause an exception in &bw[0].
 			if ( bw.empty() )
 			if ( bw.empty() )
 			{
 			{
 				abNoNeed[a] = bChanged = true;
 				abNoNeed[a] = bChanged = true;
@@ -177,7 +170,7 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
 
 
 			// copy the weight list. should always be less weights than before, so we don't need a new allocation
 			// copy the weight list. should always be less weights than before, so we don't need a new allocation
 			ai_assert( bw.size() <= bone->mNumWeights);
 			ai_assert( bw.size() <= bone->mNumWeights);
-			bone->mNumWeights = (unsigned int) bw.size();
+			bone->mNumWeights = static_cast<unsigned int>( bw.size() );
 			::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
 			::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
 		}
 		}
 
 

+ 3 - 3
code/MD3FileData.h

@@ -263,9 +263,9 @@ inline void LatLngNormalToVec3(uint16_t p_iNormal, float* p_afOut)
 	lat *= 3.141926f/128.0f;
 	lat *= 3.141926f/128.0f;
 	lng *= 3.141926f/128.0f;
 	lng *= 3.141926f/128.0f;
 
 
-	p_afOut[0] = cosf(lat) * sinf(lng);
-	p_afOut[1] = sinf(lat) * sinf(lng);
-	p_afOut[2] = cosf(lng);
+	p_afOut[0] = std::cos(lat) * std::sin(lng);
+	p_afOut[1] = std::sin(lat) * std::sin(lng);
+	p_afOut[2] = std::cos(lng);
 	return;
 	return;
 }
 }
 
 

+ 1 - 1
code/MD5Parser.h

@@ -259,7 +259,7 @@ inline void ConvertQuaternion (const aiVector3D& in, aiQuaternion& out) {
 
 
 	if (t < 0.0f)
 	if (t < 0.0f)
 		out.w = 0.0f;
 		out.w = 0.0f;
-	else out.w = sqrt (t);
+	else out.w = std::sqrt (t);
 }
 }
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------

+ 36 - 32
code/ObjExporter.cpp

@@ -75,6 +75,7 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 
+static const std::string MaterialExt = ".mtl";
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 ObjExporter :: ObjExporter(const char* _filename, const aiScene* pScene)
 ObjExporter :: ObjExporter(const char* _filename, const aiScene* pScene)
@@ -107,7 +108,7 @@ std::string ObjExporter :: GetMaterialLibName()
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 std::string ObjExporter :: GetMaterialLibFileName()
 std::string ObjExporter :: GetMaterialLibFileName()
 {	
 {	
-	return filename + ".mtl";
+    return filename + MaterialExt;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -132,7 +133,7 @@ std::string ObjExporter :: GetMaterialName(unsigned int index)
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void ObjExporter :: WriteMaterialFile()
+void ObjExporter::WriteMaterialFile()
 {
 {
 	WriteHeader(mOutputMat);
 	WriteHeader(mOutputMat);
 
 
@@ -144,16 +145,16 @@ void ObjExporter :: WriteMaterialFile()
 
 
 		aiColor4D c;
 		aiColor4D c;
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE,c)) {
-			mOutputMat << "kd " << c.r << " " << c.g << " " << c.b << endl;
+			mOutputMat << "Kd " << c.r << " " << c.g << " " << c.b << endl;
 		}
 		}
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT,c)) {
-			mOutputMat << "ka " << c.r << " " << c.g << " " << c.b << endl;
+			mOutputMat << "Ka " << c.r << " " << c.g << " " << c.b << endl;
 		}
 		}
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
-			mOutputMat << "ks " << c.r << " " << c.g << " " << c.b << endl;
+			mOutputMat << "Ks " << c.r << " " << c.g << " " << c.b << endl;
 		}
 		}
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_EMISSIVE,c)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_EMISSIVE,c)) {
-			mOutputMat << "ke " << c.r << " " << c.g << " " << c.b << endl;
+			mOutputMat << "Ke " << c.r << " " << c.g << " " << c.b << endl;
 		}
 		}
 
 
 		float o;
 		float o;
@@ -170,16 +171,19 @@ void ObjExporter :: WriteMaterialFile()
 
 
 		aiString s;
 		aiString s;
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_DIFFUSE(0),s)) {
-			mOutputMat << "map_kd " << s.data << endl;
+			mOutputMat << "map_Kd " << s.data << endl;
 		}
 		}
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_AMBIENT(0),s)) {
-			mOutputMat << "map_ka " << s.data << endl;
+			mOutputMat << "map_Ka " << s.data << endl;
 		}
 		}
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SPECULAR(0),s)) {
-			mOutputMat << "map_ks " << s.data << endl;
+			mOutputMat << "map_Ks " << s.data << endl;
 		}
 		}
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_SHININESS(0),s)) {
-			mOutputMat << "map_ns " << s.data << endl;
+			mOutputMat << "map_Ns " << s.data << endl;
+		}
+		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_OPACITY(0),s)) {
+			mOutputMat << "map_d " << s.data << endl;
 		}
 		}
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_HEIGHT(0),s) || AI_SUCCESS == mat->Get(AI_MATKEY_TEXTURE_NORMALS(0),s)) {
 			// implementations seem to vary here, so write both variants
 			// implementations seem to vary here, so write both variants
@@ -199,7 +203,7 @@ void ObjExporter :: WriteGeometryFile()
 
 
 	// collect mesh geometry
 	// collect mesh geometry
 	aiMatrix4x4 mBase;
 	aiMatrix4x4 mBase;
-	AddNode(pScene->mRootNode,mBase);
+	AddNode(pScene->mRootNode, mBase);
 
 
 	// write vertex positions
 	// write vertex positions
 	vpMap.getVectors(vp);
 	vpMap.getVectors(vp);
@@ -228,7 +232,9 @@ void ObjExporter :: WriteGeometryFile()
 	// now write all mesh instances
 	// now write all mesh instances
 	BOOST_FOREACH(const MeshInstance& m, meshes) {
 	BOOST_FOREACH(const MeshInstance& m, meshes) {
 		mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl;
 		mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl;
-		mOutput << "g " << m.name << endl;
+		if (!m.name.empty()) {
+			mOutput << "g " << m.name << endl;
+		}
 		mOutput << "usemtl " << m.matname << endl;
 		mOutput << "usemtl " << m.matname << endl;
 
 
 		BOOST_FOREACH(const Face& f, m.faces) {
 		BOOST_FOREACH(const Face& f, m.faces) {
@@ -243,11 +249,8 @@ void ObjExporter :: WriteGeometryFile()
 					if (fv.vt) {
 					if (fv.vt) {
 						mOutput << fv.vt;
 						mOutput << fv.vt;
 					}
 					}
-					if (f.kind == 'f') {
-						mOutput << '/';
-						if (fv.vn) {
-							mOutput << fv.vn;
-						}
+					if (f.kind == 'f' && fv.vn) {
+						mOutput << '/' << fv.vn;
 					}
 					}
 				}
 				}
 			}
 			}
@@ -258,14 +261,12 @@ void ObjExporter :: WriteGeometryFile()
 	}
 	}
 }
 }
 
 
-
-
-
-
+// ------------------------------------------------------------------------------------------------
 int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec)
 int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec)
 {
 {
-	vecIndexMap::dataType::iterator vertIt = vecMap.find(vec); 
-	if(vertIt != vecMap.end()){// vertex already exists, so reference it
+	vecIndexMap::dataType::iterator vertIt = vecMap.find(vec);
+	// vertex already exists, so reference it
+	if(vertIt != vecMap.end()){
 		return vertIt->second;
 		return vertIt->second;
 	}
 	}
 	vecMap[vec] = mNextIndex;
 	vecMap[vec] = mNextIndex;
@@ -274,6 +275,7 @@ int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec)
 	return ret;
 	return ret;
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
 void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs )
 void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs )
 {
 {
 	vecs.resize(vecMap.size());
 	vecs.resize(vecMap.size());
@@ -282,14 +284,13 @@ void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs )
 	}
 	}
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat)
+void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat)
 {
 {
 	meshes.push_back(MeshInstance());
 	meshes.push_back(MeshInstance());
 	MeshInstance& mesh = meshes.back();
 	MeshInstance& mesh = meshes.back();
 
 
-	mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_"+std::string(m->mName.data,m->mName.length) : "");
+	mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_" + std::string(m->mName.data,m->mName.length) : "");
 	mesh.matname = GetMaterialName(m->mMaterialIndex);
 	mesh.matname = GetMaterialName(m->mMaterialIndex);
 
 
 	mesh.faces.resize(m->mNumFaces);
 	mesh.faces.resize(m->mNumFaces);
@@ -317,7 +318,8 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri
 			face.indices[a].vp = vpMap.getIndex(vert);
 			face.indices[a].vp = vpMap.getIndex(vert);
 
 
 			if (m->mNormals) {
 			if (m->mNormals) {
-				face.indices[a].vn = vnMap.getIndex(m->mNormals[idx]);
+				aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx];
+				face.indices[a].vn = vnMap.getIndex(norm);
 			}
 			}
 			else{
 			else{
 				face.indices[a].vn = 0;
 				face.indices[a].vn = 0;
@@ -334,18 +336,20 @@ void ObjExporter :: AddMesh(const aiString& name, const aiMesh* m, const aiMatri
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void ObjExporter :: AddNode(const aiNode* nd, const aiMatrix4x4& mParent)
+void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent)
 {
 {
 	const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
 	const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
 
 
 	for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
 	for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
-		AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]],mAbs);
+		AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs);
 	}
 	}
 
 
 	for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
 	for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
-		AddNode(nd->mChildren[i],mAbs);
+		AddNode(nd->mChildren[i], mAbs);
 	}
 	}
 }
 }
 
 
-#endif
-#endif
+// ------------------------------------------------------------------------------------------------
+
+#endif // ASSIMP_BUILD_NO_OBJ_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 38 - 29
code/ObjFileImporter.cpp

@@ -62,7 +62,7 @@ static const aiImporterDesc desc = {
 
 
 static const unsigned int ObjMinSize = 16;
 static const unsigned int ObjMinSize = 16;
 
 
-namespace Assimp	{
+namespace Assimp {
 
 
 using namespace std;
 using namespace std;
 
 
@@ -109,9 +109,7 @@ const aiImporterDesc* ObjFileImporter::GetInfo () const
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Obj-file import implementation
 //	Obj-file import implementation
 void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
 void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
-{
-    DefaultIOSystem io;
-    
+{    
 	// Read file into memory
 	// Read file into memory
 	const std::string mode = "rb";
 	const std::string mode = "rb";
 	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
 	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
@@ -139,7 +137,23 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 	{
 	{
 		strModelName = pFile;
 		strModelName = pFile;
 	}
 	}
-	
+
+	// process all '\'
+	std::vector<char> ::iterator iter = m_Buffer.begin();
+	while (iter != m_Buffer.end())
+	{
+		if (*iter == '\\')
+		{
+			// remove '\'
+			iter = m_Buffer.erase(iter);
+			// remove next character
+			while (*iter == '\r' || *iter == '\n')
+				iter = m_Buffer.erase(iter);
+		}
+		else
+			++iter;
+	}
+
 	// parse the file into a temporary representation
 	// parse the file into a temporary representation
 	ObjFileParser parser(m_Buffer, strModelName, pIOHandler);
 	ObjFileParser parser(m_Buffer, strModelName, pIOHandler);
 
 
@@ -216,16 +230,10 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 	for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
 	for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
 	{
 	{
 		unsigned int meshId = pObject->m_Meshes[ i ];
 		unsigned int meshId = pObject->m_Meshes[ i ];
-		aiMesh *pMesh = new aiMesh;
-		createTopology( pModel, pObject, meshId, pMesh );	
-		if ( pMesh->mNumVertices > 0 ) 
-		{
+		aiMesh *pMesh = createTopology( pModel, pObject, meshId );	
+        if( pMesh && pMesh->mNumFaces > 0 ) {
 			MeshArray.push_back( pMesh );
 			MeshArray.push_back( pMesh );
 		}
 		}
-		else
-		{
-			delete pMesh;
-		}
 	}
 	}
 
 
 	// Create all nodes from the sub-objects stored in the current object
 	// Create all nodes from the sub-objects stored in the current object
@@ -258,45 +266,44 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Create topology data
 //	Create topology data
-void ObjFileImporter::createTopology(const ObjFile::Model* pModel, 
-									 const ObjFile::Object* pData, 
-									 unsigned int uiMeshIndex,
-									 aiMesh* pMesh )
+aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData, 
+                                         unsigned int uiMeshIndex )
 {
 {
 	// Checking preconditions
 	// Checking preconditions
 	ai_assert( NULL != pModel );
 	ai_assert( NULL != pModel );
     if( NULL == pData ) {
     if( NULL == pData ) {
-        return;
+        return NULL;
     }
     }
 
 
 	// Create faces
 	// Create faces
 	ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
 	ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
-	ai_assert( NULL != pObjMesh );
-
-	pMesh->mNumFaces = 0;
+    if( !pObjMesh ) {
+        return NULL;
+    }
+    ai_assert( NULL != pObjMesh );
+    aiMesh* pMesh = new aiMesh;
 	for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
 	for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
 	{
 	{
-		ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
-	
+		ObjFile::Face *const inp = pObjMesh->m_Faces[ index ];
+        ai_assert( NULL != inp  );
+
 		if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
 		if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
 			pMesh->mNumFaces += inp->m_pVertices->size() - 1;
 			pMesh->mNumFaces += inp->m_pVertices->size() - 1;
 			pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
 			pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
-		}
-		else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
+		} else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
 			pMesh->mNumFaces += inp->m_pVertices->size();
 			pMesh->mNumFaces += inp->m_pVertices->size();
 			pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
 			pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
 		} else {
 		} else {
 			++pMesh->mNumFaces;
 			++pMesh->mNumFaces;
 			if (inp->m_pVertices->size() > 3) {
 			if (inp->m_pVertices->size() > 3) {
 				pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
 				pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
-			}
-			else {
+			} else {
 				pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
 				pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	unsigned int uiIdxCount = 0u;
+	unsigned int uiIdxCount( 0u );
 	if ( pMesh->mNumFaces > 0 )
 	if ( pMesh->mNumFaces > 0 )
 	{
 	{
 		pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
 		pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
@@ -305,7 +312,7 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
 			pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
 			pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
 		}
 		}
 
 
-		unsigned int outIndex = 0;
+		unsigned int outIndex( 0 );
 
 
 		// Copy all data from all stored meshes
 		// Copy all data from all stored meshes
 		for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
 		for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
@@ -339,6 +346,8 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
 
 
 	// Create mesh vertices
 	// Create mesh vertices
 	createVertexArray(pModel, pData, uiMeshIndex, pMesh, uiIdxCount);
 	createVertexArray(pModel, pData, uiMeshIndex, pMesh, uiIdxCount);
+
+    return pMesh;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/ObjFileImporter.h

@@ -91,8 +91,8 @@ private:
 		aiNode *pParent, aiScene* pScene, std::vector<aiMesh*> &MeshArray);
 		aiNode *pParent, aiScene* pScene, std::vector<aiMesh*> &MeshArray);
 
 
 	//!	\brief	Creates topology data like faces and meshes for the geometry.
 	//!	\brief	Creates topology data like faces and meshes for the geometry.
-	void createTopology(const ObjFile::Model* pModel, const ObjFile::Object* pData,
-		unsigned int uiMeshIndex, aiMesh* pMesh);	
+    aiMesh *createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData,
+		unsigned int uiMeshIndex );	
 	
 	
 	//!	\brief	Creates vertices from model.
 	//!	\brief	Creates vertices from model.
 	void createVertexArray(const ObjFile::Model* pModel, const ObjFile::Object* pCurrentObject,
 	void createVertexArray(const ObjFile::Model* pModel, const ObjFile::Object* pCurrentObject,

+ 24 - 28
code/ObjFileMtlImporter.cpp

@@ -46,14 +46,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ObjTools.h"
 #include "ObjTools.h"
 #include "ObjFileData.h"
 #include "ObjFileData.h"
 #include "fast_atof.h"
 #include "fast_atof.h"
+#include "ParsingUtils.h"
 
 
 namespace Assimp	{
 namespace Assimp	{
 
 
 // Material specific token
 // Material specific token
-static const std::string DiffuseTexture      = "map_kd";
-static const std::string AmbientTexture      = "map_ka";
-static const std::string SpecularTexture     = "map_ks";
+static const std::string DiffuseTexture      = "map_Kd";
+static const std::string AmbientTexture      = "map_Ka";
+static const std::string SpecularTexture     = "map_Ks";
 static const std::string OpacityTexture      = "map_d";
 static const std::string OpacityTexture      = "map_d";
+static const std::string EmmissiveTexture    = "map_emissive";
 static const std::string BumpTexture1        = "map_bump";
 static const std::string BumpTexture1        = "map_bump";
 static const std::string BumpTexture2        = "map_Bump";
 static const std::string BumpTexture2        = "map_Bump";
 static const std::string BumpTexture3        = "bump";
 static const std::string BumpTexture3        = "bump";
@@ -128,6 +130,7 @@ void ObjFileMtlImporter::load()
 	{
 	{
 		switch (*m_DataIt)
 		switch (*m_DataIt)
 		{
 		{
+		case 'k':
 		case 'K':
 		case 'K':
 			{
 			{
 				++m_DataIt;
 				++m_DataIt;
@@ -163,25 +166,27 @@ void ObjFileMtlImporter::load()
 			}
 			}
 			break;
 			break;
 
 
-		case 'N':	// Shineness
+		case 'N':
+		case 'n':
 			{
 			{
 				++m_DataIt;
 				++m_DataIt;
-				switch(*m_DataIt) 
+				switch(*m_DataIt)
 				{
 				{
-				case 's':
+				case 's':	// Specular exponent
 					++m_DataIt;
 					++m_DataIt;
 					getFloatValue(m_pModel->m_pCurrentMaterial->shineness);
 					getFloatValue(m_pModel->m_pCurrentMaterial->shineness);
 					break;
 					break;
-				case 'i': //Index Of refraction 
+				case 'i':	// Index Of refraction
 					++m_DataIt;
 					++m_DataIt;
 					getFloatValue(m_pModel->m_pCurrentMaterial->ior);
 					getFloatValue(m_pModel->m_pCurrentMaterial->ior);
 					break;
 					break;
+				case 'e':	// New material
+					createMaterial();
+					break;
 				}
 				}
 				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-				break;
 			}
 			}
 			break;
 			break;
-		
 
 
 		case 'm':	// Texture
 		case 'm':	// Texture
 		case 'b':   // quick'n'dirty - for 'bump' sections
 		case 'b':   // quick'n'dirty - for 'bump' sections
@@ -191,13 +196,6 @@ void ObjFileMtlImporter::load()
 			}
 			}
 			break;
 			break;
 
 
-		case 'n':	// New material name
-			{
-				createMaterial();
-				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-			}
-			break;
-
 		case 'i':	// Illumination model
 		case 'i':	// Illumination model
 			{
 			{
 				m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
 				m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
@@ -221,15 +219,17 @@ void ObjFileMtlImporter::getColorRGBA( aiColor3D *pColor )
 {
 {
 	ai_assert( NULL != pColor );
 	ai_assert( NULL != pColor );
 	
 	
-	float r, g, b;
+	float r( 0.0f ), g( 0.0f ), b( 0.0f );
 	m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, r );
 	m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, r );
 	pColor->r = r;
 	pColor->r = r;
 	
 	
-	m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, g );
-	pColor->g = g;
-
-	m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, b );
-	pColor->b = b;
+    // we have to check if color is default 0 with only one token
+    if( !IsLineEnd( *m_DataIt ) ) {
+        m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, g );
+        m_DataIt = getFloat<DataArrayIt>( m_DataIt, m_DataItEnd, b );
+    }
+    pColor->g = g;
+    pColor->b = b;
 }
 }
 
 
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
@@ -253,7 +253,7 @@ void ObjFileMtlImporter::getFloatValue( float &value )
 void ObjFileMtlImporter::createMaterial()
 void ObjFileMtlImporter::createMaterial()
 {	
 {	
 	std::string line( "" );
 	std::string line( "" );
-	while ( !isNewLine( *m_DataIt ) ) {
+    while( !IsLineEnd( *m_DataIt ) ) {
 		line += *m_DataIt;
 		line += *m_DataIt;
 		++m_DataIt;
 		++m_DataIt;
 	}
 	}
@@ -303,11 +303,7 @@ void ObjFileMtlImporter::getTexture() {
 		// Opacity texture
 		// Opacity texture
 		out = & m_pModel->m_pCurrentMaterial->textureOpacity;
 		out = & m_pModel->m_pCurrentMaterial->textureOpacity;
 		clampIndex = ObjFile::Material::TextureOpacityType;
 		clampIndex = ObjFile::Material::TextureOpacityType;
-	} else if (!ASSIMP_strincmp( pPtr,"map_ka",6)) {
-		// Ambient texture
-		out = & m_pModel->m_pCurrentMaterial->textureAmbient;
-		clampIndex = ObjFile::Material::TextureAmbientType;
-	} else if (!ASSIMP_strincmp(&(*m_DataIt),"map_emissive",6)) {
+	} else if (!ASSIMP_strincmp( pPtr, EmmissiveTexture.c_str(), EmmissiveTexture.size())) {
 		// Emissive texture
 		// Emissive texture
 		out = & m_pModel->m_pCurrentMaterial->textureEmissive;
 		out = & m_pModel->m_pCurrentMaterial->textureEmissive;
 		clampIndex = ObjFile::Material::TextureEmissiveType;
 		clampIndex = ObjFile::Material::TextureEmissiveType;

+ 42 - 32
code/ObjFileParser.cpp

@@ -113,8 +113,8 @@ void ObjFileParser::parseFile()
 					getVector3(m_pModel->m_Vertices);
 					getVector3(m_pModel->m_Vertices);
 				} else if (*m_DataIt == 't') {
 				} else if (*m_DataIt == 't') {
 					// read in texture coordinate ( 2D or 3D )
 					// read in texture coordinate ( 2D or 3D )
-                    ++m_DataIt;
-                    getVector( m_pModel->m_TextureCoord );
+                                        ++m_DataIt;
+                                        getVector( m_pModel->m_TextureCoord );
 				} else if (*m_DataIt == 'n') {
 				} else if (*m_DataIt == 'n') {
 					// Read in normal vector definition
 					// Read in normal vector definition
 					++m_DataIt;
 					++m_DataIt;
@@ -186,12 +186,12 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length)
 {
 {
 	size_t index = 0;
 	size_t index = 0;
 	m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
 	m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
-	while ( m_DataIt != m_DataItEnd && !isSeparator(*m_DataIt) )
-	{
+    while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
 		pBuffer[index] = *m_DataIt;
 		pBuffer[index] = *m_DataIt;
 		index++;
 		index++;
-		if (index == length-1)
-			break;
+        if( index == length - 1 ) {
+            break;
+        }
 		++m_DataIt;
 		++m_DataIt;
 	}
 	}
 
 
@@ -233,12 +233,13 @@ void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
 void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
 void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
     size_t numComponents( 0 );
     size_t numComponents( 0 );
-    DataArrayIt tmp( m_DataIt );
+    const char* tmp( &m_DataIt[0] );
     while( !IsLineEnd( *tmp ) ) {
     while( !IsLineEnd( *tmp ) ) {
-        if( *tmp == ' ' ) {
-            ++numComponents;
+        if ( !SkipSpaces( &tmp ) ) {
+            break;
         }
         }
-        tmp++;
+        SkipToken( tmp );
+        ++numComponents;
     }
     }
     float x, y, z;
     float x, y, z;
     if( 2 == numComponents ) {
     if( 2 == numComponents ) {
@@ -344,7 +345,7 @@ void ObjFileParser::getFace(aiPrimitiveType type)
 			}
 			}
 			iPos++;
 			iPos++;
 		}
 		}
-		else if ( isSeparator(*pPtr) )
+        else if( IsSpaceOrNewLine( *pPtr ) )
 		{
 		{
 			iPos = 0;
 			iPos = 0;
 		}
 		}
@@ -462,8 +463,9 @@ void ObjFileParser::getMaterialDesc()
 		return;
 		return;
 
 
 	char *pStart = &(*m_DataIt);
 	char *pStart = &(*m_DataIt);
-	while ( m_DataIt != m_DataItEnd && !isSeparator(*m_DataIt) )
-		++m_DataIt;
+    while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
 
 
 	// Get name
 	// Get name
 	std::string strName(pStart, &(*m_DataIt));
 	std::string strName(pStart, &(*m_DataIt));
@@ -517,12 +519,14 @@ void ObjFileParser::getMaterialLib()
 {
 {
 	// Translate tuple
 	// Translate tuple
 	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
 	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
-	if (m_DataIt ==  m_DataItEnd)
-		return;
+    if( m_DataIt == m_DataItEnd ) {
+        return;
+    }
 	
 	
 	char *pStart = &(*m_DataIt);
 	char *pStart = &(*m_DataIt);
-	while (m_DataIt != m_DataItEnd && !isNewLine(*m_DataIt))
-		m_DataIt++;
+    while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
 
 
 	// Check for existence
 	// Check for existence
 	const std::string strMatName(pStart, &(*m_DataIt));
 	const std::string strMatName(pStart, &(*m_DataIt));
@@ -550,13 +554,15 @@ void ObjFileParser::getNewMaterial()
 {
 {
 	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
 	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
 	m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
 	m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
-	if ( m_DataIt == m_DataItEnd )
-		return;
+    if( m_DataIt == m_DataItEnd ) {
+        return;
+    }
 
 
 	char *pStart = &(*m_DataIt);
 	char *pStart = &(*m_DataIt);
 	std::string strMat( pStart, *m_DataIt );
 	std::string strMat( pStart, *m_DataIt );
-	while ( m_DataIt != m_DataItEnd && isSeparator( *m_DataIt ) )
-		m_DataIt++;
+    while( m_DataIt != m_DataItEnd && IsSpaceOrNewLine( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
 	std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
 	std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
 	if ( it == m_pModel->m_MaterialMap.end() )
 	if ( it == m_pModel->m_MaterialMap.end() )
 	{
 	{
@@ -581,8 +587,9 @@ void ObjFileParser::getNewMaterial()
 int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
 int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
 {
 {
 	int mat_index = -1;
 	int mat_index = -1;
-	if ( strMaterialName.empty() )
-		return mat_index;
+    if( strMaterialName.empty() ) {
+        return mat_index;
+    }
 	for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index)
 	for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index)
 	{
 	{
 		if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
 		if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
@@ -601,8 +608,9 @@ void ObjFileParser::getGroupName()
 	std::string strGroupName;
 	std::string strGroupName;
    
    
 	m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName);
 	m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName);
-	if ( isEndOfBuffer( m_DataIt, m_DataItEnd ) )
-		return;
+    if( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) {
+        return;
+    }
 
 
 	// Change active group, if necessary
 	// Change active group, if necessary
 	if ( m_pModel->m_strActiveGroup != strGroupName )
 	if ( m_pModel->m_strActiveGroup != strGroupName )
@@ -653,11 +661,13 @@ void ObjFileParser::getGroupNumberAndResolution()
 void ObjFileParser::getObjectName()
 void ObjFileParser::getObjectName()
 {
 {
 	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
 	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
-	if (m_DataIt == m_DataItEnd)
-		return;
+    if( m_DataIt == m_DataItEnd ) {
+        return;
+    }
 	char *pStart = &(*m_DataIt);
 	char *pStart = &(*m_DataIt);
-	while ( m_DataIt != m_DataItEnd && !isSeparator( *m_DataIt ) )
-		++m_DataIt;
+    while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
+        ++m_DataIt;
+    }
 
 
 	std::string strObjectName(pStart, &(*m_DataIt));
 	std::string strObjectName(pStart, &(*m_DataIt));
 	if (!strObjectName.empty()) 
 	if (!strObjectName.empty()) 
@@ -678,8 +688,9 @@ void ObjFileParser::getObjectName()
 		}
 		}
 
 
 		// Allocate a new object, if current one was not found before
 		// Allocate a new object, if current one was not found before
-		if ( NULL == m_pModel->m_pCurrent )
-			createObject(strObjectName);
+        if( NULL == m_pModel->m_pCurrent ) {
+            createObject( strObjectName );
+        }
 	}
 	}
 	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 }
@@ -694,7 +705,6 @@ void ObjFileParser::createObject(const std::string &strObjectName)
 	m_pModel->m_pCurrent->m_strObjName = strObjectName;
 	m_pModel->m_pCurrent->m_strObjName = strObjectName;
 	m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
 	m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
 	
 	
-
 	createMesh();
 	createMesh();
 
 
 	if( m_pModel->m_pCurrentMaterial )
 	if( m_pModel->m_pCurrentMaterial )

+ 15 - 35
code/ObjTools.h

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define OBJ_TOOLS_H_INC
 #define OBJ_TOOLS_H_INC
 
 
 #include "fast_atof.h"
 #include "fast_atof.h"
+#include "ParsingUtils.h"
 
 
 namespace Assimp
 namespace Assimp
 {
 {
@@ -68,28 +69,6 @@ inline bool isEndOfBuffer(  char_t it, char_t end )
 	return ( it == end );	
 	return ( it == end );	
 }
 }
 
 
-/** @brief	Returns true, if token is a space on any supported platform
-*	@param	token	Token to search in
-*	@return	true, if token is a space			
-*/
-inline bool isSeparator( char token )
-{
-	return ( token == ' ' || 
-			token == '\n' || 
-			token == '\f' || 
-			token == '\r' ||
-			token == '\t' );
-}
-
-/**	@brief	Returns true, fi token id a new line marking token.
- *	@param	token	Token to search in
- *	@return	true, if token is a newline token.
- */
-inline bool isNewLine( char token )
-{
-	return ( token == '\n' || token == '\f' || token == '\r' );
-}
-
 /**	@brief	Returns next word separated by a space
 /**	@brief	Returns next word separated by a space
  *	@param	pBuffer	Pointer to data buffer
  *	@param	pBuffer	Pointer to data buffer
  *	@param	pEnd	Pointer to end of buffer
  *	@param	pEnd	Pointer to end of buffer
@@ -100,7 +79,7 @@ inline Char_T getNextWord( Char_T pBuffer, Char_T pEnd )
 {
 {
 	while ( !isEndOfBuffer( pBuffer, pEnd ) )
 	while ( !isEndOfBuffer( pBuffer, pEnd ) )
 	{
 	{
-		if ( !isSeparator( *pBuffer ) || isNewLine( *pBuffer ) )
+        if( !IsSpaceOrNewLine( *pBuffer ) || IsLineEnd( *pBuffer ) )
 			break;
 			break;
 		pBuffer++;
 		pBuffer++;
 	}
 	}
@@ -117,7 +96,7 @@ inline Char_T getNextToken( Char_T pBuffer, Char_T pEnd )
 {
 {
 	while ( !isEndOfBuffer( pBuffer, pEnd ) )
 	while ( !isEndOfBuffer( pBuffer, pEnd ) )
 	{
 	{
-		if ( isSeparator( *pBuffer ) )
+        if( IsSpaceOrNewLine( *pBuffer ) )
 			break;
 			break;
 		pBuffer++;
 		pBuffer++;
 	}
 	}
@@ -127,14 +106,14 @@ inline Char_T getNextToken( Char_T pBuffer, Char_T pEnd )
 /**	@brief	Skips a line
 /**	@brief	Skips a line
  *	@param	it		Iterator set to current position
  *	@param	it		Iterator set to current position
  *	@param	end		Iterator set to end of scratch buffer for readout
  *	@param	end		Iterator set to end of scratch buffer for readout
- *	@param	uiLine	Current linenumber in format
+ *	@param	uiLine	Current line number in format
  *	@return	Current-iterator with new position
  *	@return	Current-iterator with new position
  */
  */
 template<class char_t>
 template<class char_t>
-inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine )
-{
-	while ( !isEndOfBuffer( it, end ) && !isNewLine( *it ) )
-		++it;
+inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) {
+    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) {
+        ++it;
+    }
 	if ( it != end )
 	if ( it != end )
 	{
 	{
 		++it;
 		++it;
@@ -157,15 +136,16 @@ template<class char_t>
 inline char_t getName( char_t it, char_t end, std::string &name )
 inline char_t getName( char_t it, char_t end, std::string &name )
 {
 {
 	name = "";
 	name = "";
-	if ( isEndOfBuffer( it, end ) )
-		return end;
+    if( isEndOfBuffer( it, end ) ) {
+        return end;
+    }
 	
 	
 	char *pStart = &( *it );
 	char *pStart = &( *it );
-	while ( !isEndOfBuffer( it, end ) && !isNewLine( *it ) ) {
+    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) {
 		++it;
 		++it;
 	}
 	}
 
 
-	while(isEndOfBuffer( it, end ) || isNewLine( *it ) || isSeparator(*it)) {
+    while( isEndOfBuffer( it, end ) || IsLineEnd( *it ) || IsSpaceOrNewLine( *it ) ) {
 		--it;
 		--it;
 	}
 	}
 	++it;
 	++it;
@@ -196,7 +176,7 @@ inline char_t CopyNextWord( char_t it, char_t end, char *pBuffer, size_t length
 {
 {
 	size_t index = 0;
 	size_t index = 0;
 	it = getNextWord<char_t>( it, end );
 	it = getNextWord<char_t>( it, end );
-	while ( !isSeparator( *it ) && !isEndOfBuffer( it, end ) )
+    while( !IsSpaceOrNewLine( *it ) && !isEndOfBuffer( it, end ) )
 	{
 	{
 		pBuffer[index] = *it ;
 		pBuffer[index] = *it ;
 		index++;
 		index++;
@@ -259,4 +239,4 @@ unsigned int tokenize( const string_type& str, std::vector<string_type>& tokens,
 
 
 } // Namespace Assimp
 } // Namespace Assimp
 
 
-#endif
+#endif // OBJ_TOOLS_H_INC

+ 5 - 6
code/OgreBinarySerializer.cpp

@@ -376,14 +376,14 @@ void OgreBinarySerializer::ReadMeshSkeletonLink(Mesh *mesh)
 	mesh->skeletonRef = ReadLine();
 	mesh->skeletonRef = ReadLine();
 }
 }
 
 
-void OgreBinarySerializer::ReadMeshBounds(Mesh *mesh)
+void OgreBinarySerializer::ReadMeshBounds(Mesh * /*mesh*/)
 {
 {
 	// Skip bounds, not compatible with Assimp.
 	// Skip bounds, not compatible with Assimp.
 	// 2x float vec3 + 1x float sphere radius
 	// 2x float vec3 + 1x float sphere radius
 	SkipBytes(sizeof(float) * 7);
 	SkipBytes(sizeof(float) * 7);
 }
 }
 
 
-void OgreBinarySerializer::ReadMeshExtremes(Mesh *mesh)
+void OgreBinarySerializer::ReadMeshExtremes(Mesh * /*mesh*/)
 {
 {
 	// Skip extremes, not compatible with Assimp.
 	// Skip extremes, not compatible with Assimp.
 	size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE; 
 	size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE; 
@@ -534,7 +534,6 @@ void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh *submesh)
 void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh)
 void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh)
 {
 {
 	uint16_t id = 0;
 	uint16_t id = 0;
-	uint16_t submeshIndex = 0;
 
 
 	if (!AtEnd())
 	if (!AtEnd())
 	{
 	{
@@ -644,7 +643,7 @@ void OgreBinarySerializer::ReadGeometryVertexBuffer(VertexData *dest)
 	DefaultLogger::get()->debug(Formatter::format() << "    - Read vertex buffer for source " << bindIndex << " of " << numBytes << " bytes");
 	DefaultLogger::get()->debug(Formatter::format() << "    - Read vertex buffer for source " << bindIndex << " of " << numBytes << " bytes");
 }
 }
 
 
-void OgreBinarySerializer::ReadEdgeList(Mesh *mesh)
+void OgreBinarySerializer::ReadEdgeList(Mesh * /*mesh*/)
 {
 {
 	// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
 	// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
 
 
@@ -1055,7 +1054,7 @@ void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton)
 	DefaultLogger::get()->debug(Formatter::format() << "    " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)");	
 	DefaultLogger::get()->debug(Formatter::format() << "    " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)");	
 }
 }
 
 
-void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest)
+void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, Animation *dest)
 {
 {
 	uint16_t boneId = Read<uint16_t>();
 	uint16_t boneId = Read<uint16_t>();
 	Bone *bone = dest->parentSkeleton->BoneById(boneId);
 	Bone *bone = dest->parentSkeleton->BoneById(boneId);
@@ -1097,7 +1096,7 @@ void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *d
 	dest->transformKeyFrames.push_back(keyframe);
 	dest->transformKeyFrames.push_back(keyframe);
 }
 }
 
 
-void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton *skeleton)
+void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton * /*skeleton*/)
 {
 {
 	// Skip bounds, not compatible with Assimp.
 	// Skip bounds, not compatible with Assimp.
 	ReadLine(); // skeleton name
 	ReadLine(); // skeleton name

+ 6 - 2
code/OgreBinarySerializer.h

@@ -75,8 +75,8 @@ private:
 	};
 	};
 	
 	
 	OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) :
 	OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) :
-		m_reader(reader),
 		m_currentLen(0),
 		m_currentLen(0),
+		m_reader(reader),
 		assetMode(mode)
 		assetMode(mode)
 	{
 	{
 	}
 	}
@@ -301,11 +301,12 @@ enum MeshChunkId
 						// unsigned short poseIndex 
 						// unsigned short poseIndex 
 						// float influence
 						// float influence
 		// Optional submesh extreme vertex list chink
 		// Optional submesh extreme vertex list chink
-		M_TABLE_EXTREMES = 0xE000,
+		M_TABLE_EXTREMES = 0xE000
 		// unsigned short submesh_index;
 		// unsigned short submesh_index;
 		// float extremes [n_extremes][3];
 		// float extremes [n_extremes][3];
 };
 };
 
 
+/*
 static std::string MeshHeaderToString(MeshChunkId id)
 static std::string MeshHeaderToString(MeshChunkId id)
 {
 {
 	switch(id)
 	switch(id)
@@ -347,6 +348,7 @@ static std::string MeshHeaderToString(MeshChunkId id)
 	}
 	}
 	return "Unknown_MeshChunkId";
 	return "Unknown_MeshChunkId";
 }
 }
+*/
 
 
 enum SkeletonChunkId
 enum SkeletonChunkId
 {
 {
@@ -393,6 +395,7 @@ enum SkeletonChunkId
 		// float scale							: scale to apply to trans/scale keys
 		// float scale							: scale to apply to trans/scale keys
 };
 };
 
 
+/*
 static std::string SkeletonHeaderToString(SkeletonChunkId id)
 static std::string SkeletonHeaderToString(SkeletonChunkId id)
 {
 {
 	switch(id)
 	switch(id)
@@ -409,6 +412,7 @@ static std::string SkeletonHeaderToString(SkeletonChunkId id)
 	}
 	}
 	return "Unknown_SkeletonChunkId";
 	return "Unknown_SkeletonChunkId";
 }
 }
+*/
 } // Ogre
 } // Ogre
 } // Assimp
 } // Assimp
 
 

+ 4 - 4
code/OgreImporter.cpp

@@ -108,10 +108,10 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
 		MemoryStreamReader reader(f);
 		MemoryStreamReader reader(f);
 
 
 		// Import mesh
 		// Import mesh
-		boost::scoped_ptr<Mesh> mesh = OgreBinarySerializer::ImportMesh(&reader);
+		boost::scoped_ptr<Mesh> mesh(OgreBinarySerializer::ImportMesh(&reader));
 
 
 		// Import skeleton
 		// Import skeleton
-		OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh);
+		OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh.get());
 
 
 		// Import mesh referenced materials
 		// Import mesh referenced materials
 		ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
 		ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
@@ -128,10 +128,10 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
 		boost::scoped_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
 		boost::scoped_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
 
 
 		// Import mesh
 		// Import mesh
-		boost::scoped_ptr<MeshXml> mesh = OgreXmlSerializer::ImportMesh(reader.get());
+		boost::scoped_ptr<MeshXml> mesh(OgreXmlSerializer::ImportMesh(reader.get()));
 		
 		
 		// Import skeleton
 		// Import skeleton
-		OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh);
+		OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh.get());
 
 
 		// Import mesh referenced materials
 		// Import mesh referenced materials
 		ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
 		ReadMaterials(pFile, pIOHandler, pScene, mesh.get());

+ 14 - 12
code/OgreStructs.cpp

@@ -325,7 +325,7 @@ uint32_t VertexData::VertexSize(uint16_t source) const
 MemoryStream *VertexData::VertexBuffer(uint16_t source)
 MemoryStream *VertexData::VertexBuffer(uint16_t source)
 {
 {
 	if (vertexBindings.find(source) != vertexBindings.end())
 	if (vertexBindings.find(source) != vertexBindings.end())
-		return vertexBindings[source];
+		return vertexBindings[source].get();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -404,9 +404,9 @@ size_t IndexData::FaceSize() const
 // Mesh
 // Mesh
 
 
 Mesh::Mesh() :
 Mesh::Mesh() :
-	sharedVertexData(0),
-	skeleton(0),
-	hasSkeletalAnimations(false)
+	hasSkeletalAnimations(false),
+	skeleton(NULL),
+	sharedVertexData(NULL)
 {
 {
 }
 }
 
 
@@ -712,8 +712,8 @@ aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent)
 // MeshXml
 // MeshXml
 
 
 MeshXml::MeshXml() :
 MeshXml::MeshXml() :
-	sharedVertexData(0),
-	skeleton(0)
+	skeleton(0),
+	sharedVertexData(0)
 {
 {
 }
 }
 
 
@@ -797,8 +797,8 @@ void MeshXml::ConvertToAssimpScene(aiScene* dest)
 // SubMeshXml
 // SubMeshXml
 
 
 SubMeshXml::SubMeshXml() :
 SubMeshXml::SubMeshXml() :
-	vertexData(0),
-	indexData(new IndexDataXml())
+	indexData(new IndexDataXml()),
+	vertexData(0)
 {
 {
 }
 }
 
 
@@ -912,8 +912,8 @@ aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent)
 // Animation
 // Animation
 
 
 Animation::Animation(Skeleton *parent) :
 Animation::Animation(Skeleton *parent) :
+	parentMesh(NULL),
 	parentSkeleton(parent),
 	parentSkeleton(parent),
-	parentMesh(0),
 	length(0.0f),
 	length(0.0f),
 	baseTime(-1.0f)
 	baseTime(-1.0f)
 {
 {
@@ -963,6 +963,8 @@ aiAnimation *Animation::ConvertToAssimpAnimation()
 // Skeleton
 // Skeleton
 
 
 Skeleton::Skeleton() :
 Skeleton::Skeleton() :
+	bones(),
+	animations(),
 	blendMode(ANIMBLEND_AVERAGE)
 	blendMode(ANIMBLEND_AVERAGE)
 {
 {
 }
 }
@@ -1103,7 +1105,7 @@ aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode)
 	return node;
 	return node;
 }
 }
 
 
-aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWeight> &boneWeights)
+aiBone *Bone::ConvertToAssimpBone(Skeleton * /*parent*/, const std::vector<aiVertexWeight> &boneWeights)
 {
 {
 	aiBone *bone = new aiBone();
 	aiBone *bone = new aiBone();
 	bone->mName = name;
 	bone->mName = name;
@@ -1122,8 +1124,8 @@ aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWe
 // VertexAnimationTrack
 // VertexAnimationTrack
 
 
 VertexAnimationTrack::VertexAnimationTrack() :
 VertexAnimationTrack::VertexAnimationTrack() :
-	target(0),
-	type(VAT_NONE)
+	type(VAT_NONE),
+	target(0)
 {
 {
 }
 }
 
 

+ 45 - 32
code/OptimizeMeshes.cpp

@@ -47,22 +47,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
 #ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
 
 
 using namespace Assimp;
 using namespace Assimp;
+
 #include "OptimizeMeshes.h"
 #include "OptimizeMeshes.h"
 #include "ProcessHelper.h"
 #include "ProcessHelper.h"
 #include "SceneCombiner.h"
 #include "SceneCombiner.h"
 
 
+static const unsigned int NotSet   = 0xffffffff;
+static const unsigned int DeadBeef = 0xdeadbeef;
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 OptimizeMeshesProcess::OptimizeMeshesProcess()
 OptimizeMeshesProcess::OptimizeMeshesProcess()
 : pts (false)
 : pts (false)
-, max_verts (0xffffffff)
-, max_faces (0xffffffff)
-{}
+, max_verts( NotSet )
+, max_faces( NotSet ) {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
-OptimizeMeshesProcess::~OptimizeMeshesProcess()
-{}
+OptimizeMeshesProcess::~OptimizeMeshesProcess() {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 // Returns whether the processing step is present in the given flag field.
@@ -74,17 +80,17 @@ bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const
 	// That's a serious design flaw, consider redesign.
 	// That's a serious design flaw, consider redesign.
 	if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
 	if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
 		pts = (0 != (pFlags & aiProcess_SortByPType));
 		pts = (0 != (pFlags & aiProcess_SortByPType));
-		max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : max_verts;
+        max_verts = ( 0 != ( pFlags & aiProcess_SplitLargeMeshes ) ) ? DeadBeef : max_verts;
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Setup properties for the postprocessing step
+// Setup properties for the post-processing step
 void OptimizeMeshesProcess::SetupProperties(const Importer* pImp)
 void OptimizeMeshesProcess::SetupProperties(const Importer* pImp)
 {
 {
-	if (max_verts == 0xdeadbeef /* magic hack */) {
+    if( max_verts == DeadBeef /* magic hack */ ) {
 		max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
 		max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
 		max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
 		max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
 	}
 	}
@@ -104,35 +110,36 @@ void OptimizeMeshesProcess::Execute( aiScene* pScene)
 	mScene = pScene;
 	mScene = pScene;
 
 
 	// need to clear persistent members from previous runs
 	// need to clear persistent members from previous runs
-	merge_list.clear();
-	output.clear();
+	merge_list.resize( 0 );
+	output.resize( 0 );
 
 
+    // ensure we have the right sizes
 	merge_list.reserve(pScene->mNumMeshes);
 	merge_list.reserve(pScene->mNumMeshes);
 	output.reserve(pScene->mNumMeshes);
 	output.reserve(pScene->mNumMeshes);
 
 
 	// Prepare lookup tables
 	// Prepare lookup tables
 	meshes.resize(pScene->mNumMeshes);
 	meshes.resize(pScene->mNumMeshes);
 	FindInstancedMeshes(pScene->mRootNode);
 	FindInstancedMeshes(pScene->mRootNode);
-	if (max_verts == 0xdeadbeef) /* undo the magic hack */
-		max_verts = 0xffffffff;
+    if( max_verts == DeadBeef ) /* undo the magic hack */
+		max_verts = NotSet;
 
 
 	// ... instanced meshes are immediately processed and added to the output list
 	// ... instanced meshes are immediately processed and added to the output list
 	for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) {
 	for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) {
 		meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]);
 		meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]);
 
 
-		if (meshes[i].instance_cnt > 1 && meshes[i].output_id == 0xffffffff) {
+		if (meshes[i].instance_cnt > 1 && meshes[i].output_id == NotSet ) {
 			meshes[i].output_id = n++;
 			meshes[i].output_id = n++;
 			output.push_back(mScene->mMeshes[i]);
 			output.push_back(mScene->mMeshes[i]);
 		}
 		}
 	}
 	}
 
 
-	// and process all nodes in the scenegraoh recursively
+	// and process all nodes in the scenegraph recursively
 	ProcessNode(pScene->mRootNode);
 	ProcessNode(pScene->mRootNode);
 	if (!output.size()) {
 	if (!output.size()) {
 		throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong");
 		throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong");
 	}
 	}
 
 
-	meshes.clear();
+	meshes.resize( 0 );
 	ai_assert(output.size() <= num_old);
 	ai_assert(output.size() <= num_old);
 
 
 	mScene->mNumMeshes = output.size();
 	mScene->mNumMeshes = output.size();
@@ -142,8 +149,9 @@ void OptimizeMeshesProcess::Execute( aiScene* pScene)
 		char tmp[512];
 		char tmp[512];
 		::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes);
 		::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes);
 		DefaultLogger::get()->info(tmp);
 		DefaultLogger::get()->info(tmp);
-	}
-	else DefaultLogger::get()->debug("OptimizeMeshesProcess finished");
+    } else {
+        DefaultLogger::get()->debug( "OptimizeMeshesProcess finished" );
+    }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -157,7 +165,7 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
 			im = meshes[im].output_id;
 			im = meshes[im].output_id;
 		}
 		}
 		else  {
 		else  {
-			merge_list.clear();
+			merge_list.resize( 0 );
 			unsigned int verts = 0, faces = 0;
 			unsigned int verts = 0, faces = 0;
 
 
 			// Find meshes to merge with us
 			// Find meshes to merge with us
@@ -170,8 +178,9 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
 					faces += mScene->mMeshes[am]->mNumFaces;
 					faces += mScene->mMeshes[am]->mNumFaces;
 
 
 					--pNode->mNumMeshes;
 					--pNode->mNumMeshes;
-					for (unsigned int n = a; n < pNode->mNumMeshes; ++n)
-						pNode->mMeshes[n] = pNode->mMeshes[n+1];
+                    for( unsigned int n = a; n < pNode->mNumMeshes; ++n ) {
+                        pNode->mMeshes[ n ] = pNode->mMeshes[ n + 1 ];
+                    }
 
 
 					--a;
 					--a;
 				}
 				}
@@ -184,8 +193,7 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
 				aiMesh* out;
 				aiMesh* out;
 				SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end());
 				SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end());
 				output.push_back(out);
 				output.push_back(out);
-			}
-			else {
+			} else {
 				output.push_back(mScene->mMeshes[im]);
 				output.push_back(mScene->mMeshes[im]);
 			}
 			}
 			im = output.size()-1;
 			im = output.size()-1;
@@ -193,8 +201,9 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
 	}
 	}
 
 
 
 
-	for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
-		ProcessNode(pNode->mChildren[i]);
+    for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) {
+        ProcessNode( pNode->mChildren[ i ] );
+    }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -206,8 +215,8 @@ bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned i
 
 
 	aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b];
 	aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b];
 
 
-	if ((0xffffffff != max_verts && verts+mb->mNumVertices > max_verts) ||
-		(0xffffffff != max_faces && faces+mb->mNumFaces    > max_faces)) {
+	if ((NotSet != max_verts && verts+mb->mNumVertices > max_verts) ||
+		(NotSet != max_faces && faces+mb->mNumFaces    > max_faces)) {
 		return false;
 		return false;
 	}
 	}
 
 
@@ -221,7 +230,7 @@ bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned i
 		return false;
 		return false;
 
 
 	// If both meshes are skinned, check whether we have many bones defined in both meshes. 
 	// If both meshes are skinned, check whether we have many bones defined in both meshes. 
-	// If yes, we can savely join them. 
+	// If yes, we can join them. 
 	if (ma->HasBones()) {
 	if (ma->HasBones()) {
 		// TODO
 		// TODO
 		return false;
 		return false;
@@ -230,14 +239,18 @@ bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned i
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Buidl a LUT of all instanced meshes
+// Build a LUT of all instanced meshes
 void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode)
 void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode)
 {
 {
-	for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
-		++meshes[pNode->mMeshes[i]].instance_cnt; 
+    for( unsigned int i = 0; i < pNode->mNumMeshes; ++i ) {
+        ++meshes[ pNode->mMeshes[ i ] ].instance_cnt;
+    }
 
 
-	for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
-		FindInstancedMeshes(pNode->mChildren[i]);
+    for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) {
+        FindInstancedMeshes( pNode->mChildren[ i ] );
+    }
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+
 #endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
 #endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS

+ 60 - 27
code/ParsingUtils.h

@@ -46,16 +46,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_PARSING_UTILS_H_INC
 #define AI_PARSING_UTILS_H_INC
 
 
 #include "StringComparison.h"
 #include "StringComparison.h"
+
 namespace Assimp {
 namespace Assimp {
 
 
-	// NOTE: the functions below are mostly intended as replacement for
-	// std::upper, std::lower, std::isupper, std::islower, std::isspace.
-	// we don't bother of locales. We don't want them. We want reliable
-	// (i.e. identical) results across all locales.
+// NOTE: the functions below are mostly intended as replacement for
+// std::upper, std::lower, std::isupper, std::islower, std::isspace.
+// we don't bother of locales. We don't want them. We want reliable
+// (i.e. identical) results across all locales.
+
+// The functions below accept any character type, but know only
+// about ASCII. However, UTF-32 is the only safe ASCII superset to
+// use since it doesn't have multi-byte sequences.
 
 
-	// The functions below accept any character type, but know only
-	// about ASCII. However, UTF-32 is the only safe ASCII superset to
-	// use since it doesn't have multibyte sequences.
+static const unsigned int BufferSize = 4096;
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
@@ -63,118 +66,145 @@ AI_FORCE_INLINE char_t ToLower( char_t in)
 {
 {
 	return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in;
 	return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in;
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE char_t ToUpper( char_t in)
-{
-	return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in;
+AI_FORCE_INLINE char_t ToUpper( char_t in) {
+    return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in;
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool IsUpper( char_t in)
 AI_FORCE_INLINE bool IsUpper( char_t in)
 {
 {
 	return (in >= (char_t)'A' && in <= (char_t)'Z');
 	return (in >= (char_t)'A' && in <= (char_t)'Z');
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool IsLower( char_t in)
 AI_FORCE_INLINE bool IsLower( char_t in)
 {
 {
 	return (in >= (char_t)'a' && in <= (char_t)'z');
 	return (in >= (char_t)'a' && in <= (char_t)'z');
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool IsSpace( char_t in)
 AI_FORCE_INLINE bool IsSpace( char_t in)
 {
 {
 	return (in == (char_t)' ' || in == (char_t)'\t');
 	return (in == (char_t)' ' || in == (char_t)'\t');
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool IsLineEnd( char_t in)
 AI_FORCE_INLINE bool IsLineEnd( char_t in)
 {
 {
-	return (in == (char_t)'\r' || in == (char_t)'\n' || in == (char_t)'\0');
+	return (in==(char_t)'\r'||in==(char_t)'\n'||in==(char_t)'\0'||in==(char_t)'\f');
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool IsSpaceOrNewLine( char_t in)
 AI_FORCE_INLINE bool IsSpaceOrNewLine( char_t in)
 {
 {
 	return IsSpace<char_t>(in) || IsLineEnd<char_t>(in);
 	return IsSpace<char_t>(in) || IsLineEnd<char_t>(in);
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool SkipSpaces( const char_t* in, const char_t** out)
 AI_FORCE_INLINE bool SkipSpaces( const char_t* in, const char_t** out)
 {
 {
-	while (*in == (char_t)' ' || *in == (char_t)'\t')in++;
+    while( *in == ( char_t )' ' || *in == ( char_t )'\t' ) {
+        ++in;
+    }
 	*out = in;
 	*out = in;
 	return !IsLineEnd<char_t>(*in);
 	return !IsLineEnd<char_t>(*in);
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool SkipSpaces( const char_t** inout)
 AI_FORCE_INLINE bool SkipSpaces( const char_t** inout)
 {
 {
 	return SkipSpaces<char_t>(*inout,inout);
 	return SkipSpaces<char_t>(*inout,inout);
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool SkipLine( const char_t* in, const char_t** out)
 AI_FORCE_INLINE bool SkipLine( const char_t* in, const char_t** out)
 {
 {
-	while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0')in++;
+    while( *in != ( char_t )'\r' && *in != ( char_t )'\n' && *in != ( char_t )'\0' ) {
+        ++in;
+    }
 
 
 	// files are opened in binary mode. Ergo there are both NL and CR
 	// files are opened in binary mode. Ergo there are both NL and CR
-	while (*in == (char_t)'\r' || *in == (char_t)'\n')in++;
+    while( *in == ( char_t )'\r' || *in == ( char_t )'\n' ) {
+        ++in;
+    }
 	*out = in;
 	*out = in;
 	return *in != (char_t)'\0';
 	return *in != (char_t)'\0';
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool SkipLine( const char_t** inout)
 AI_FORCE_INLINE bool SkipLine( const char_t** inout)
 {
 {
 	return SkipLine<char_t>(*inout,inout);
 	return SkipLine<char_t>(*inout,inout);
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
 AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
 {
 {
-	while (*in == (char_t)' ' || *in == (char_t)'\t' ||
-		*in == (char_t)'\r' || *in == (char_t)'\n')in++;
+    while( *in == ( char_t )' ' || *in == ( char_t )'\t' || *in == ( char_t )'\r' || *in == ( char_t )'\n' ) {
+        ++in;
+    }
 	*out = in;
 	*out = in;
 	return *in != '\0';
 	return *in != '\0';
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t** inout)
 AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t** inout)
 {
 {
 	return SkipSpacesAndLineEnd<char_t>(*inout,inout);
 	return SkipSpacesAndLineEnd<char_t>(*inout,inout);
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE bool GetNextLine(const char_t*& buffer, char_t out[4096])
+AI_FORCE_INLINE bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] )
 {
 {
-	if ((char_t)'\0' == *buffer)return false;
+    if( ( char_t )'\0' == *buffer ) {
+        return false;
+    }
 
 
 	char* _out = out;
 	char* _out = out;
-	char* const end = _out+4096;
-	while (!IsLineEnd( *buffer ) && _out < end)
-		*_out++ = *buffer++;
+    char* const end = _out + BufferSize;
+    while( !IsLineEnd( *buffer ) && _out < end ) {
+        *_out++ = *buffer++;
+    }
 	*_out = (char_t)'\0';
 	*_out = (char_t)'\0';
 
 
-	while (IsLineEnd( *buffer ) && '\0' != *buffer)++buffer;
-	return true;
+    while( IsLineEnd( *buffer ) && '\0' != *buffer ) {
+        ++buffer;
+    }
+
+    return true;
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool IsNumeric( char_t in)
 AI_FORCE_INLINE bool IsNumeric( char_t in)
 {
 {
 	return ( in >= '0' && in <= '9' ) || '-' == in || '+' == in;
 	return ( in >= '0' && in <= '9' ) || '-' == in || '+' == in;
 }
 }
+
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
 AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len)
 AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len)
 {
 {
-	if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len]))
-	{
+	if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) {
 		in += len+1;
 		in += len+1;
 		return true;
 		return true;
 	}
 	}
+
 	return false;
 	return false;
 }
 }
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
@@ -185,8 +215,7 @@ AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len
  */
  */
 AI_FORCE_INLINE bool TokenMatchI(const char*& in, const char* token, unsigned int len)
 AI_FORCE_INLINE bool TokenMatchI(const char*& in, const char* token, unsigned int len)
 {
 {
-	if (!ASSIMP_strincmp(token,in,len) && IsSpaceOrNewLine(in[len]))
-	{
+	if (!ASSIMP_strincmp(token,in,len) && IsSpaceOrNewLine(in[len])) {
 		in += len+1;
 		in += len+1;
 		return true;
 		return true;
 	}
 	}
@@ -206,5 +235,9 @@ AI_FORCE_INLINE std::string GetNextToken(const char*& in)
 	while (!IsSpaceOrNewLine(*in))++in;
 	while (!IsSpaceOrNewLine(*in))++in;
 	return std::string(cur,(size_t)(in-cur));
 	return std::string(cur,(size_t)(in-cur));
 }
 }
+
+// ---------------------------------------------------------------------------------
+
 } // ! namespace Assimp
 } // ! namespace Assimp
+
 #endif // ! AI_PARSING_UTILS_H_INC
 #endif // ! AI_PARSING_UTILS_H_INC

+ 103 - 6
code/PlyExporter.cpp

@@ -64,6 +64,20 @@ void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
 	outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
 	outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
 }
 }
 
 
+void ExportScenePlyBinary(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+{
+	// invoke the exporter 
+	PlyExporter exporter(pFile, pScene, true);
+
+	// we're still here - export successfully completed. Write the file.
+	boost::scoped_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
+	if (outfile == NULL) {
+		throw DeadlyExportError("could not open output .ply file: " + std::string(pFile));
+	}
+
+	outfile->Write(exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()), 1);
+}
+
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 
 #define PLY_EXPORT_HAS_NORMALS 0x1
 #define PLY_EXPORT_HAS_NORMALS 0x1
@@ -72,7 +86,7 @@ void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
 #define PLY_EXPORT_HAS_COLORS (PLY_EXPORT_HAS_TEXCOORDS << AI_MAX_NUMBER_OF_TEXTURECOORDS)
 #define PLY_EXPORT_HAS_COLORS (PLY_EXPORT_HAS_TEXCOORDS << AI_MAX_NUMBER_OF_TEXTURECOORDS)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene)
+PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool binary)
 : filename(_filename)
 : filename(_filename)
 , pScene(pScene)
 , pScene(pScene)
 , endl("\n") 
 , endl("\n") 
@@ -102,7 +116,16 @@ PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene)
 	}
 	}
 
 
 	mOutput << "ply" << endl;
 	mOutput << "ply" << endl;
-	mOutput << "format ascii 1.0" << endl;
+	if (binary) {
+#if (defined AI_BUILD_BIG_ENDIAN)
+		mOutput << "format binary_big_endian 1.0" << endl;
+#else
+		mOutput << "format binary_little_endian 1.0" << endl;
+#endif
+	}
+	else {
+		mOutput << "format ascii 1.0" << endl;
+	}
 	mOutput << "comment Created by Open Asset Import Library - http://assimp.sf.net (v"
 	mOutput << "comment Created by Open Asset Import Library - http://assimp.sf.net (v"
 		<< aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' 
 		<< aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' 
 		<< aiGetVersionRevision() << ")" << endl;
 		<< aiGetVersionRevision() << ")" << endl;
@@ -163,17 +186,29 @@ PlyExporter :: PlyExporter(const char* _filename, const aiScene* pScene)
 	mOutput << "end_header" << endl;
 	mOutput << "end_header" << endl;
 
 
 	for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
 	for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
-		WriteMeshVerts(pScene->mMeshes[i],components);
+		if (binary) {
+			WriteMeshVertsBinary(pScene->mMeshes[i], components);
+		}
+		else {
+			WriteMeshVerts(pScene->mMeshes[i], components);
+		}
 	}
 	}
 	for (unsigned int i = 0, ofs = 0; i < pScene->mNumMeshes; ++i) {
 	for (unsigned int i = 0, ofs = 0; i < pScene->mNumMeshes; ++i) {
-		WriteMeshIndices(pScene->mMeshes[i],ofs);
+		if (binary) {
+			WriteMeshIndicesBinary(pScene->mMeshes[i], ofs);
+		}
+		else {
+			WriteMeshIndices(pScene->mMeshes[i], ofs);
+		}
 		ofs += pScene->mMeshes[i]->mNumVertices;
 		ofs += pScene->mMeshes[i]->mNumVertices;
 	}
 	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void PlyExporter :: WriteMeshVerts(const aiMesh* m, unsigned int components)
+void PlyExporter::WriteMeshVerts(const aiMesh* m, unsigned int components)
 {
 {
+	// If a component (for instance normal vectors) is present in at least one mesh in the scene,
+	// then default values are written for meshes that do not contain this component.
 	for (unsigned int i = 0; i < m->mNumVertices; ++i) {
 	for (unsigned int i = 0; i < m->mNumVertices; ++i) {
 		mOutput << 
 		mOutput << 
 			m->mVertices[i].x << " " << 
 			m->mVertices[i].x << " " << 
@@ -237,7 +272,57 @@ void PlyExporter :: WriteMeshVerts(const aiMesh* m, unsigned int components)
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void PlyExporter :: WriteMeshIndices(const aiMesh* m, unsigned int offset)
+void PlyExporter::WriteMeshVertsBinary(const aiMesh* m, unsigned int components)
+{
+	// If a component (for instance normal vectors) is present in at least one mesh in the scene,
+	// then default values are written for meshes that do not contain this component.
+	aiVector3D defaultNormal(0, 0, 0);
+	aiVector2D defaultUV(-1, -1);
+	aiColor4D defaultColor(-1, -1, -1, -1);
+	for (unsigned int i = 0; i < m->mNumVertices; ++i) {
+		mOutput.write(reinterpret_cast<const char*>(&m->mVertices[i].x), 12);
+		if (components & PLY_EXPORT_HAS_NORMALS) {
+			if (m->HasNormals()) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mNormals[i].x), 12);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
+			}
+		}
+
+		for (unsigned int n = PLY_EXPORT_HAS_TEXCOORDS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_TEXTURECOORDS; n <<= 1, ++c) {
+			if (m->HasTextureCoords(c)) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mTextureCoords[c][i].x), 6);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultUV.x), 6);
+			}
+		}
+
+		for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
+			if (m->HasVertexColors(c)) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mColors[c][i].r), 16);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultColor.r), 16);
+			}
+		}
+
+		if (components & PLY_EXPORT_HAS_TANGENTS_BITANGENTS) {
+			if (m->HasTangentsAndBitangents()) {
+				mOutput.write(reinterpret_cast<const char*>(&m->mTangents[i].x), 12);
+				mOutput.write(reinterpret_cast<const char*>(&m->mBitangents[i].x), 12);
+			}
+			else {
+				mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
+				mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
+			}
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+void PlyExporter::WriteMeshIndices(const aiMesh* m, unsigned int offset)
 {
 {
 	for (unsigned int i = 0; i < m->mNumFaces; ++i) {
 	for (unsigned int i = 0; i < m->mNumFaces; ++i) {
 		const aiFace& f = m->mFaces[i];
 		const aiFace& f = m->mFaces[i];
@@ -248,4 +333,16 @@ void PlyExporter :: WriteMeshIndices(const aiMesh* m, unsigned int offset)
 	}
 	}
 }
 }
 
 
+void PlyExporter::WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset)
+{
+	for (unsigned int i = 0; i < m->mNumFaces; ++i) {
+		const aiFace& f = m->mFaces[i];
+		mOutput.write(reinterpret_cast<const char*>(&f.mNumIndices), 4);
+		for (unsigned int c = 0; c < f.mNumIndices; ++c) {
+			unsigned int index = f.mIndices[c] + offset;
+			mOutput.write(reinterpret_cast<const char*>(&index), 4);
+		}
+	}
+}
+
 #endif
 #endif

+ 4 - 1
code/PlyExporter.h

@@ -59,7 +59,7 @@ class PlyExporter
 {
 {
 public:
 public:
 	/// Constructor for a specific scene to export
 	/// Constructor for a specific scene to export
-	PlyExporter(const char* filename, const aiScene* pScene);
+	PlyExporter(const char* filename, const aiScene* pScene, bool binary = false);
 
 
 public:
 public:
 
 
@@ -71,6 +71,9 @@ private:
 	void WriteMeshVerts(const aiMesh* m, unsigned int components);
 	void WriteMeshVerts(const aiMesh* m, unsigned int components);
 	void WriteMeshIndices(const aiMesh* m, unsigned int ofs);
 	void WriteMeshIndices(const aiMesh* m, unsigned int ofs);
 
 
+	void WriteMeshVertsBinary(const aiMesh* m, unsigned int components);
+	void WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset);
+
 private:
 private:
 
 
 	const std::string filename;
 	const std::string filename;

+ 1 - 1
code/PlyParser.cpp

@@ -182,7 +182,7 @@ PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOu
 	{
 	{
 		eOut = PLY::EST_Opacity;
 		eOut = PLY::EST_Opacity;
 	}
 	}
-	else if (TokenMatch(pCur,"specular_power",6))
+	else if (TokenMatch(pCur,"specular_power",14))
 	{
 	{
 		eOut = PLY::EST_PhongPower;
 		eOut = PLY::EST_PhongPower;
 	}
 	}

+ 6 - 6
code/PolyTools.h

@@ -118,9 +118,9 @@ inline bool IsCCW(T* in, size_t npoints) {
 			((-in[i+2].y + in[i+1].y) *
 			((-in[i+2].y + in[i+1].y) *
 			(-in[i+2].y + in[i+1].y));
 			(-in[i+2].y + in[i+1].y));
 
 
-		b = sqrt(bb);
-		c = sqrt(cc);
-		theta = acos((bb + cc - aa) / (2 * b * c));
+		b = std::sqrt(bb);
+		c = std::sqrt(cc);
+		theta = std::acos((bb + cc - aa) / (2 * b * c));
 
 
 		if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) {
 		if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) {
 			//	if (convex(in[i].x, in[i].y,
 			//	if (convex(in[i].x, in[i].y,
@@ -146,9 +146,9 @@ inline bool IsCCW(T* in, size_t npoints) {
 	cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) +
 	cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) +
 		((-in[1].y + in[0].y) * (-in[1].y + in[0].y));
 		((-in[1].y + in[0].y) * (-in[1].y + in[0].y));
 
 
-	b = sqrt(bb);
-	c = sqrt(cc);
-	theta = acos((bb + cc - aa) / (2 * b * c));
+	b = std::sqrt(bb);
+	c = std::sqrt(cc);
+	theta = std::acos((bb + cc - aa) / (2 * b * c));
 
 
 	//if (convex(in[npoints-2].x, in[npoints-2].y,
 	//if (convex(in[npoints-2].x, in[npoints-2].y,
 	//	in[0].x, in[0].y,
 	//	in[0].x, in[0].y,

+ 10 - 8
code/Q3BSPFileImporter.cpp

@@ -73,11 +73,13 @@ static const aiImporterDesc desc = {
 
 
 namespace Assimp {
 namespace Assimp {
 
 
+/*
 static void getSupportedExtensions(std::vector<std::string> &supportedExtensions) {
 static void getSupportedExtensions(std::vector<std::string> &supportedExtensions) {
     supportedExtensions.push_back( ".jpg" );
     supportedExtensions.push_back( ".jpg" );
     supportedExtensions.push_back( ".png" );
     supportedExtensions.push_back( ".png" );
     supportedExtensions.push_back( ".tga" );
     supportedExtensions.push_back( ".tga" );
 }
 }
+*/
     
     
 using namespace Q3BSP;
 using namespace Q3BSP;
 
 
@@ -628,7 +630,7 @@ aiFace *Q3BSPFileImporter::getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx )
 bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel,
 bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel,
 												 Q3BSP::Q3BSPZipArchive *pArchive, aiScene*,
 												 Q3BSP::Q3BSPZipArchive *pArchive, aiScene*,
 												 aiMaterial *pMatHelper, int textureId ) {
 												 aiMaterial *pMatHelper, int textureId ) {
-	if ( NULL == pArchive || NULL == pArchive || NULL == pMatHelper ) {
+	if ( NULL == pArchive || NULL == pMatHelper ) {
 		return false;
 		return false;
 	}
 	}
 
 
@@ -639,17 +641,17 @@ bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pMode
 	bool res = true;
 	bool res = true;
 	sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ];
 	sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ];
 	if ( !pTexture ) {
 	if ( !pTexture ) {
-        return false;
-    }
+		return false;
+	}
 
 
-    std::vector<std::string> supportedExtensions;
-    supportedExtensions.push_back( ".jpg" );
-    supportedExtensions.push_back( ".png" );
-    supportedExtensions.push_back( ".tga" );
+	std::vector<std::string> supportedExtensions;
+	supportedExtensions.push_back( ".jpg" );
+	supportedExtensions.push_back( ".png" );
+	supportedExtensions.push_back( ".tga" );
 	std::string textureName, ext;
 	std::string textureName, ext;
 	if ( expandFile( pArchive, pTexture->strName, supportedExtensions, textureName, ext ) ) {
 	if ( expandFile( pArchive, pTexture->strName, supportedExtensions, textureName, ext ) ) {
 		IOStream *pTextureStream = pArchive->Open( textureName.c_str() );
 		IOStream *pTextureStream = pArchive->Open( textureName.c_str() );
-		if ( !pTextureStream ) {
+		if ( pTextureStream ) {
 			size_t texSize = pTextureStream->FileSize();
 			size_t texSize = pTextureStream->FileSize();
 			aiTexture *pTexture = new aiTexture;
 			aiTexture *pTexture = new aiTexture;
 			pTexture->mHeight = 0;
 			pTexture->mHeight = 0;

+ 5 - 5
code/Q3BSPZipArchive.cpp

@@ -68,25 +68,25 @@ voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
 	return (voidpf) io_system->Open(filename, mode_fopen);
 	return (voidpf) io_system->Open(filename, mode_fopen);
 }
 }
 
 
-uLong IOSystem2Unzip::read(voidpf opaque, voidpf stream, void* buf, uLong size) {
+uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
 	IOStream* io_stream = (IOStream*) stream;
 	IOStream* io_stream = (IOStream*) stream;
 
 
 	return io_stream->Read(buf, 1, size);
 	return io_stream->Read(buf, 1, size);
 }
 }
 
 
-uLong IOSystem2Unzip::write(voidpf opaque, voidpf stream, const void* buf, uLong size) {
+uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
 	IOStream* io_stream = (IOStream*) stream;
 	IOStream* io_stream = (IOStream*) stream;
 
 
 	return io_stream->Write(buf, 1, size);
 	return io_stream->Write(buf, 1, size);
 }
 }
 
 
-long IOSystem2Unzip::tell(voidpf opaque, voidpf stream) {
+long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
 	IOStream* io_stream = (IOStream*) stream;
 	IOStream* io_stream = (IOStream*) stream;
 
 
 	return io_stream->Tell();
 	return io_stream->Tell();
 }
 }
 
 
-long IOSystem2Unzip::seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
+long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
 	IOStream* io_stream = (IOStream*) stream;
 	IOStream* io_stream = (IOStream*) stream;
 
 
 	aiOrigin assimp_origin;
 	aiOrigin assimp_origin;
@@ -115,7 +115,7 @@ int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
 	return 0;
 	return 0;
 }
 }
 
 
-int IOSystem2Unzip::testerror(voidpf opaque, voidpf stream) {
+int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 2
code/STLLoader.cpp

@@ -348,8 +348,8 @@ bool STLImporter::LoadBinaryFile()
 	bool bIsMaterialise = false;
 	bool bIsMaterialise = false;
 
 
 	// search for an occurence of "COLOR=" in the header
 	// search for an occurence of "COLOR=" in the header
-	const char* sz2 = (const char*)mBuffer;
-	const char* const szEnd = sz2+80;
+	const unsigned char* sz2 = (const unsigned char*)mBuffer;
+	const unsigned char* const szEnd = sz2+80;
 	while (sz2 < szEnd)	{
 	while (sz2 < szEnd)	{
 
 
 		if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ &&
 		if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ &&

+ 46 - 0
code/SceneCombiner.cpp

@@ -38,6 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
+// TODO: refactor entire file to get rid of the "flat-copy" first approach
+// to copying structures. This easily breaks in the most unintuitive way
+// possible as new fields are added to assimp structures.
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 /** @file Implements Assimp::SceneCombiner. This is a smart utility
 /** @file Implements Assimp::SceneCombiner. This is a smart utility
@@ -1194,10 +1197,53 @@ void SceneCombiner::Copy     (aiNode** _dest, const aiNode* src)
 	// get a flat copy
 	// get a flat copy
 	::memcpy(dest,src,sizeof(aiNode));
 	::memcpy(dest,src,sizeof(aiNode));
 
 
+	if (src->mMetaData) {
+		Copy(&dest->mMetaData, src->mMetaData);
+	}
+
 	// and reallocate all arrays
 	// and reallocate all arrays
 	GetArrayCopy( dest->mMeshes, dest->mNumMeshes );
 	GetArrayCopy( dest->mMeshes, dest->mNumMeshes );
 	CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren);
 	CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren);
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+void SceneCombiner::Copy (aiMetadata** _dest, const aiMetadata* src)
+{
+	ai_assert(NULL != _dest && NULL != src);
+
+	aiMetadata* dest = *_dest = new aiMetadata();
+	dest->mNumProperties = src->mNumProperties;
+	dest->mKeys = new aiString[src->mNumProperties];
+	std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys);
+
+	dest->mValues = new aiMetadataEntry[src->mNumProperties];
+	for (unsigned int i = 0; i < src->mNumProperties; ++i) {
+		aiMetadataEntry& in = src->mValues[i];
+		aiMetadataEntry& out = dest->mValues[i];
+		out.mType = in.mType;
+		switch (dest->mValues[i].mType) {
+		case AI_BOOL:
+			out.mData = new bool(*static_cast<bool*>(in.mData));
+			break;
+		case AI_INT:
+			out.mData = new int(*static_cast<int*>(in.mData));
+			break;
+		case AI_UINT64:
+			out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
+			break;
+		case AI_FLOAT:
+			out.mData = new float(*static_cast<float*>(in.mData));
+			break;
+		case AI_AISTRING:
+			out.mData = new aiString(*static_cast<aiString*>(in.mData));
+			break;
+		case AI_AIVECTOR3D:
+			out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
+			break;
+		default:
+			ai_assert(false);
+		}
+	}
+}
 
 
 }
 }

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů