Browse Source

Third Party update delta

Josh Engebretson 9 years ago
parent
commit
209b390328
100 changed files with 11853 additions and 8241 deletions
  1. 23 0
      Source/ThirdParty/Assimp/CHANGES
  2. 0 8
      Source/ThirdParty/Assimp/CMake/FindZLIB.cmake
  3. 750 145
      Source/ThirdParty/Assimp/CMakeLists.txt
  4. 10 0
      Source/ThirdParty/Assimp/CREDITS
  5. 12 0
      Source/ThirdParty/Assimp/CodeConventions.md
  6. 1 1
      Source/ThirdParty/Assimp/INSTALL
  7. 1 1
      Source/ThirdParty/Assimp/README
  8. 129 0
      Source/ThirdParty/Assimp/Readme.md
  9. 8 0
      Source/ThirdParty/Assimp/code/.editorconfig
  10. 15 3
      Source/ThirdParty/Assimp/code/ACLoader.cpp
  11. 7 0
      Source/ThirdParty/Assimp/code/Bitmap.h
  12. 7 0
      Source/ThirdParty/Assimp/code/BlenderDNA.h
  13. 1 1
      Source/ThirdParty/Assimp/code/BlenderScene.h
  14. 7 0
      Source/ThirdParty/Assimp/code/BlobIOSystem.h
  15. 22 22
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/LICENSE_1_0.txt
  16. 99 99
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/foreach.hpp
  17. 82 82
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/format.hpp
  18. 26 26
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/lexical_cast.hpp
  19. 57 57
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/make_shared.hpp
  20. 37 37
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/math/common_factor_rt.hpp
  21. 36 36
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/noncopyable.hpp
  22. 45 45
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/pointer_cast.hpp
  23. 79 79
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/scoped_array.hpp
  24. 79 79
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/scoped_ptr.hpp
  25. 228 228
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_array.hpp
  26. 260 260
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_ptr.hpp
  27. 20 20
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/static_assert.hpp
  28. 73 73
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/timer.hpp
  29. 283 283
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/tuple/tuple.hpp
  30. 7 0
      Source/ThirdParty/Assimp/code/ByteSwapper.h
  31. 644 0
      Source/ThirdParty/Assimp/code/C4DImporter.cpp
  32. 123 0
      Source/ThirdParty/Assimp/code/C4DImporter.h
  33. 7 0
      Source/ThirdParty/Assimp/code/ColladaHelper.h
  34. 36 7
      Source/ThirdParty/Assimp/code/ColladaParser.cpp
  35. 333 332
      Source/ThirdParty/Assimp/code/ColladaParser.h
  36. 8 0
      Source/ThirdParty/Assimp/code/FBXBinaryTokenizer.cpp
  37. 1 12
      Source/ThirdParty/Assimp/code/FBXConverter.cpp
  38. 7 0
      Source/ThirdParty/Assimp/code/FBXDocument.h
  39. 7 0
      Source/ThirdParty/Assimp/code/FBXParser.h
  40. 2 2
      Source/ThirdParty/Assimp/code/FixNormalsStep.cpp
  41. 8 0
      Source/ThirdParty/Assimp/code/HMPFileData.h
  42. 7 0
      Source/ThirdParty/Assimp/code/Hash.h
  43. 8 3
      Source/ThirdParty/Assimp/code/IFCBoolean.cpp
  44. 4 1
      Source/ThirdParty/Assimp/code/IFCGeometry.cpp
  45. 18 15
      Source/ThirdParty/Assimp/code/IFCOpenings.cpp
  46. 4 1
      Source/ThirdParty/Assimp/code/IFCUtil.cpp
  47. 6 0
      Source/ThirdParty/Assimp/code/IRRShared.h
  48. 7 0
      Source/ThirdParty/Assimp/code/ImporterRegistry.cpp
  49. 3 0
      Source/ThirdParty/Assimp/code/LWOLoader.cpp
  50. 7 0
      Source/ThirdParty/Assimp/code/MD2FileData.h
  51. 7 0
      Source/ThirdParty/Assimp/code/MD3FileData.h
  52. 7 0
      Source/ThirdParty/Assimp/code/MD3Loader.cpp
  53. 6 0
      Source/ThirdParty/Assimp/code/MD5Parser.h
  54. 7 0
      Source/ThirdParty/Assimp/code/MDCFileData.h
  55. 6 0
      Source/ThirdParty/Assimp/code/MDLFileData.h
  56. 3 0
      Source/ThirdParty/Assimp/code/MDLLoader.cpp
  57. 7 0
      Source/ThirdParty/Assimp/code/MaterialSystem.h
  58. 7 0
      Source/ThirdParty/Assimp/code/MemoryIOWrapper.h
  59. 7 0
      Source/ThirdParty/Assimp/code/NDOLoader.h
  60. 6 6
      Source/ThirdParty/Assimp/code/ObjExporter.cpp
  61. 1 1
      Source/ThirdParty/Assimp/code/ObjExporter.h
  62. 14 16
      Source/ThirdParty/Assimp/code/ObjFileData.h
  63. 31 19
      Source/ThirdParty/Assimp/code/ObjFileImporter.cpp
  64. 15 9
      Source/ThirdParty/Assimp/code/ObjFileMtlImporter.cpp
  65. 4 7
      Source/ThirdParty/Assimp/code/ObjFileMtlImporter.h
  66. 56 51
      Source/ThirdParty/Assimp/code/ObjFileParser.cpp
  67. 19 20
      Source/ThirdParty/Assimp/code/ObjFileParser.h
  68. 185 0
      Source/ThirdParty/Assimp/code/OgreImporter.hpp
  69. 7 0
      Source/ThirdParty/Assimp/code/OgreParsingUtils.h
  70. 88 0
      Source/ThirdParty/Assimp/code/OgreXmlHelper.hpp
  71. 53 0
      Source/ThirdParty/Assimp/code/OpenGEXExporter.cpp
  72. 65 0
      Source/ThirdParty/Assimp/code/OpenGEXExporter.h
  73. 963 0
      Source/ThirdParty/Assimp/code/OpenGEXImporter.cpp
  74. 193 0
      Source/ThirdParty/Assimp/code/OpenGEXImporter.h
  75. 265 0
      Source/ThirdParty/Assimp/code/OpenGEXStructs.h
  76. 18 5
      Source/ThirdParty/Assimp/code/PlyExporter.cpp
  77. 13 4
      Source/ThirdParty/Assimp/code/PlyLoader.cpp
  78. 7 0
      Source/ThirdParty/Assimp/code/Q3DLoader.h
  79. 7 0
      Source/ThirdParty/Assimp/code/SGSpatialSort.h
  80. 183 135
      Source/ThirdParty/Assimp/code/STLLoader.cpp
  81. 7 1
      Source/ThirdParty/Assimp/code/SceneCombiner.h
  82. 7 0
      Source/ThirdParty/Assimp/code/SmoothingGroups.h
  83. 7 0
      Source/ThirdParty/Assimp/code/StringComparison.h
  84. 5 1
      Source/ThirdParty/Assimp/code/Subdivision.cpp
  85. 7 0
      Source/ThirdParty/Assimp/code/UnrealLoader.h
  86. 6 0
      Source/ThirdParty/Assimp/code/XFileHelper.h
  87. 9 7
      Source/ThirdParty/Assimp/code/fast_atof.h
  88. 0 105
      Source/ThirdParty/Assimp/code/makefile.mingw
  89. 7 0
      Source/ThirdParty/Assimp/code/qnan.h
  90. 14 14
      Source/ThirdParty/Assimp/code/res/resource.h
  91. 1 1
      Source/ThirdParty/Assimp/code/revision.h
  92. 29 29
      Source/ThirdParty/Assimp/contrib/clipper/License.txt
  93. 3448 3448
      Source/ThirdParty/Assimp/contrib/clipper/clipper.cpp
  94. 306 306
      Source/ThirdParty/Assimp/contrib/clipper/clipper.hpp
  95. 8 0
      Source/ThirdParty/Assimp/contrib/cppunit_note.txt
  96. 809 809
      Source/ThirdParty/Assimp/contrib/irrXML/CXMLReaderImpl.h
  97. 73 73
      Source/ThirdParty/Assimp/contrib/irrXML/heapsort.h
  98. 444 444
      Source/ThirdParty/Assimp/contrib/irrXML/irrArray.h
  99. 664 664
      Source/ThirdParty/Assimp/contrib/irrXML/irrString.h
  100. 108 108
      Source/ThirdParty/Assimp/contrib/irrXML/irrTypes.h

+ 23 - 0
Source/ThirdParty/Assimp/CHANGES

@@ -2,6 +2,29 @@
 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)
 

+ 0 - 8
Source/ThirdParty/Assimp/CMake/FindZLIB.cmake

@@ -1,8 +0,0 @@
-# Spicific to Atomic Game Engine
-# Assimp includes zlib
-
-set(ZLIB_FOUND 1 CACHE INTERNAL "ZLib Found")
-set(ZLIB_INCLUDE_DIR "${zlib_SOURCE_DIR}" CACHE INTERNAL "ZLib include")
-set(ZLIB_LIBRARIES zlib CACHE INTERNAL "ZLib target")
-
-mark_as_advanced(ZLIB_FOUND ZLIB_INCLUDE_DIR ZLIB_LIBRARIES)

+ 750 - 145
Source/ThirdParty/Assimp/CMakeLists.txt

@@ -1,145 +1,750 @@
-#
-# Listing and grouping of all the source files.
-# 1) Set the file lists for each component
-# 2) Create a Source Group for each component, for IDE project orginization
-# 3) Add libassimp using the file lists (eliminates duplication of file names between
-#    source groups and library command)
-#
-
-# Modified by Lasse Oorni and Yao Wei Tjong for Urho3D
-
-project(Assimp)
-set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
-
-if (MINGW)
-    # The IFCReaderGen.cpp.obj has too many sections in DEBUG configuration build
-    # Since GCC does not support /bigobj compiler flags as in MSVC, we use optimization flags to reduce the object file size
-    set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O1")
-    set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1")
-endif ()
-
-INCLUDE_DIRECTORIES( code )
-INCLUDE_DIRECTORIES( include )
-INCLUDE_DIRECTORIES( code/BoostWorkaround )
-INCLUDE_DIRECTORIES( contrib/unzip )
-ADD_DEFINITIONS( -DASSIMP_BUILD_BOOST_WORKAROUND -DASSIMP_BUILD_NO_C4D_IMPORTER -DASSIMP_BUILD_NO_OPENGEX_IMPORTER -DASSIMP_BUILD_NO_ASSBIN_IMPORTER)
-
-file (GLOB_RECURSE CODE_FILES code/*.cpp code/*.h)
-
-SET( IrrXML_SRCS
-	code/irrXMLWrapper.h
-	contrib/irrXML/CXMLReaderImpl.h
-	contrib/irrXML/heapsort.h
-	contrib/irrXML/irrArray.h
-	contrib/irrXML/irrString.h
-	contrib/irrXML/irrTypes.h
-	contrib/irrXML/irrXML.cpp
-	contrib/irrXML/irrXML.h
-)
-SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS})
-
-SET( ConvertUTF_SRCS
-	contrib/ConvertUTF/ConvertUTF.h
-	contrib/ConvertUTF/ConvertUTF.c
-)
-SOURCE_GROUP( ConvertUTF FILES ${ConvertUTF_SRCS})
-
-SET( Clipper_SRCS
-	contrib/clipper/clipper.hpp
-	contrib/clipper/clipper.cpp
-)
-SOURCE_GROUP( Clipper FILES ${Clipper_SRCS})
-
-SET( Poly2Tri_SRCS
-	contrib/poly2tri/poly2tri/common/shapes.cc
-	contrib/poly2tri/poly2tri/common/shapes.h
-	contrib/poly2tri/poly2tri/common/utils.h
-	contrib/poly2tri/poly2tri/sweep/advancing_front.h
-	contrib/poly2tri/poly2tri/sweep/advancing_front.cc
-	contrib/poly2tri/poly2tri/sweep/cdt.cc
-	contrib/poly2tri/poly2tri/sweep/cdt.h
-	contrib/poly2tri/poly2tri/sweep/sweep.cc
-	contrib/poly2tri/poly2tri/sweep/sweep.h
-	contrib/poly2tri/poly2tri/sweep/sweep_context.cc
-	contrib/poly2tri/poly2tri/sweep/sweep_context.h
-)
-SOURCE_GROUP( Poly2Tri FILES ${Poly2Tri_SRCS})
-
-SET( unzip_SRCS
-	contrib/unzip/crypt.h
-	contrib/unzip/ioapi.c
-	contrib/unzip/ioapi.h
-	contrib/unzip/unzip.c
-	contrib/unzip/unzip.h
-)
-SOURCE_GROUP( unzip FILES ${unzip_SRCS})
-
-SET( zlib_SRCS
-	contrib/zlib/adler32.c
-	contrib/zlib/compress.c
-	contrib/zlib/crc32.c
-	contrib/zlib/crc32.h
-	contrib/zlib/deflate.c
-	contrib/zlib/deflate.h
-#	contrib/zlib/gzclose.c
-#	contrib/zlib/gzguts.h
-#	contrib/zlib/gzlib.c
-#	contrib/zlib/gzread.c
-#	contrib/zlib/gzwrite.c
-	contrib/zlib/infback.c
-	contrib/zlib/inffast.c
-	contrib/zlib/inffast.h
-	contrib/zlib/inffixed.h
-	contrib/zlib/inflate.c
-	contrib/zlib/inflate.h
-	contrib/zlib/inftrees.c
-	contrib/zlib/inftrees.h
-	contrib/zlib/trees.c
-	contrib/zlib/trees.h
-	contrib/zlib/zconf.h
-	contrib/zlib/zlib.h
-	contrib/zlib/zutil.c
-	contrib/zlib/zutil.h
-)
-SOURCE_GROUP( zlib FILES ${zlib_SRCS})
-
-if ( MSVC80 OR MSVC90 OR MSVC10 )
-	ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
-	ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
-endif ( MSVC80 OR MSVC90 OR MSVC10 )
-
-SET( SOURCE_FILES
-	# Assimp Files
-        ${CODE_FILES}
-
-)
-
-SET( CONTRIB_FILES
-	# Third-party libraries
-	${IrrXML_SRCS}
-	${ConvertUTF_SRCS}
-	${unzip_SRCS}
-#	${zlib_SRCS}
-	${Poly2Tri_SRCS}
-	${Clipper_SRCS}
-	# Necessary to show the headers in the project when using the VC++ generator:
-	${Boost_SRCS}
-)
-
-find_package(ZLIB)
-if (ZLIB_FOUND)
-    include_directories(${ZLIB_INCLUDE_DIRS})
-else ()
-    message(STATUS "Using contrib version of zlib.")
-    list(APPEND CONTRIB_FILES ${zlib_SRCS})
-endif ()
-
-
-set (TARGET_NAME Assimp)
-list (APPEND SOURCE_FILES ${CONTRIB_FILES} ${PUBLIC_HEADERS} ${COMPILER_HEADERS})
-
-#set_source_files_properties (contrib/clipper/clipper.cpp contrib/irrXML/irrXML.cpp PROPERTIES NO_PCH TRUE)
-#enable_pch (code/AssimpPCH.h)
-
-add_library(Assimp ${SOURCE_FILES})
-target_link_libraries(Assimp zlib)
+#
+# Listing and grouping of all the source files.
+# 1) Set the file lists for each component
+# 2) Create a Source Group for each component, for IDE project orginization
+# 3) Add libassimp using the file lists (eliminates duplication of file names between
+#    source groups and library command)
+#
+
+# Modified by Lasse Oorni and Yao Wei Tjong for Urho3D
+
+if (MINGW)
+    # The IFCReaderGen.cpp.obj has too many sections in DEBUG configuration build
+    # Since GCC does not support /bigobj compiler flags as in MSVC, we use optimization flags to reduce the object file size
+    set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O1")
+    set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1")
+endif ()
+
+INCLUDE_DIRECTORIES( code )
+INCLUDE_DIRECTORIES( include )
+INCLUDE_DIRECTORIES( code/BoostWorkaround )
+INCLUDE_DIRECTORIES( contrib/unzip )
+ADD_DEFINITIONS( -DASSIMP_BUILD_BOOST_WORKAROUND )
+
+SET( HEADER_PATH include/assimp )
+
+SET( COMPILER_HEADERS
+  ${HEADER_PATH}/Compiler/pushpack1.h
+  ${HEADER_PATH}/Compiler/poppack1.h
+  ${HEADER_PATH}/Compiler/pstdint.h
+)
+SOURCE_GROUP( Compiler FILES ${COMPILER_HEADERS})
+
+SET( PUBLIC_HEADERS
+  ${HEADER_PATH}/anim.h
+  ${HEADER_PATH}/ai_assert.h
+  ${HEADER_PATH}/camera.h
+  ${HEADER_PATH}/color4.h
+  ${HEADER_PATH}/color4.inl
+  ${HEADER_PATH}/config.h
+  ${HEADER_PATH}/defs.h
+  ${HEADER_PATH}/cfileio.h
+  ${HEADER_PATH}/light.h
+  ${HEADER_PATH}/material.h
+  ${HEADER_PATH}/material.inl
+  ${HEADER_PATH}/matrix3x3.h
+  ${HEADER_PATH}/matrix3x3.inl
+  ${HEADER_PATH}/matrix4x4.h
+  ${HEADER_PATH}/matrix4x4.inl
+  ${HEADER_PATH}/mesh.h
+  ${HEADER_PATH}/postprocess.h
+  ${HEADER_PATH}/quaternion.h
+  ${HEADER_PATH}/quaternion.inl
+  ${HEADER_PATH}/scene.h
+  ${HEADER_PATH}/metadata.h
+  ${HEADER_PATH}/texture.h
+  ${HEADER_PATH}/types.h
+  ${HEADER_PATH}/vector2.h
+  ${HEADER_PATH}/vector2.inl
+  ${HEADER_PATH}/vector3.h
+  ${HEADER_PATH}/vector3.inl
+  ${HEADER_PATH}/version.h
+  ${HEADER_PATH}/cimport.h
+  ${HEADER_PATH}/importerdesc.h
+  ${HEADER_PATH}/Importer.hpp
+  ${HEADER_PATH}/DefaultLogger.hpp
+  ${HEADER_PATH}/ProgressHandler.hpp
+  ${HEADER_PATH}/IOStream.hpp
+  ${HEADER_PATH}/IOSystem.hpp
+  ${HEADER_PATH}/Logger.hpp
+  ${HEADER_PATH}/LogStream.hpp
+  ${HEADER_PATH}/NullLogger.hpp
+  ${HEADER_PATH}/cexport.h
+  ${HEADER_PATH}/Exporter.hpp
+)
+
+SET( Core_SRCS
+  code/Assimp.cpp
+)
+
+SET( Boost_SRCS
+  code/BoostWorkaround/boost/math/common_factor_rt.hpp
+  code/BoostWorkaround/boost/foreach.hpp
+  code/BoostWorkaround/boost/format.hpp
+  code/BoostWorkaround/boost/scoped_array.hpp
+  code/BoostWorkaround/boost/scoped_ptr.hpp
+  code/BoostWorkaround/boost/shared_array.hpp
+  code/BoostWorkaround/boost/shared_ptr.hpp
+  code/BoostWorkaround/boost/make_shared.hpp
+  code/BoostWorkaround/boost/static_assert.hpp
+  code/BoostWorkaround/boost/tuple/tuple.hpp
+)
+SOURCE_GROUP(Boost FILES ${Boost_SRCS})
+
+SET( Logging_SRCS
+  ${HEADER_PATH}/DefaultLogger.hpp
+  ${HEADER_PATH}/LogStream.hpp
+  ${HEADER_PATH}/Logger.hpp
+  ${HEADER_PATH}/NullLogger.hpp
+  code/Win32DebugLogStream.h
+  code/DefaultLogger.cpp
+  code/FileLogStream.h
+  code/StdOStreamLogStream.h
+)
+SOURCE_GROUP(Logging FILES ${Logging_SRCS})
+
+SET( Common_SRCS
+  code/fast_atof.h
+  code/qnan.h
+  code/BaseImporter.cpp
+  code/BaseImporter.h
+  code/BaseProcess.cpp
+  code/BaseProcess.h
+  code/Importer.h
+  code/ScenePrivate.h
+  code/PostStepRegistry.cpp
+  code/ImporterRegistry.cpp
+  code/ByteSwapper.h
+  code/DefaultProgressHandler.h
+  code/DefaultIOStream.cpp
+  code/DefaultIOStream.h
+  code/DefaultIOSystem.cpp
+  code/DefaultIOSystem.h
+  code/CInterfaceIOWrapper.h
+  code/Hash.h
+  code/Importer.cpp
+  code/IFF.h
+  code/MemoryIOWrapper.h
+  code/ParsingUtils.h
+  code/StreamReader.h
+  code/StreamWriter.h
+  code/StringComparison.h
+  code/SGSpatialSort.cpp
+  code/SGSpatialSort.h
+  code/VertexTriangleAdjacency.cpp
+  code/VertexTriangleAdjacency.h
+  code/GenericProperty.h
+  code/SpatialSort.cpp
+  code/SpatialSort.h
+  code/SceneCombiner.cpp
+  code/SceneCombiner.h
+  code/ScenePreprocessor.cpp
+  code/ScenePreprocessor.h
+  code/SkeletonMeshBuilder.cpp
+  code/SkeletonMeshBuilder.h
+  code/SplitByBoneCountProcess.cpp
+  code/SplitByBoneCountProcess.h
+  code/SmoothingGroups.h
+  code/StandardShapes.cpp
+  code/StandardShapes.h
+  code/TargetAnimation.cpp
+  code/TargetAnimation.h
+  code/RemoveComments.cpp
+  code/RemoveComments.h
+  code/Subdivision.cpp
+  code/Subdivision.h
+  code/Vertex.h
+  code/LineSplitter.h
+  code/TinyFormatter.h
+  code/Profiler.h
+  code/LogAux.h
+  code/Bitmap.cpp
+  code/Bitmap.h
+  code/XMLTools.h
+  code/Version.cpp
+)
+SOURCE_GROUP(Common FILES ${Common_SRCS})
+
+IF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
+  SET( C4D_SRCS
+    code/C4DImporter.cpp
+    code/C4DImporter.h
+  )
+  SOURCE_GROUP( C4D FILES ${C4D_SRCS})
+ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
+
+# macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
+# this way selective loaders can be compiled (reduces filesize + compile time)
+MACRO(ADD_ASSIMP_IMPORTER name)
+  OPTION(ASSIMP_BUILD_${name}_IMPORTER "build the ${name} importer" TRUE)
+  IF(ASSIMP_BUILD_${name}_IMPORTER)
+    LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN})
+    SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}")
+    SET(${name}_SRCS ${ARGN})
+    SOURCE_GROUP(${name} FILES ${ARGN})
+  ELSE()
+    SET(${name}_SRC "")
+    SET(ASSIMP_IMPORTERS_DISABLED "${ASSIMP_IMPORTERS_DISABLED} ${name}")
+    add_definitions(-DASSIMP_BUILD_NO_${name}_IMPORTER)
+  ENDIF()
+ENDMACRO()
+
+SET(ASSIMP_LOADER_SRCS "")
+SET(ASSIMP_IMPORTERS_ENABLED "") # list of enabled importers
+SET(ASSIMP_IMPORTERS_DISABLED "") # disabled list (used to print)
+
+ADD_ASSIMP_IMPORTER(3DS
+  code/3DSConverter.cpp
+  code/3DSHelper.h
+  code/3DSLoader.cpp
+  code/3DSLoader.h
+  code/3DSExporter.h
+  code/3DSExporter.cpp
+)
+
+ADD_ASSIMP_IMPORTER(AC
+  code/ACLoader.cpp
+  code/ACLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(ASE
+  code/ASELoader.cpp
+  code/ASELoader.h
+  code/ASEParser.cpp
+  code/ASEParser.h
+)
+
+ADD_ASSIMP_IMPORTER(ASSBIN
+  code/AssbinExporter.h
+  code/AssbinExporter.cpp
+  code/AssbinLoader.h
+  code/AssbinLoader.cpp
+)
+
+ADD_ASSIMP_IMPORTER(ASSXML
+  code/AssxmlExporter.h
+  code/AssxmlExporter.cpp
+)
+
+ADD_ASSIMP_IMPORTER(B3D
+  code/B3DImporter.cpp
+  code/B3DImporter.h
+)
+
+ADD_ASSIMP_IMPORTER(BVH
+  code/BVHLoader.cpp
+  code/BVHLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(COLLADA
+  code/ColladaHelper.h
+  code/ColladaLoader.cpp
+  code/ColladaLoader.h
+  code/ColladaParser.cpp
+  code/ColladaParser.h
+  code/ColladaExporter.h
+  code/ColladaExporter.cpp
+)
+
+ADD_ASSIMP_IMPORTER(DXF
+  code/DXFLoader.cpp
+  code/DXFLoader.h
+  code/DXFHelper.h
+)
+
+ADD_ASSIMP_IMPORTER(CSM
+  code/CSMLoader.cpp
+  code/CSMLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(HMP
+  code/HMPFileData.h
+  code/HMPLoader.cpp
+  code/HMPLoader.h
+  code/HalfLifeFileData.h
+)
+
+#FIXME: allow to set IRRMESH by option
+ADD_ASSIMP_IMPORTER(IRR
+  code/IRRLoader.cpp
+  code/IRRLoader.h
+  code/IRRMeshLoader.cpp
+  code/IRRMeshLoader.h
+  code/IRRShared.cpp
+  code/IRRShared.h
+)
+
+ADD_ASSIMP_IMPORTER(LWO
+  code/LWOAnimation.cpp
+  code/LWOAnimation.h
+  code/LWOBLoader.cpp
+  code/LWOFileData.h
+  code/LWOLoader.cpp
+  code/LWOLoader.h
+  code/LWOMaterial.cpp
+)
+
+ADD_ASSIMP_IMPORTER(LWS
+  code/LWSLoader.cpp
+  code/LWSLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(MD2
+  code/MD2FileData.h
+  code/MD2Loader.cpp
+  code/MD2Loader.h
+  code/MD2NormalTable.h
+)
+
+ADD_ASSIMP_IMPORTER(MD3
+  code/MD3FileData.h
+  code/MD3Loader.cpp
+  code/MD3Loader.h
+)
+
+ADD_ASSIMP_IMPORTER(MD5
+  code/MD5Loader.cpp
+  code/MD5Loader.h
+  code/MD5Parser.cpp
+  code/MD5Parser.h
+)
+
+ADD_ASSIMP_IMPORTER(MDC
+  code/MDCFileData.h
+  code/MDCLoader.cpp
+  code/MDCLoader.h
+  code/MDCNormalTable.h
+)
+
+ADD_ASSIMP_IMPORTER(MDL
+  code/MDLDefaultColorMap.h
+  code/MDLFileData.h
+  code/MDLLoader.cpp
+  code/MDLLoader.h
+  code/MDLMaterialLoader.cpp
+)
+
+SET( MaterialSystem_SRCS
+  code/MaterialSystem.cpp
+  code/MaterialSystem.h
+)
+SOURCE_GROUP( MaterialSystem FILES ${MaterialSystem_SRCS})
+
+ADD_ASSIMP_IMPORTER(NFF
+  code/NFFLoader.cpp
+  code/NFFLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(NDO
+  code/NDOLoader.cpp
+  code/NDOLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(OFF
+  code/OFFLoader.cpp
+  code/OFFLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(OBJ
+  code/ObjFileData.h
+  code/ObjFileImporter.cpp
+  code/ObjFileImporter.h
+  code/ObjFileMtlImporter.cpp
+  code/ObjFileMtlImporter.h
+  code/ObjFileParser.cpp
+  code/ObjFileParser.h
+  code/ObjTools.h
+  code/ObjExporter.h
+  code/ObjExporter.cpp
+)
+
+ADD_ASSIMP_IMPORTER(OGRE
+  code/OgreImporter.h
+  code/OgreStructs.h
+  code/OgreParsingUtils.h
+  code/OgreBinarySerializer.h
+  code/OgreXmlSerializer.h
+  code/OgreImporter.cpp
+  code/OgreStructs.cpp
+  code/OgreBinarySerializer.cpp
+  code/OgreXmlSerializer.cpp
+  code/OgreMaterial.cpp
+)
+
+ADD_ASSIMP_IMPORTER(OPENGEX
+  code/OpenGEXExporter.cpp
+  code/OpenGEXExporter.h
+  code/OpenGEXImporter.cpp
+  code/OpenGEXImporter.h
+  code/OpenGEXStructs.h
+)
+
+ADD_ASSIMP_IMPORTER(PLY
+  code/PlyLoader.cpp
+  code/PlyLoader.h
+  code/PlyParser.cpp
+  code/PlyParser.h
+  code/PlyExporter.cpp
+  code/PlyExporter.h
+)
+
+ADD_ASSIMP_IMPORTER(MS3D
+  code/MS3DLoader.cpp
+  code/MS3DLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(COB
+  code/COBLoader.cpp
+  code/COBLoader.h
+  code/COBScene.h
+)
+
+ADD_ASSIMP_IMPORTER(BLEND
+  code/BlenderLoader.cpp
+  code/BlenderLoader.h
+  code/BlenderDNA.cpp
+  code/BlenderDNA.h
+  code/BlenderDNA.inl
+  code/BlenderScene.cpp
+  code/BlenderScene.h
+  code/BlenderSceneGen.h
+  code/BlenderIntermediate.h
+  code/BlenderModifier.h
+  code/BlenderModifier.cpp
+  code/BlenderBMesh.h
+  code/BlenderBMesh.cpp
+  code/BlenderTessellator.h
+  code/BlenderTessellator.cpp
+)
+
+ADD_ASSIMP_IMPORTER(IFC
+  code/IFCLoader.cpp
+  code/IFCLoader.h
+  code/IFCReaderGen.cpp
+  code/IFCReaderGen.h
+  code/IFCUtil.h
+  code/IFCUtil.cpp
+  code/IFCGeometry.cpp
+  code/IFCMaterial.cpp
+  code/IFCProfile.cpp
+  code/IFCCurve.cpp
+  code/IFCBoolean.cpp
+  code/IFCOpenings.cpp
+  code/STEPFile.h
+  code/STEPFileReader.h
+  code/STEPFileReader.cpp
+  code/STEPFileEncoding.cpp
+  code/STEPFileEncoding.h
+)
+
+ADD_ASSIMP_IMPORTER(XGL
+  code/XGLLoader.cpp
+  code/XGLLoader.h
+)
+
+
+ADD_ASSIMP_IMPORTER(FBX
+  code/FBXImporter.cpp
+  code/FBXCompileConfig.h
+  code/FBXImporter.h
+  code/FBXParser.cpp
+  code/FBXParser.h
+  code/FBXTokenizer.cpp
+  code/FBXTokenizer.h
+  code/FBXImportSettings.h
+  code/FBXConverter.h
+  code/FBXConverter.cpp
+  code/FBXUtil.h
+  code/FBXUtil.cpp
+  code/FBXDocument.h
+  code/FBXDocument.cpp
+  code/FBXProperties.h
+  code/FBXProperties.cpp
+  code/FBXMeshGeometry.cpp
+  code/FBXMaterial.cpp
+  code/FBXModel.cpp
+  code/FBXAnimation.cpp
+  code/FBXNodeAttribute.cpp
+  code/FBXDeformer.cpp
+  code/FBXBinaryTokenizer.cpp
+  code/FBXDocumentUtil.cpp
+)
+
+SET( PostProcessing_SRCS
+  code/CalcTangentsProcess.cpp
+  code/CalcTangentsProcess.h
+  code/ComputeUVMappingProcess.cpp
+  code/ComputeUVMappingProcess.h
+  code/ConvertToLHProcess.cpp
+  code/ConvertToLHProcess.h
+  code/FindDegenerates.cpp
+  code/FindDegenerates.h
+  code/FindInstancesProcess.cpp
+  code/FindInstancesProcess.h
+  code/FindInvalidDataProcess.cpp
+  code/FindInvalidDataProcess.h
+  code/FixNormalsStep.cpp
+  code/FixNormalsStep.h
+  code/GenFaceNormalsProcess.cpp
+  code/GenFaceNormalsProcess.h
+  code/GenVertexNormalsProcess.cpp
+  code/GenVertexNormalsProcess.h
+  code/PretransformVertices.cpp
+  code/PretransformVertices.h
+  code/ImproveCacheLocality.cpp
+  code/ImproveCacheLocality.h
+  code/JoinVerticesProcess.cpp
+  code/JoinVerticesProcess.h
+  code/LimitBoneWeightsProcess.cpp
+  code/LimitBoneWeightsProcess.h
+  code/RemoveRedundantMaterials.cpp
+  code/RemoveRedundantMaterials.h
+  code/RemoveVCProcess.cpp
+  code/RemoveVCProcess.h
+  code/SortByPTypeProcess.cpp
+  code/SortByPTypeProcess.h
+  code/SplitLargeMeshes.cpp
+  code/SplitLargeMeshes.h
+  code/TextureTransform.cpp
+  code/TextureTransform.h
+  code/TriangulateProcess.cpp
+  code/TriangulateProcess.h
+  code/ValidateDataStructure.cpp
+  code/ValidateDataStructure.h
+  code/OptimizeGraph.cpp
+  code/OptimizeGraph.h
+  code/OptimizeMeshes.cpp
+  code/OptimizeMeshes.h
+  code/DeboneProcess.cpp
+  code/DeboneProcess.h
+  code/ProcessHelper.h
+  code/ProcessHelper.cpp
+  code/PolyTools.h
+  code/MakeVerboseFormat.cpp
+  code/MakeVerboseFormat.h
+)
+SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
+
+ADD_ASSIMP_IMPORTER(Q3D
+  code/Q3DLoader.cpp
+  code/Q3DLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(Q3BSP
+  code/Q3BSPFileData.h
+  code/Q3BSPFileParser.h
+  code/Q3BSPFileParser.cpp
+  code/Q3BSPFileImporter.h
+  code/Q3BSPFileImporter.cpp
+  code/Q3BSPZipArchive.h
+  code/Q3BSPZipArchive.cpp
+)
+
+ADD_ASSIMP_IMPORTER(RAW
+  code/RawLoader.cpp
+  code/RawLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(SMD
+  code/SMDLoader.cpp
+  code/SMDLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(STL
+  code/STLLoader.cpp
+  code/STLLoader.h
+  code/STLExporter.h
+  code/STLExporter.cpp
+)
+
+ADD_ASSIMP_IMPORTER(TERRAGEN
+  code/TerragenLoader.cpp
+  code/TerragenLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(3D
+  code/UnrealLoader.cpp
+  code/UnrealLoader.h
+)
+
+ADD_ASSIMP_IMPORTER(X
+  code/XFileHelper.h
+  code/XFileImporter.cpp
+  code/XFileImporter.h
+  code/XFileParser.cpp
+  code/XFileParser.h
+  code/XFileExporter.h
+  code/XFileExporter.cpp
+)
+
+SET( Step_SRCS
+  code/StepExporter.h
+  code/StepExporter.cpp
+)
+SOURCE_GROUP( Step FILES ${Step_SRCS})
+
+SET( Exporter_SRCS
+  code/Exporter.cpp
+  code/AssimpCExport.cpp
+  code/BlobIOSystem.h
+)
+SOURCE_GROUP( Exporter FILES ${Exporter_SRCS})
+
+SET( Extra_SRCS
+  code/MD4FileData.h
+)
+SOURCE_GROUP( Extra FILES ${Extra_SRCS})
+
+SET( IrrXML_SRCS
+  code/irrXMLWrapper.h
+  contrib/irrXML/CXMLReaderImpl.h
+  contrib/irrXML/heapsort.h
+  contrib/irrXML/irrArray.h
+  contrib/irrXML/irrString.h
+  contrib/irrXML/irrTypes.h
+  contrib/irrXML/irrXML.cpp
+  contrib/irrXML/irrXML.h
+)
+SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS})
+
+SET( ConvertUTF_SRCS
+  contrib/ConvertUTF/ConvertUTF.h
+  contrib/ConvertUTF/ConvertUTF.c
+)
+SOURCE_GROUP( ConvertUTF FILES ${ConvertUTF_SRCS})
+
+SET( Clipper_SRCS
+  contrib/clipper/clipper.hpp
+  contrib/clipper/clipper.cpp
+)
+SOURCE_GROUP( Clipper FILES ${Clipper_SRCS})
+
+
+SET( Poly2Tri_SRCS
+  contrib/poly2tri/poly2tri/common/shapes.cc
+  contrib/poly2tri/poly2tri/common/shapes.h
+  contrib/poly2tri/poly2tri/common/utils.h
+  contrib/poly2tri/poly2tri/sweep/advancing_front.h
+  contrib/poly2tri/poly2tri/sweep/advancing_front.cc
+  contrib/poly2tri/poly2tri/sweep/cdt.cc
+  contrib/poly2tri/poly2tri/sweep/cdt.h
+  contrib/poly2tri/poly2tri/sweep/sweep.cc
+  contrib/poly2tri/poly2tri/sweep/sweep.h
+  contrib/poly2tri/poly2tri/sweep/sweep_context.cc
+  contrib/poly2tri/poly2tri/sweep/sweep_context.h
+)
+SOURCE_GROUP( Poly2Tri FILES ${Poly2Tri_SRCS})
+
+SET( unzip_SRCS
+  contrib/unzip/crypt.h
+  contrib/unzip/ioapi.c
+  contrib/unzip/ioapi.h
+  contrib/unzip/unzip.c
+  contrib/unzip/unzip.h
+)
+SOURCE_GROUP( unzip FILES ${unzip_SRCS})
+
+SET( zlib_SRCS
+  contrib/zlib/adler32.c
+  contrib/zlib/compress.c
+  contrib/zlib/crc32.c
+  contrib/zlib/crc32.h
+  contrib/zlib/deflate.c
+  contrib/zlib/deflate.h
+#  contrib/zlib/gzclose.c
+#  contrib/zlib/gzguts.h
+#  contrib/zlib/gzlib.c
+#  contrib/zlib/gzread.c
+#  contrib/zlib/gzwrite.c
+  contrib/zlib/infback.c
+  contrib/zlib/inffast.c
+  contrib/zlib/inffast.h
+  contrib/zlib/inffixed.h
+  contrib/zlib/inflate.c
+  contrib/zlib/inflate.h
+  contrib/zlib/inftrees.c
+  contrib/zlib/inftrees.h
+  contrib/zlib/trees.c
+  contrib/zlib/trees.h
+  contrib/zlib/uncompr.c
+  contrib/zlib/zconf.h
+  contrib/zlib/zlib.h
+  contrib/zlib/zutil.c
+  contrib/zlib/zutil.h
+)
+SOURCE_GROUP( zlib FILES ${zlib_SRCS})
+
+SET ( openddl_parser_SRCS
+  contrib/openddlparser/code/OpenDDLParser.cpp
+  contrib/openddlparser/code/DDLNode.cpp
+  contrib/openddlparser/code/Value.cpp
+  contrib/openddlparser/include/openddlparser/OpenDDLParser.h
+  contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
+  contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
+  contrib/openddlparser/include/openddlparser/DDLNode.h
+  contrib/openddlparser/include/openddlparser/Value.h
+)
+SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
+
+# VC2010 fixes
+if(MSVC10)
+  option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
+  if( VC10_STDINT_FIX )
+    ADD_DEFINITIONS( -D_STDINT )
+  endif( VC10_STDINT_FIX )
+endif(MSVC10)
+
+if ( MSVC )
+  ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
+  ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
+endif ( MSVC )
+
+# Urho3D: disable status prints
+# MESSAGE(STATUS "Enabled formats:${ASSIMP_IMPORTERS_ENABLED}")
+# MESSAGE(STATUS "Disabled formats:${ASSIMP_IMPORTERS_DISABLED}")
+
+SET( SOURCE_FILES
+  # Assimp Files
+  ${Core_SRCS}
+  ${Common_SRCS}
+  ${Logging_SRCS}
+  ${Exporter_SRCS}
+  ${PostProcessing_SRCS}
+  ${MaterialSystem_SRCS}
+  ${Step_SRCS}
+
+  # Model Support
+  ${ASSIMP_LOADER_SRCS}
+
+  # Third-party libraries
+  ${IrrXML_SRCS}
+  ${ConvertUTF_SRCS}
+  ${unzip_SRCS}
+  ${zlib_SRCS}
+  ${Poly2Tri_SRCS}
+  ${Clipper_SRCS}
+  ${openddl_parser_SRCS}
+  # Necessary to show the headers in the project when using the VC++ generator:
+  ${Boost_SRCS}
+
+  ${PUBLIC_HEADERS}
+  ${COMPILER_HEADERS}
+
+)
+add_definitions( -DOPENDDLPARSER_BUILD )
+
+INCLUDE_DIRECTORIES(
+  contrib/openddlparser/include
+)
+
+# Urho3D: set the corresponding "no importer" define
+IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
+  SET( SOURCE_FILES ${SOURCE_FILES} ${C4D_SRCS})
+  INCLUDE_DIRECTORIES(${C4D_INCLUDES})
+ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
+  add_definitions(-DASSIMP_BUILD_NO_C4D_IMPORTER)
+ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
+
+set (TARGET_NAME Assimp)
+list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH YES)   # Since we only build AssetImporter as a single-arch native tool, there is no point to build Assimp as universal binary library
+setup_library ()

+ 10 - 0
Source/ThirdParty/Assimp/CREDITS

@@ -148,3 +148,13 @@ Bugfixes for uv-tanget calculation.
 
 - Jonne Nauha
 Ogre Binary format support
+
+- Filip Wasil, Tieto Poland Sp. z o.o.
+Android JNI asset extraction support
+
+- Richard Steffen
+Contributed ExportProperties interface
+Contributed X File exporter
+Contributed Step (stp) exporter
+
+

+ 12 - 0
Source/ThirdParty/Assimp/CodeConventions.md

@@ -0,0 +1,12 @@
+
+Open Asset Import Library Coding Conventions
+==
+
+If you want to participate as a developer in the **Open Asset Import Library** please read and respect the following coding conventions. This will ensure consistency throughout the codebase and help all the Open Asset Import Library users.
+
+Spacing
+==
+
+* Use UNIX-style line endings (LF)
+* Remove any trailing whitespace
+* Expand tabs to 4 spaces

+ 1 - 1
Source/ThirdParty/Assimp/INSTALL

@@ -1,6 +1,6 @@
 Open Asset Import Library (assimp)
 
-Copyright (c) 2006-2012, assimp team
+Copyright (c) 2006-2015, assimp team
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms, 

+ 1 - 1
Source/ThirdParty/Assimp/README

@@ -1 +1 @@
-See Readme.md
+See Readme.md

+ 129 - 0
Source/ThirdParty/Assimp/Readme.md

@@ -0,0 +1,129 @@
+Open Asset Import Library (assimp) 
+========
+
+Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
+
+APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
+
+Additionally, assimp features various __mesh post processing tools__: 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 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.
+The current build status is:
+
+Linux [![Linux Build Status](https://travis-ci.org/assimp/assimp.png)](https://travis-ci.org/assimp/assimp)
+Windows [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
+Coverity<a href="https://scan.coverity.com/projects/5607">
+  <img alt="Coverity Scan Build Status"
+       src="https://scan.coverity.com/projects/5607/badge.svg"/>
+</a>
+
+__[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__
+
+#### Supported file formats ####
+
+A full list [is here](http://assimp.sourceforge.net/main_features_formats.html).
+__Importers__:
+
+- 3DS
+- BLEND (Blender)
+- DAE/Collada
+- FBX
+- IFC-STEP 
+- ASE
+- DXF
+- HMP
+- MD2
+- MD3 
+- MD5
+- MDC
+- MDL
+- NFF
+- PLY
+- STL
+- X 
+- OBJ
+- OpenGEX
+- SMD
+- LWO 
+- LXO 
+- LWS  
+- TER 
+- AC3D 
+- MS3D 
+- COB
+- Q3BSP
+- XGL
+- CSM
+- BVH
+- B3D
+- NDO
+- Ogre Binary
+- Ogre XML
+- Q3D
+- ASSBIN (Assimp custom format)
+ 
+Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
+
+- C4D (https://github.com/acgessler/assimp-cinema4d)
+
+__Exporters__:
+
+- DAE (Collada)
+- STL
+- OBJ
+- PLY
+- X
+- 3DS
+- JSON (for WebGl, via https://github.com/acgessler/assimp2json)
+- ASSBIN
+	
+### Building ###
+
+
+Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
+
+
+#### Repository structure ####
+
+
+Open Asset Import Library is implemented in C++. The directory structure is:
+
+	/code		Source code
+	/contrib	Third-party libraries
+	/doc		Documentation (doxysource and pre-compiled docs)
+	/include	Public header C and C++ header files
+	/scripts 	Scripts used to generate the loading code for some formats
+	/port		Ports to other languages and scripts to maintain those.
+	/test		Unit- and regression tests, test suite of models
+	/tools		Tools (old assimp viewer, command line `assimp`)
+	/samples	A small number of samples to illustrate possible 
+                        use cases for Assimp
+	/workspaces	Build enviroments for vc,xcode,... (deprecated,
+			CMake has superseeded all legacy build options!)
+
+
+### Where to get help ###
+
+
+For more information, visit [our website](http://assimp.sourceforge.net/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
+(CHMs for Windows are included in some release packages and should be located right here in the root folder).
+
+If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
+
+For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
+  [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) 
+
+And we also have an IRC-channel at freenode: #assetimporterlib .
+### Contributing ###
+
+Contributions to assimp are highly appreciated. The easiest way to get involved is to submit 
+a pull request with your changes against the main repository's `master` branch.
+
+### License ###
+
+Our license is based on the modified, __3-clause BSD__-License. 
+
+An _informal_ summary is: do whatever you want, but include Assimp's license text with your product - 
+and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp.
+For the legal details, see the `LICENSE` file. 
+

+ 8 - 0
Source/ThirdParty/Assimp/code/.editorconfig

@@ -0,0 +1,8 @@
+# See <http://EditorConfig.org> for details
+
+[*.{h,hpp,c,cpp}]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_size = 4
+indent_style = space

+ 15 - 3
Source/ThirdParty/Assimp/code/ACLoader.cpp

@@ -89,6 +89,9 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 // read a string (may be enclosed in double quotation marks). buffer must point to "
 #define AI_AC_GET_STRING(out) \
+    if (*buffer == '\0') { \
+        throw DeadlyImportError("AC3D: Unexpected EOF in string"); \
+    } \
     ++buffer; \
     const char* sz = buffer; \
     while ('\"' != *buffer) \
@@ -293,7 +296,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
             SkipSpaces(&buffer);
 
             unsigned int t = strtoul10(buffer,&buffer);
-            if (t >= std::numeric_limits<int32_t>::max() / sizeof(aiVector3D)) {
+            if (t >= AI_MAX_ALLOC(aiVector3D)) {
                 throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
             }
             obj.vertices.reserve(t);
@@ -349,8 +352,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
                 {
                     if(!GetNextLine())
                     {
-                        DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete");
-                        break;
+                        throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
                     }
                     if (TokenMatch(buffer,"mat",3))
                     {
@@ -585,9 +587,19 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
 
                 // allocate storage for vertices and normals
                 mesh->mNumFaces = (*cit).first;
+                if (mesh->mNumFaces == 0) {
+                    throw DeadlyImportError("AC3D: No faces");
+                } else if (mesh->mNumFaces > AI_MAX_ALLOC(aiFace)) {
+                    throw DeadlyImportError("AC3D: Too many faces, would run out of memory");
+                }
                 aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
 
                 mesh->mNumVertices = (*cit).second;
+                if (mesh->mNumVertices == 0) {
+                    throw DeadlyImportError("AC3D: No vertices");
+                } else if (mesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) {
+                    throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
+                }
                 aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
                 unsigned int cur = 0;
 

+ 7 - 0
Source/ThirdParty/Assimp/code/Bitmap.h

@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Bitmap.h
  *  @brief Defines bitmap format helper for textures
  *
@@ -48,7 +50,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_BITMAP_H_INC
 #define AI_BITMAP_H_INC
 
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <cstddef>
 struct aiTexture;
 

+ 7 - 0
Source/ThirdParty/Assimp/code/BlenderDNA.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  BlenderDNA.h
  *  @brief Blender `DNA` (file format specification embedded in
  *    blend file itself) loader.
@@ -49,7 +51,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "TinyFormatter.h"
 #include "StreamReader.h"
 #include "../include/assimp/DefaultLogger.hpp"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <boost/shared_ptr.hpp>
 
 

+ 1 - 1
Source/ThirdParty/Assimp/code/BlenderScene.h

@@ -103,7 +103,7 @@ struct Image;
 // -------------------------------------------------------------------------------
 struct ID : ElemBase {
 
-    char name[24] WARN;
+    char name[1024] WARN;
     short flag;
 };
 

+ 7 - 0
Source/ThirdParty/Assimp/code/BlobIOSystem.h

@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Provides cheat implementations for IOSystem and IOStream to
  *  redirect exporter output to a blob chain.*/
 
@@ -50,7 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "./../include/assimp/IOSystem.hpp"
 #include "./../include/assimp/DefaultLogger.hpp"
 #include <boost/foreach.hpp>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <set>
 #include <vector>
 

+ 22 - 22
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/LICENSE_1_0.txt

@@ -1,23 +1,23 @@
-Boost Software License - Version 1.0 - August 17th, 2003
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 DEALINGS IN THE SOFTWARE.

+ 99 - 99
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/foreach.hpp

@@ -1,99 +1,99 @@
-
-#ifndef BOOST_FOREACH
-
-///////////////////////////////////////////////////////////////////////////////
-// A stripped down version of FOREACH for
-// illustration purposes. NOT FOR GENERAL USE.
-// For a complete implementation, see BOOST_FOREACH at
-// http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler
-//
-// Copyright 2004 Eric Niebler.
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-//
-// Adapted to Assimp November 29th, 2008 (Alexander Gessler).
-// Added code to handle both const and non-const iterators, simplified some
-// parts.
-///////////////////////////////////////////////////////////////////////////////
-
-namespace boost {
-namespace foreach_detail {
-
-///////////////////////////////////////////////////////////////////////////////
-// auto_any
-
-struct auto_any_base
-{
-    operator bool() const { return false; }
-};
-
-template<typename T>
-struct auto_any : auto_any_base
-{
-    auto_any(T const& t) : item(t) {}
-    mutable T item;
-};
-
-template<typename T>
-T& auto_any_cast(auto_any_base const& any)
-{
-    return static_cast<auto_any<T> const&>(any).item;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// FOREACH helper function
-
-template<typename T>
-auto_any<typename T::const_iterator> begin(T const& t)
-{
-    return t.begin();
-}
-
-template<typename T>
-auto_any<typename T::const_iterator> end(T const& t)
-{
-    return t.end();
-}
-
-// iterator
-template<typename T>
-bool done(auto_any_base const& cur, auto_any_base const& end, T&)
-{
-    typedef typename T::iterator iter_type;
-    return auto_any_cast<iter_type>(cur) == auto_any_cast<iter_type>(end);
-}
-
-template<typename T>
-void next(auto_any_base const& cur, T&)
-{
-    ++auto_any_cast<typename T::iterator>(cur);
-}
-
-template<typename T>
-typename T::reference deref(auto_any_base const& cur, T&)
-{
-    return *auto_any_cast<typename T::iterator>(cur);
-}
-
-template<typename T>
-typename T::const_reference deref(auto_any_base const& cur, const T&)
-{
-    return *auto_any_cast<typename T::iterator>(cur);
-}
-
-} // end foreach_detail
-
-///////////////////////////////////////////////////////////////////////////////
-// FOREACH
-
-#define BOOST_FOREACH(item, container)                      \
-	if(boost::foreach_detail::auto_any_base const& foreach_magic_b = boost::foreach_detail::begin(container)) {} else       \
-    if(boost::foreach_detail::auto_any_base const& foreach_magic_e = boost::foreach_detail::end(container))   {} else       \
-    for(;!boost::foreach_detail::done(foreach_magic_b,foreach_magic_e,container);  boost::foreach_detail::next(foreach_magic_b,container))   \
-        if (bool ugly_and_unique_break = false) {} else							\
-        for(item = boost::foreach_detail::deref(foreach_magic_b,container); !ugly_and_unique_break; ugly_and_unique_break = true)
-
-} // end boost
-
-#endif
+
+#ifndef BOOST_FOREACH
+
+///////////////////////////////////////////////////////////////////////////////
+// A stripped down version of FOREACH for
+// illustration purposes. NOT FOR GENERAL USE.
+// For a complete implementation, see BOOST_FOREACH at
+// http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler
+//
+// Copyright 2004 Eric Niebler.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// Adapted to Assimp November 29th, 2008 (Alexander Gessler).
+// Added code to handle both const and non-const iterators, simplified some
+// parts.
+///////////////////////////////////////////////////////////////////////////////
+
+namespace boost {
+namespace foreach_detail {
+
+///////////////////////////////////////////////////////////////////////////////
+// auto_any
+
+struct auto_any_base
+{
+    operator bool() const { return false; }
+};
+
+template<typename T>
+struct auto_any : auto_any_base
+{
+    auto_any(T const& t) : item(t) {}
+    mutable T item;
+};
+
+template<typename T>
+T& auto_any_cast(auto_any_base const& any)
+{
+    return static_cast<auto_any<T> const&>(any).item;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// FOREACH helper function
+
+template<typename T>
+auto_any<typename T::const_iterator> begin(T const& t)
+{
+    return t.begin();
+}
+
+template<typename T>
+auto_any<typename T::const_iterator> end(T const& t)
+{
+    return t.end();
+}
+
+// iterator
+template<typename T>
+bool done(auto_any_base const& cur, auto_any_base const& end, T&)
+{
+    typedef typename T::iterator iter_type;
+    return auto_any_cast<iter_type>(cur) == auto_any_cast<iter_type>(end);
+}
+
+template<typename T>
+void next(auto_any_base const& cur, T&)
+{
+    ++auto_any_cast<typename T::iterator>(cur);
+}
+
+template<typename T>
+typename T::reference deref(auto_any_base const& cur, T&)
+{
+    return *auto_any_cast<typename T::iterator>(cur);
+}
+
+template<typename T>
+typename T::const_reference deref(auto_any_base const& cur, const T&)
+{
+    return *auto_any_cast<typename T::iterator>(cur);
+}
+
+} // end foreach_detail
+
+///////////////////////////////////////////////////////////////////////////////
+// FOREACH
+
+#define BOOST_FOREACH(item, container)                      \
+	if(boost::foreach_detail::auto_any_base const& foreach_magic_b = boost::foreach_detail::begin(container)) {} else       \
+    if(boost::foreach_detail::auto_any_base const& foreach_magic_e = boost::foreach_detail::end(container))   {} else       \
+    for(;!boost::foreach_detail::done(foreach_magic_b,foreach_magic_e,container);  boost::foreach_detail::next(foreach_magic_b,container))   \
+        if (bool ugly_and_unique_break = false) {} else							\
+        for(item = boost::foreach_detail::deref(foreach_magic_b,container); !ugly_and_unique_break; ugly_and_unique_break = true)
+
+} // end boost
+
+#endif

+ 82 - 82
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/format.hpp

@@ -1,82 +1,82 @@
-
-
-
-/* DEPRECATED! - use code/TinyFormatter.h instead.
- *
- *
- * */
-
-#ifndef AI_BOOST_FORMAT_DUMMY_INCLUDED
-#define AI_BOOST_FORMAT_DUMMY_INCLUDED
-
-#if (!defined BOOST_FORMAT_HPP) || (defined ASSIMP_FORCE_NOBOOST)
-
-#include <string>
-#include <vector>
-#include <sstream> 
-
-namespace boost
-{
-
-
-	class format
-	{
-	public:
-		format (const std::string& _d)
-			: d(_d)
-		{
-		}
-
-		template <typename T>
-		format& operator % (T in) 
-		{
-			// XXX add replacement for boost::lexical_cast?
-			
-			std::ostringstream ss;
-			ss << in; // note: ss cannot be an rvalue, or  the global operator << (const char*) is not called for T == const char*.
-			chunks.push_back( ss.str());
-			return *this;
-		}
-
-
-		operator std::string () const {
-			std::string res; // pray for NRVO to kick in
-
-			size_t start = 0, last = 0;
-
-			std::vector<std::string>::const_iterator chunkin = chunks.begin();
-
-			for ( start = d.find('%');start != std::string::npos;  start = d.find('%',last)) {
-				res += d.substr(last,start-last);
-				last = start+2;
-				if (d[start+1] == '%') {
-					res += "%";
-					continue;
-				}
-
-				if (chunkin == chunks.end()) {
-					break;
-				}
-
-				res += *chunkin++;
-			}
-			res += d.substr(last);
-			return res;
-		}
-
-	private:
-		std::string d;
-		std::vector<std::string> chunks;
-	};
-
-	inline std::string str(const std::string& s) {
-		return s;
-	} 
-}
-
-
-#else
-#	error "format.h was already included"
-#endif //
-#endif // !! AI_BOOST_FORMAT_DUMMY_INCLUDED
-
+
+
+
+/* DEPRECATED! - use code/TinyFormatter.h instead.
+ *
+ *
+ * */
+
+#ifndef AI_BOOST_FORMAT_DUMMY_INCLUDED
+#define AI_BOOST_FORMAT_DUMMY_INCLUDED
+
+#if (!defined BOOST_FORMAT_HPP) || (defined ASSIMP_FORCE_NOBOOST)
+
+#include <string>
+#include <vector>
+#include <sstream> 
+
+namespace boost
+{
+
+
+	class format
+	{
+	public:
+		format (const std::string& _d)
+			: d(_d)
+		{
+		}
+
+		template <typename T>
+		format& operator % (T in) 
+		{
+			// XXX add replacement for boost::lexical_cast?
+			
+			std::ostringstream ss;
+			ss << in; // note: ss cannot be an rvalue, or  the global operator << (const char*) is not called for T == const char*.
+			chunks.push_back( ss.str());
+			return *this;
+		}
+
+
+		operator std::string () const {
+			std::string res; // pray for NRVO to kick in
+
+			size_t start = 0, last = 0;
+
+			std::vector<std::string>::const_iterator chunkin = chunks.begin();
+
+			for ( start = d.find('%');start != std::string::npos;  start = d.find('%',last)) {
+				res += d.substr(last,start-last);
+				last = start+2;
+				if (d[start+1] == '%') {
+					res += "%";
+					continue;
+				}
+
+				if (chunkin == chunks.end()) {
+					break;
+				}
+
+				res += *chunkin++;
+			}
+			res += d.substr(last);
+			return res;
+		}
+
+	private:
+		std::string d;
+		std::vector<std::string> chunks;
+	};
+
+	inline std::string str(const std::string& s) {
+		return s;
+	} 
+}
+
+
+#else
+#	error "format.h was already included"
+#endif //
+#endif // !! AI_BOOST_FORMAT_DUMMY_INCLUDED
+

+ 26 - 26
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/lexical_cast.hpp

@@ -1,26 +1,26 @@
-/// A quick replacement for boost::lexical_cast for all the Boost haters out there
-
-#ifndef __AI_BOOST_WORKAROUND_LEXICAL_CAST
-#define __AI_BOOST_WORKAROUND_LEXICAL_CAST
-
-#include <sstream>
-
-namespace boost
-{
-
-	/// A quick replacement for boost::lexical_cast - should work for all types a stringstream can handle
-	template <typename TargetType, typename SourceType>
-	TargetType lexical_cast( const SourceType& source)
-	{
-		std::stringstream stream;
-		TargetType result;
-
-		stream << source;
-		stream >> result;
-		return result;
-	}
-
-} // namespace boost
-
-#endif // __AI_BOOST_WORKAROUND_LEXICAL_CAST
-
+/// A quick replacement for boost::lexical_cast for all the Boost haters out there
+
+#ifndef __AI_BOOST_WORKAROUND_LEXICAL_CAST
+#define __AI_BOOST_WORKAROUND_LEXICAL_CAST
+
+#include <sstream>
+
+namespace boost
+{
+
+	/// A quick replacement for boost::lexical_cast - should work for all types a stringstream can handle
+	template <typename TargetType, typename SourceType>
+	TargetType lexical_cast( const SourceType& source)
+	{
+		std::stringstream stream;
+		TargetType result;
+
+		stream << source;
+		stream >> result;
+		return result;
+	}
+
+} // namespace boost
+
+#endif // __AI_BOOST_WORKAROUND_LEXICAL_CAST
+

+ 57 - 57
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/make_shared.hpp

@@ -1,57 +1,57 @@
-
-// please note that this replacement implementation does not
-// provide the performance benefit of the original, which
-// makes only one allocation as opposed to two allocations
-// (smart pointer counter and payload) which are usually
-// required if object and smart pointer are constructed
-// independently.
-
-#ifndef INCLUDED_AI_BOOST_MAKE_SHARED
-#define INCLUDED_AI_BOOST_MAKE_SHARED
-
-
-namespace boost {
-
-	template <typename T>
-	shared_ptr<T> make_shared() {
-		return shared_ptr<T>(new T());
-	}
-
-	template <typename T, typename T0>
-	shared_ptr<T> make_shared(const T0& t0) {
-		return shared_ptr<T>(new T(t0));
-	}
-
-	template <typename T, typename T0,typename T1>
-	shared_ptr<T> make_shared(const T0& t0, const T1& t1) {
-		return shared_ptr<T>(new T(t0,t1));
-	}
-
-	template <typename T, typename T0,typename T1,typename T2>
-	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2) {
-		return shared_ptr<T>(new T(t0,t1,t2));
-	}
-
-	template <typename T, typename T0,typename T1,typename T2,typename T3>
-	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3) {
-		return shared_ptr<T>(new T(t0,t1,t2,t3));
-	}
-
-	template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4>
-	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4) {
-		return shared_ptr<T>(new T(t0,t1,t2,t3,t4));
-	}
-
-	template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4, typename T5>
-	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) {
-		return shared_ptr<T>(new T(t0,t1,t2,t3,t4,t5));
-	}
-
-	template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4, typename T5, typename T6>
-	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) {
-		return shared_ptr<T>(new T(t0,t1,t2,t3,t4,t5,t6));
-	}
-}
-
-
-#endif 
+
+// please note that this replacement implementation does not
+// provide the performance benefit of the original, which
+// makes only one allocation as opposed to two allocations
+// (smart pointer counter and payload) which are usually
+// required if object and smart pointer are constructed
+// independently.
+
+#ifndef INCLUDED_AI_BOOST_MAKE_SHARED
+#define INCLUDED_AI_BOOST_MAKE_SHARED
+
+
+namespace boost {
+
+	template <typename T>
+	shared_ptr<T> make_shared() {
+		return shared_ptr<T>(new T());
+	}
+
+	template <typename T, typename T0>
+	shared_ptr<T> make_shared(const T0& t0) {
+		return shared_ptr<T>(new T(t0));
+	}
+
+	template <typename T, typename T0,typename T1>
+	shared_ptr<T> make_shared(const T0& t0, const T1& t1) {
+		return shared_ptr<T>(new T(t0,t1));
+	}
+
+	template <typename T, typename T0,typename T1,typename T2>
+	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2) {
+		return shared_ptr<T>(new T(t0,t1,t2));
+	}
+
+	template <typename T, typename T0,typename T1,typename T2,typename T3>
+	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3) {
+		return shared_ptr<T>(new T(t0,t1,t2,t3));
+	}
+
+	template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4>
+	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4) {
+		return shared_ptr<T>(new T(t0,t1,t2,t3,t4));
+	}
+
+	template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4, typename T5>
+	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) {
+		return shared_ptr<T>(new T(t0,t1,t2,t3,t4,t5));
+	}
+
+	template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4, typename T5, typename T6>
+	shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) {
+		return shared_ptr<T>(new T(t0,t1,t2,t3,t4,t5,t6));
+	}
+}
+
+
+#endif 

+ 37 - 37
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/math/common_factor_rt.hpp

@@ -1,37 +1,37 @@
-
-
-#ifndef BOOST_MATH_COMMON_FACTOR_RT_HPP
-#define BOOST_MATH_COMMON_FACTOR_RT_HPP
-
-
-namespace boost	{
-namespace math	{
-
-// TODO: use binary GCD for unsigned integers ....
-template < typename IntegerType >
-IntegerType  gcd( IntegerType a, IntegerType b )
-{
-	const IntegerType zero = (IntegerType)0;
-	while ( true )
-	{
-		if ( a == zero )
-			return b;
-		b %= a;
-
-		if ( b == zero )
-			return a;
-		a %= b;
-	}
-}
-
-template < typename IntegerType >
-IntegerType  lcm( IntegerType a, IntegerType b )
-{
-	const IntegerType t = gcd (a,b);
-	if (!t)return t;
-	return a / t * b;
-}
-
-}}
-
-#endif
+
+
+#ifndef BOOST_MATH_COMMON_FACTOR_RT_HPP
+#define BOOST_MATH_COMMON_FACTOR_RT_HPP
+
+
+namespace boost	{
+namespace math	{
+
+// TODO: use binary GCD for unsigned integers ....
+template < typename IntegerType >
+IntegerType  gcd( IntegerType a, IntegerType b )
+{
+	const IntegerType zero = (IntegerType)0;
+	while ( true )
+	{
+		if ( a == zero )
+			return b;
+		b %= a;
+
+		if ( b == zero )
+			return a;
+		a %= b;
+	}
+}
+
+template < typename IntegerType >
+IntegerType  lcm( IntegerType a, IntegerType b )
+{
+	const IntegerType t = gcd (a,b);
+	if (!t)return t;
+	return a / t * b;
+}
+
+}}
+
+#endif

+ 36 - 36
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/noncopyable.hpp

@@ -1,36 +1,36 @@
-//  Boost noncopyable.hpp header file  --------------------------------------//
-
-//  (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost
-//  Software License, Version 1.0. (See accompanying file
-//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-
-//  See http://www.boost.org/libs/utility for documentation.
-
-#ifndef BOOST_NONCOPYABLE_HPP_INCLUDED
-#define BOOST_NONCOPYABLE_HPP_INCLUDED
-
-namespace boost {
-
-//  Private copy constructor and copy assignment ensure classes derived from
-//  class noncopyable cannot be copied.
-
-//  Contributed by Dave Abrahams
-
-namespace noncopyable_  // protection from unintended ADL
-{
-  class noncopyable
-  {
-   protected:
-      noncopyable() {}
-      ~noncopyable() {}
-   private:  // emphasize the following members are private
-      noncopyable( const noncopyable& );
-      const noncopyable& operator=( const noncopyable& );
-  };
-}
-
-typedef noncopyable_::noncopyable noncopyable;
-
-} // namespace boost
-
-#endif  // BOOST_NONCOPYABLE_HPP_INCLUDED
+//  Boost noncopyable.hpp header file  --------------------------------------//
+
+//  (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost
+//  Software License, Version 1.0. (See accompanying file
+//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org/libs/utility for documentation.
+
+#ifndef BOOST_NONCOPYABLE_HPP_INCLUDED
+#define BOOST_NONCOPYABLE_HPP_INCLUDED
+
+namespace boost {
+
+//  Private copy constructor and copy assignment ensure classes derived from
+//  class noncopyable cannot be copied.
+
+//  Contributed by Dave Abrahams
+
+namespace noncopyable_  // protection from unintended ADL
+{
+  class noncopyable
+  {
+   protected:
+      noncopyable() {}
+      ~noncopyable() {}
+   private:  // emphasize the following members are private
+      noncopyable( const noncopyable& );
+      const noncopyable& operator=( const noncopyable& );
+  };
+}
+
+typedef noncopyable_::noncopyable noncopyable;
+
+} // namespace boost
+
+#endif  // BOOST_NONCOPYABLE_HPP_INCLUDED

+ 45 - 45
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/pointer_cast.hpp

@@ -1,45 +1,45 @@
-//////////////////////////////////////////////////////////////////////////////
-//
-// (C) Copyright Ion Gaztanaga 2005. 
-// Distributed under the Boost Software License, Version 1.0. 
-// (See accompanying file LICENSE_1_0.txt or copy at 
-//  http://www.boost.org/LICENSE_1_0.txt)
-//
-//////////////////////////////////////////////////////////////////////////////
-
-#ifndef BOOST_POINTER_CAST_HPP
-#define BOOST_POINTER_CAST_HPP
-
-namespace boost { 
-
-//static_pointer_cast overload for raw pointers
-template<class T, class U>
-inline T* static_pointer_cast(U *ptr)
-{  
-   return static_cast<T*>(ptr);
-}
-
-//dynamic_pointer_cast overload for raw pointers
-template<class T, class U>
-inline T* dynamic_pointer_cast(U *ptr)
-{  
-   return dynamic_cast<T*>(ptr);
-}
-
-//const_pointer_cast overload for raw pointers
-template<class T, class U>
-inline T* const_pointer_cast(U *ptr)
-{  
-   return const_cast<T*>(ptr);
-}
-
-//reinterpret_pointer_cast overload for raw pointers
-template<class T, class U>
-inline T* reinterpret_pointer_cast(U *ptr)
-{  
-   return reinterpret_cast<T*>(ptr);
-}
-
-} // namespace boost
-
-#endif   //BOOST_POINTER_CAST_HPP
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005. 
+// Distributed under the Boost Software License, Version 1.0. 
+// (See accompanying file LICENSE_1_0.txt or copy at 
+//  http://www.boost.org/LICENSE_1_0.txt)
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_POINTER_CAST_HPP
+#define BOOST_POINTER_CAST_HPP
+
+namespace boost { 
+
+//static_pointer_cast overload for raw pointers
+template<class T, class U>
+inline T* static_pointer_cast(U *ptr)
+{  
+   return static_cast<T*>(ptr);
+}
+
+//dynamic_pointer_cast overload for raw pointers
+template<class T, class U>
+inline T* dynamic_pointer_cast(U *ptr)
+{  
+   return dynamic_cast<T*>(ptr);
+}
+
+//const_pointer_cast overload for raw pointers
+template<class T, class U>
+inline T* const_pointer_cast(U *ptr)
+{  
+   return const_cast<T*>(ptr);
+}
+
+//reinterpret_pointer_cast overload for raw pointers
+template<class T, class U>
+inline T* reinterpret_pointer_cast(U *ptr)
+{  
+   return reinterpret_cast<T*>(ptr);
+}
+
+} // namespace boost
+
+#endif   //BOOST_POINTER_CAST_HPP

+ 79 - 79
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/scoped_array.hpp

@@ -1,79 +1,79 @@
-
-#ifndef __AI_BOOST_SCOPED_ARRAY_INCLUDED
-#define __AI_BOOST_SCOPED_ARRAY_INCLUDED
-
-#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED
-
-namespace boost {
-
-// small replacement for boost::scoped_array
-template <class T>
-class scoped_array
-{
-public:
-
-	// provide a default construtctor
-	scoped_array()
-		: ptr(0)
-	{
-	}
-
-	// construction from an existing heap object of type T
-	scoped_array(T* _ptr)
-		: ptr(_ptr)
-	{
-	}
-
-	// automatic destruction of the wrapped object at the
-	// end of our lifetime
-	~scoped_array()
-	{
-		delete[] ptr;
-	}
-
-	inline T* get()
-	{
-		return ptr;
-	}
-
-	inline T* operator-> ()
-	{
-		return ptr;
-	}
-
-	inline void reset (T* t = 0)
-	{
-		delete[] ptr;
-		ptr = t;
-	}
-
-	T & operator[](std::ptrdiff_t i) const
-	{
-		return ptr[i];
-	}
-
-	void swap(scoped_array & b)
-	{
-		std::swap(ptr, b.ptr);
-	}
-
-private:
-
-	// encapsulated object pointer
-	T* ptr;
-
-};
-
-template<class T>
-inline void swap(scoped_array<T> & a, scoped_array<T> & b)
-{
-	a.swap(b);
-}
-
-} // end of namespace boost
-
-#else
-#	error "scoped_array.h was already included"
-#endif
-#endif // __AI_BOOST_SCOPED_ARRAY_INCLUDED
-
+
+#ifndef __AI_BOOST_SCOPED_ARRAY_INCLUDED
+#define __AI_BOOST_SCOPED_ARRAY_INCLUDED
+
+#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED
+
+namespace boost {
+
+// small replacement for boost::scoped_array
+template <class T>
+class scoped_array
+{
+public:
+
+	// provide a default construtctor
+	scoped_array()
+		: ptr(0)
+	{
+	}
+
+	// construction from an existing heap object of type T
+	scoped_array(T* _ptr)
+		: ptr(_ptr)
+	{
+	}
+
+	// automatic destruction of the wrapped object at the
+	// end of our lifetime
+	~scoped_array()
+	{
+		delete[] ptr;
+	}
+
+	inline T* get()
+	{
+		return ptr;
+	}
+
+	inline T* operator-> ()
+	{
+		return ptr;
+	}
+
+	inline void reset (T* t = 0)
+	{
+		delete[] ptr;
+		ptr = t;
+	}
+
+	T & operator[](std::ptrdiff_t i) const
+	{
+		return ptr[i];
+	}
+
+	void swap(scoped_array & b)
+	{
+		std::swap(ptr, b.ptr);
+	}
+
+private:
+
+	// encapsulated object pointer
+	T* ptr;
+
+};
+
+template<class T>
+inline void swap(scoped_array<T> & a, scoped_array<T> & b)
+{
+	a.swap(b);
+}
+
+} // end of namespace boost
+
+#else
+#	error "scoped_array.h was already included"
+#endif
+#endif // __AI_BOOST_SCOPED_ARRAY_INCLUDED
+

+ 79 - 79
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/scoped_ptr.hpp

@@ -1,79 +1,79 @@
-
-#ifndef __AI_BOOST_SCOPED_PTR_INCLUDED
-#define __AI_BOOST_SCOPED_PTR_INCLUDED
-
-#ifndef BOOST_SCOPED_PTR_HPP_INCLUDED
-
-namespace boost {
-
-// small replacement for boost::scoped_ptr
-template <class T>
-class scoped_ptr
-{
-public:
-
-	// provide a default construtctor
-	scoped_ptr()
-		: ptr(0)
-	{
-	}
-
-	// construction from an existing heap object of type T
-	scoped_ptr(T* _ptr)
-		: ptr(_ptr)
-	{
-	}
-
-	// automatic destruction of the wrapped object at the
-	// end of our lifetime
-	~scoped_ptr()
-	{
-		delete ptr;
-	}
-
-	inline T* get() const
-	{
-		return ptr;
-	}
-
-	inline operator T*()
-	{
-		return ptr;
-	}
-
-	inline T* operator-> ()
-	{
-		return ptr;
-	}
-
-	inline void reset (T* t = 0)
-	{
-		delete ptr;
-		ptr = t;
-	}
-
-	void swap(scoped_ptr & b)
-	{
-		std::swap(ptr, b.ptr);
-	}
-
-private:
-
-	// encapsulated object pointer
-	T* ptr;
-
-};
-
-template<class T>
-inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b)
-{
-	a.swap(b);
-}
-
-} // end of namespace boost
-
-#else
-#	error "scoped_ptr.h was already included"
-#endif
-#endif // __AI_BOOST_SCOPED_PTR_INCLUDED
-
+
+#ifndef __AI_BOOST_SCOPED_PTR_INCLUDED
+#define __AI_BOOST_SCOPED_PTR_INCLUDED
+
+#ifndef BOOST_SCOPED_PTR_HPP_INCLUDED
+
+namespace boost {
+
+// small replacement for boost::scoped_ptr
+template <class T>
+class scoped_ptr
+{
+public:
+
+	// provide a default construtctor
+	scoped_ptr()
+		: ptr(0)
+	{
+	}
+
+	// construction from an existing heap object of type T
+	scoped_ptr(T* _ptr)
+		: ptr(_ptr)
+	{
+	}
+
+	// automatic destruction of the wrapped object at the
+	// end of our lifetime
+	~scoped_ptr()
+	{
+		delete ptr;
+	}
+
+	inline T* get() const
+	{
+		return ptr;
+	}
+
+	inline operator T*()
+	{
+		return ptr;
+	}
+
+	inline T* operator-> ()
+	{
+		return ptr;
+	}
+
+	inline void reset (T* t = 0)
+	{
+		delete ptr;
+		ptr = t;
+	}
+
+	void swap(scoped_ptr & b)
+	{
+		std::swap(ptr, b.ptr);
+	}
+
+private:
+
+	// encapsulated object pointer
+	T* ptr;
+
+};
+
+template<class T>
+inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b)
+{
+	a.swap(b);
+}
+
+} // end of namespace boost
+
+#else
+#	error "scoped_ptr.h was already included"
+#endif
+#endif // __AI_BOOST_SCOPED_PTR_INCLUDED
+

+ 228 - 228
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_array.hpp

@@ -1,228 +1,228 @@
-
-#ifndef INCLUDED_AI_BOOST_SHARED_ARRAY
-#define INCLUDED_AI_BOOST_SHARED_ARRAY
-
-#ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED
-
-// ------------------------------
-// Internal stub
-namespace boost {
-	namespace array_detail {
-		class controller {
-		public:
-
-			controller()
-				: cnt(1)
-			{}
-		
-		public:
-
-			template <typename T>
-			controller* decref(T* pt) {
-				if (--cnt <= 0) {
-					delete this;
-					delete[] pt;
-				}
-				return NULL;
-			}
-		
-			controller* incref() {
-				++cnt;
-				return this;
-			}
-
-			long get() const {
-				return cnt;
-			}
-
-		private:
-			long cnt;
-		};
-
-		struct empty {};
-		
-		template <typename DEST, typename SRC>
-		struct is_convertible_stub {
-			
-			struct yes {char s[1];};
-			struct no  {char s[2];};
-
-			static yes foo(DEST*);
-			static no  foo(...);
-
-			enum {result = (sizeof(foo((SRC*)0)) == sizeof(yes) ? 1 : 0)};	
-		};
-
-		template <bool> struct enable_if {};
-		template <> struct enable_if<true> {
-			typedef empty result;
-		};
-
-		template <typename DEST, typename SRC>
-		struct is_convertible : public enable_if<is_convertible_stub<DEST,SRC>::result > {
-		};
-	}
-
-// ------------------------------
-// Small replacement for boost::shared_array, not threadsafe because no
-// atomic reference counter is in use.
-// ------------------------------
-template <class T>
-class shared_array
-{
-	template <typename TT> friend class shared_array;
-
-	template<class TT> friend bool operator== (const shared_array<TT>& a, const shared_array<TT>& b);
-	template<class TT> friend bool operator!= (const shared_array<TT>& a, const shared_array<TT>& b);
-	template<class TT> friend bool operator<  (const shared_array<TT>& a, const shared_array<TT>& b);
-
-public:
-
-	typedef T element_type;
-
-public:
-
-	// provide a default constructor
-	shared_array()
-		: ptr()
-		, ctr(NULL)
-	{
-	}
-
-	// construction from an existing object of type T
-	explicit shared_array(T* ptr)
-		: ptr(ptr)
-		, ctr(ptr ? new array_detail::controller() : NULL)
-	{
-	}
-
-	shared_array(const shared_array& r)
-		: ptr(r.ptr)
-		, ctr(r.ctr ? r.ctr->incref() : NULL)
-	{
-	}
-
-	template <typename Y>
-	shared_array(const shared_array<Y>& r,typename detail::is_convertible<T,Y>::result = detail::empty())
-		: ptr(r.ptr)
-		, ctr(r.ctr ? r.ctr->incref() : NULL)
-	{
-	}
-
-	// automatic destruction of the wrapped object when all
-	// references are freed.
-	~shared_array()	{
-		if (ctr) {
-			ctr = ctr->decref(ptr);
-		}
-	}
-
-	shared_array& operator=(const shared_array& r) {
-		if (this == &r) {
-			return *this;
-		}
-		if (ctr) {
-			ctr->decref(ptr);
-		}
-		ptr = r.ptr;
-		ctr = ptr?r.ctr->incref():NULL;
-		return *this;
-	}
-
-	template <typename Y>
-	shared_array& operator=(const shared_array<Y>& r) {
-		if (this == &r) {
-			return *this;
-		}
-		if (ctr) {
-			ctr->decref(ptr);
-		}
-		ptr = r.ptr;
-		ctr = ptr?r.ctr->incref():NULL;
-		return *this;
-	}
-
-	// pointer access
-	inline operator T*()	{
-		return ptr;
-	}
-
-	inline T* operator-> () const	{
-		return ptr;
-	}
-
-	// standard semantics
-	inline T* get() {
-		return ptr;
-	}
-
-	T& operator[] (std::ptrdiff_t index) const {
-		return ptr[index];
-	}
-
-	inline const T* get() const	{
-		return ptr;
-	}
-
-	inline operator bool () const {
-		return ptr != NULL;
-	}
-
-	inline bool unique() const {
-		return use_count() == 1;
-	}
-
-	inline long use_count() const {
-		return ctr->get();
-	}
-
-	inline void reset (T* t = 0)	{
-		if (ctr) {
-			ctr->decref(ptr);
-		}
-		ptr = t;
-		ctr = ptr?new array_detail::controller():NULL;
-	}
-
-	void swap(shared_array & b)	{
-		std::swap(ptr, b.ptr);
-		std::swap(ctr, b.ctr);
-	}
-
-
-private:
-
-	// encapsulated object pointer
-	T* ptr;
-
-	// control block
-	array_detail::controller* ctr;
-};
-
-template<class T>
-inline void swap(shared_array<T> & a, shared_array<T> & b)
-{
-	a.swap(b);
-}
-
-template<class T>
-bool operator== (const shared_array<T>& a, const shared_array<T>& b) {
-	return a.ptr == b.ptr;
-}
-template<class T>
-bool operator!= (const shared_array<T>& a, const shared_array<T>& b) {
-	return a.ptr != b.ptr;
-}
-	
-template<class T>
-bool operator< (const shared_array<T>& a, const shared_array<T>& b) {
-	return a.ptr < b.ptr;
-}
-
-
-} // end of namespace boost
-
-#else
-#	error "shared_array.h was already included"
-#endif
-#endif // INCLUDED_AI_BOOST_SHARED_ARRAY
+
+#ifndef INCLUDED_AI_BOOST_SHARED_ARRAY
+#define INCLUDED_AI_BOOST_SHARED_ARRAY
+
+#ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED
+
+// ------------------------------
+// Internal stub
+namespace boost {
+	namespace array_detail {
+		class controller {
+		public:
+
+			controller()
+				: cnt(1)
+			{}
+		
+		public:
+
+			template <typename T>
+			controller* decref(T* pt) {
+				if (--cnt <= 0) {
+					delete this;
+					delete[] pt;
+				}
+				return NULL;
+			}
+		
+			controller* incref() {
+				++cnt;
+				return this;
+			}
+
+			long get() const {
+				return cnt;
+			}
+
+		private:
+			long cnt;
+		};
+
+		struct empty {};
+		
+		template <typename DEST, typename SRC>
+		struct is_convertible_stub {
+			
+			struct yes {char s[1];};
+			struct no  {char s[2];};
+
+			static yes foo(DEST*);
+			static no  foo(...);
+
+			enum {result = (sizeof(foo((SRC*)0)) == sizeof(yes) ? 1 : 0)};	
+		};
+
+		template <bool> struct enable_if {};
+		template <> struct enable_if<true> {
+			typedef empty result;
+		};
+
+		template <typename DEST, typename SRC>
+		struct is_convertible : public enable_if<is_convertible_stub<DEST,SRC>::result > {
+		};
+	}
+
+// ------------------------------
+// Small replacement for boost::shared_array, not threadsafe because no
+// atomic reference counter is in use.
+// ------------------------------
+template <class T>
+class shared_array
+{
+	template <typename TT> friend class shared_array;
+
+	template<class TT> friend bool operator== (const shared_array<TT>& a, const shared_array<TT>& b);
+	template<class TT> friend bool operator!= (const shared_array<TT>& a, const shared_array<TT>& b);
+	template<class TT> friend bool operator<  (const shared_array<TT>& a, const shared_array<TT>& b);
+
+public:
+
+	typedef T element_type;
+
+public:
+
+	// provide a default constructor
+	shared_array()
+		: ptr()
+		, ctr(NULL)
+	{
+	}
+
+	// construction from an existing object of type T
+	explicit shared_array(T* ptr)
+		: ptr(ptr)
+		, ctr(ptr ? new array_detail::controller() : NULL)
+	{
+	}
+
+	shared_array(const shared_array& r)
+		: ptr(r.ptr)
+		, ctr(r.ctr ? r.ctr->incref() : NULL)
+	{
+	}
+
+	template <typename Y>
+	shared_array(const shared_array<Y>& r,typename detail::is_convertible<T,Y>::result = detail::empty())
+		: ptr(r.ptr)
+		, ctr(r.ctr ? r.ctr->incref() : NULL)
+	{
+	}
+
+	// automatic destruction of the wrapped object when all
+	// references are freed.
+	~shared_array()	{
+		if (ctr) {
+			ctr = ctr->decref(ptr);
+		}
+	}
+
+	shared_array& operator=(const shared_array& r) {
+		if (this == &r) {
+			return *this;
+		}
+		if (ctr) {
+			ctr->decref(ptr);
+		}
+		ptr = r.ptr;
+		ctr = ptr?r.ctr->incref():NULL;
+		return *this;
+	}
+
+	template <typename Y>
+	shared_array& operator=(const shared_array<Y>& r) {
+		if (this == &r) {
+			return *this;
+		}
+		if (ctr) {
+			ctr->decref(ptr);
+		}
+		ptr = r.ptr;
+		ctr = ptr?r.ctr->incref():NULL;
+		return *this;
+	}
+
+	// pointer access
+	inline operator T*()	{
+		return ptr;
+	}
+
+	inline T* operator-> () const	{
+		return ptr;
+	}
+
+	// standard semantics
+	inline T* get() {
+		return ptr;
+	}
+
+	T& operator[] (std::ptrdiff_t index) const {
+		return ptr[index];
+	}
+
+	inline const T* get() const	{
+		return ptr;
+	}
+
+	inline operator bool () const {
+		return ptr != NULL;
+	}
+
+	inline bool unique() const {
+		return use_count() == 1;
+	}
+
+	inline long use_count() const {
+		return ctr->get();
+	}
+
+	inline void reset (T* t = 0)	{
+		if (ctr) {
+			ctr->decref(ptr);
+		}
+		ptr = t;
+		ctr = ptr?new array_detail::controller():NULL;
+	}
+
+	void swap(shared_array & b)	{
+		std::swap(ptr, b.ptr);
+		std::swap(ctr, b.ctr);
+	}
+
+
+private:
+
+	// encapsulated object pointer
+	T* ptr;
+
+	// control block
+	array_detail::controller* ctr;
+};
+
+template<class T>
+inline void swap(shared_array<T> & a, shared_array<T> & b)
+{
+	a.swap(b);
+}
+
+template<class T>
+bool operator== (const shared_array<T>& a, const shared_array<T>& b) {
+	return a.ptr == b.ptr;
+}
+template<class T>
+bool operator!= (const shared_array<T>& a, const shared_array<T>& b) {
+	return a.ptr != b.ptr;
+}
+	
+template<class T>
+bool operator< (const shared_array<T>& a, const shared_array<T>& b) {
+	return a.ptr < b.ptr;
+}
+
+
+} // end of namespace boost
+
+#else
+#	error "shared_array.h was already included"
+#endif
+#endif // INCLUDED_AI_BOOST_SHARED_ARRAY

+ 260 - 260
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_ptr.hpp

@@ -1,260 +1,260 @@
-
-#ifndef INCLUDED_AI_BOOST_SHARED_PTR
-#define INCLUDED_AI_BOOST_SHARED_PTR
-
-#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
-
-// ------------------------------
-// Internal stub
-
-#include <stddef.h> //NULL
-#include <algorithm> //std::swap
-namespace boost {
-	namespace detail {
-		class controller {
-		public:
-
-			controller()
-				: cnt(1)
-			{}
-		
-		public:
-
-			template <typename T>
-			controller* decref(T* pt) {
-				if (--cnt <= 0) {
-					delete this;
-					delete pt;
-				}
-				return NULL;
-			}
-		
-			controller* incref() {
-				++cnt;
-				return this;
-			}
-
-			long get() const {
-				return cnt;
-			}
-
-		private:
-			long cnt;
-		};
-
-		struct empty {};
-		
-		template <typename DEST, typename SRC>
-		struct is_convertible_stub {
-			
-			struct yes {char s[1];};
-			struct no  {char s[2];};
-
-			static yes foo(DEST*);
-			static no  foo(...);
-
-			enum {result = (sizeof(foo((SRC*)0)) == sizeof(yes) ? 1 : 0)};	
-		};
-
-		template <bool> struct enable_if {};
-		template <> struct enable_if<true> {
-			typedef empty result;
-		};
-
-		template <typename DEST, typename SRC>
-		struct is_convertible : public enable_if<is_convertible_stub<DEST,SRC>::result > {
-		};
-	}
-
-// ------------------------------
-// Small replacement for boost::shared_ptr, not threadsafe because no
-// atomic reference counter is in use.
-// ------------------------------
-template <class T>
-class shared_ptr
-{
-	template <typename TT> friend class shared_ptr;
-
-	template<class TT, class U> friend shared_ptr<TT> static_pointer_cast   (shared_ptr<U> ptr);
-	template<class TT, class U> friend shared_ptr<TT> dynamic_pointer_cast  (shared_ptr<U> ptr);
-	template<class TT, class U> friend shared_ptr<TT> const_pointer_cast    (shared_ptr<U> ptr);
-
-	template<class TT> friend bool operator== (const shared_ptr<TT>& a, const shared_ptr<TT>& b);
-	template<class TT> friend bool operator!= (const shared_ptr<TT>& a, const shared_ptr<TT>& b);
-	template<class TT> friend bool operator<  (const shared_ptr<TT>& a, const shared_ptr<TT>& b);
-
-public:
-
-	typedef T element_type;
-
-public:
-
-	// provide a default constructor
-	shared_ptr()
-		: ptr()
-		, ctr(NULL)
-	{
-	}
-
-	// construction from an existing object of type T
-	explicit shared_ptr(T* ptr)
-		: ptr(ptr)
-		, ctr(ptr ? new detail::controller() : NULL)
-	{
-	}
-
-	shared_ptr(const shared_ptr& r)
-		: ptr(r.ptr)
-		, ctr(r.ctr ? r.ctr->incref() : NULL)
-	{
-	}
-
-	template <typename Y>
-	shared_ptr(const shared_ptr<Y>& r,typename detail::is_convertible<T,Y>::result = detail::empty())
-		: ptr(r.ptr)
-		, ctr(r.ctr ? r.ctr->incref() : NULL)
-	{
-	}
-
-	// automatic destruction of the wrapped object when all
-	// references are freed.
-	~shared_ptr()	{
-		if (ctr) {
-			ctr = ctr->decref(ptr);
-		}
-	}
-
-	shared_ptr& operator=(const shared_ptr& r) {
-		if (this == &r) {
-			return *this;
-		}
-		if (ctr) {
-			ctr->decref(ptr);
-		}
-		ptr = r.ptr;
-		ctr = ptr?r.ctr->incref():NULL;
-		return *this;
-	}
-
-	template <typename Y>
-	shared_ptr& operator=(const shared_ptr<Y>& r) {
-		if (this == &r) {
-			return *this;
-		}
-		if (ctr) {
-			ctr->decref(ptr);
-		}
-		ptr = r.ptr;
-		ctr = ptr?r.ctr->incref():NULL;
-		return *this;
-	}
-
-	// pointer access
-	inline operator T*() const {
-		return ptr;
-	}
-
-	inline T* operator-> () const	{
-		return ptr;
-	}
-
-	// standard semantics
-	inline T* get() {
-		return ptr;
-	}
-
-	inline const T* get() const	{
-		return ptr;
-	}
-
-	inline operator bool () const {
-		return ptr != NULL;
-	}
-
-	inline bool unique() const {
-		return use_count() == 1;
-	}
-
-	inline long use_count() const {
-		return ctr->get();
-	}
-
-	inline void reset (T* t = 0)	{
-		if (ctr) {
-			ctr->decref(ptr);
-		}
-		ptr = t;
-		ctr = ptr?new detail::controller():NULL;
-	}
-
-	void swap(shared_ptr & b)	{
-		std::swap(ptr, b.ptr);
-		std::swap(ctr, b.ctr);
-	}
-
-private:
-
-
-	// for use by the various xxx_pointer_cast helper templates
-	explicit shared_ptr(T* ptr, detail::controller* ctr)
-		: ptr(ptr)
-		, ctr(ctr->incref())
-	{
-	}
-
-private:
-
-	// encapsulated object pointer
-	T* ptr;
-
-	// control block
-	detail::controller* ctr;
-};
-
-template<class T>
-inline void swap(shared_ptr<T> & a, shared_ptr<T> & b)
-{
-	a.swap(b);
-}
-
-template<class T>
-bool operator== (const shared_ptr<T>& a, const shared_ptr<T>& b) {
-	return a.ptr == b.ptr;
-}
-template<class T>
-bool operator!= (const shared_ptr<T>& a, const shared_ptr<T>& b) {
-	return a.ptr != b.ptr;
-}
-	
-template<class T>
-bool operator< (const shared_ptr<T>& a, const shared_ptr<T>& b) {
-	return a.ptr < b.ptr;
-}
-
-
-template<class T, class U>
-inline shared_ptr<T> static_pointer_cast( shared_ptr<U> ptr)
-{  
-   return shared_ptr<T>(static_cast<T*>(ptr.ptr),ptr.ctr);
-}
-
-template<class T, class U>
-inline shared_ptr<T> dynamic_pointer_cast( shared_ptr<U> ptr)
-{  
-   return shared_ptr<T>(dynamic_cast<T*>(ptr.ptr),ptr.ctr);
-}
-
-template<class T, class U>
-inline shared_ptr<T> const_pointer_cast( shared_ptr<U> ptr)
-{  
-   return shared_ptr<T>(const_cast<T*>(ptr.ptr),ptr.ctr);
-}
-
-
-
-} // end of namespace boost
-
-#else
-#	error "shared_ptr.h was already included"
-#endif
-#endif // INCLUDED_AI_BOOST_SHARED_PTR
+
+#ifndef INCLUDED_AI_BOOST_SHARED_PTR
+#define INCLUDED_AI_BOOST_SHARED_PTR
+
+#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
+
+// ------------------------------
+// Internal stub
+
+#include <stddef.h> //NULL
+#include <algorithm> //std::swap
+namespace boost {
+	namespace detail {
+		class controller {
+		public:
+
+			controller()
+				: cnt(1)
+			{}
+		
+		public:
+
+			template <typename T>
+			controller* decref(T* pt) {
+				if (--cnt <= 0) {
+					delete this;
+					delete pt;
+				}
+				return NULL;
+			}
+		
+			controller* incref() {
+				++cnt;
+				return this;
+			}
+
+			long get() const {
+				return cnt;
+			}
+
+		private:
+			long cnt;
+		};
+
+		struct empty {};
+		
+		template <typename DEST, typename SRC>
+		struct is_convertible_stub {
+			
+			struct yes {char s[1];};
+			struct no  {char s[2];};
+
+			static yes foo(DEST*);
+			static no  foo(...);
+
+			enum {result = (sizeof(foo((SRC*)0)) == sizeof(yes) ? 1 : 0)};	
+		};
+
+		template <bool> struct enable_if {};
+		template <> struct enable_if<true> {
+			typedef empty result;
+		};
+
+		template <typename DEST, typename SRC>
+		struct is_convertible : public enable_if<is_convertible_stub<DEST,SRC>::result > {
+		};
+	}
+
+// ------------------------------
+// Small replacement for boost::shared_ptr, not threadsafe because no
+// atomic reference counter is in use.
+// ------------------------------
+template <class T>
+class shared_ptr
+{
+	template <typename TT> friend class shared_ptr;
+
+	template<class TT, class U> friend shared_ptr<TT> static_pointer_cast   (shared_ptr<U> ptr);
+	template<class TT, class U> friend shared_ptr<TT> dynamic_pointer_cast  (shared_ptr<U> ptr);
+	template<class TT, class U> friend shared_ptr<TT> const_pointer_cast    (shared_ptr<U> ptr);
+
+	template<class TT> friend bool operator== (const shared_ptr<TT>& a, const shared_ptr<TT>& b);
+	template<class TT> friend bool operator!= (const shared_ptr<TT>& a, const shared_ptr<TT>& b);
+	template<class TT> friend bool operator<  (const shared_ptr<TT>& a, const shared_ptr<TT>& b);
+
+public:
+
+	typedef T element_type;
+
+public:
+
+	// provide a default constructor
+	shared_ptr()
+		: ptr()
+		, ctr(NULL)
+	{
+	}
+
+	// construction from an existing object of type T
+	explicit shared_ptr(T* ptr)
+		: ptr(ptr)
+		, ctr(ptr ? new detail::controller() : NULL)
+	{
+	}
+
+	shared_ptr(const shared_ptr& r)
+		: ptr(r.ptr)
+		, ctr(r.ctr ? r.ctr->incref() : NULL)
+	{
+	}
+
+	template <typename Y>
+	shared_ptr(const shared_ptr<Y>& r,typename detail::is_convertible<T,Y>::result = detail::empty())
+		: ptr(r.ptr)
+		, ctr(r.ctr ? r.ctr->incref() : NULL)
+	{
+	}
+
+	// automatic destruction of the wrapped object when all
+	// references are freed.
+	~shared_ptr()	{
+		if (ctr) {
+			ctr = ctr->decref(ptr);
+		}
+	}
+
+	shared_ptr& operator=(const shared_ptr& r) {
+		if (this == &r) {
+			return *this;
+		}
+		if (ctr) {
+			ctr->decref(ptr);
+		}
+		ptr = r.ptr;
+		ctr = ptr?r.ctr->incref():NULL;
+		return *this;
+	}
+
+	template <typename Y>
+	shared_ptr& operator=(const shared_ptr<Y>& r) {
+		if (this == &r) {
+			return *this;
+		}
+		if (ctr) {
+			ctr->decref(ptr);
+		}
+		ptr = r.ptr;
+		ctr = ptr?r.ctr->incref():NULL;
+		return *this;
+	}
+
+	// pointer access
+	inline operator T*() const {
+		return ptr;
+	}
+
+	inline T* operator-> () const	{
+		return ptr;
+	}
+
+	// standard semantics
+	inline T* get() {
+		return ptr;
+	}
+
+	inline const T* get() const	{
+		return ptr;
+	}
+
+	inline operator bool () const {
+		return ptr != NULL;
+	}
+
+	inline bool unique() const {
+		return use_count() == 1;
+	}
+
+	inline long use_count() const {
+		return ctr->get();
+	}
+
+	inline void reset (T* t = 0)	{
+		if (ctr) {
+			ctr->decref(ptr);
+		}
+		ptr = t;
+		ctr = ptr?new detail::controller():NULL;
+	}
+
+	void swap(shared_ptr & b)	{
+		std::swap(ptr, b.ptr);
+		std::swap(ctr, b.ctr);
+	}
+
+private:
+
+
+	// for use by the various xxx_pointer_cast helper templates
+	explicit shared_ptr(T* ptr, detail::controller* ctr)
+		: ptr(ptr)
+		, ctr(ctr->incref())
+	{
+	}
+
+private:
+
+	// encapsulated object pointer
+	T* ptr;
+
+	// control block
+	detail::controller* ctr;
+};
+
+template<class T>
+inline void swap(shared_ptr<T> & a, shared_ptr<T> & b)
+{
+	a.swap(b);
+}
+
+template<class T>
+bool operator== (const shared_ptr<T>& a, const shared_ptr<T>& b) {
+	return a.ptr == b.ptr;
+}
+template<class T>
+bool operator!= (const shared_ptr<T>& a, const shared_ptr<T>& b) {
+	return a.ptr != b.ptr;
+}
+	
+template<class T>
+bool operator< (const shared_ptr<T>& a, const shared_ptr<T>& b) {
+	return a.ptr < b.ptr;
+}
+
+
+template<class T, class U>
+inline shared_ptr<T> static_pointer_cast( shared_ptr<U> ptr)
+{  
+   return shared_ptr<T>(static_cast<T*>(ptr.ptr),ptr.ctr);
+}
+
+template<class T, class U>
+inline shared_ptr<T> dynamic_pointer_cast( shared_ptr<U> ptr)
+{  
+   return shared_ptr<T>(dynamic_cast<T*>(ptr.ptr),ptr.ctr);
+}
+
+template<class T, class U>
+inline shared_ptr<T> const_pointer_cast( shared_ptr<U> ptr)
+{  
+   return shared_ptr<T>(const_cast<T*>(ptr.ptr),ptr.ctr);
+}
+
+
+
+} // end of namespace boost
+
+#else
+#	error "shared_ptr.h was already included"
+#endif
+#endif // INCLUDED_AI_BOOST_SHARED_PTR

+ 20 - 20
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/static_assert.hpp

@@ -1,20 +1,20 @@
-
-#ifndef AI_BOOST_STATIC_ASSERT_INCLUDED
-#define AI_BOOST_STATIC_ASSERT_INCLUDED
-
-#ifndef BOOST_STATIC_ASSERT
-
-namespace boost {
-	namespace detail {
-
-		template <bool b>  class static_assertion_failure;
-		template <>        class static_assertion_failure<true> {};
-	}
-}
-
-
-#define BOOST_STATIC_ASSERT(eval) \
-{boost::detail::static_assertion_failure<(eval)> assert_dummy;(void)assert_dummy;}
-
-#endif
-#endif // !! AI_BOOST_STATIC_ASSERT_INCLUDED
+
+#ifndef AI_BOOST_STATIC_ASSERT_INCLUDED
+#define AI_BOOST_STATIC_ASSERT_INCLUDED
+
+#ifndef BOOST_STATIC_ASSERT
+
+namespace boost {
+	namespace detail {
+
+		template <bool b>  class static_assertion_failure;
+		template <>        class static_assertion_failure<true> {};
+	}
+}
+
+
+#define BOOST_STATIC_ASSERT(eval) \
+{boost::detail::static_assertion_failure<(eval)> assert_dummy;(void)assert_dummy;}
+
+#endif
+#endif // !! AI_BOOST_STATIC_ASSERT_INCLUDED

+ 73 - 73
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/timer.hpp

@@ -1,73 +1,73 @@
-//  boost timer.hpp header file  ---------------------------------------------//
-
-//  Copyright Beman Dawes 1994-99.  Distributed under the Boost
-//  Software License, Version 1.0. (See accompanying file
-//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-
-//  See http://www.boost.org/libs/timer for documentation.
-
-//  Revision History
-//  01 Apr 01  Modified to use new <boost/limits.hpp> header. (JMaddock)
-//  12 Jan 01  Change to inline implementation to allow use without library
-//             builds. See docs for more rationale. (Beman Dawes) 
-//  25 Sep 99  elapsed_max() and elapsed_min() added (John Maddock)
-//  16 Jul 99  Second beta
-//   6 Jul 99  Initial boost version
-
-#ifndef BOOST_TIMER_HPP
-#define BOOST_TIMER_HPP
-
-//#include <boost/config.hpp>
-#include <ctime>
-#include <limits>
-//#include <boost/limits.hpp>
-
-# ifdef BOOST_NO_STDC_NAMESPACE
-    namespace std { using ::clock_t; using ::clock; }
-# endif
-
-
-namespace boost {
-
-//  timer  -------------------------------------------------------------------//
-
-//  A timer object measures elapsed time.
-
-//  It is recommended that implementations measure wall clock rather than CPU
-//  time since the intended use is performance measurement on systems where
-//  total elapsed time is more important than just process or CPU time.
-
-//  Warnings: The maximum measurable elapsed time may well be only 596.5+ hours
-//  due to implementation limitations.  The accuracy of timings depends on the
-//  accuracy of timing information provided by the underlying platform, and
-//  this varies a great deal from platform to platform.
-
-class timer
-{
- public:
-         timer() { _start_time = std::clock(); } // postcondition: elapsed()==0
-//         timer( const timer& src );      // post: elapsed()==src.elapsed()
-//        ~timer(){}
-//  timer& operator=( const timer& src );  // post: elapsed()==src.elapsed()
-  void   restart() { _start_time = std::clock(); } // post: elapsed()==0
-  double elapsed() const                  // return elapsed time in seconds
-    { return  double(std::clock() - _start_time) / CLOCKS_PER_SEC; }
-
-  double elapsed_max() const   // return estimated maximum value for elapsed()
-  // Portability warning: elapsed_max() may return too high a value on systems
-  // where std::clock_t overflows or resets at surprising values.
-  {
-    return (double((std::numeric_limits<std::clock_t>::max)())
-       - double(_start_time)) / double(CLOCKS_PER_SEC); 
-  }
-
-  double elapsed_min() const            // return minimum value for elapsed()
-   { return double(1)/double(CLOCKS_PER_SEC); }
-
- private:
-  std::clock_t _start_time;
-}; // timer
-
-} // namespace boost
-
-#endif  // BOOST_TIMER_HPP
+//  boost timer.hpp header file  ---------------------------------------------//
+
+//  Copyright Beman Dawes 1994-99.  Distributed under the Boost
+//  Software License, Version 1.0. (See accompanying file
+//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org/libs/timer for documentation.
+
+//  Revision History
+//  01 Apr 01  Modified to use new <boost/limits.hpp> header. (JMaddock)
+//  12 Jan 01  Change to inline implementation to allow use without library
+//             builds. See docs for more rationale. (Beman Dawes) 
+//  25 Sep 99  elapsed_max() and elapsed_min() added (John Maddock)
+//  16 Jul 99  Second beta
+//   6 Jul 99  Initial boost version
+
+#ifndef BOOST_TIMER_HPP
+#define BOOST_TIMER_HPP
+
+//#include <boost/config.hpp>
+#include <ctime>
+#include <limits>
+//#include <boost/limits.hpp>
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+    namespace std { using ::clock_t; using ::clock; }
+# endif
+
+
+namespace boost {
+
+//  timer  -------------------------------------------------------------------//
+
+//  A timer object measures elapsed time.
+
+//  It is recommended that implementations measure wall clock rather than CPU
+//  time since the intended use is performance measurement on systems where
+//  total elapsed time is more important than just process or CPU time.
+
+//  Warnings: The maximum measurable elapsed time may well be only 596.5+ hours
+//  due to implementation limitations.  The accuracy of timings depends on the
+//  accuracy of timing information provided by the underlying platform, and
+//  this varies a great deal from platform to platform.
+
+class timer
+{
+ public:
+         timer() { _start_time = std::clock(); } // postcondition: elapsed()==0
+//         timer( const timer& src );      // post: elapsed()==src.elapsed()
+//        ~timer(){}
+//  timer& operator=( const timer& src );  // post: elapsed()==src.elapsed()
+  void   restart() { _start_time = std::clock(); } // post: elapsed()==0
+  double elapsed() const                  // return elapsed time in seconds
+    { return  double(std::clock() - _start_time) / CLOCKS_PER_SEC; }
+
+  double elapsed_max() const   // return estimated maximum value for elapsed()
+  // Portability warning: elapsed_max() may return too high a value on systems
+  // where std::clock_t overflows or resets at surprising values.
+  {
+    return (double((std::numeric_limits<std::clock_t>::max)())
+       - double(_start_time)) / double(CLOCKS_PER_SEC); 
+  }
+
+  double elapsed_min() const            // return minimum value for elapsed()
+   { return double(1)/double(CLOCKS_PER_SEC); }
+
+ private:
+  std::clock_t _start_time;
+}; // timer
+
+} // namespace boost
+
+#endif  // BOOST_TIMER_HPP

+ 283 - 283
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/tuple/tuple.hpp

@@ -1,283 +1,283 @@
-// A very small replacement for boost::tuple
-// (c) Alexander Gessler, 2008 [[email protected]]
-
-#ifndef BOOST_TUPLE_INCLUDED
-#define BOOST_TUPLE_INCLUDED
-
-namespace boost	{
-	namespace detail	{
-
-		// Represents an empty tuple slot (up to 5 supported)
-		struct nulltype {};
-
-		// For readable error messages
-		struct tuple_component_idx_out_of_bounds;
-
-		// To share some code for the const/nonconst versions of the getters
-		template <bool b, typename T>
-		struct ConstIf {
-			typedef T t;
-		};
-
-		template <typename T>
-		struct ConstIf<true,T> {
-			typedef const T t;
-		};
-
-		// Predeclare some stuff
-		template <typename, unsigned, typename, bool, unsigned> struct value_getter;
-
-		// Helper to obtain the type of a tuple element
-		template <typename T, unsigned NIDX, typename TNEXT, unsigned N /*= 0*/>
-		struct type_getter	{
-			typedef type_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,N> next_elem_getter;
-			typedef typename next_elem_getter::type type;
-		};
-
-		template <typename T, unsigned NIDX, typename TNEXT >
-		struct type_getter <T,NIDX,TNEXT,NIDX>	{
-			typedef T type;
-		};
-
-		// Base class for all explicit specializations of list_elem
-		template <typename T, unsigned NIDX, typename TNEXT >
-		struct list_elem_base {
-
-			// Store template parameters
-			typedef TNEXT next_type;
-			typedef T type;
-
-			static const unsigned nidx = NIDX;
-		};
-
-		// Represents an element in the tuple component list
-		template <typename T, unsigned NIDX, typename TNEXT >
-		struct list_elem : list_elem_base<T,NIDX,TNEXT>{
-
-			// Real members
-			T me;
-			TNEXT next;
-
-			// Get the value of a specific tuple element
-			template <unsigned N>
-			typename type_getter<T,NIDX,TNEXT,N>::type& get () {
-				value_getter <T,NIDX,TNEXT,false,N> s;
-				return s(*this);
-			}
-
-			// Get the value of a specific tuple element
-			template <unsigned N>
-			const typename type_getter<T,NIDX,TNEXT,N>::type& get () const {
-				value_getter <T,NIDX,TNEXT,true,N> s;
-				return s(*this);
-			}
-
-			// Explicit cast
-			template <typename T2, typename TNEXT2 >
-			operator list_elem<T2,NIDX,TNEXT2> () const	{
-				list_elem<T2,NIDX,TNEXT2> ret;
-				ret.me   = (T2)me;
-				ret.next = next;
-				return ret;
-			}
-
-			// Recursively compare two elements (last element returns always true)
-			bool operator == (const list_elem& s) const	{
-				return (me == s.me && next == s.next);
-			}
-		};
-
-		// Represents a non-used tuple element - the very last element processed
-		template <typename TNEXT, unsigned NIDX  >
-		struct list_elem<nulltype,NIDX,TNEXT> : list_elem_base<nulltype,NIDX,TNEXT> {
-			template <unsigned N, bool IS_CONST = true> struct value_getter		{
-				/* just dummy members to produce readable error messages */
-				tuple_component_idx_out_of_bounds operator () (typename ConstIf<IS_CONST,list_elem>::t& me);
-			};
-			template <unsigned N> struct type_getter  {
-				/* just dummy members to produce readable error messages */
-				typedef tuple_component_idx_out_of_bounds type;
-			};
-
-			// dummy
-			list_elem& operator = (const list_elem& /*other*/)	{
-				return *this;
-			}
-
-			// dummy
-			bool operator == (const list_elem& other)	{
-				return true;
-			}
-		};
-
-		// Represents the absolute end of the list
-		typedef list_elem<nulltype,0,int> list_end;
-
-		// Helper obtain to query the value of a tuple element
-		// NOTE: This can't be a nested class as the compiler won't accept a full or
-		// partial specialization of a nested class of a non-specialized template
-		template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST, unsigned N>
-		struct value_getter	 {
-
-			// calling list_elem
-			typedef list_elem<T,NIDX,TNEXT> outer_elem;
-
-			// typedef for the getter for next element
-			typedef value_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,
-				IS_CONST, N> next_value_getter;
-
-			typename ConstIf<IS_CONST,typename type_getter<T,NIDX,TNEXT,N>::type>::t&
-				operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
-
-				next_value_getter s;
-				return s(me.next);
-			}
-		};
-
-		template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST>
-		struct value_getter <T,NIDX,TNEXT,IS_CONST,NIDX>	{
-			typedef list_elem<T,NIDX,TNEXT> outer_elem;
-
-			typename ConstIf<IS_CONST,T>::t& operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
-				return me.me;
-			}
-		};
-	}
-
-	// A very minimal implementation for up to 5 elements
-	template <typename T0  = detail::nulltype,
-		      typename T1  = detail::nulltype,
-			  typename T2  = detail::nulltype,
-			  typename T3  = detail::nulltype,
-			  typename T4  = detail::nulltype>
-	class tuple	{
-
-		template <typename T0b,
-		      typename T1b,
-			  typename T2b,
-			  typename T3b,
-			  typename T4b >
-		friend class tuple;
-
-	private:
-
-		typedef detail::list_elem<T0,0,
-					detail::list_elem<T1,1,
-						detail::list_elem<T2,2,
-							detail::list_elem<T3,3,
-								detail::list_elem<T4,4,
-									detail::list_end > > > > > very_long;
-
-		very_long m;
-
-	public:
-
-		// Get a specific tuple element
-		template <unsigned N>
-		typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get ()	{
-			return m.template get<N>();
-		}
-
-		// ... and the const version
-		template <unsigned N>
-		const typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () const	{
-			return m.template get<N>();
-		}
-
-
-		// comparison operators
-		bool operator== (const tuple& other) const	{
-			return m == other.m;
-		}
-
-		// ... and the other way round
-		bool operator!= (const tuple& other) const	{
-			return !(m == other.m);
-		}
-
-		// cast to another tuple - all single elements must be convertible
-		template <typename T0b, typename T1b,typename T2b,typename T3b, typename T4b>
-		operator tuple <T0b,T1b,T2b,T3b,T4b> () const {
-			tuple <T0b,T1b,T2b,T3b,T4b> s;
-			s.m = (typename tuple <T0b,T1b,T2b,T3b,T4b>::very_long)m;
-			return s;
-		}
-	};
-
-	// Another way to access an element ...
-	template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
-	inline typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get (
-			tuple<T0,T1,T2,T3,T4>& m)	{
-			return m.template get<N>();
-		}
-
-	// ... and the const version
-	template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
-	inline const typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get (
-			const tuple<T0,T1,T2,T3,T4>& m)	{
-			return m.template get<N>();
-		}
-
-	// Constructs a tuple with 5 elements
-	template <typename T0,typename T1,typename T2,typename T3,typename T4>
-	inline tuple <T0,T1,T2,T3,T4> make_tuple (const T0& t0,
-		const T1& t1,const T2& t2,const T3& t3,const T4& t4) {
-
-		tuple <T0,T1,T2,T3,T4> t;
-		t.template get<0>() = t0;
-		t.template get<1>() = t1;
-		t.template get<2>() = t2;
-		t.template get<3>() = t3;
-		t.template get<4>() = t4;
-		return t;
-	}
-
-	// Constructs a tuple with 4 elements
-	template <typename T0,typename T1,typename T2,typename T3>
-	inline tuple <T0,T1,T2,T3> make_tuple (const T0& t0,
-		const T1& t1,const T2& t2,const T3& t3) {
-		tuple <T0,T1,T2,T3> t;
-		t.template get<0>() = t0;
-		t.template get<1>() = t1;
-		t.template get<2>() = t2;
-		t.template get<3>() = t3;
-		return t;
-	}
-
-	// Constructs a tuple with 3 elements
-	template <typename T0,typename T1,typename T2>
-	inline tuple <T0,T1,T2> make_tuple (const T0& t0,
-		const T1& t1,const T2& t2) {
-		tuple <T0,T1,T2> t;
-		t.template get<0>() = t0;
-		t.template get<1>() = t1;
-		t.template get<2>() = t2;
-		return t;
-	}
-
-	// Constructs a tuple with 2 elements 
-	template <typename T0,typename T1>
-	inline tuple <T0,T1> make_tuple (const T0& t0,
-		const T1& t1) {
-		tuple <T0,T1> t;
-		t.template get<0>() = t0;
-		t.template get<1>() = t1;
-		return t;
-	}
-
-	// Constructs a tuple with 1 elements (well ...)
-	template <typename T0>
-	inline tuple <T0> make_tuple (const T0& t0) {
-		tuple <T0> t;
-		t.template get<0>() = t0;
-		return t;
-	}
-
-	// Constructs a tuple with 0 elements (well ...)
-	inline tuple <> make_tuple () {
-		tuple <> t;
-		return t;
-	}
-}
-
-#endif // !! BOOST_TUPLE_INCLUDED
+// A very small replacement for boost::tuple
+// (c) Alexander Gessler, 2008 [[email protected]]
+
+#ifndef BOOST_TUPLE_INCLUDED
+#define BOOST_TUPLE_INCLUDED
+
+namespace boost	{
+	namespace detail	{
+
+		// Represents an empty tuple slot (up to 5 supported)
+		struct nulltype {};
+
+		// For readable error messages
+		struct tuple_component_idx_out_of_bounds;
+
+		// To share some code for the const/nonconst versions of the getters
+		template <bool b, typename T>
+		struct ConstIf {
+			typedef T t;
+		};
+
+		template <typename T>
+		struct ConstIf<true,T> {
+			typedef const T t;
+		};
+
+		// Predeclare some stuff
+		template <typename, unsigned, typename, bool, unsigned> struct value_getter;
+
+		// Helper to obtain the type of a tuple element
+		template <typename T, unsigned NIDX, typename TNEXT, unsigned N /*= 0*/>
+		struct type_getter	{
+			typedef type_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,N> next_elem_getter;
+			typedef typename next_elem_getter::type type;
+		};
+
+		template <typename T, unsigned NIDX, typename TNEXT >
+		struct type_getter <T,NIDX,TNEXT,NIDX>	{
+			typedef T type;
+		};
+
+		// Base class for all explicit specializations of list_elem
+		template <typename T, unsigned NIDX, typename TNEXT >
+		struct list_elem_base {
+
+			// Store template parameters
+			typedef TNEXT next_type;
+			typedef T type;
+
+			static const unsigned nidx = NIDX;
+		};
+
+		// Represents an element in the tuple component list
+		template <typename T, unsigned NIDX, typename TNEXT >
+		struct list_elem : list_elem_base<T,NIDX,TNEXT>{
+
+			// Real members
+			T me;
+			TNEXT next;
+
+			// Get the value of a specific tuple element
+			template <unsigned N>
+			typename type_getter<T,NIDX,TNEXT,N>::type& get () {
+				value_getter <T,NIDX,TNEXT,false,N> s;
+				return s(*this);
+			}
+
+			// Get the value of a specific tuple element
+			template <unsigned N>
+			const typename type_getter<T,NIDX,TNEXT,N>::type& get () const {
+				value_getter <T,NIDX,TNEXT,true,N> s;
+				return s(*this);
+			}
+
+			// Explicit cast
+			template <typename T2, typename TNEXT2 >
+			operator list_elem<T2,NIDX,TNEXT2> () const	{
+				list_elem<T2,NIDX,TNEXT2> ret;
+				ret.me   = (T2)me;
+				ret.next = next;
+				return ret;
+			}
+
+			// Recursively compare two elements (last element returns always true)
+			bool operator == (const list_elem& s) const	{
+				return (me == s.me && next == s.next);
+			}
+		};
+
+		// Represents a non-used tuple element - the very last element processed
+		template <typename TNEXT, unsigned NIDX  >
+		struct list_elem<nulltype,NIDX,TNEXT> : list_elem_base<nulltype,NIDX,TNEXT> {
+			template <unsigned N, bool IS_CONST = true> struct value_getter		{
+				/* just dummy members to produce readable error messages */
+				tuple_component_idx_out_of_bounds operator () (typename ConstIf<IS_CONST,list_elem>::t& me);
+			};
+			template <unsigned N> struct type_getter  {
+				/* just dummy members to produce readable error messages */
+				typedef tuple_component_idx_out_of_bounds type;
+			};
+
+			// dummy
+			list_elem& operator = (const list_elem& /*other*/)	{
+				return *this;
+			}
+
+			// dummy
+			bool operator == (const list_elem& other)	{
+				return true;
+			}
+		};
+
+		// Represents the absolute end of the list
+		typedef list_elem<nulltype,0,int> list_end;
+
+		// Helper obtain to query the value of a tuple element
+		// NOTE: This can't be a nested class as the compiler won't accept a full or
+		// partial specialization of a nested class of a non-specialized template
+		template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST, unsigned N>
+		struct value_getter	 {
+
+			// calling list_elem
+			typedef list_elem<T,NIDX,TNEXT> outer_elem;
+
+			// typedef for the getter for next element
+			typedef value_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,
+				IS_CONST, N> next_value_getter;
+
+			typename ConstIf<IS_CONST,typename type_getter<T,NIDX,TNEXT,N>::type>::t&
+				operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
+
+				next_value_getter s;
+				return s(me.next);
+			}
+		};
+
+		template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST>
+		struct value_getter <T,NIDX,TNEXT,IS_CONST,NIDX>	{
+			typedef list_elem<T,NIDX,TNEXT> outer_elem;
+
+			typename ConstIf<IS_CONST,T>::t& operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) {
+				return me.me;
+			}
+		};
+	}
+
+	// A very minimal implementation for up to 5 elements
+	template <typename T0  = detail::nulltype,
+		      typename T1  = detail::nulltype,
+			  typename T2  = detail::nulltype,
+			  typename T3  = detail::nulltype,
+			  typename T4  = detail::nulltype>
+	class tuple	{
+
+		template <typename T0b,
+		      typename T1b,
+			  typename T2b,
+			  typename T3b,
+			  typename T4b >
+		friend class tuple;
+
+	private:
+
+		typedef detail::list_elem<T0,0,
+					detail::list_elem<T1,1,
+						detail::list_elem<T2,2,
+							detail::list_elem<T3,3,
+								detail::list_elem<T4,4,
+									detail::list_end > > > > > very_long;
+
+		very_long m;
+
+	public:
+
+		// Get a specific tuple element
+		template <unsigned N>
+		typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get ()	{
+			return m.template get<N>();
+		}
+
+		// ... and the const version
+		template <unsigned N>
+		const typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () const	{
+			return m.template get<N>();
+		}
+
+
+		// comparison operators
+		bool operator== (const tuple& other) const	{
+			return m == other.m;
+		}
+
+		// ... and the other way round
+		bool operator!= (const tuple& other) const	{
+			return !(m == other.m);
+		}
+
+		// cast to another tuple - all single elements must be convertible
+		template <typename T0b, typename T1b,typename T2b,typename T3b, typename T4b>
+		operator tuple <T0b,T1b,T2b,T3b,T4b> () const {
+			tuple <T0b,T1b,T2b,T3b,T4b> s;
+			s.m = (typename tuple <T0b,T1b,T2b,T3b,T4b>::very_long)m;
+			return s;
+		}
+	};
+
+	// Another way to access an element ...
+	template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
+	inline typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get (
+			tuple<T0,T1,T2,T3,T4>& m)	{
+			return m.template get<N>();
+		}
+
+	// ... and the const version
+	template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4>
+	inline const typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get (
+			const tuple<T0,T1,T2,T3,T4>& m)	{
+			return m.template get<N>();
+		}
+
+	// Constructs a tuple with 5 elements
+	template <typename T0,typename T1,typename T2,typename T3,typename T4>
+	inline tuple <T0,T1,T2,T3,T4> make_tuple (const T0& t0,
+		const T1& t1,const T2& t2,const T3& t3,const T4& t4) {
+
+		tuple <T0,T1,T2,T3,T4> t;
+		t.template get<0>() = t0;
+		t.template get<1>() = t1;
+		t.template get<2>() = t2;
+		t.template get<3>() = t3;
+		t.template get<4>() = t4;
+		return t;
+	}
+
+	// Constructs a tuple with 4 elements
+	template <typename T0,typename T1,typename T2,typename T3>
+	inline tuple <T0,T1,T2,T3> make_tuple (const T0& t0,
+		const T1& t1,const T2& t2,const T3& t3) {
+		tuple <T0,T1,T2,T3> t;
+		t.template get<0>() = t0;
+		t.template get<1>() = t1;
+		t.template get<2>() = t2;
+		t.template get<3>() = t3;
+		return t;
+	}
+
+	// Constructs a tuple with 3 elements
+	template <typename T0,typename T1,typename T2>
+	inline tuple <T0,T1,T2> make_tuple (const T0& t0,
+		const T1& t1,const T2& t2) {
+		tuple <T0,T1,T2> t;
+		t.template get<0>() = t0;
+		t.template get<1>() = t1;
+		t.template get<2>() = t2;
+		return t;
+	}
+
+	// Constructs a tuple with 2 elements 
+	template <typename T0,typename T1>
+	inline tuple <T0,T1> make_tuple (const T0& t0,
+		const T1& t1) {
+		tuple <T0,T1> t;
+		t.template get<0>() = t0;
+		t.template get<1>() = t1;
+		return t;
+	}
+
+	// Constructs a tuple with 1 elements (well ...)
+	template <typename T0>
+	inline tuple <T0> make_tuple (const T0& t0) {
+		tuple <T0> t;
+		t.template get<0>() = t0;
+		return t;
+	}
+
+	// Constructs a tuple with 0 elements (well ...)
+	inline tuple <> make_tuple () {
+		tuple <> t;
+		return t;
+	}
+}
+
+#endif // !! BOOST_TUPLE_INCLUDED

+ 7 - 0
Source/ThirdParty/Assimp/code/ByteSwapper.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Helper class tp perform various byte oder swappings
    (e.g. little to big endian) */
 #ifndef AI_BYTESWAPPER_H_INC
@@ -45,7 +47,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "../include/assimp/ai_assert.h"
 #include "../include/assimp/types.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 #if _MSC_VER >= 1400
 #include <stdlib.h>

+ 644 - 0
Source/ThirdParty/Assimp/code/C4DImporter.cpp

@@ -0,0 +1,644 @@
+/*
+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  C4DImporter.cpp
+ *  @brief Implementation of the Cinema4D importer class.
+ */
+#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
+
+// no #ifdefing here, Cinema4D support is carried out in a branch of assimp
+// where it is turned on in the CMake settings.
+
+#ifndef _MSC_VER
+#   error C4D support is currently MSVC only
+#endif
+
+#include "C4DImporter.h"
+#include "TinyFormatter.h"
+
+#if defined(_M_X64) || defined(__amd64__)
+#   define __C4D_64BIT
+#endif
+
+#define __PC
+#include "c4d_file.h"
+#include "default_alien_overloads.h"
+
+using namespace _melange_;
+
+// overload this function and fill in your own unique data
+void GetWriterInfo(LONG &id, String &appname)
+{
+    id = 2424226;
+    appname = "Open Asset Import Library";
+}
+
+using namespace Assimp;
+using namespace Assimp::Formatter;
+
+namespace Assimp {
+    template<> const std::string LogFunctions<C4DImporter>::log_prefix = "C4D: ";
+}
+
+static const aiImporterDesc desc = {
+    "Cinema4D Importer",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportBinaryFlavour,
+    0,
+    0,
+    0,
+    0,
+    "c4d"
+};
+
+
+// ------------------------------------------------------------------------------------------------
+C4DImporter::C4DImporter()
+{}
+
+// ------------------------------------------------------------------------------------------------
+C4DImporter::~C4DImporter()
+{}
+
+// ------------------------------------------------------------------------------------------------
+bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+{
+    const std::string& extension = GetExtension(pFile);
+    if (extension == "c4d") {
+        return true;
+    }
+
+    else if ((!extension.length() || checkSig) && pIOHandler)   {
+        // TODO
+    }
+    return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiImporterDesc* C4DImporter::GetInfo () const
+{
+    return &desc;
+}
+
+// ------------------------------------------------------------------------------------------------
+void C4DImporter::SetupProperties(const Importer* /*pImp*/)
+{
+    // nothing to be done for the moment
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// Imports the given file into the given scene structure.
+void C4DImporter::InternReadFile( const std::string& pFile,
+    aiScene* pScene, IOSystem* pIOHandler)
+{
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
+
+    if( file.get() == NULL) {
+        ThrowException("failed to open file " + pFile);
+    }
+
+    const size_t file_size = file->FileSize();
+
+    std::vector<uint8_t> mBuffer(file_size);
+    file->Read(&mBuffer[0], 1, file_size);
+
+    Filename f;
+    f.SetMemoryReadMode(&mBuffer[0], file_size);
+
+    // open document first
+    BaseDocument* doc = LoadDocument(f, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS);
+    if(doc == NULL) {
+        ThrowException("failed to read document " + pFile);
+    }
+
+    pScene->mRootNode = new aiNode("<C4DRoot>");
+
+    // first convert all materials
+    ReadMaterials(doc->GetFirstMaterial());
+
+    // process C4D scenegraph recursively
+    try {
+        RecurseHierarchy(doc->GetFirstObject(), pScene->mRootNode);
+    }
+    catch(...) {
+        BOOST_FOREACH(aiMesh* mesh, meshes) {
+            delete mesh;
+        }
+        BaseDocument::Free(doc);
+        throw;
+    }
+    BaseDocument::Free(doc);
+
+    // copy meshes over
+    pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
+    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
+    std::copy(meshes.begin(), meshes.end(), pScene->mMeshes);
+
+    // copy materials over, adding a default material if necessary
+    unsigned int mat_count = static_cast<unsigned int>(materials.size());
+    BOOST_FOREACH(aiMesh* mesh, meshes) {
+        ai_assert(mesh->mMaterialIndex <= mat_count);
+        if(mesh->mMaterialIndex >= mat_count) {
+            ++mat_count;
+
+            ScopeGuard<aiMaterial> def_material(new aiMaterial());
+            const aiString name(AI_DEFAULT_MATERIAL_NAME);
+            def_material->AddProperty(&name, AI_MATKEY_NAME);
+
+            materials.push_back(def_material.dismiss());
+            break;
+        }
+    }
+
+    pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
+    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]();
+    std::copy(materials.begin(), materials.end(), pScene->mMaterials);
+}
+
+
+// ------------------------------------------------------------------------------------------------
+bool C4DImporter::ReadShader(aiMaterial* out, _melange_::BaseShader* shader)
+{
+    // based on Melange sample code (C4DImportExport.cpp)
+    while(shader) {
+        if(shader->GetType() == Xlayer) {
+            BaseContainer* container = shader->GetDataInstance();
+            GeData blend = container->GetData(SLA_LAYER_BLEND);
+            iBlendDataType* blend_list = reinterpret_cast<iBlendDataType*>(blend.GetCustomDataType(CUSTOMDATA_BLEND_LIST));
+            if (!blend_list)
+            {
+                LogWarn("ignoring XLayer shader: no blend list given");
+                continue;
+            }
+
+            LayerShaderLayer *lsl = dynamic_cast<LayerShaderLayer*>(blend_list->m_BlendLayers.GetObject(0));
+
+            // Ignore the actual layer blending - models for real-time rendering should not
+            // use them in a non-trivial way. Just try to find textures that we can apply
+            // to the model.
+            while (lsl)
+            {
+                if (lsl->GetType() == TypeFolder)
+                {
+                    BlendFolder* const folder = dynamic_cast<BlendFolder*>(lsl);
+                    LayerShaderLayer *subLsl = dynamic_cast<LayerShaderLayer*>(folder->m_Children.GetObject(0));
+
+                    while (subLsl)
+                    {
+                        if (subLsl->GetType() == TypeShader) {
+                            BlendShader* const shader = dynamic_cast<BlendShader*>(subLsl);
+                            if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
+                                return true;
+                            }
+                        }
+
+                        subLsl = subLsl->GetNext();
+                    }
+                }
+                else if (lsl->GetType() == TypeShader) {
+                    BlendShader* const shader = dynamic_cast<BlendShader*>(lsl);
+                    if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
+                        return true;
+                    }
+                }
+
+                lsl = lsl->GetNext();
+            }
+        }
+        else if ( shader->GetType() == Xbitmap )
+        {
+            aiString path;
+            shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1);
+            path.length = ::strlen(path.data);
+            out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
+            return true;
+        }
+        else {
+            LogWarn("ignoring shader type: " + std::string(GetObjectTypeName(shader->GetType())));
+        }
+        shader = shader->GetNext();
+    }
+    return false;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+void C4DImporter::ReadMaterials(_melange_::BaseMaterial* mat)
+{
+    // based on Melange sample code
+    while (mat)
+    {
+        const String& name = mat->GetName();
+        if (mat->GetType() == Mmaterial)
+        {
+            aiMaterial* out = new aiMaterial();
+            material_mapping[mat] = static_cast<unsigned int>(materials.size());
+            materials.push_back(out);
+
+            aiString ai_name;
+            name.GetCString(ai_name.data, MAXLEN-1);
+            ai_name.length = ::strlen(ai_name.data);
+            out->AddProperty(&ai_name, AI_MATKEY_NAME);
+
+            Material& m = dynamic_cast<Material&>(*mat);
+
+            if (m.GetChannelState(CHANNEL_COLOR))
+            {
+                GeData data;
+                mat->GetParameter(MATERIAL_COLOR_COLOR, data);
+                Vector color = data.GetVector();
+                mat->GetParameter(MATERIAL_COLOR_BRIGHTNESS, data);
+                const Real brightness = data.GetReal();
+
+                color *= brightness;
+
+                aiVector3D v;
+                v.x = color.x;
+                v.y = color.y;
+                v.z = color.z;
+                out->AddProperty(&v, 1, AI_MATKEY_COLOR_DIFFUSE);
+            }
+
+            BaseShader* const shader = m.GetShader(MATERIAL_COLOR_SHADER);
+            if(shader) {
+                ReadShader(out, shader);
+            }
+        }
+        else
+        {
+            LogWarn("ignoring plugin material: " + std::string(GetObjectTypeName(mat->GetType())));
+        }
+        mat = mat->GetNext();
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent)
+{
+    ai_assert(parent != NULL);
+    std::vector<aiNode*> nodes;
+
+    // based on Melange sample code
+    while (object)
+    {
+        const String& name = object->GetName();
+        const LONG type = object->GetType();
+        const Matrix& ml = object->GetMl();
+
+        aiString string;
+        name.GetCString(string.data, MAXLEN-1);
+        string.length = ::strlen(string.data);
+        aiNode* const nd = new aiNode();
+
+        nd->mParent = parent;
+        nd->mName = string;
+
+        nd->mTransformation.a1 = ml.v1.x;
+        nd->mTransformation.b1 = ml.v1.y;
+        nd->mTransformation.c1 = ml.v1.z;
+
+        nd->mTransformation.a2 = ml.v2.x;
+        nd->mTransformation.b2 = ml.v2.y;
+        nd->mTransformation.c2 = ml.v2.z;
+
+        nd->mTransformation.a3 = ml.v3.x;
+        nd->mTransformation.b3 = ml.v3.y;
+        nd->mTransformation.c3 = ml.v3.z;
+
+        nd->mTransformation.a4 = ml.off.x;
+        nd->mTransformation.b4 = ml.off.y;
+        nd->mTransformation.c4 = ml.off.z;
+
+        nodes.push_back(nd);
+
+        GeData data;
+        if (type == Ocamera)
+        {
+            object->GetParameter(CAMERAOBJECT_FOV, data);
+            // TODO: read camera
+        }
+        else if (type == Olight)
+        {
+            // TODO: read light
+        }
+        else if (type == Opolygon)
+        {
+            aiMesh* const mesh = ReadMesh(object);
+            if(mesh != NULL) {
+                nd->mNumMeshes = 1;
+                nd->mMeshes = new unsigned int[1];
+                nd->mMeshes[0] = static_cast<unsigned int>(meshes.size());
+                meshes.push_back(mesh);
+            }
+        }
+        else {
+            LogWarn("ignoring object: " + std::string(GetObjectTypeName(type)));
+        }
+
+        RecurseHierarchy(object->GetDown(), nd);
+        object = object->GetNext();
+    }
+
+    // copy nodes over to parent
+    parent->mNumChildren = static_cast<unsigned int>(nodes.size());
+    parent->mChildren = new aiNode*[parent->mNumChildren]();
+    std::copy(nodes.begin(), nodes.end(), parent->mChildren);
+}
+
+
+// ------------------------------------------------------------------------------------------------
+aiMesh* C4DImporter::ReadMesh(BaseObject* object)
+{
+    assert(object != NULL && object->GetType() == Opolygon);
+
+    // based on Melange sample code
+    PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
+    ai_assert(polyObject != NULL);
+
+    const LONG pointCount = polyObject->GetPointCount();
+    const LONG polyCount = polyObject->GetPolygonCount();
+    if(!polyObject || !pointCount) {
+        LogWarn("ignoring mesh with zero vertices or faces");
+        return NULL;
+    }
+
+    const Vector* points = polyObject->GetPointR();
+    ai_assert(points != NULL);
+
+    const CPolygon* polys = polyObject->GetPolygonR();
+    ai_assert(polys != NULL);
+
+    ScopeGuard<aiMesh> mesh(new aiMesh());
+    mesh->mNumFaces = static_cast<unsigned int>(polyCount);
+    aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
+
+    mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+    mesh->mMaterialIndex = 0;
+
+    unsigned int vcount = 0;
+
+    // first count vertices
+    for (LONG i = 0; i < polyCount; i++)
+    {
+        vcount += 3;
+
+        // TODO: do we also need to handle lines or points with similar checks?
+        if (polys[i].c != polys[i].d)
+        {
+            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+            ++vcount;
+        }
+    }
+
+    ai_assert(vcount > 0);
+
+    mesh->mNumVertices = vcount;
+    aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+    aiVector3D* normals, *uvs, *tangents, *bitangents;
+    unsigned int n = 0;
+
+    // check if there are normals, tangents or UVW coordinates
+    BaseTag* tag = object->GetTag(Tnormal);
+    NormalTag* normals_src = NULL;
+    if(tag) {
+        normals_src = dynamic_cast<NormalTag*>(tag);
+        normals = mesh->mNormals = new aiVector3D[mesh->mNumVertices]();
+    }
+
+    tag = object->GetTag(Ttangent);
+    TangentTag* tangents_src = NULL;
+    if(tag) {
+        tangents_src = dynamic_cast<TangentTag*>(tag);
+        tangents = mesh->mTangents = new aiVector3D[mesh->mNumVertices]();
+        bitangents = mesh->mBitangents = new aiVector3D[mesh->mNumVertices]();
+    }
+
+    tag = object->GetTag(Tuvw);
+    UVWTag* uvs_src = NULL;
+    if(tag) {
+        uvs_src = dynamic_cast<UVWTag*>(tag);
+        uvs = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]();
+    }
+
+    // copy vertices and extra channels over and populate faces
+    for (LONG i = 0; i < polyCount; ++i, ++face)
+    {
+        ai_assert(polys[i].a < pointCount && polys[i].a >= 0);
+        const Vector& pointA = points[polys[i].a];
+        verts->x = pointA.x;
+        verts->y = pointA.y;
+        verts->z = pointA.z;
+        ++verts;
+
+        ai_assert(polys[i].b < pointCount && polys[i].b >= 0);
+        const Vector& pointB = points[polys[i].b];
+        verts->x = pointB.x;
+        verts->y = pointB.y;
+        verts->z = pointB.z;
+        ++verts;
+
+        ai_assert(polys[i].c < pointCount && polys[i].c >= 0);
+        const Vector& pointC = points[polys[i].c];
+        verts->x = pointC.x;
+        verts->y = pointC.y;
+        verts->z = pointC.z;
+        ++verts;
+
+        // TODO: do we also need to handle lines or points with similar checks?
+        if (polys[i].c != polys[i].d)
+        {
+            ai_assert(polys[i].d < pointCount && polys[i].d >= 0);
+
+            face->mNumIndices = 4;
+            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+            const Vector& pointD = points[polys[i].d];
+            verts->x = pointD.x;
+            verts->y = pointD.y;
+            verts->z = pointD.z;
+            ++verts;
+        }
+        else {
+            face->mNumIndices = 3;
+        }
+        face->mIndices = new unsigned int[face->mNumIndices];
+        for(unsigned int j = 0; j < face->mNumIndices; ++j) {
+            face->mIndices[j] = n++;
+        }
+
+        // copy normals
+        if (normals_src) {
+            if(i >= normals_src->GetNormalCount()) {
+                LogError("unexpected number of normals, ignoring");
+            }
+            else {
+                const NormalStruct& nor = normals_src->GetNormals(i);
+                normals->x = nor.a.x;
+                normals->y = nor.a.y;
+                normals->z = nor.a.z;
+                ++normals;
+
+                normals->x = nor.b.x;
+                normals->y = nor.b.y;
+                normals->z = nor.b.z;
+                ++normals;
+
+                normals->x = nor.c.x;
+                normals->y = nor.c.y;
+                normals->z = nor.c.z;
+                ++normals;
+
+                if(face->mNumIndices == 4) {
+                    normals->x = nor.d.x;
+                    normals->y = nor.d.y;
+                    normals->z = nor.d.z;
+                    ++normals;
+                }
+            }
+        }
+
+        // copy tangents and bitangents
+        if (tangents_src) {
+
+            for(unsigned int k = 0; k < face->mNumIndices; ++k) {
+                LONG l;
+                switch(k) {
+                case 0:
+                    l = polys[i].a;
+                    break;
+                case 1:
+                    l = polys[i].b;
+                    break;
+                case 2:
+                    l = polys[i].c;
+                    break;
+                case 3:
+                    l = polys[i].d;
+                    break;
+                default:
+                    ai_assert(false);
+                }
+                if(l >= tangents_src->GetDataCount()) {
+                    LogError("unexpected number of tangents, ignoring");
+                    break;
+                }
+
+                Tangent tan = tangents_src->GetDataR()[l];
+                tangents->x = tan.vl.x;
+                tangents->y = tan.vl.y;
+                tangents->z = tan.vl.z;
+                ++tangents;
+
+                bitangents->x = tan.vr.x;
+                bitangents->y = tan.vr.y;
+                bitangents->z = tan.vr.z;
+                ++bitangents;
+            }
+        }
+
+        // copy UVs
+        if (uvs_src) {
+            if(i >= uvs_src->GetDataCount()) {
+                LogError("unexpected number of UV coordinates, ignoring");
+            }
+            else {
+                UVWStruct uvw;
+                uvs_src->Get(uvs_src->GetDataAddressR(),i,uvw);
+
+                uvs->x = uvw.a.x;
+                uvs->y = 1.0f-uvw.a.y;
+                uvs->z = uvw.a.z;
+                ++uvs;
+
+                uvs->x = uvw.b.x;
+                uvs->y = 1.0f-uvw.b.y;
+                uvs->z = uvw.b.z;
+                ++uvs;
+
+                uvs->x = uvw.c.x;
+                uvs->y = 1.0f-uvw.c.y;
+                uvs->z = uvw.c.z;
+                ++uvs;
+
+                if(face->mNumIndices == 4) {
+                    uvs->x = uvw.d.x;
+                    uvs->y = 1.0f-uvw.d.y;
+                    uvs->z = uvw.d.z;
+                    ++uvs;
+                }
+            }
+        }
+    }
+
+    mesh->mMaterialIndex = ResolveMaterial(polyObject);
+    return mesh.dismiss();
+}
+
+
+// ------------------------------------------------------------------------------------------------
+unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj)
+{
+    ai_assert(obj != NULL);
+
+    const unsigned int mat_count = static_cast<unsigned int>(materials.size());
+
+    BaseTag* tag = obj->GetTag(Ttexture);
+    if(tag == NULL) {
+        return mat_count;
+    }
+
+    TextureTag& ttag = dynamic_cast<TextureTag&>(*tag);
+
+    BaseMaterial* const mat = ttag.GetMaterial();
+    assert(mat != NULL);
+
+    const MaterialMap::const_iterator it = material_mapping.find(mat);
+    if(it == material_mapping.end()) {
+        return mat_count;
+    }
+
+    ai_assert((*it).second < mat_count);
+    return (*it).second;
+}
+
+#endif // ASSIMP_BUILD_NO_C4D_IMPORTER
+

+ 123 - 0
Source/ThirdParty/Assimp/code/C4DImporter.h

@@ -0,0 +1,123 @@
+/*
+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  C4DImporter.h
+ *  @brief Declaration of the Cinema4D (*.c4d) importer class.
+ */
+#ifndef INCLUDED_AI_CINEMA_4D_LOADER_H
+#define INCLUDED_AI_CINEMA_4D_LOADER_H
+
+#include "BaseImporter.h"
+#include "LogAux.h"
+
+#include <set>
+struct aiNode;
+struct aiMesh;
+struct aiMaterial;
+
+struct aiImporterDesc;
+
+namespace _melange_ {
+    class BaseObject; // c4d_file.h
+    class PolygonObject;
+    class BaseMaterial;
+    class BaseShader;
+}
+
+namespace Assimp    {
+
+    // TinyFormatter.h
+    namespace Formatter {
+        template <typename T,typename TR, typename A> class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
+    }
+
+// -------------------------------------------------------------------------------------------
+/** Importer class to load Cinema4D files using the Melange library to be obtained from
+ *  www.plugincafe.com
+ *
+ *  Note that Melange is not free software. */
+// -------------------------------------------------------------------------------------------
+class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter>
+{
+public:
+
+    C4DImporter();
+    ~C4DImporter();
+
+
+public:
+
+    // --------------------
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
+
+protected:
+
+    // --------------------
+    const aiImporterDesc* GetInfo () const;
+
+    // --------------------
+    void SetupProperties(const Importer* pImp);
+
+    // --------------------
+    void InternReadFile( const std::string& pFile, aiScene* pScene,
+        IOSystem* pIOHandler);
+
+private:
+
+    void ReadMaterials(_melange_::BaseMaterial* mat);
+    void RecurseHierarchy(_melange_::BaseObject* object, aiNode* parent);
+    aiMesh* ReadMesh(_melange_::BaseObject* object);
+    unsigned int ResolveMaterial(_melange_::PolygonObject* obj);
+
+    bool ReadShader(aiMaterial* out, _melange_::BaseShader* shader);
+
+    std::vector<aiMesh*> meshes;
+    std::vector<aiMaterial*> materials;
+
+    typedef std::map<_melange_::BaseMaterial*, unsigned int> MaterialMap;
+    MaterialMap material_mapping;
+
+}; // !class C4DImporter
+
+} // end of namespace Assimp
+#endif // INCLUDED_AI_CINEMA_4D_LOADER_H
+

+ 7 - 0
Source/ThirdParty/Assimp/code/ColladaHelper.h

@@ -40,13 +40,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 #ifndef AI_COLLADAHELPER_H_INC
 #define AI_COLLADAHELPER_H_INC
 
 #include <string>
 #include <map>
 #include <vector>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include "../include/assimp/light.h"
 #include "../include/assimp/mesh.h"
 #include "../include/assimp/material.h"

+ 36 - 7
Source/ThirdParty/Assimp/code/ColladaParser.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
 
 #include <sstream>
+#include <stdarg.h>
 #include "ColladaParser.h"
 #include "fast_atof.h"
 #include "ParsingUtils.h"
@@ -1066,6 +1067,12 @@ void ColladaParser::ReadLight( Collada::Light& pLight)
                 pLight.mFalloffAngle = ReadFloatFromTextContent();
                 TestClosing("hotspot_beam");
             }
+            // OpenCOLLADA extensions
+            // -------------------------------------------------------
+            else if (IsElement("decay_falloff")) {
+                pLight.mOuterAngle = ReadFloatFromTextContent();
+                TestClosing("decay_falloff");
+            }
         }
         else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
             if( strcmp( mReader->getNodeName(), "light") == 0)
@@ -1998,7 +2005,8 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
     }
 
 #ifdef ASSIMP_BUILD_DEBUG
-    if (primType != Prim_TriFans && primType != Prim_TriStrips) {
+	if (primType != Prim_TriFans && primType != Prim_TriStrips &&
+        primType != Prim_Lines) { // this is ONLY to workaround a bug in SketchUp 15.3.331 where it writes the wrong 'count' when it writes out the 'lines'.
         ai_assert(actualPrimitives == numPrimitives);
     }
 #endif
@@ -2107,13 +2115,19 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pP
         }
     }
 
-    // complain if the index count doesn't fit
-    if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets)
-        ThrowException( "Expected different index count in <p> element.");
-    else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
-        ThrowException( "Expected different index count in <p> element.");
+	// complain if the index count doesn't fit
+    if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets) {
+        if (pPrimType == Prim_Lines) {
+            // HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines'
+            ReportWarning( "Expected different index count in <p> element, %d instead of %d.", indices.size(), expectedPointCount * numOffsets);
+            pNumPrimitives = (indices.size() / numOffsets) / 2;
+        } else
+            ThrowException( "Expected different index count in <p> element.");
+
+    } else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
+		ThrowException( "Expected different index count in <p> element.");
 
-    // find the data for all sources
+	// find the data for all sources
   for( std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
     {
     InputChannel& input = *it;
@@ -2712,6 +2726,21 @@ AI_WONT_RETURN void ColladaParser::ThrowException( const std::string& pError) co
 {
     throw DeadlyImportError( boost::str( boost::format( "Collada: %s - %s") % mFileName % pError));
 }
+void ColladaParser::ReportWarning(const char* msg,...)
+{
+    ai_assert(NULL != msg);
+    
+    va_list args;
+    va_start(args,msg);
+    
+    char szBuffer[3000];
+    const int iLen = vsprintf(szBuffer,msg,args);
+    ai_assert(iLen > 0);
+    
+    va_end(args);
+    DefaultLogger::get()->warn("Validation warning: " + std::string(szBuffer,iLen));
+}
+
 
 // ------------------------------------------------------------------------------------------------
 // Skips all data until the end node of the current element

+ 333 - 332
Source/ThirdParty/Assimp/code/ColladaParser.h

@@ -1,42 +1,42 @@
 /*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2015, 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.
-
-----------------------------------------------------------------------
-*/
+ Open Asset Import Library (assimp)
+ ----------------------------------------------------------------------
+ 
+ Copyright (c) 2006-2015, assimp team
+ All rights reserved.
+ 
+ Redistribution and use of this software in source and binary forms,
+ with or without modification, are permitted provided that the
+ following conditions are met:
+ 
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+ 
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+ 
+ * Neither the name of the assimp team, nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of the assimp team.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+ ----------------------------------------------------------------------
+ */
 
 /** @file ColladaParser.h
  *  @brief Defines the parser helper class for the collada loader
@@ -52,301 +52,302 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp
 {
-
-// ------------------------------------------------------------------------------------------
-/** Parser helper class for the Collada loader.
- *
- *  Does all the XML reading and builds internal data structures from it,
- *  but leaves the resolving of all the references to the loader.
-*/
-class ColladaParser
-{
-    friend class ColladaLoader;
-
-protected:
-    /** Constructor from XML file */
-    ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
-
-    /** Destructor */
-    ~ColladaParser();
-
-    /** Reads the contents of the file */
-    void ReadContents();
-
-    /** Reads the structure of the file */
-    void ReadStructure();
-
-    /** Reads asset informations such as coordinate system informations and legal blah */
-    void ReadAssetInfo();
-
-    /** Reads the animation library */
-    void ReadAnimationLibrary();
-
-    /** Reads an animation into the given parent structure */
-    void ReadAnimation( Collada::Animation* pParent);
-
-    /** Reads an animation sampler into the given anim channel */
-    void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
-
-    /** Reads the skeleton controller library */
-    void ReadControllerLibrary();
-
-    /** Reads a controller into the given mesh structure */
-    void ReadController( Collada::Controller& pController);
-
-    /** Reads the joint definitions for the given controller */
-    void ReadControllerJoints( Collada::Controller& pController);
-
-    /** Reads the joint weights for the given controller */
-    void ReadControllerWeights( Collada::Controller& pController);
-
-    /** Reads the image library contents */
-    void ReadImageLibrary();
-
-    /** Reads an image entry into the given image */
-    void ReadImage( Collada::Image& pImage);
-
-    /** Reads the material library */
-    void ReadMaterialLibrary();
-
-    /** Reads a material entry into the given material */
-    void ReadMaterial( Collada::Material& pMaterial);
-
-    /** Reads the camera library */
-    void ReadCameraLibrary();
-
-    /** Reads a camera entry into the given camera */
-    void ReadCamera( Collada::Camera& pCamera);
-
-    /** Reads the light library */
-    void ReadLightLibrary();
-
-    /** Reads a light entry into the given light */
-    void ReadLight( Collada::Light& pLight);
-
-    /** Reads the effect library */
-    void ReadEffectLibrary();
-
-    /** Reads an effect entry into the given effect*/
-    void ReadEffect( Collada::Effect& pEffect);
-
-    /** Reads an COMMON effect profile */
-    void ReadEffectProfileCommon( Collada::Effect& pEffect);
-
-    /** Read sampler properties */
-    void ReadSamplerProperties( Collada::Sampler& pSampler);
-
-    /** Reads an effect entry containing a color or a texture defining that color */
-    void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
-
-    /** Reads an effect entry containing a float */
-    void ReadEffectFloat( float& pFloat);
-
-    /** Reads an effect parameter specification of any kind */
-    void ReadEffectParam( Collada::EffectParam& pParam);
-
-    /** Reads the geometry library contents */
-    void ReadGeometryLibrary();
-
-    /** Reads a geometry from the geometry library. */
-    void ReadGeometry( Collada::Mesh* pMesh);
-
-    /** Reads a mesh from the geometry library */
-    void ReadMesh( Collada::Mesh* pMesh);
-
-    /** Reads a source element - a combination of raw data and an accessor defining
-     * things that should not be redefinable. Yes, that's another rant.
-     */
-    void ReadSource();
-
-    /** Reads a data array holding a number of elements, and stores it in the global library.
-     * Currently supported are array of floats and arrays of strings.
-     */
-    void ReadDataArray();
-
-    /** Reads an accessor and stores it in the global library under the given ID -
-     * accessors use the ID of the parent <source> element
+    
+    // ------------------------------------------------------------------------------------------
+    /** Parser helper class for the Collada loader.
+     *
+     *  Does all the XML reading and builds internal data structures from it,
+     *  but leaves the resolving of all the references to the loader.
      */
-    void ReadAccessor( const std::string& pID);
-
-    /** Reads input declarations of per-vertex mesh data into the given mesh */
-    void ReadVertexData( Collada::Mesh* pMesh);
-
-    /** Reads input declarations of per-index mesh data into the given mesh */
-    void ReadIndexData( Collada::Mesh* pMesh);
-
-    /** Reads a single input channel element and stores it in the given array, if valid */
-    void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
-
-    /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
-    size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
-        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 */
-    void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
-
-    /** Reads the library of node hierarchies and scene parts */
-    void ReadSceneLibrary();
-
-    /** Reads a scene node's contents including children and stores it in the given node */
-    void ReadSceneNode( Collada::Node* pNode);
-
-    /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
-    void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
-
-    /** Reads a mesh reference in a node and adds it to the node's mesh list */
-    void ReadNodeGeometry( Collada::Node* pNode);
-
-    /** Reads the collada scene */
-    void ReadScene();
-
-    // Processes bind_vertex_input and bind elements
-    void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
-
-protected:
-    /** Aborts the file reading with an exception */
-    AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
-
-    /** Skips all data until the end node of the current element */
-    void SkipElement();
-
-    /** Skips all data until the end node of the given element */
-    void SkipElement( const char* pElement);
-
-    /** Compares the current xml element name to the given string and returns true if equal */
-    bool IsElement( const char* pName) const;
-
-    /** Tests for the opening tag of the given element, throws an exception if not found */
-    void TestOpening( const char* pName);
-
-    /** Tests for the closing tag of the given element, throws an exception if not found */
-    void TestClosing( const char* pName);
-
-    /** Checks the present element for the presence of the attribute, returns its index
-        or throws an exception if not found */
-    int GetAttribute( const char* pAttr) const;
-
-    /** Returns the index of the named attribute or -1 if not found. Does not throw,
-        therefore useful for optional attributes */
-    int TestAttribute( const char* pAttr) const;
-
-    /** Reads the text contents of an element, throws an exception if not given.
-        Skips leading whitespace. */
-    const char* GetTextContent();
-
-    /** Reads the text contents of an element, returns NULL if not given.
-        Skips leading whitespace. */
-    const char* TestTextContent();
-
-    /** Reads a single bool from current text content */
-    bool ReadBoolFromTextContent();
-
-    /** Reads a single float from current text content */
-    float ReadFloatFromTextContent();
-
-    /** Calculates the resulting transformation from all the given transform steps */
-    aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
-
-    /** Determines the input data type for the given semantic string */
-    Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
-
-    /** Finds the item in the given library by its reference, throws if not found */
-    template <typename Type> const Type& ResolveLibraryReference(
-        const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
-
-protected:
-    /** Filename, for a verbose error message */
-    std::string mFileName;
-
-    /** XML reader, member for everyday use */
-    irr::io::IrrXMLReader* mReader;
-
-    /** All data arrays found in the file by ID. Might be referred to by actually
-        everyone. Collada, you are a steaming pile of indirection. */
-    typedef std::map<std::string, Collada::Data> DataLibrary;
-    DataLibrary mDataLibrary;
-
-    /** Same for accessors which define how the data in a data array is accessed. */
-    typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
-    AccessorLibrary mAccessorLibrary;
-
-    /** Mesh library: mesh by ID */
-    typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
-    MeshLibrary mMeshLibrary;
-
-    /** node library: root node of the hierarchy part by ID */
-    typedef std::map<std::string, Collada::Node*> NodeLibrary;
-    NodeLibrary mNodeLibrary;
-
-    /** Image library: stores texture properties by ID */
-    typedef std::map<std::string, Collada::Image> ImageLibrary;
-    ImageLibrary mImageLibrary;
-
-    /** Effect library: surface attributes by ID */
-    typedef std::map<std::string, Collada::Effect> EffectLibrary;
-    EffectLibrary mEffectLibrary;
-
-    /** Material library: surface material by ID */
-    typedef std::map<std::string, Collada::Material> MaterialLibrary;
-    MaterialLibrary mMaterialLibrary;
-
-    /** Light library: surface light by ID */
-    typedef std::map<std::string, Collada::Light> LightLibrary;
-    LightLibrary mLightLibrary;
-
-    /** Camera library: surface material by ID */
-    typedef std::map<std::string, Collada::Camera> CameraLibrary;
-    CameraLibrary mCameraLibrary;
-
-    /** Controller library: joint controllers by ID */
-    typedef std::map<std::string, Collada::Controller> ControllerLibrary;
-    ControllerLibrary mControllerLibrary;
-
-    /** Pointer to the root node. Don't delete, it just points to one of
-        the nodes in the node library. */
-    Collada::Node* mRootNode;
-
-    /** Root animation container */
-    Collada::Animation mAnims;
-
-    /** Size unit: how large compared to a meter */
-    float mUnitSize;
-
-    /** Which is the up vector */
-    enum { UP_X, UP_Y, UP_Z } mUpDirection;
-
-    /** Collada file format version */
-    Collada::FormatVersion mFormat;
-};
-
-// ------------------------------------------------------------------------------------------------
-// Check for element match
-inline bool ColladaParser::IsElement( const char* pName) const
-{
-    ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
-    return ::strcmp( mReader->getNodeName(), pName) == 0;
-}
-
-// ------------------------------------------------------------------------------------------------
-// Finds the item in the given library by its reference, throws if not found
-template <typename Type>
-const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
-{
-    typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
-    if( it == pLibrary.end())
-        ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
-    return it->second;
-}
-
+    class ColladaParser
+    {
+        friend class ColladaLoader;
+        
+    protected:
+        /** Constructor from XML file */
+        ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
+        
+        /** Destructor */
+        ~ColladaParser();
+        
+        /** Reads the contents of the file */
+        void ReadContents();
+        
+        /** Reads the structure of the file */
+        void ReadStructure();
+        
+        /** Reads asset informations such as coordinate system informations and legal blah */
+        void ReadAssetInfo();
+        
+        /** Reads the animation library */
+        void ReadAnimationLibrary();
+        
+        /** Reads an animation into the given parent structure */
+        void ReadAnimation( Collada::Animation* pParent);
+        
+        /** Reads an animation sampler into the given anim channel */
+        void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
+        
+        /** Reads the skeleton controller library */
+        void ReadControllerLibrary();
+        
+        /** Reads a controller into the given mesh structure */
+        void ReadController( Collada::Controller& pController);
+        
+        /** Reads the joint definitions for the given controller */
+        void ReadControllerJoints( Collada::Controller& pController);
+        
+        /** Reads the joint weights for the given controller */
+        void ReadControllerWeights( Collada::Controller& pController);
+        
+        /** Reads the image library contents */
+        void ReadImageLibrary();
+        
+        /** Reads an image entry into the given image */
+        void ReadImage( Collada::Image& pImage);
+        
+        /** Reads the material library */
+        void ReadMaterialLibrary();
+        
+        /** Reads a material entry into the given material */
+        void ReadMaterial( Collada::Material& pMaterial);
+        
+        /** Reads the camera library */
+        void ReadCameraLibrary();
+        
+        /** Reads a camera entry into the given camera */
+        void ReadCamera( Collada::Camera& pCamera);
+        
+        /** Reads the light library */
+        void ReadLightLibrary();
+        
+        /** Reads a light entry into the given light */
+        void ReadLight( Collada::Light& pLight);
+        
+        /** Reads the effect library */
+        void ReadEffectLibrary();
+        
+        /** Reads an effect entry into the given effect*/
+        void ReadEffect( Collada::Effect& pEffect);
+        
+        /** Reads an COMMON effect profile */
+        void ReadEffectProfileCommon( Collada::Effect& pEffect);
+        
+        /** Read sampler properties */
+        void ReadSamplerProperties( Collada::Sampler& pSampler);
+        
+        /** Reads an effect entry containing a color or a texture defining that color */
+        void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
+        
+        /** Reads an effect entry containing a float */
+        void ReadEffectFloat( float& pFloat);
+        
+        /** Reads an effect parameter specification of any kind */
+        void ReadEffectParam( Collada::EffectParam& pParam);
+        
+        /** Reads the geometry library contents */
+        void ReadGeometryLibrary();
+        
+        /** Reads a geometry from the geometry library. */
+        void ReadGeometry( Collada::Mesh* pMesh);
+        
+        /** Reads a mesh from the geometry library */
+        void ReadMesh( Collada::Mesh* pMesh);
+        
+        /** Reads a source element - a combination of raw data and an accessor defining
+         * things that should not be redefinable. Yes, that's another rant.
+         */
+        void ReadSource();
+        
+        /** Reads a data array holding a number of elements, and stores it in the global library.
+         * Currently supported are array of floats and arrays of strings.
+         */
+        void ReadDataArray();
+        
+        /** Reads an accessor and stores it in the global library under the given ID -
+         * accessors use the ID of the parent <source> element
+         */
+        void ReadAccessor( const std::string& pID);
+        
+        /** Reads input declarations of per-vertex mesh data into the given mesh */
+        void ReadVertexData( Collada::Mesh* pMesh);
+        
+        /** Reads input declarations of per-index mesh data into the given mesh */
+        void ReadIndexData( Collada::Mesh* pMesh);
+        
+        /** Reads a single input channel element and stores it in the given array, if valid */
+        void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
+        
+        /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
+        size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
+                              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 */
+        void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
+        
+        /** Reads the library of node hierarchies and scene parts */
+        void ReadSceneLibrary();
+        
+        /** Reads a scene node's contents including children and stores it in the given node */
+        void ReadSceneNode( Collada::Node* pNode);
+        
+        /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
+        void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
+        
+        /** Reads a mesh reference in a node and adds it to the node's mesh list */
+        void ReadNodeGeometry( Collada::Node* pNode);
+        
+        /** Reads the collada scene */
+        void ReadScene();
+        
+        // Processes bind_vertex_input and bind elements
+        void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
+        
+    protected:
+        /** Aborts the file reading with an exception */
+        AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
+        void ReportWarning(const char* msg,...);
+
+        /** Skips all data until the end node of the current element */
+        void SkipElement();
+        
+        /** Skips all data until the end node of the given element */
+        void SkipElement( const char* pElement);
+        
+        /** Compares the current xml element name to the given string and returns true if equal */
+        bool IsElement( const char* pName) const;
+        
+        /** Tests for the opening tag of the given element, throws an exception if not found */
+        void TestOpening( const char* pName);
+        
+        /** Tests for the closing tag of the given element, throws an exception if not found */
+        void TestClosing( const char* pName);
+        
+        /** Checks the present element for the presence of the attribute, returns its index
+         or throws an exception if not found */
+        int GetAttribute( const char* pAttr) const;
+        
+        /** Returns the index of the named attribute or -1 if not found. Does not throw,
+         therefore useful for optional attributes */
+        int TestAttribute( const char* pAttr) const;
+        
+        /** Reads the text contents of an element, throws an exception if not given.
+         Skips leading whitespace. */
+        const char* GetTextContent();
+        
+        /** Reads the text contents of an element, returns NULL if not given.
+         Skips leading whitespace. */
+        const char* TestTextContent();
+        
+        /** Reads a single bool from current text content */
+        bool ReadBoolFromTextContent();
+        
+        /** Reads a single float from current text content */
+        float ReadFloatFromTextContent();
+        
+        /** Calculates the resulting transformation from all the given transform steps */
+        aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
+        
+        /** Determines the input data type for the given semantic string */
+        Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
+        
+        /** Finds the item in the given library by its reference, throws if not found */
+        template <typename Type> const Type& ResolveLibraryReference(
+                                                                     const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
+        
+    protected:
+        /** Filename, for a verbose error message */
+        std::string mFileName;
+        
+        /** XML reader, member for everyday use */
+        irr::io::IrrXMLReader* mReader;
+        
+        /** All data arrays found in the file by ID. Might be referred to by actually
+         everyone. Collada, you are a steaming pile of indirection. */
+        typedef std::map<std::string, Collada::Data> DataLibrary;
+        DataLibrary mDataLibrary;
+        
+        /** Same for accessors which define how the data in a data array is accessed. */
+        typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
+        AccessorLibrary mAccessorLibrary;
+        
+        /** Mesh library: mesh by ID */
+        typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
+        MeshLibrary mMeshLibrary;
+        
+        /** node library: root node of the hierarchy part by ID */
+        typedef std::map<std::string, Collada::Node*> NodeLibrary;
+        NodeLibrary mNodeLibrary;
+        
+        /** Image library: stores texture properties by ID */
+        typedef std::map<std::string, Collada::Image> ImageLibrary;
+        ImageLibrary mImageLibrary;
+        
+        /** Effect library: surface attributes by ID */
+        typedef std::map<std::string, Collada::Effect> EffectLibrary;
+        EffectLibrary mEffectLibrary;
+        
+        /** Material library: surface material by ID */
+        typedef std::map<std::string, Collada::Material> MaterialLibrary;
+        MaterialLibrary mMaterialLibrary;
+        
+        /** Light library: surface light by ID */
+        typedef std::map<std::string, Collada::Light> LightLibrary;
+        LightLibrary mLightLibrary;
+        
+        /** Camera library: surface material by ID */
+        typedef std::map<std::string, Collada::Camera> CameraLibrary;
+        CameraLibrary mCameraLibrary;
+        
+        /** Controller library: joint controllers by ID */
+        typedef std::map<std::string, Collada::Controller> ControllerLibrary;
+        ControllerLibrary mControllerLibrary;
+        
+        /** Pointer to the root node. Don't delete, it just points to one of
+         the nodes in the node library. */
+        Collada::Node* mRootNode;
+        
+        /** Root animation container */
+        Collada::Animation mAnims;
+        
+        /** Size unit: how large compared to a meter */
+        float mUnitSize;
+        
+        /** Which is the up vector */
+        enum { UP_X, UP_Y, UP_Z } mUpDirection;
+        
+        /** Collada file format version */
+        Collada::FormatVersion mFormat;
+    };
+    
+    // ------------------------------------------------------------------------------------------------
+    // Check for element match
+    inline bool ColladaParser::IsElement( const char* pName) const
+    {
+        ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
+        return ::strcmp( mReader->getNodeName(), pName) == 0;
+    }
+    
+    // ------------------------------------------------------------------------------------------------
+    // Finds the item in the given library by its reference, throws if not found
+    template <typename Type>
+    const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
+    {
+        typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
+        if( it == pLibrary.end())
+            ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
+        return it->second;
+    }
+    
 } // end of namespace Assimp
 
 #endif // AI_COLLADAPARSER_H_INC

+ 8 - 0
Source/ThirdParty/Assimp/code/FBXBinaryTokenizer.cpp

@@ -37,6 +37,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 ----------------------------------------------------------------------
 */
+
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  FBXBinaryTokenizer.cpp
  *  @brief Implementation of a fake lexer for binary fbx files -
  *    we emit tokens so the parser needs almost no special handling
@@ -48,7 +51,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXTokenizer.h"
 #include "FBXUtil.h"
 #include "../include/assimp/defs.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include "Exceptional.h"
 #include "ByteSwapper.h"
 

+ 1 - 12
Source/ThirdParty/Assimp/code/FBXConverter.cpp

@@ -725,18 +725,7 @@ private:
                 const TransformationComp comp = static_cast<TransformationComp>(i);
 
                 if (chain[i].IsIdentity() && (anim_chain_bitmask & bit) == 0) {
-
-                    // ATOMIC BEGIN
-                    // Only optimize these out if not a TRS
-                    // As these may be animated in an external FBX
-                    // and should not be dropped
-                    if (comp != TransformationComp_Translation &&
-                        comp != TransformationComp_Rotation &&
-                        comp != TransformationComp_Scaling)
-                    {
-                        continue;
-                    }
-                    // ATOMIC END
+                    continue;
                 }
 
                 aiNode* nd = new aiNode();

+ 7 - 0
Source/ThirdParty/Assimp/code/FBXDocument.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  FBXDocument.h
  *  @brief FBX DOM
  */
@@ -47,7 +49,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <map>
 #include <string>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <numeric>
 #include <boost/scoped_ptr.hpp>
 #include "../include/assimp/ai_assert.h"

+ 7 - 0
Source/ThirdParty/Assimp/code/FBXParser.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  FBXParser.h
  *  @brief FBX parsing code
  */
@@ -48,7 +50,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <string>
 #include <utility>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 #include <boost/shared_ptr.hpp>
 #include <boost/scoped_ptr.hpp>

+ 2 - 2
Source/ThirdParty/Assimp/code/FixNormalsStep.cpp

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

+ 8 - 0
Source/ThirdParty/Assimp/code/HMPFileData.h

@@ -37,6 +37,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 ----------------------------------------------------------------------
 */
+
+// Modified by Lasse Oorni for Urho3D
+
 //!
 //! @file Data structures for the 3D Game Studio Heightmap format (HMP)
 //!
@@ -45,7 +48,12 @@ namespace Assimp    {
 namespace HMP   {
 
 #include "./../include/assimp/Compiler/pushpack1.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 // to make it easier for us, we test the magic word against both "endianesses"
 #define AI_HMP_MAGIC_NUMBER_BE_4    AI_MAKE_MAGIC("HMP4")

+ 7 - 0
Source/ThirdParty/Assimp/code/Hash.h

@@ -38,10 +38,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 #ifndef AI_HASH_H_INCLUDED
 #define AI_HASH_H_INCLUDED
 
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <string.h>
 
 // ------------------------------------------------------------------------------------------------

+ 8 - 3
Source/ThirdParty/Assimp/code/IFCBoolean.cpp

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  IFCBoolean.cpp
  *  @brief Implements a subset of Ifc boolean operations
  */
@@ -109,7 +111,8 @@ void FilterPolygon(std::vector<IfcVector3>& resultpoly)
     }
 
     IfcVector3 vmin, vmax;
-    ArrayBounds(resultpoly.data(), resultpoly.size(), vmin, vmax);
+    // Urho3D: modified to not use C++11
+    ArrayBounds(&resultpoly[0], resultpoly.size(), vmin, vmax);
 
     // filter our IfcFloat points - those may happen if a point lies
     // directly on the intersection line or directly on the clipping plane
@@ -420,7 +423,8 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
     }
 
     // determine winding order by calculating the normal.
-    IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(profile->verts.data(), profile->verts.size());
+    // Urho3D: modified to not use C++11
+    IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(&profile->verts[0], profile->verts.size());
 
     IfcMatrix4 proj_inv;
     ConvertAxisPlacement(proj_inv,hs->Position);
@@ -603,7 +607,8 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
 
             // determine the direction in which we're marching along the boundary polygon. If the src poly is faced upwards
             // and the boundary is also winded this way, we need to march *backwards* on the boundary.
-            const IfcVector3 polyNormal = IfcMatrix3(proj) * TempMesh::ComputePolygonNormal(blackside.data(), blackside.size());
+            // Urho3D: modified to not use C++11
+            const IfcVector3 polyNormal = IfcMatrix3(proj) * TempMesh::ComputePolygonNormal(&blackside[0], blackside.size());
             bool marchBackwardsOnBoundary = (profileNormal * polyNormal) >= 0.0;
 
             // Build closed loops from these intersections. Starting from an intersection leaving the boundary we

+ 4 - 1
Source/ThirdParty/Assimp/code/IFCGeometry.cpp

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  IFCGeometry.cpp
  *  @brief Geometry conversion and synthesis for IFC
  */
@@ -559,7 +561,8 @@ void ProcessExtrudedArea(const IfcExtrudedAreaSolid& solid, const TempMesh& curv
     IfcVector3 dir = IfcMatrix3(trafo) * extrusionDir;
 
     // reverse profile polygon if it's winded in the wrong direction in relation to the extrusion direction
-    IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(in.data(), in.size());
+    // Urho3D: modified to not use C++11
+    IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(&in[0], in.size());
     if( profileNormal * dir < 0.0 )
         std::reverse(in.begin(), in.end());
 

+ 18 - 15
Source/ThirdParty/Assimp/code/IFCOpenings.cpp

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  IFCOpenings.cpp
  *  @brief Implements a subset of Ifc CSG operations for pouring
   *    holes for windows and doors into walls.
@@ -602,12 +604,12 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
     const IfcVector2& m0, const IfcVector2& m1,
     IfcVector2& out0, IfcVector2& out1)
 {
-    const IfcVector2& n0_to_n1 = n1 - n0;
+    const IfcVector2 n0_to_n1 = n1 - n0;
 
-    const IfcVector2& n0_to_m0 = m0 - n0;
-    const IfcVector2& n1_to_m1 = m1 - n1;
+    const IfcVector2 n0_to_m0 = m0 - n0;
+    const IfcVector2 n1_to_m1 = m1 - n1;
 
-    const IfcVector2& n0_to_m1 = m1 - n0;
+    const IfcVector2 n0_to_m1 = m1 - n0;
 
     const IfcFloat e = 1e-5f;
     const IfcFloat smalle = 1e-9f;
@@ -902,11 +904,12 @@ size_t CloseWindows(ContourVector& contours,
             curmesh.vertcnt.reserve(curmesh.vertcnt.size() + (*it).contour.size());
 
             // compare base poly normal and contour normal to detect if we need to reverse the face winding
-            IfcVector3 basePolyNormal = TempMesh::ComputePolygonNormal( curmesh.verts.data(), curmesh.vertcnt.front());
+            // Urho3D: modified to not use C++11
+            IfcVector3 basePolyNormal = TempMesh::ComputePolygonNormal( &curmesh.verts[0], curmesh.vertcnt.front());
             std::vector<IfcVector3> worldSpaceContourVtx( it->contour.size());
             for( size_t a = 0; a < it->contour.size(); ++a )
                 worldSpaceContourVtx[a] = minv * IfcVector3( it->contour[a].x, it->contour[a].y, 0.0);
-            IfcVector3 contourNormal = TempMesh::ComputePolygonNormal( worldSpaceContourVtx.data(), worldSpaceContourVtx.size());
+            IfcVector3 contourNormal = TempMesh::ComputePolygonNormal( &worldSpaceContourVtx[0], worldSpaceContourVtx.size());
             bool reverseCountourFaces = (contourNormal * basePolyNormal) > 0.0;
 
             // XXX this algorithm is really a bit inefficient - both in terms
@@ -927,7 +930,7 @@ size_t CloseWindows(ContourVector& contours,
                 IfcFloat best = static_cast<IfcFloat>(1e10);
                 IfcVector3 bestv;
 
-                const IfcVector3& world_point = minv * IfcVector3(proj_point.x,proj_point.y,0.0f);
+                const IfcVector3 world_point = minv * IfcVector3(proj_point.x,proj_point.y,0.0f);
 
                 BOOST_FOREACH(const TempOpening* opening, refs) {
                     BOOST_FOREACH(const IfcVector3& other, opening->wallPoints) {
@@ -1066,7 +1069,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 
     // Project all points into the new coordinate system, collect min/max verts on the way
     BOOST_FOREACH(const IfcVector3& x, in_verts) {
-        const IfcVector3& vv = m * x;
+        const IfcVector3 vv = m * x;
         // keep Z offset in the plane coordinate system. Ignoring precision issues
         // (which  are present, of course), this should be the same value for
         // all polygon vertices (assuming the polygon is planar).
@@ -1144,7 +1147,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
     std::vector<IfcVector2> contour_flat;
 
     IfcVector3 nor;
-    const IfcMatrix4& m = ProjectOntoPlane(contour_flat, curmesh,  ok, nor);
+    const IfcMatrix4 m = ProjectOntoPlane(contour_flat, curmesh,  ok, nor);
     if(!ok) {
         return false;
     }
@@ -1227,7 +1230,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 
             bool side_flag = true;
             if (!is_2d_source) {
-                const IfcVector3& face_nor = ((profile_verts[vi_total+2] - profile_verts[vi_total]) ^
+                const IfcVector3 face_nor = ((profile_verts[vi_total+2] - profile_verts[vi_total]) ^
                     (profile_verts[vi_total+1] - profile_verts[vi_total])).Normalize();
 
                 const IfcFloat abs_dot_face_nor = std::abs(nor * face_nor);
@@ -1242,7 +1245,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
             for (unsigned int vi = 0, vend = profile_vertcnts[f]; vi < vend; ++vi, ++vi_total) {
                 const IfcVector3& x = profile_verts[vi_total];
 
-                const IfcVector3& v = m * x;
+                const IfcVector3 v = m * x;
                 IfcVector2 vv(v.x, v.y);
 
                 //if(check_intersection) {
@@ -1322,7 +1325,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
                 MakeDisjunctWindowContours(other, temp_contour, poly);
                 if(poly.size() == 1) {
 
-                    const BoundingBox& newbb = GetBoundingBox(poly[0].outer);
+                    const BoundingBox newbb = GetBoundingBox(poly[0].outer);
                     if (!BoundingBoxesOverlapping(ibb, newbb )) {
                          // Good guy bounding box
                          bb = newbb ;
@@ -1438,7 +1441,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
     // working coordinate system.
     bool ok;
     IfcVector3 nor;
-    const IfcMatrix3& m = DerivePlaneCoordinateSpace(curmesh, ok, nor);
+    const IfcMatrix3 m = DerivePlaneCoordinateSpace(curmesh, ok, nor);
     if (!ok) {
         return false;
     }
@@ -1686,13 +1689,13 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
             continue;
         }
 
-        const std::vector<p2t::Triangle*>& tris = cdt->GetTriangles();
+        const std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
 
         // Collect the triangles we just produced
         BOOST_FOREACH(p2t::Triangle* tri, tris) {
             for(int i = 0; i < 3; ++i) {
 
-                const IfcVector2& v = IfcVector2(
+                const IfcVector2 v = IfcVector2(
                     static_cast<IfcFloat>( tri->GetPoint(i)->x ),
                     static_cast<IfcFloat>( tri->GetPoint(i)->y )
                 );

+ 4 - 1
Source/ThirdParty/Assimp/code/IFCUtil.cpp

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  IFCUtil.cpp
  *  @brief Implementation of conversion routines for some common Ifc helper entities.
  */
@@ -311,7 +313,8 @@ void TempMesh::FixupFaceOrientation()
         }
 
         // calculate its normal and reverse the poly if its facing towards the mesh center
-        IfcVector3 farthestNormal = ComputePolygonNormal(verts.data() + faceStartIndices[farthestIndex], vertcnt[farthestIndex]);
+        // Urho3D: modified to not use C++11
+        IfcVector3 farthestNormal = ComputePolygonNormal(&verts[0] + faceStartIndices[farthestIndex], vertcnt[farthestIndex]);
         IfcVector3 farthestCenter = std::accumulate(verts.begin() + faceStartIndices[farthestIndex],
             verts.begin() + faceStartIndices[farthestIndex] + vertcnt[farthestIndex], IfcVector3(0.0))
             / IfcFloat(vertcnt[farthestIndex]);

+ 6 - 0
Source/ThirdParty/Assimp/code/IRRShared.h

@@ -1,4 +1,5 @@
 
+// Modified by Lasse Oorni for Urho3D
 
 /** @file  IRRShared.h
   * @brief Shared utilities for the IRR and IRRMESH loaders
@@ -9,7 +10,12 @@
 
 #include "irrXMLWrapper.h"
 #include "BaseImporter.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 struct aiMaterial;
 

+ 7 - 0
Source/ThirdParty/Assimp/code/ImporterRegistry.cpp

@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file ImporterRegistry.cpp
 
 Central registry for all importers available. Do not edit this file
@@ -46,6 +48,11 @@ directly (unless you are adding new loaders), instead use the
 corresponding preprocessor flag to selectively disable formats.
 */
 
+// Urho3D: disable IRRMESH if IRR disabled
+#ifdef ASSIMP_BUILD_NO_IRR_IMPORTER
+#define ASSIMP_BUILD_NO_IRRMESH_IMPORTER
+#endif
+
 // ------------------------------------------------------------------------------------------------
 // Importers
 // (include_new_importers_here)

+ 3 - 0
Source/ThirdParty/Assimp/code/LWOLoader.cpp

@@ -954,6 +954,9 @@ inline void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int
     LWO::ReferrerList& refList  = mCurLayer->mPointReferrers;
     unsigned int i;
 
+    if (idx >= base->abAssigned.size()) {
+        throw DeadlyImportError("Bad index");
+    }
     base->abAssigned[idx] = true;
     for (i = 0; i < numRead;++i) {
         base->rawData[idx*base->dims+i]= data[i];

+ 7 - 0
Source/ThirdParty/Assimp/code/MD2FileData.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  MD2FileData.h
  *  @brief Defines helper data structures for importing MD2 files
  *  http://linux.ucla.edu/~phaethon/q3/formats/md2-schoenblum.html
@@ -48,7 +50,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/types.h"
 #include "../include/assimp/mesh.h"
 #include "../include/assimp/anim.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 #include "./../include/assimp/Compiler/pushpack1.h"
 

+ 7 - 0
Source/ThirdParty/Assimp/code/MD3FileData.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Md3FileData.h
  *
  *  @brief Defines helper data structures for importing MD3 files.
@@ -49,7 +51,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 #include <sstream>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 #include "../include/assimp/types.h"
 #include "../include/assimp/mesh.h"

+ 7 - 0
Source/ThirdParty/Assimp/code/MD3Loader.cpp

@@ -783,6 +783,13 @@ void MD3Importer::InternReadFile( const std::string& pFile,
 
     // Allocate output storage
     pScene->mNumMeshes = pcHeader->NUM_SURFACES;
+    if (pcHeader->NUM_SURFACES == 0) {
+        throw DeadlyImportError("MD3: No surfaces");
+    } else if (pcHeader->NUM_SURFACES > AI_MAX_ALLOC(aiMesh)) {
+        // We allocate pointers but check against the size of aiMesh
+        // since those pointers will eventually have to point to real objects
+        throw DeadlyImportError("MD3: Too many surfaces, would run out of memory");
+    }
     pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
 
     pScene->mNumMaterials = pcHeader->NUM_SURFACES;

+ 6 - 0
Source/ThirdParty/Assimp/code/MD5Parser.h

@@ -38,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
 
 /** @file  MD5Parser.h
  *  @brief Definition of the .MD5 parser class.
@@ -49,7 +50,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/types.h"
 #include "ParsingUtils.h"
 #include <vector>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 struct aiFace;
 

+ 7 - 0
Source/ThirdParty/Assimp/code/MDCFileData.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Defines the helper data structures for importing MDC files
 
 **********************************************************************
@@ -54,7 +56,12 @@ http://themdcfile.planetwolfenstein.gamespy.com/MDC_File_Format.pdf
 #include "../include/assimp/anim.h"
 
 #include "./../include/assimp/Compiler/pushpack1.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 namespace Assimp {
 namespace MDC {

+ 6 - 0
Source/ThirdParty/Assimp/code/MDLFileData.h

@@ -38,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
 
 /**
  * @file  MDLFileData.h
@@ -56,7 +57,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "./../include/assimp/anim.h"
 #include "./../include/assimp/mesh.h"
 #include "./../include/assimp/Compiler/pushpack1.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <vector>
 
 struct aiMaterial;

+ 3 - 0
Source/ThirdParty/Assimp/code/MDLLoader.cpp

@@ -355,6 +355,9 @@ void MDLImporter::InternReadFile_Quake1( )
     for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i)
     {
         union{BE_NCONST MDL::Skin* pcSkin;BE_NCONST MDL::GroupSkin* pcGroupSkin;};
+        if (szCurrent + sizeof(MDL::Skin) > this->mBuffer + this->iFileSize) {
+            throw DeadlyImportError("[Quake 1 MDL] Unexpected EOF");
+        }
         pcSkin = (BE_NCONST MDL::Skin*)szCurrent;
 
         AI_SWAP4( pcSkin->group );

+ 7 - 0
Source/ThirdParty/Assimp/code/MaterialSystem.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file MaterialSystem.h
  *  Now that #MaterialHelper is gone, this file only contains some
  *  internal material utility functions.
@@ -45,7 +47,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_MATERIALSYSTEM_H_INC
 #define AI_MATERIALSYSTEM_H_INC
 
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 struct aiMaterial;
 

+ 7 - 0
Source/ThirdParty/Assimp/code/MemoryIOWrapper.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file MemoryIOWrapper.h
  *  Handy IOStream/IOSystem implemetation to read directly from a memory buffer */
 #ifndef AI_MEMORYIOSTREAM_H_INC
@@ -46,7 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/IOStream.hpp"
 #include "../include/assimp/IOSystem.hpp"
 #include "../include/assimp/ai_assert.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 namespace Assimp    {
 #define AI_MEMORYIO_MAGIC_FILENAME "$$$___magic___$$$"

+ 7 - 0
Source/ThirdParty/Assimp/code/NDOLoader.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file NDOLoader.h
  *  Declaration of the Nendo importer class.
  */
@@ -46,7 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "../include/assimp/vector3.h"
 #include "BaseImporter.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <string>
 #include <vector>
 

+ 6 - 6
Source/ThirdParty/Assimp/code/ObjExporter.cpp

@@ -44,15 +44,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
 
 #include "ObjExporter.h"
-#include "../include/assimp/version.h"
-#include "../include/assimp/IOSystem.hpp"
-#include "../include/assimp/Exporter.hpp"
-#include <boost/scoped_ptr.hpp>
 #include "Exceptional.h"
-#include "../include/assimp/material.h"
-#include "../include/assimp/scene.h"
 #include "StringComparison.h"
+#include <assimp/version.h>
+#include <assimp/IOSystem.hpp>
+#include <assimp/Exporter.hpp>
+#include <assimp/material.h>
+#include <assimp/scene.h>
 #include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
 
 
 using namespace Assimp;

+ 1 - 1
Source/ThirdParty/Assimp/code/ObjExporter.h

@@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_OBJEXPORTER_H_INC
 #define AI_OBJEXPORTER_H_INC
 
-#include "../include/assimp/types.h"
+#include <assimp/types.h>
 #include <sstream>
 #include <vector>
 #include <map>

+ 14 - 16
Source/ThirdParty/Assimp/code/ObjFileData.h

@@ -43,15 +43,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <vector>
 #include <map>
-#include "../include/assimp/types.h"
-#include "../include/assimp/mesh.h"
+#include <assimp/types.h>
+#include <assimp/mesh.h>
 
-namespace Assimp
-{
+namespace Assimp {
+namespace ObjFile {
 
-namespace ObjFile
-{
-// ------------------------------------------------------------------------------------------------
 struct Object;
 struct Face;
 struct Material;
@@ -219,10 +216,10 @@ struct Material
 // ------------------------------------------------------------------------------------------------
 //! \struct Mesh
 //! \brief  Data structure to store a mesh
-struct Mesh
-{
+struct Mesh {
     static const unsigned int NoMaterial = ~0u;
-
+    /// The name for the mesh
+    std::string m_name;
     /// Array with pointer to all stored faces
     std::vector<Face*> m_Faces;
     /// Assigned material
@@ -235,13 +232,14 @@ struct Mesh
     unsigned int m_uiMaterialIndex;
     /// True, if normals are stored.
     bool m_hasNormals;
+
     /// Constructor
-    Mesh() :
-        m_pMaterial(NULL),
-        m_uiNumIndices(0),
-        m_uiMaterialIndex( NoMaterial ),
-        m_hasNormals(false)
-    {
+    Mesh( const std::string &name ) 
+    : m_name( name )
+    , m_pMaterial(NULL)
+    , m_uiNumIndices(0)
+    , m_uiMaterialIndex( NoMaterial )
+    , m_hasNormals(false) {
         memset(m_uiUVCoordinates, 0, sizeof( unsigned int ) * AI_MAX_NUMBER_OF_TEXTURECOORDS);
     }
 

+ 31 - 19
Source/ThirdParty/Assimp/code/ObjFileImporter.cpp

@@ -47,10 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ObjFileParser.h"
 #include "ObjFileData.h"
 #include <boost/scoped_ptr.hpp>
-#include "../include/assimp/Importer.hpp"
-#include "../include/assimp/scene.h"
-#include "../include/assimp/ai_assert.h"
-#include "../include/assimp/DefaultLogger.hpp"
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+#include <assimp/ai_assert.h>
+#include <assimp/DefaultLogger.hpp>
 
 
 static const aiImporterDesc desc = {
@@ -133,15 +133,16 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
     TextFileToBuffer(file.get(),m_Buffer);
 
     // Get the model name
-    std::string  strModelName;
+    std::string  modelName, folderName;
     std::string::size_type pos = pFile.find_last_of( "\\/" );
-    if ( pos != std::string::npos )
-    {
-        strModelName = pFile.substr(pos+1, pFile.size() - pos - 1);
-    }
-    else
-    {
-        strModelName = pFile;
+    if ( pos != std::string::npos ) {
+        modelName = pFile.substr(pos+1, pFile.size() - pos - 1);
+        folderName = pFile.substr( 0, pos );
+        if ( folderName.empty() ) {
+            pIOHandler->PushDirectory( folderName );
+        }
+    } else {
+        modelName = pFile;
     }
 
     // process all '\'
@@ -161,13 +162,18 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
     }
 
     // parse the file into a temporary representation
-    ObjFileParser parser(m_Buffer, strModelName, pIOHandler);
+    ObjFileParser parser(m_Buffer, modelName, pIOHandler);
 
     // And create the proper return structures out of it
     CreateDataFromImport(parser.GetModel(), pScene);
 
     // Clean up allocated storage for the next import
     m_Buffer.clear();
+
+    // Pop directory stack
+    if ( pIOHandler->StackSize() > 0 ) {
+        pIOHandler->PopDirectory();
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -289,6 +295,10 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
     }
     ai_assert( NULL != pObjMesh );
     aiMesh* pMesh = new aiMesh;
+    if( !pObjMesh->m_name.empty() ) {
+        pMesh->mName.Set( pObjMesh->m_name );
+    }
+
     for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
     {
         ObjFile::Face *const inp = pObjMesh->m_Faces[ index ];
@@ -311,19 +321,16 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
     }
 
     unsigned int uiIdxCount( 0u );
-    if ( pMesh->mNumFaces > 0 )
-    {
+    if ( pMesh->mNumFaces > 0 ) {
         pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
-        if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial )
-        {
+        if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial ) {
             pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
         }
 
         unsigned int outIndex( 0 );
 
         // 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++) {
             ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
             if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
                 for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) {
@@ -379,6 +386,11 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
 
     // Copy vertices of this mesh instance
     pMesh->mNumVertices = numIndices;
+    if (pMesh->mNumVertices == 0) {
+        throw DeadlyImportError( "OBJ: no vertices" );
+    } else if (pMesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) {
+        throw DeadlyImportError( "OBJ: Too many vertices, would run out of memory" );
+    }
     pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
 
     // Allocate buffer for normal vectors

+ 15 - 9
Source/ThirdParty/Assimp/code/ObjFileMtlImporter.cpp

@@ -48,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ObjFileData.h"
 #include "fast_atof.h"
 #include "ParsingUtils.h"
-#include "../include/assimp/material.h"
-#include "../include/assimp/DefaultLogger.hpp"
+#include <assimp/material.h>
+#include <assimp/DefaultLogger.hpp>
 
 
 namespace Assimp    {
@@ -162,11 +162,17 @@ void ObjFileMtlImporter::load()
             }
             break;
 
-        case 'd':   // Alpha value
+        case 'd':   
             {
-                ++m_DataIt;
-                getFloatValue( m_pModel->m_pCurrentMaterial->alpha );
-                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+                if( *(m_DataIt+1) == 'i' && *( m_DataIt + 2 ) == 's' && *( m_DataIt + 3 ) == 'p' ) {
+                    // A displacement map
+                    getTexture();
+                } else {
+                    // Alpha value
+                    ++m_DataIt;
+                    getFloatValue( m_pModel->m_pCurrentMaterial->alpha );
+                    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+                }
             }
             break;
 
@@ -343,9 +349,9 @@ void ObjFileMtlImporter::getTexture() {
     getTextureOption(clamp);
     m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
 
-    std::string strTexture;
-    m_DataIt = getName<DataArrayIt>( m_DataIt, m_DataItEnd, strTexture );
-    out->Set( strTexture );
+    std::string texture;
+    m_DataIt = getName<DataArrayIt>( m_DataIt, m_DataItEnd, texture );
+    out->Set( texture );
 }
 
 /* /////////////////////////////////////////////////////////////////////////////

+ 4 - 7
Source/ThirdParty/Assimp/code/ObjFileMtlImporter.h

@@ -44,14 +44,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiColor3D;
 
-namespace Assimp
-{
-
-namespace ObjFile
-{
-struct Model;
-struct Material;
+namespace Assimp {
 
+namespace ObjFile {
+    struct Model;
+    struct Material;
 }
 
 

+ 56 - 51
Source/ThirdParty/Assimp/code/ObjFileParser.cpp

@@ -47,12 +47,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ObjTools.h"
 #include "ObjFileData.h"
 #include "ParsingUtils.h"
-#include "../include/assimp/types.h"
 #include "DefaultIOSystem.h"
 #include "BaseImporter.h"
-#include "../include/assimp/DefaultLogger.hpp"
-#include "../include/assimp/material.h"
-#include "../include/assimp/Importer.hpp"
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/material.h>
+#include <assimp/Importer.hpp>
 #include <cstdlib>
 
 
@@ -62,21 +61,21 @@ const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
 
 // -------------------------------------------------------------------
 //  Constructor with loaded data and directories.
-ObjFileParser::ObjFileParser(std::vector<char> &Data,const std::string &strModelName, IOSystem *io ) :
-    m_DataIt(Data.begin()),
-    m_DataItEnd(Data.end()),
+ObjFileParser::ObjFileParser(std::vector<char> &data,const std::string &modelName, IOSystem *io ) :
+    m_DataIt(data.begin()),
+    m_DataItEnd(data.end()),
     m_pModel(NULL),
     m_uiLine(0),
     m_pIO( io )
 {
-    std::fill_n(m_buffer,BUFFERSIZE,0);
+    std::fill_n(m_buffer,Buffersize,0);
 
     // Create the model instance to store all the data
     m_pModel = new ObjFile::Model();
-    m_pModel->m_ModelName = strModelName;
+    m_pModel->m_ModelName = modelName;
 
     // create default material and store it
-    m_pModel->m_pDefaultMaterial = new ObjFile::Material();
+    m_pModel->m_pDefaultMaterial = new ObjFile::Material;
     m_pModel->m_pDefaultMaterial->MaterialName.Set( DEFAULT_MATERIAL );
     m_pModel->m_MaterialLib.push_back( DEFAULT_MATERIAL );
     m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial;
@@ -249,20 +248,20 @@ void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
     }
     float x, y, z;
     if( 2 == numComponents ) {
-        copyNextWord( m_buffer, BUFFERSIZE );
+        copyNextWord( m_buffer, Buffersize );
         x = ( float ) fast_atof( m_buffer );
 
-        copyNextWord( m_buffer, BUFFERSIZE );
+        copyNextWord( m_buffer, Buffersize );
         y = ( float ) fast_atof( m_buffer );
         z = 0.0;
     } else if( 3 == numComponents ) {
-        copyNextWord( m_buffer, BUFFERSIZE );
+        copyNextWord( m_buffer, Buffersize );
         x = ( float ) fast_atof( m_buffer );
 
-        copyNextWord( m_buffer, BUFFERSIZE );
+        copyNextWord( m_buffer, Buffersize );
         y = ( float ) fast_atof( m_buffer );
 
-        copyNextWord( m_buffer, BUFFERSIZE );
+        copyNextWord( m_buffer, Buffersize );
         z = ( float ) fast_atof( m_buffer );
     } else {
         throw DeadlyImportError( "OBJ: Invalid number of components" );
@@ -275,13 +274,13 @@ void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
 //  Get values for a new 3D vector instance
 void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
     float x, y, z;
-    copyNextWord(m_buffer, BUFFERSIZE);
+    copyNextWord(m_buffer, Buffersize);
     x = (float) fast_atof(m_buffer);
 
-    copyNextWord(m_buffer, BUFFERSIZE);
+    copyNextWord(m_buffer, Buffersize);
     y = (float) fast_atof(m_buffer);
 
-    copyNextWord( m_buffer, BUFFERSIZE );
+    copyNextWord( m_buffer, Buffersize );
     z = ( float ) fast_atof( m_buffer );
 
     point3d_array.push_back( aiVector3D( x, y, z ) );
@@ -292,10 +291,10 @@ void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
 //  Get values for a new 2D vector instance
 void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
     float x, y;
-    copyNextWord(m_buffer, BUFFERSIZE);
+    copyNextWord(m_buffer, Buffersize);
     x = (float) fast_atof(m_buffer);
 
-    copyNextWord(m_buffer, BUFFERSIZE);
+    copyNextWord(m_buffer, Buffersize);
     y = (float) fast_atof(m_buffer);
 
     point2d_array.push_back(aiVector2D(x, y));
@@ -307,12 +306,12 @@ void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
 //  Get values for a new face instance
 void ObjFileParser::getFace(aiPrimitiveType type)
 {
-    copyNextLine(m_buffer, BUFFERSIZE);
+    copyNextLine(m_buffer, Buffersize);
     if (m_DataIt == m_DataItEnd)
         return;
 
     char *pPtr = m_buffer;
-    char *pEnd = &pPtr[BUFFERSIZE];
+    char *pEnd = &pPtr[Buffersize];
     pPtr = getNextToken<char*>(pPtr, pEnd);
     if (pPtr == pEnd || *pPtr == '\0')
         return;
@@ -413,38 +412,41 @@ void ObjFileParser::getFace(aiPrimitiveType type)
         pPtr += iStep;
     }
 
-    if ( pIndices->empty() )
-    {
+    if ( pIndices->empty() ) {
         DefaultLogger::get()->error("Obj: Ignoring empty face");
+        // skip line and clean up 
         m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+        delete pNormalID;
         delete pTexID;
+        delete pIndices;
+
         return;
     }
 
     ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID, type );
 
     // Set active material, if one set
-    if (NULL != m_pModel->m_pCurrentMaterial)
+    if( NULL != m_pModel->m_pCurrentMaterial ) {
         face->m_pMaterial = m_pModel->m_pCurrentMaterial;
-    else
+    } else {
         face->m_pMaterial = m_pModel->m_pDefaultMaterial;
+    }
 
     // Create a default object, if nothing is there
-    if ( NULL == m_pModel->m_pCurrent )
+    if( NULL == m_pModel->m_pCurrent ) {
         createObject( "defaultobject" );
+    }
 
     // Assign face to mesh
-    if ( NULL == m_pModel->m_pCurrentMesh )
-    {
-        createMesh();
+    if ( NULL == m_pModel->m_pCurrentMesh ) {
+        createMesh( "defaultobject" );
     }
 
     // Store the face
     m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
     m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
     m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size();
-    if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal )
-    {
+    if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) {
         m_pModel->m_pCurrentMesh->m_hasNormals = true;
     }
     // Skip the rest of the line
@@ -466,8 +468,9 @@ void ObjFileParser::getMaterialDesc()
 
     // Get next data for material data
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
-    if (m_DataIt == m_DataItEnd)
+    if (m_DataIt == m_DataItEnd) {
         return;
+    }
 
     char *pStart = &(*m_DataIt);
     while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
@@ -481,19 +484,16 @@ void ObjFileParser::getMaterialDesc()
 
     // Search for material
     std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strName );
-    if ( it == m_pModel->m_MaterialMap.end() )
-    {
+    if ( it == m_pModel->m_MaterialMap.end() ) {
         // Not found, use default material
         m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
         DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping");
-    }
-    else
-    {
+    } else {
         // Found, using detected material
         m_pModel->m_pCurrentMaterial = (*it).second;
         if ( needsNewMesh( strName ))
         {
-            createMesh();
+            createMesh( strName  );
         }
         m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName );
     }
@@ -537,18 +537,24 @@ void ObjFileParser::getMaterialLib()
 
     // Check for existence
     const std::string strMatName(pStart, &(*m_DataIt));
-    IOStream *pFile = m_pIO->Open(strMatName);
+    std::string absName;
+    if ( m_pIO->StackSize() > 0 ) {
+        const std::string &path = m_pIO->CurrentDirectory();
+        absName = path + strMatName;
+    } else {
+        absName = strMatName;
+    }
+    IOStream *pFile = m_pIO->Open( absName );
 
-    if (!pFile )
-    {
-        DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
+    if (!pFile ) {
+        DefaultLogger::get()->error( "OBJ: Unable to locate material file " + strMatName );
         m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
         return;
     }
 
     // Import material library data from file
     std::vector<char> buffer;
-    BaseImporter::TextFileToBuffer(pFile,buffer);
+    BaseImporter::TextFileToBuffer( pFile, buffer );
     m_pIO->Close( pFile );
 
     // Importing the material library
@@ -582,7 +588,7 @@ void ObjFileParser::getNewMaterial()
         // Set new material
         if ( needsNewMesh( strMat ) )
         {
-            createMesh();
+            createMesh( strMat );
         }
         m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
     }
@@ -703,16 +709,15 @@ void ObjFileParser::getObjectName()
 }
 // -------------------------------------------------------------------
 //  Creates a new object instance
-void ObjFileParser::createObject(const std::string &strObjectName)
+void ObjFileParser::createObject(const std::string &objName)
 {
     ai_assert( NULL != m_pModel );
-    //ai_assert( !strObjectName.empty() );
 
     m_pModel->m_pCurrent = new ObjFile::Object;
-    m_pModel->m_pCurrent->m_strObjName = strObjectName;
+    m_pModel->m_pCurrent->m_strObjName = objName;
     m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
 
-    createMesh();
+    createMesh( objName  );
 
     if( m_pModel->m_pCurrentMaterial )
     {
@@ -723,10 +728,10 @@ void ObjFileParser::createObject(const std::string &strObjectName)
 }
 // -------------------------------------------------------------------
 //  Creates a new mesh
-void ObjFileParser::createMesh()
+void ObjFileParser::createMesh( const std::string &meshName )
 {
     ai_assert( NULL != m_pModel );
-    m_pModel->m_pCurrentMesh = new ObjFile::Mesh;
+    m_pModel->m_pCurrentMesh = new ObjFile::Mesh( meshName );
     m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
     unsigned int meshId = m_pModel->m_Meshes.size()-1;
     if ( NULL != m_pModel->m_pCurrent )

+ 19 - 20
Source/ThirdParty/Assimp/code/ObjFileParser.h

@@ -43,30 +43,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <string>
 #include <map>
-#include "../include/assimp/vector2.h"
-#include "../include/assimp/vector3.h"
-#include "../include/assimp/mesh.h"
-
-namespace Assimp
-{
-
-namespace ObjFile
-{
-struct Model;
-struct Object;
-struct Material;
-struct Point3;
-struct Point2;
+#include <assimp/vector2.h>
+#include <assimp/vector3.h>
+#include <assimp/mesh.h>
+
+namespace Assimp {
+
+namespace ObjFile {
+    struct Model;
+    struct Object;
+    struct Material;
+    struct Point3;
+    struct Point2;
 }
+
 class ObjFileImporter;
 class IOSystem;
 
 /// \class  ObjFileParser
 /// \brief  Parser for a obj waveform file
-class ObjFileParser
-{
+class ObjFileParser {
 public:
-    static const size_t BUFFERSIZE = 4096;
+    static const size_t Buffersize = 4096;
     typedef std::vector<char> DataArray;
     typedef std::vector<char>::iterator DataArrayIt;
     typedef std::vector<char>::const_iterator ConstDataArrayIt;
@@ -113,9 +111,9 @@ private:
     /// Parse object name
     void getObjectName();
     /// Creates a new object.
-    void createObject(const std::string &strObjectName);
+    void createObject( const std::string &strObjectName );
     /// Creates a new mesh.
-    void createMesh();
+    void createMesh( const std::string &meshName );
     /// Returns true, if a new mesh instance must be created.
     bool needsNewMesh( const std::string &rMaterialName );
     /// Error report in token
@@ -138,9 +136,10 @@ private:
     //! Current line (for debugging)
     unsigned int m_uiLine;
     //! Helper buffer
-    char m_buffer[BUFFERSIZE];
+    char m_buffer[Buffersize];
     /// Pointer to IO system instance.
     IOSystem *m_pIO;
+    /// Path to the current model
 };
 
 }   // Namespace Assimp

+ 185 - 0
Source/ThirdParty/Assimp/code/OgreImporter.hpp

@@ -0,0 +1,185 @@
+#include "BaseImporter.h"
+
+#include <vector>
+
+#include "OgreXmlHelper.hpp"
+#include "irrXMLWrapper.h"
+
+/// Ogre Importer TODO
+/*	- Read Vertex Colors
+	- Read multiple TexCoords
+*/
+
+
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+
+//Forward declarations:
+struct Face;
+struct Weight;
+struct Bone;
+struct Animation;
+struct Track;
+struct Keyframe;
+
+///A submesh from Ogre
+struct SubMesh
+{	
+	bool SharedData;
+
+	std::string Name;
+	std::string MaterialName;
+	std::vector<Face> FaceList;
+
+	std::vector<aiVector3D> Positions; bool HasPositions;
+	std::vector<aiVector3D> Normals; bool HasNormals;
+	std::vector<aiVector3D> Tangents; bool HasTangents;
+	std::vector<std::vector<aiVector3D> > Uvs;//arbitrary number of texcoords, they are nearly always 2d, but assimp has always 3d texcoords, n vectors(outer) with texcoords for each vertex(inner)
+
+	std::vector< std::vector<Weight> > Weights;//a list(inner) of bones for each vertex(outer)
+	int MaterialIndex;///< The Index in the Assimp Materialarray from the material witch is attached to this submesh
+	unsigned int BonesUsed;//the highest index of a bone from a bone weight, this is needed to create the assimp bone structur (converting from Vertex-Bones to Bone-Vertices)
+
+	SubMesh(): SharedData(false), HasPositions(false), HasNormals(false), HasTangents(false),
+		MaterialIndex(-1), BonesUsed(0) {}//initialize everything
+};
+
+
+///The Main Ogre Importer Class
+class OgreImporter : public BaseImporter
+{
+public:
+	virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
+	virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+	virtual const aiImporterDesc* GetInfo () const;
+	virtual void SetupProperties(const Importer* pImp);
+private:
+
+
+	//-------------------------------- OgreMesh.cpp -------------------------------
+	/// Helper Functions to read parts of the XML File
+	void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);//the submesh reference is the result value
+
+	/// Reads a single Vertexbuffer and writes its data in the Submesh
+	static void ReadVertexBuffer(SubMesh &theSubMesh, XmlReader *Reader, unsigned int NumVertices);
+
+	/// Reads bone weights are stores them into the given submesh
+	static void ReadBoneWeights(SubMesh &theSubMesh, XmlReader *Reader);
+
+	/// After Loading a SubMehs some work needs to be done (make all Vertexes unique, normalize weights)
+	static void ProcessSubMesh(SubMesh &theSubMesh, SubMesh &theSharedGeometry);
+
+	/// Uses the bone data to convert a SubMesh into a aiMesh which will be created and returned
+	aiMesh* CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector<Bone>& Bones) const;
+	
+
+	//-------------------------------- OgreSkeleton.cpp -------------------------------
+	/// Writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it!
+	void LoadSkeleton(std::string FileName, std::vector<Bone> &Bones, std::vector<Animation> &Animations) const;
+
+	/// Converts the animations in aiAnimations and puts them into the scene
+	void PutAnimationsInScene(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
+
+	/// Creates the aiskeleton in current scene
+	void CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations);
+
+	/// Recursivly creates a filled aiNode from a given root bone
+	static aiNode* CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode);
+	
+
+	//-------------------------------- OgreMaterial.cpp -------------------------------
+	aiMaterial* LoadMaterial(const std::string MaterialName) const;
+	void ReadTechnique(std::stringstream &ss, aiMaterial* NewMaterial) const;
+	
+
+
+
+	//Now we don't have to give theses parameters to all functions
+	std::string m_CurrentFilename;
+	std::string m_MaterialLibFilename;
+	bool m_TextureTypeFromFilename;
+	IOSystem* m_CurrentIOHandler;
+	aiScene *m_CurrentScene;
+	SubMesh m_SharedGeometry;///< we will just use the vertexbuffers of the submesh
+};
+
+///For the moment just triangles, no other polygon types!
+struct Face
+{
+	unsigned int VertexIndices[3];
+};
+
+struct BoneAssignment
+{
+	unsigned int BoneId;//this is, what we get from ogre
+	std::string BoneName;//this is, what we need for assimp
+};
+
+///for a vertex->bone structur
+struct Weight
+{
+	unsigned int BoneId;
+	float Value;
+};
+
+
+/// Helper Class to describe an ogre-bone for the skeleton:
+/** All Id's are signed ints, because than we have -1 as a simple INVALID_ID Value (we start from 0 so 0 is a valid bone ID!*/
+struct Bone
+{
+	int Id;
+	int ParentId;
+	std::string Name;
+	aiVector3D Position;
+	float RotationAngle;
+	aiVector3D RotationAxis;
+	std::vector<int> Children;
+	aiMatrix4x4 BoneToWorldSpace;
+
+	///ctor
+	Bone(): Id(-1), ParentId(-1), RotationAngle(0.0f) {}
+	///this operator is needed to sort the bones after Id's
+	bool operator<(const Bone& rval) const
+		{return Id<rval.Id; }
+	///this operator is needed to find a bone by its name in a vector<Bone>
+	bool operator==(const std::string& rval) const
+		{return Name==rval; }
+	bool operator==(const aiString& rval) const
+	{return Name==std::string(rval.data); }
+
+	// implemented in OgreSkeleton.cpp
+	void CalculateBoneToWorldSpaceMatrix(std::vector<Bone>& Bones);
+};
+
+
+
+///Describes an Ogre Animation
+struct Animation
+{
+	std::string Name;
+	float Length;
+	std::vector<Track> Tracks;
+};
+
+///a track (keyframes for one bone) from an animation
+struct Track
+{
+	std::string BoneName;
+	std::vector<Keyframe> Keyframes;
+};
+
+/// keyframe (bone transformation) from a track from a animation
+struct Keyframe
+{
+	float Time;
+	aiVector3D Position;
+	aiQuaternion Rotation;
+	aiVector3D Scaling;
+};
+
+}//namespace Ogre
+}//namespace Assimp

+ 7 - 0
Source/ThirdParty/Assimp/code/OgreParsingUtils.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 #ifndef AI_OGREPARSINGUTILS_H_INC
 #define AI_OGREPARSINGUTILS_H_INC
 
@@ -46,7 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ParsingUtils.h"
 #include <functional>
 #include <algorithm>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <sstream>
 #include <cctype>
 

+ 88 - 0
Source/ThirdParty/Assimp/code/OgreXmlHelper.hpp

@@ -0,0 +1,88 @@
+
+#include "irrXMLWrapper.h"
+#include "fast_atof.h"
+
+namespace Assimp
+{
+namespace Ogre
+{
+	
+typedef irr::io::IrrXMLReader XmlReader;
+
+
+//------------Helper Funktion to Get a Attribute Save---------------
+template<typename t> inline t GetAttribute(XmlReader* Reader, std::string Name);
+
+/*
+{
+	BOOST_STATIC_ASSERT(false);
+	return t();
+}
+*/
+
+template<> inline int GetAttribute<int>(XmlReader* Reader, std::string Name)
+{
+	const char* Value=Reader->getAttributeValue(Name.c_str());
+	if(Value)
+		return atoi(Value);
+	else
+		throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
+}
+
+template<> inline unsigned int GetAttribute<unsigned int>(XmlReader* Reader, std::string Name)
+{
+	const char* Value=Reader->getAttributeValue(Name.c_str());
+	if(Value)
+		return static_cast<unsigned int>(atoi(Value));//yes, ugly, but pfff
+	else
+		throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
+}
+
+template<> inline float GetAttribute<float>(XmlReader* Reader, std::string Name)
+{
+	const char* Value=Reader->getAttributeValue(Name.c_str());
+	if(Value)
+		return fast_atof(Value);
+	else
+		throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
+}
+
+template<> inline std::string GetAttribute<std::string>(XmlReader* Reader, std::string Name)
+{
+	const char* Value=Reader->getAttributeValue(Name.c_str());
+	if(Value)
+		return std::string(Value);
+	else
+		throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
+}
+
+template<> inline bool GetAttribute<bool>(XmlReader* Reader, std::string Name)
+{
+	const char* Value=Reader->getAttributeValue(Name.c_str());
+	if(Value)
+	{
+		if(Value==std::string("true"))
+			return true;
+		else if(Value==std::string("false"))
+			return false;
+		else
+			throw DeadlyImportError(std::string("Bool value has invalid value: "+Name+" / "+Value+" / "+Reader->getNodeName()));
+	}
+	else
+		throw DeadlyImportError(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str());
+}
+//__________________________________________________________________
+
+inline bool XmlRead(XmlReader* Reader)
+{
+	do
+	{
+		if(!Reader->read())
+			return false;
+	}
+	while(Reader->getNodeType()!=irr::io::EXN_ELEMENT);
+	return true;
+}
+
+}//namespace Ogre
+}//namespace Assimp

+ 53 - 0
Source/ThirdParty/Assimp/code/OpenGEXExporter.cpp

@@ -0,0 +1,53 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, 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 "OpenGEXExporter.h"
+
+namespace Assimp {
+namespace OpenGEX {
+
+OpenGEXExporter::OpenGEXExporter() {
+}
+
+OpenGEXExporter::~OpenGEXExporter() {
+}
+
+
+} // Namespace openGEX
+} // Namespace Assimp

+ 65 - 0
Source/ThirdParty/Assimp/code/OpenGEXExporter.h

@@ -0,0 +1,65 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef AI_OPENGEX_EXPORTER_H
+#define AI_OPENGEX_EXPORTER_H
+
+#include "../include/assimp/types.h"
+
+#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+namespace Assimp {
+
+struct aiScene;
+
+namespace OpenGEX {
+
+    class OpenGEXExporter {
+    public:
+        OpenGEXExporter();
+        ~OpenGEXExporter();
+        bool exportScene( const char *filename, const aiScene* pScene );
+    };
+} // Namespace openGEX
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#endif // AI_OPENGEX_EXPORTER_H
+

+ 963 - 0
Source/ThirdParty/Assimp/code/OpenGEXImporter.cpp

@@ -0,0 +1,963 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#include "OpenGEXImporter.h"
+#include "DefaultIOSystem.h"
+#include "MakeVerboseFormat.h"
+
+#include <openddlparser/OpenDDLParser.h>
+#include <assimp/scene.h>
+#include <assimp/ai_assert.h>
+
+#include <vector>
+
+static const aiImporterDesc desc = {
+    "Open Game Engine Exchange",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "ogex"
+};
+
+namespace Grammar {
+    static const std::string MetricType = "Metric";
+    static const std::string Metric_DistanceType = "distance";
+    static const std::string Metric_AngleType = "angle";
+    static const std::string Metric_TimeType = "time";
+    static const std::string Metric_UpType = "up";
+    static const std::string NameType = "Name";
+    static const std::string ObjectRefType = "ObjectRef";
+    static const std::string MaterialRefType = "MaterialRef";
+    static const std::string MetricKeyType = "key";
+    static const std::string GeometryNodeType = "GeometryNode";
+    static const std::string GeometryObjectType = "GeometryObject";
+    static const std::string TransformType = "Transform";
+    static const std::string MeshType = "Mesh";
+    static const std::string VertexArrayType = "VertexArray";
+    static const std::string IndexArrayType = "IndexArray";
+    static const std::string MaterialType = "Material";
+    static const std::string ColorType = "Color";
+    static const std::string DiffuseColorToken = "diffuse";
+    static const std::string SpecularColorToken = "specular";
+    static const std::string EmissionColorToken = "emission";
+
+    static const std::string DiffuseTextureToken = "diffuse";
+    static const std::string DiffuseSpecularTextureToken = "specular";
+    static const std::string SpecularPowerTextureToken = "specular_power";
+    static const std::string EmissionTextureToken = "emission";
+    static const std::string OpacyTextureToken = "opacity";
+    static const std::string TransparencyTextureToken = "transparency";
+    static const std::string NormalTextureToken = "normal";
+
+    static const char *TextureType         = "Texture";
+
+    enum TokenType {
+        NoneType = -1,
+        MetricToken,
+        NameToken,
+        ObjectRefToken,
+        MaterialRefToken,
+        MetricKeyToken,
+        GeometryNodeToken,
+        GeometryObjectToken,
+        TransformToken,
+        MeshToken,
+        VertexArrayToken,
+        IndexArrayToken,
+        MaterialToken,
+        ColorToken,
+        TextureToken
+    };
+
+    static const std::string ValidMetricToken[ 4 ] = {
+        Metric_DistanceType,
+        Metric_AngleType,
+        Metric_TimeType,
+        Metric_UpType
+    };
+
+    static int isValidMetricType( const char *token ) {
+        if( NULL == token ) {
+            return false;
+        }
+
+        int idx( -1 );
+        for( size_t i = 0; i < 4; i++ ) {
+            if( ValidMetricToken[ i ] == token ) {
+                idx = (int) i;
+                break;
+            }
+        }
+
+        return idx;
+    }
+
+    static TokenType matchTokenType( const char *tokenType ) {
+        if( MetricType == tokenType ) {
+            return MetricToken;
+        } else if(  NameType == tokenType ) {
+            return NameToken;
+        } else if( ObjectRefType == tokenType ) {
+            return ObjectRefToken;
+        } else if( MaterialRefType == tokenType ) {
+            return MaterialRefToken;
+        } else if( MetricKeyType == tokenType ) {
+            return MetricKeyToken;
+        } else if( GeometryNodeType == tokenType ) {
+            return GeometryNodeToken;
+        } else if( GeometryObjectType == tokenType ) {
+            return GeometryObjectToken;
+        } else if( TransformType == tokenType ) {
+            return TransformToken;
+        } else if( MeshType == tokenType ) {
+            return MeshToken;
+        } else if( VertexArrayType == tokenType ) {
+            return VertexArrayToken;
+        } else if( IndexArrayType == tokenType ) {
+            return IndexArrayToken;
+        } else if(  MaterialType == tokenType ) {
+            return MaterialToken;
+        } else if( ColorType == tokenType ) {
+            return ColorToken;
+        } else if(  TextureType == tokenType ) {
+            return TextureToken;
+        }
+
+        return NoneType;
+    }
+
+} // Namespace Grammar
+
+namespace Assimp {
+namespace OpenGEX {
+
+USE_ODDLPARSER_NS
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::VertexContainer::VertexContainer()
+: m_numVerts( 0 )
+, m_vertices(NULL)
+, m_numNormals( 0 )
+, m_normals(NULL)
+, m_numUVComps()
+, m_textureCoords() {
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::VertexContainer::~VertexContainer() {
+    delete[] m_vertices;
+    delete[] m_normals;
+    for( size_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++ ) {
+        delete [] m_textureCoords[ i ];
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::RefInfo::RefInfo( aiNode *node, Type type, std::vector<std::string> &names )
+: m_node( node )
+, m_type( type )
+, m_Names( names ) {
+    // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::RefInfo::~RefInfo() {
+    // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::OpenGEXImporter()
+: m_root( NULL )
+, m_nodeChildMap()
+, m_meshCache()
+, m_mesh2refMap()
+, m_ctx( NULL )
+, m_metrics()
+, m_currentNode( NULL )
+, m_currentMesh( NULL )
+, m_currentMaterial( NULL )
+, m_tokenType( Grammar::NoneType )
+, m_nodeStack()
+, m_unresolvedRefStack() {
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::~OpenGEXImporter() {
+    m_ctx = NULL;
+}
+
+//------------------------------------------------------------------------------------------------
+bool OpenGEXImporter::CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const {
+    bool canRead( false );
+    if( !checkSig ) {
+        canRead = SimpleExtensionCheck( file, "ogex" );
+    } else {
+        static const char *token[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
+        canRead = BaseImporter::SearchFileHeaderForToken( pIOHandler, file, token, 4 );
+    }
+
+    return canRead;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
+    // open source file
+    IOStream *file = pIOHandler->Open( filename, "rb" );
+    if( !file ) {
+        throw DeadlyImportError( "Failed to open file " + filename );
+    }
+
+    std::vector<char> buffer;
+    TextFileToBuffer( file, buffer );
+
+    OpenDDLParser myParser;
+    myParser.setBuffer( &buffer[ 0 ], buffer.size() );
+    bool success( myParser.parse() );
+    if( success ) {
+        m_ctx = myParser.getContext();
+        pScene->mRootNode = new aiNode;
+        pScene->mRootNode->mName.Set( filename );
+        handleNodes( m_ctx->m_root, pScene );
+    }
+
+    copyMeshes( pScene );
+    resolveReferences();
+    createNodeTree( pScene );
+}
+
+//------------------------------------------------------------------------------------------------
+const aiImporterDesc *OpenGEXImporter::GetInfo() const {
+    return &desc;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::SetupProperties( const Importer *pImp ) {
+    if( NULL == pImp ) {
+        return;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleNodes( DDLNode *node, aiScene *pScene ) {
+    if( NULL == node ) {
+        return;
+    }
+
+    DDLNode::DllNodeList childs = node->getChildNodeList();
+    for( DDLNode::DllNodeList::iterator it = childs.begin(); it != childs.end(); ++it ) {
+        Grammar::TokenType tokenType( Grammar::matchTokenType( ( *it )->getType().c_str() ) );
+        switch( tokenType ) {
+            case Grammar::MetricToken:
+                handleMetricNode( *it, pScene );
+                break;
+
+            case Grammar::NameToken:
+                handleNameNode( *it, pScene );
+                break;
+
+            case Grammar::ObjectRefToken:
+                handleObjectRefNode( *it, pScene );
+                break;
+
+            case Grammar::MaterialRefToken:
+                handleMaterialRefNode( *it, pScene );
+                break;
+
+            case Grammar::MetricKeyToken:
+                break;
+
+            case Grammar::GeometryNodeToken:
+                handleGeometryNode( *it, pScene );
+                break;
+
+            case Grammar::GeometryObjectToken:
+                handleGeometryObject( *it, pScene );
+                break;
+
+            case Grammar::TransformToken:
+                handleTransformNode( *it, pScene );
+                break;
+
+            case Grammar::MeshToken:
+                handleMeshNode( *it, pScene );
+                break;
+
+            case Grammar::VertexArrayToken:
+                handleVertexArrayNode( *it, pScene );
+                break;
+
+            case Grammar::IndexArrayToken:
+                handleIndexArrayNode( *it, pScene );
+                break;
+
+            case Grammar::MaterialToken:
+                handleMaterialNode( *it, pScene );
+                break;
+
+            case Grammar::ColorToken:
+                handleColorNode( *it, pScene );
+                break;
+
+            case Grammar::TextureToken:
+                handleTextureNode( *it, pScene );
+                break;
+
+            default:
+                break;
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMetricNode( DDLNode *node, aiScene *pScene ) {
+    if( NULL == node || NULL == m_ctx ) {
+        return;
+    }
+
+    if( m_ctx->m_root != node->getParent() ) {
+        return;
+    }
+
+    Property *prop( node->getProperties() );
+    while( NULL != prop ) {
+        if( NULL != prop->m_key ) {
+            if( Value::ddl_string == prop->m_value->m_type ) {
+                std::string valName( ( char* ) prop->m_value->m_data );
+                int type( Grammar::isValidMetricType( valName.c_str() ) );
+                if( Grammar::NoneType != type ) {
+                    Value *val( node->getValue() );
+                    if( NULL != val ) {
+                        if( Value::ddl_float == val->m_type ) {
+                            m_metrics[ type ].m_floatValue = val->getFloat();
+                        } else if( Value::ddl_int32 == val->m_type ) {
+                            m_metrics[ type ].m_intValue = val->getInt32();
+                        } else if( Value::ddl_string == val->m_type ) {
+                            m_metrics[type].m_stringValue = std::string( val->getString() );
+                        } else {
+                            throw DeadlyImportError( "OpenGEX: invalid data type for Metric node." );
+                        }
+                    }
+                }
+            }
+        }
+        prop = prop->m_next;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleNameNode( DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    Value *val( node->getValue() );
+    if( NULL != val ) {
+        if( Value::ddl_string != val->m_type ) {
+            throw DeadlyImportError( "OpenGEX: invalid data type for value in node name." );
+            return;
+        }
+
+        const std::string name( val->getString() );
+        if( m_tokenType == Grammar::GeometryNodeToken ) {
+            m_currentNode->mName.Set( name.c_str() );
+        } else if( m_tokenType == Grammar::MaterialToken ) {
+
+        }
+
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+static void getRefNames( DDLNode *node, std::vector<std::string> &names ) {
+    ai_assert( NULL != node );
+
+    Reference *ref = node->getReferences();
+    if( NULL != ref ) {
+        for( size_t i = 0; i < ref->m_numRefs; i++ )  {
+            Name *currentName( ref->m_referencedName[ i ] );
+            if( NULL != currentName && NULL != currentName->m_id ) {
+                const std::string name( currentName->m_id->m_text.m_buffer );
+                if( !name.empty() ) {
+                    names.push_back( name );
+                }
+            }
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleObjectRefNode( DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    std::vector<std::string> objRefNames;
+    getRefNames( node, objRefNames );
+    m_currentNode->mNumMeshes = objRefNames.size();
+    m_currentNode->mMeshes = new unsigned int[ objRefNames.size() ];
+    if( !objRefNames.empty() ) {
+        m_unresolvedRefStack.push_back( new RefInfo( m_currentNode, RefInfo::MeshRef, objRefNames ) );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMaterialRefNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    std::vector<std::string> matRefNames;
+    getRefNames( node, matRefNames );
+    if( !matRefNames.empty() ) {
+        m_unresolvedRefStack.push_back( new RefInfo( m_currentNode, RefInfo::MaterialRef, matRefNames ) );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleGeometryNode( DDLNode *node, aiScene *pScene ) {
+    aiNode *newNode = new aiNode;
+    pushNode( newNode, pScene );
+    m_tokenType = Grammar::GeometryNodeToken;
+    m_currentNode = newNode;
+    handleNodes( node, pScene );
+
+    popNode();
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleGeometryObject( DDLNode *node, aiScene *pScene ) {
+    handleNodes( node, pScene );
+}
+
+//------------------------------------------------------------------------------------------------
+static void setMatrix( aiNode *node, DataArrayList *transformData ) {
+    ai_assert( NULL != node );
+    ai_assert( NULL != transformData );
+
+    float m[ 16 ];
+    size_t i( 1 );
+    Value *next( transformData->m_dataList->m_next );
+    m[ 0 ] = transformData->m_dataList->getFloat();
+    while(  next != NULL ) {
+        m[ i ] = next->getFloat();
+        next = next->m_next;
+        i++;
+    }
+
+    node->mTransformation.a1 = m[ 0 ];
+    node->mTransformation.a2 = m[ 4 ];
+    node->mTransformation.a3 = m[ 8 ];
+    node->mTransformation.a4 = m[ 12 ];
+
+    node->mTransformation.b1 = m[ 1 ];
+    node->mTransformation.b2 = m[ 5 ];
+    node->mTransformation.b3 = m[ 9 ];
+    node->mTransformation.b4 = m[ 13 ];
+
+    node->mTransformation.c1 = m[ 2 ];
+    node->mTransformation.c2 = m[ 6 ];
+    node->mTransformation.c3 = m[ 10 ];
+    node->mTransformation.c4 = m[ 14 ];
+
+    node->mTransformation.d1 = m[ 3 ];
+    node->mTransformation.d2 = m[ 7 ];
+    node->mTransformation.d3 = m[ 11 ];
+    node->mTransformation.d4 = m[ 15 ];
+
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleTransformNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+
+    DataArrayList *transformData( node->getDataArrayList() );
+    if( NULL != transformData ) {
+        if( transformData->m_numItems != 16 ) {
+            throw DeadlyImportError( "Invalid number of data for transform matrix." );
+            return;
+        }
+        setMatrix( m_currentNode, transformData );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+static void propId2StdString( Property *prop, std::string &name, std::string &key ) {
+    name = key = "";
+    if( NULL == prop ) {
+        return;
+    }
+
+    if( NULL != prop->m_key ) {
+        name = prop->m_key->m_text.m_buffer;
+        if( Value::ddl_string == prop->m_value->m_type ) {
+            key = prop->m_value->getString();
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    m_currentMesh = new aiMesh;
+    const size_t meshidx( m_meshCache.size() );
+    m_meshCache.push_back( m_currentMesh );
+
+    Property *prop = node->getProperties();
+    if( NULL != prop ) {
+        std::string propName, propKey;
+        propId2StdString( prop, propName, propKey );
+        if( "primitive" == propName ) {
+            if( "triangles" == propKey ) {
+                m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+            }
+        }
+    }
+
+    handleNodes( node, pScene );
+
+    DDLNode *parent( node->getParent() );
+    if( NULL != parent ) {
+        const std::string &name = parent->getName();
+        m_mesh2refMap[ name ] = meshidx;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+enum MeshAttribute {
+    None,
+    Position,
+    Normal,
+    TexCoord
+};
+
+//------------------------------------------------------------------------------------------------
+static MeshAttribute getAttributeByName( const char *attribName ) {
+    ai_assert( NULL != attribName  );
+
+    if( 0 == strncmp( "position", attribName, strlen( "position" ) ) ) {
+        return Position;
+    } else if( 0 == strncmp( "normal", attribName, strlen( "normal" ) ) ) {
+        return Normal;
+    } else if( 0 == strncmp( "texcoord", attribName, strlen( "texcoord" ) ) ) {
+        return TexCoord;
+    }
+
+    return None;
+}
+
+//------------------------------------------------------------------------------------------------
+static void fillVector3( aiVector3D *vec3, Value *vals ) {
+    ai_assert( NULL != vec3 );
+    ai_assert( NULL != vals );
+
+    float x( 0.0f ), y( 0.0f ), z( 0.0f );
+    Value *next( vals );
+    x = next->getFloat();
+    next = next->m_next;
+    y = next->getFloat();
+    next = next->m_next;
+    if( NULL != next ) {
+        z = next->getFloat();
+    }
+
+    vec3->Set( x, y, z );
+}
+
+//------------------------------------------------------------------------------------------------
+static size_t countDataArrayListItems( DataArrayList *vaList ) {
+    size_t numItems( 0 );
+    if( NULL == vaList ) {
+        return numItems;
+    }
+
+    DataArrayList *next( vaList );
+    while( NULL != next ) {
+        if( NULL != vaList->m_dataList ) {
+            numItems++;
+        }
+        next = next->m_next;
+    }
+
+    return numItems;
+}
+
+//------------------------------------------------------------------------------------------------
+static void copyVectorArray( size_t numItems, DataArrayList *vaList, aiVector3D *vectorArray ) {
+    for( size_t i = 0; i < numItems; i++ ) {
+        Value *next( vaList->m_dataList );
+        fillVector3( &vectorArray[ i ], next );
+        vaList = vaList->m_next;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == node ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    Property *prop( node->getProperties() );
+    if( NULL != prop ) {
+        std::string propName, propKey;
+        propId2StdString( prop, propName, propKey );
+        MeshAttribute attribType( getAttributeByName( propKey.c_str() ) );
+        if( None == attribType ) {
+            return;
+        }
+
+        DataArrayList *vaList = node->getDataArrayList();
+        if( NULL == vaList ) {
+            return;
+        }
+
+        const size_t numItems( countDataArrayListItems( vaList ) );
+        if( Position == attribType ) {
+            m_currentVertices.m_numVerts = numItems;
+            m_currentVertices.m_vertices = new aiVector3D[ numItems ];
+            copyVectorArray( numItems, vaList, m_currentVertices.m_vertices );
+        } else if( Normal == attribType ) {
+            m_currentVertices.m_numNormals = numItems;
+            m_currentVertices.m_normals = new aiVector3D[ numItems ];
+            copyVectorArray( numItems, vaList, m_currentVertices.m_normals );
+        } else if( TexCoord == attribType ) {
+            m_currentVertices.m_numUVComps[ 0 ] = numItems;
+            m_currentVertices.m_textureCoords[ 0 ] = new aiVector3D[ numItems ];
+            copyVectorArray( numItems, vaList, m_currentVertices.m_textureCoords[ 0 ] );
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == node ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    if( NULL == m_currentMesh ) {
+        throw DeadlyImportError( "No current mesh for index data found." );
+        return;
+    }
+
+    DataArrayList *vaList = node->getDataArrayList();
+    if( NULL == vaList ) {
+        return;
+    }
+
+    const size_t numItems( countDataArrayListItems( vaList ) );
+    m_currentMesh->mNumFaces = numItems;
+    m_currentMesh->mFaces = new aiFace[ numItems ];
+    m_currentMesh->mNumVertices = numItems * 3;
+    m_currentMesh->mVertices = new aiVector3D[ m_currentMesh->mNumVertices ];
+    m_currentMesh->mNormals = new aiVector3D[ m_currentMesh->mNumVertices ];
+    m_currentMesh->mNumUVComponents[ 0 ] = numItems * 3;
+    m_currentMesh->mTextureCoords[ 0 ] = new aiVector3D[ m_currentMesh->mNumUVComponents[ 0 ] ];
+
+    unsigned int index( 0 );
+    for( size_t i = 0; i < m_currentMesh->mNumFaces; i++ ) {
+        aiFace &current(  m_currentMesh->mFaces[ i ] );
+        current.mNumIndices = 3;
+        current.mIndices = new unsigned int[ current.mNumIndices ];
+        Value *next( vaList->m_dataList );
+        for( size_t indices = 0; indices < current.mNumIndices; indices++ ) {
+            const int idx = next->getInt32();
+            ai_assert( static_cast<size_t>( idx ) <= m_currentVertices.m_numVerts );
+
+            aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] );
+            aiVector3D &normal = ( m_currentVertices.m_normals[ idx ] );
+            aiVector3D &tex = ( m_currentVertices.m_textureCoords[ 0 ][ idx ] );
+
+            ai_assert( index < m_currentMesh->mNumVertices );
+            m_currentMesh->mVertices[ index ].Set( pos.x, pos.y, pos.z );
+            m_currentMesh->mNormals[ index ].Set( normal.x, normal.y, normal.z );
+            m_currentMesh->mTextureCoords[0][ index ].Set( tex.x, tex.y, tex.z );
+            current.mIndices[ indices ] = index;
+            index++;
+
+            next = next->m_next;
+        }
+        vaList = vaList->m_next;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+static void getColorRGB( aiColor3D *pColor, DataArrayList *colList ) {
+    if( NULL == pColor || NULL == colList ) {
+        return;
+    }
+
+    ai_assert( 3 == colList->m_numItems );
+    Value *val( colList->m_dataList );
+    pColor->r = val->getFloat();
+    val = val->getNext();
+    pColor->g = val->getFloat();
+    val = val->getNext();
+    pColor->b = val->getFloat();
+}
+
+//------------------------------------------------------------------------------------------------
+enum ColorType {
+    NoneColor = 0,
+    DiffuseColor,
+    SpecularColor,
+    EmissionColor
+};
+
+//------------------------------------------------------------------------------------------------
+static ColorType getColorType( Identifier *id ) {
+    if( id->m_text == Grammar::DiffuseColorToken ) {
+        return DiffuseColor;
+    } else if( id->m_text == Grammar::SpecularColorToken ) {
+        return SpecularColor;
+    } else if( id->m_text == Grammar::EmissionColorToken ) {
+        return EmissionColor;
+    }
+
+    return NoneColor;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMaterialNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    m_currentMaterial = new aiMaterial;
+    m_materialCache.push_back( m_currentMaterial );
+    m_tokenType = Grammar::MaterialToken;
+    handleNodes( node, pScene );
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == node ) {
+        return;
+    }
+
+    Property *prop = node->findPropertyByName( "attrib" );
+    if( NULL != prop ) {
+        if( NULL != prop->m_value ) {
+            DataArrayList *colList( node->getDataArrayList() );
+            if( NULL == colList ) {
+                return;
+            }
+            aiColor3D col;
+            getColorRGB( &col, colList );
+            const ColorType colType( getColorType( prop->m_key ) );
+            if( DiffuseColor == colType ) {
+                m_currentMaterial->AddProperty( &col, 1, AI_MATKEY_COLOR_DIFFUSE );
+            } else if( SpecularColor == colType ) {
+                m_currentMaterial->AddProperty( &col, 1, AI_MATKEY_COLOR_SPECULAR );
+            } else if( EmissionColor == colType ) {
+                m_currentMaterial->AddProperty( &col, 1, AI_MATKEY_COLOR_EMISSIVE );
+            }
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == node ) {
+        return;
+    }
+
+    Property *prop = node->findPropertyByName( "attrib" );
+    if( NULL != prop ) {
+        if( NULL != prop->m_value ) {
+            Value *val( node->getValue() );
+            if( NULL != val ) {
+                aiString tex;
+                tex.Set( val->getString() );
+                if( prop->m_value->getString() == Grammar::DiffuseTextureToken ) {
+                    m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
+                } else if( prop->m_value->getString() == Grammar::SpecularPowerTextureToken ) {
+                    m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR( 0 ) );
+
+                } else if( prop->m_value->getString() == Grammar::EmissionTextureToken ) {
+                    m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE( 0 ) );
+
+                } else if( prop->m_value->getString() == Grammar::OpacyTextureToken ) {
+                    m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_OPACITY( 0 ) );
+
+                } else if( prop->m_value->getString() == Grammar::TransparencyTextureToken ) {
+                    // ToDo!
+                    // m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
+                } else if( prop->m_value->getString() == Grammar::NormalTextureToken ) {
+                    m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS( 0 ) );
+
+                }
+                else {
+                    ai_assert( false );
+                }
+            }
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::copyMeshes( aiScene *pScene ) {
+    if( m_meshCache.empty() ) {
+        return;
+    }
+
+    pScene->mNumMeshes = m_meshCache.size();
+    pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
+    std::copy( m_meshCache.begin(), m_meshCache.end(), pScene->mMeshes );
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::resolveReferences() {
+    if( m_unresolvedRefStack.empty() ) {
+        return;
+    }
+
+    RefInfo *currentRefInfo( NULL );
+    for( std::vector<RefInfo*>::iterator it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it ) {
+        currentRefInfo = *it;
+        if( NULL != currentRefInfo ) {
+            aiNode *node( currentRefInfo->m_node );
+            if( RefInfo::MeshRef == currentRefInfo->m_type ) {
+                for( size_t i = 0; i < currentRefInfo->m_Names.size(); i++ ) {
+                    const std::string &name(currentRefInfo->m_Names[ i ] );
+                    ReferenceMap::const_iterator it( m_mesh2refMap.find( name ) );
+                    if( m_mesh2refMap.end() != it ) {
+                        unsigned int meshIdx = m_mesh2refMap[ name ];
+                        node->mMeshes[ i ] = meshIdx;
+                    }
+                }
+            } else if( RefInfo::MaterialRef == currentRefInfo->m_type ) {
+                // ToDo!
+            } else {
+                throw DeadlyImportError( "Unknown reference info to resolve." );
+            }
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::createNodeTree( aiScene *pScene ) {
+    if( NULL == m_root ) {
+        return;
+    }
+
+    if( m_root->m_children.empty() ) {
+        return;
+    }
+
+    pScene->mRootNode->mNumChildren = m_root->m_children.size();
+    pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren ];
+    std::copy( m_root->m_children.begin(), m_root->m_children.end(), pScene->mRootNode->mChildren );
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::pushNode( aiNode *node, aiScene *pScene ) {
+    ai_assert( NULL != pScene );
+
+    if( NULL != node ) {
+        ChildInfo *info( NULL );
+        if( m_nodeStack.empty() ) {
+            node->mParent = pScene->mRootNode;
+            NodeChildMap::iterator it( m_nodeChildMap.find( node->mParent ) );
+            if( m_nodeChildMap.end() == it ) {
+                info = new ChildInfo;
+                m_root = info;
+                m_nodeChildMap[ node->mParent ] = info;
+            } else {
+                info = it->second;
+            }
+            info->m_children.push_back( node );
+        } else {
+            aiNode *parent( m_nodeStack.back() );
+            ai_assert( NULL != parent );
+            node->mParent = parent;
+            NodeChildMap::iterator it( m_nodeChildMap.find( node->mParent ) );
+            if( m_nodeChildMap.end() == it ) {
+                info = new ChildInfo;
+                m_nodeChildMap[ node->mParent ] = info;
+            } else {
+                info = it->second;
+            }
+            info->m_children.push_back( node );
+        }
+        m_nodeStack.push_back( node );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+aiNode *OpenGEXImporter::popNode() {
+    if( m_nodeStack.empty() ) {
+        return NULL;
+    }
+
+    aiNode *node( top() );
+    m_nodeStack.pop_back();
+
+    return node;
+}
+
+//------------------------------------------------------------------------------------------------
+aiNode *OpenGEXImporter::top() const {
+    if( m_nodeStack.empty() ) {
+        return NULL;
+    }
+
+    return m_nodeStack.back();
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::clearNodeStack() {
+    m_nodeStack.clear();
+}
+
+//------------------------------------------------------------------------------------------------
+
+} // Namespace OpenGEX
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER

+ 193 - 0
Source/ThirdParty/Assimp/code/OpenGEXImporter.h

@@ -0,0 +1,193 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef AI_OPENGEX_IMPORTER_H
+#define AI_OPENGEX_IMPORTER_H
+
+#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#include "BaseImporter.h"
+#include <assimp/mesh.h>
+
+#include <vector>
+#include <list>
+
+namespace ODDLParser {
+    class DDLNode;
+    struct Context;
+}
+struct aiNode;
+struct aiMaterial;
+
+namespace Assimp {
+namespace OpenGEX {
+
+struct MetricInfo {
+    enum Type {
+        Distance = 0,
+        Angle,
+        Time,
+        Up,
+        Max
+    };
+
+    std::string m_stringValue;
+    float m_floatValue;
+    int m_intValue;
+
+    MetricInfo()
+    : m_stringValue( "" )
+    , m_floatValue( 0.0f )
+    , m_intValue( -1 ) {
+        // empty
+    }
+};
+
+/** @brief  This class is used to implement the OpenGEX importer
+ *
+ *  See http://opengex.org/OpenGEX.pdf for spec.
+ */
+class OpenGEXImporter : public BaseImporter {
+public:
+    /// The class constructor.
+    OpenGEXImporter();
+
+    /// The class destructor.
+    virtual ~OpenGEXImporter();
+
+    /// BaseImporter override.
+    virtual bool CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const;
+
+    /// BaseImporter override.
+    virtual void InternReadFile( const std::string &file, aiScene *pScene, IOSystem *pIOHandler );
+
+    /// BaseImporter override.
+    virtual const aiImporterDesc *GetInfo() const;
+
+    /// BaseImporter override.
+    virtual void SetupProperties( const Importer *pImp );
+
+protected:
+    void handleNodes( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMetricNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleNameNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleObjectRefNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMaterialRefNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleGeometryNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleGeometryObject( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleTransformNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMaterialNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleColorNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void copyMeshes( aiScene *pScene );
+    void resolveReferences();
+    void pushNode( aiNode *node, aiScene *pScene );
+    aiNode *popNode();
+    aiNode *top() const;
+    void clearNodeStack();
+    void createNodeTree( aiScene *pScene );
+
+private:
+    struct VertexContainer {
+        size_t m_numVerts;
+        aiVector3D *m_vertices;
+        size_t m_numNormals;
+        aiVector3D *m_normals;
+        size_t m_numUVComps[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
+        aiVector3D *m_textureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
+
+        VertexContainer();
+        ~VertexContainer();
+
+    private:
+        VertexContainer( const VertexContainer & );
+        VertexContainer &operator = ( const VertexContainer & );
+    };
+
+    struct RefInfo {
+        enum Type {
+            MeshRef,
+            MaterialRef
+        };
+
+        aiNode *m_node;
+        Type m_type;
+        std::vector<std::string> m_Names;
+
+        RefInfo( aiNode *node, Type type, std::vector<std::string> &names );
+        ~RefInfo();
+
+    private:
+        RefInfo( const RefInfo & );
+        RefInfo &operator = ( const RefInfo & );
+    };
+
+    struct ChildInfo {
+        typedef std::list<aiNode*> NodeList;
+        std::list<aiNode*> m_children;
+    };
+    ChildInfo *m_root;
+    typedef std::map<aiNode*, ChildInfo*> NodeChildMap;
+    NodeChildMap m_nodeChildMap;
+
+    std::vector<aiMesh*> m_meshCache;
+    typedef std::map<std::string, size_t> ReferenceMap;
+    std::map<std::string, size_t> m_mesh2refMap;
+
+    ODDLParser::Context *m_ctx;
+    MetricInfo m_metrics[ MetricInfo::Max ];
+    aiNode *m_currentNode;
+    VertexContainer m_currentVertices;
+    aiMesh *m_currentMesh;
+    aiMaterial *m_currentMaterial;
+    int m_tokenType;
+    std::vector<aiMaterial*> m_materialCache;
+    std::vector<aiNode*> m_nodeStack;
+    std::vector<RefInfo*> m_unresolvedRefStack;
+};
+
+} // Namespace OpenGEX
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#endif // AI_OPENGEX_IMPORTER_H

+ 265 - 0
Source/ThirdParty/Assimp/code/OpenGEXStructs.h

@@ -0,0 +1,265 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef AI_OPENGEXSTRUCTS_H_INC
+#define AI_OPENGEXSTRUCTS_H_INC
+
+#include <string>
+#include <map>
+
+namespace Assimp {
+namespace OpenGEX {
+
+struct Skin;
+struct Object;
+struct LightObject;
+struct CameraObject;
+struct Material;
+struct BoneNode;
+struct BoneCountArray;
+struct BoneIndexArray;
+struct BoneWeightArray;
+
+struct Metric {
+    float m_distance;
+    float m_angle;
+    float m_time;
+    float m_up;
+};
+
+struct VertexArray {
+    std::string arrayAttrib;
+    unsigned int morphIndex;
+};
+
+struct IndexArray {
+    unsigned int materialIndex;
+    unsigned int restartIndex;
+    std::string frontFace;
+};
+
+struct Mesh {
+    unsigned int meshLevel;
+    std::string meshPrimitive;
+    Skin *skinStructure;
+};
+
+struct Node {
+    std::string nodeName;
+};
+
+struct GeometryNode {
+    bool visibleFlag[ 2 ];
+    bool shadowFlag[ 2 ];
+    bool motionBlurFlag[ 2 ];
+};
+
+struct LightNode {
+    bool shadowFlag[ 2 ];
+    const LightObject *lightObjectStructure;
+};
+
+struct CameraNode {
+    const CameraObject *cameraObjectStructure;
+};
+
+struct GeometryObject {
+    Object *object;
+    bool visibleFlag;
+    bool shadowFlag;
+    bool motionBlurFlag;
+    std::map<std::string, Mesh*> meshMap;
+};
+
+struct LightObject {
+    Object *object;
+    std::string typeString;
+    bool shadowFlag;
+};
+
+
+struct CameraObject {
+    float focalLength;
+    float nearDepth;
+    float farDepth;
+};
+
+struct Matrix {
+    bool objectFlag;
+};
+
+struct Transform {
+    Matrix *matrix;
+    int transformCount;
+    const float *transformArray;
+};
+
+struct Translation {
+    std::string translationKind;
+};
+
+struct Rotation {
+    std::string rotationKind;
+};
+
+struct Scale {
+    std::string scaleKind;
+};
+
+struct Name {
+    std::string name;
+};
+
+
+struct ObjectRef {
+    Object *targetStructure;
+};
+
+struct MaterialRef {
+    unsigned int materialIndex;
+    const Material *targetStructure;
+};
+
+struct BoneRefArray {
+    int boneCount;
+    const BoneNode **boneNodeArray;
+};
+
+struct BoneCount {
+    int vertexCount;
+    const unsigned short *boneCountArray;
+    unsigned short *arrayStorage;
+};
+
+struct BoneIndex {
+    int boneIndexCount;
+    const unsigned short *boneIndexArray;
+    unsigned short *arrayStorage;
+};
+
+
+struct BoneWeight {
+    int boneWeightCount;
+    const float *boneWeightArray;
+};
+
+struct Skeleton {
+    const BoneRefArray *boneRefArrayStructure;
+    const Transform *transformStructure;
+};
+
+struct Skin {
+    const Skeleton *skeletonStructure;
+    const BoneCountArray *boneCountArrayStructure;
+    const BoneIndexArray *boneIndexArrayStructure;
+    const BoneWeightArray *boneWeightArrayStructure;
+};
+
+struct Material {
+    bool twoSidedFlag;
+    const char *materialName;
+};
+
+struct Attrib {
+    std::string attribString;
+};
+
+struct Param {
+    float param;
+};
+
+struct Color {
+    float color[ 4 ];
+};
+
+struct Texture {
+    std::string textureName;
+    unsigned int texcoordIndex;
+};
+
+struct Atten {
+    std::string attenKind;
+    std::string curveType;
+
+    float beginParam;
+    float endParam;
+
+    float scaleParam;
+    float offsetParam;
+
+    float constantParam;
+    float linearParam;
+    float quadraticParam;
+
+    float powerParam;
+};
+
+struct Key {
+    std::string keyKind;
+    bool scalarFlag;
+};
+
+struct Curve {
+    std::string curveType;
+    const Key *keyValueStructure;
+    const Key *keyControlStructure[ 2 ];
+    const Key *keyTensionStructure;
+    const Key *keyContinuityStructure;
+    const Key *keyBiasStructure;
+};
+
+struct Animation {
+    int clipIndex;
+    bool beginFlag;
+    bool endFlag;
+    float beginTime;
+    float endTime;
+};
+
+struct OpenGexDataDescription {
+    float distanceScale;
+    float angleScale;
+    float timeScale;
+    int upDirection;
+};
+
+} // Namespace OpenGEX
+} // Namespace Assimp
+
+#endif // AI_OPENGEXSTRUCTS_H_INC

+ 18 - 5
Source/ThirdParty/Assimp/code/PlyExporter.cpp

@@ -189,7 +189,12 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina
     }
 
     mOutput << "element face " << faces << endl;
-    mOutput << "property list uint uint vertex_index" << endl;
+
+    // uchar seems to be the most common type for the number of indices per polygon and int seems to be most common for the vertex indices.
+    // For instance, MeshLab fails to load meshes in which both types are uint. Houdini seems to have problems as well.
+    // Obviously, using uchar will not work for meshes with polygons with more than 255 indices, but how realistic is this case?
+    mOutput << "property list uchar int vertex_index" << endl;
+
     mOutput << "end_header" << endl;
 
     for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
@@ -342,16 +347,24 @@ void PlyExporter::WriteMeshIndices(const aiMesh* m, unsigned int offset)
     }
 }
 
-void PlyExporter::WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset)
+// Generic method in case we want to use different data types for the indices or make this configurable.
+template<typename NumIndicesType, typename IndexType>
+void WriteMeshIndicesBinary_Generic(const aiMesh* m, unsigned int offset, std::ostringstream& output)
 {
     for (unsigned int i = 0; i < m->mNumFaces; ++i) {
         const aiFace& f = m->mFaces[i];
-        mOutput.write(reinterpret_cast<const char*>(&f.mNumIndices), 4);
+        NumIndicesType numIndices = static_cast<NumIndicesType>(f.mNumIndices);
+        output.write(reinterpret_cast<const char*>(&numIndices), sizeof(NumIndicesType));
         for (unsigned int c = 0; c < f.mNumIndices; ++c) {
-            unsigned int index = f.mIndices[c] + offset;
-            mOutput.write(reinterpret_cast<const char*>(&index), 4);
+            IndexType index = f.mIndices[c] + offset;
+            output.write(reinterpret_cast<const char*>(&index), sizeof(IndexType));
         }
     }
 }
 
+void PlyExporter::WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset)
+{
+    WriteMeshIndicesBinary_Generic<unsigned char, int>(m, offset, mOutput);
+}
+
 #endif

+ 13 - 4
Source/ThirdParty/Assimp/code/PlyLoader.cpp

@@ -310,6 +310,10 @@ void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
                 iNum += (unsigned int)(*avFaces)[aiSplit[p][i]].mIndices.size();
             }
             p_pcOut->mNumVertices = iNum;
+            if( 0 == iNum ) {     // nothing to do 
+                delete[] aiSplit; // cleanup
+                return;
+            }
             p_pcOut->mVertices = new aiVector3D[iNum];
 
             if (!avColors->empty())
@@ -335,20 +339,25 @@ void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
                 for (unsigned int q = 0; q <  p_pcOut->mFaces[iNum].mNumIndices;++q)
                 {
                     p_pcOut->mFaces[iNum].mIndices[q] = iVertex;
-                    p_pcOut->mVertices[iVertex] = (*avPositions)[(*avFaces)[*i].mIndices[q]];
+                    const size_t idx = ( *avFaces )[ *i ].mIndices[ q ];
+                    if( idx >= ( *avPositions ).size() ) {
+                        // out of border
+                        continue;
+                    }
+                    p_pcOut->mVertices[ iVertex ] = ( *avPositions )[ idx ];
 
                     if (!avColors->empty())
-                        p_pcOut->mColors[0][iVertex] = (*avColors)[(*avFaces)[*i].mIndices[q]];
+                        p_pcOut->mColors[ 0 ][ iVertex ] = ( *avColors )[ idx ];
 
                     if (!avTexCoords->empty())
                     {
-                        const aiVector2D& vec = (*avTexCoords)[(*avFaces)[*i].mIndices[q]];
+                        const aiVector2D& vec = ( *avTexCoords )[ idx ];
                         p_pcOut->mTextureCoords[0][iVertex].x = vec.x;
                         p_pcOut->mTextureCoords[0][iVertex].y = vec.y;
                     }
 
                     if (!avNormals->empty())
-                        p_pcOut->mNormals[iVertex] = (*avNormals)[(*avFaces)[*i].mIndices[q]];
+                        p_pcOut->mNormals[ iVertex ] = ( *avNormals )[ idx ];
                     iVertex++;
                 }
 

+ 7 - 0
Source/ThirdParty/Assimp/code/Q3DLoader.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  Q3DLoader.h
  *  @brief Declaration of the Q3D importer class.
  */
@@ -47,7 +49,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BaseImporter.h"
 #include "../include/assimp/types.h"
 #include <vector>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 namespace Assimp    {
 

+ 7 - 0
Source/ThirdParty/Assimp/code/SGSpatialSort.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** Small helper classes to optimise finding vertizes close to a given location
  */
 #ifndef AI_D3DSSPATIALSORT_H_INC
@@ -45,7 +47,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "../include/assimp/types.h"
 #include <vector>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 namespace Assimp    {
 

+ 183 - 135
Source/ThirdParty/Assimp/code/STLLoader.cpp

@@ -75,8 +75,9 @@ static const aiImporterDesc desc = {
 // 2) 4 byte face count
 // 3) 50 bytes per face
 bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
-    if (fileSize < 84)
+    if( fileSize < 84 ) {
         return false;
+    }
 
     const uint32_t faceCount = *reinterpret_cast<const uint32_t*>(buffer + 80);
     const uint32_t expectedBinaryFileSize = faceCount * 50 + 84;
@@ -99,7 +100,20 @@ bool IsAsciiSTL(const char* buffer, unsigned int fileSize) {
     if (buffer + 5 >= bufferEnd)
         return false;
 
-    return strncmp(buffer, "solid", 5) == 0;
+    bool isASCII( strncmp( buffer, "solid", 5 ) == 0 );
+    if( isASCII ) {
+        // A lot of importers are write solid even if the file is binary. So we have to check for ASCII-characters.
+        if( fileSize >= 500 ) {
+            isASCII = true;
+            for( unsigned int i = 0; i < 500; i++ ) {
+                if( buffer[ i ] > 127 ) {
+                    isASCII = false;
+                    break;
+                }
+            }
+        }
+    }
+    return isASCII;
 }
 } // namespace
 
@@ -122,23 +136,37 @@ bool STLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
 {
     const std::string extension = GetExtension(pFile);
 
-    if (extension == "stl")
+    if( extension == "stl" ) {
         return true;
-    else if (!extension.length() || checkSig)   {
-        if (!pIOHandler)
+    } else if (!extension.length() || checkSig)   {
+        if( !pIOHandler ) {
             return true;
+        }
         const char* tokens[] = {"STL","solid"};
         return SearchFileHeaderForToken(pIOHandler,pFile,tokens,2);
     }
+    
     return false;
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiImporterDesc* STLImporter::GetInfo () const
-{
+const aiImporterDesc* STLImporter::GetInfo () const {
     return &desc;
 }
 
+void addFacesToMesh(aiMesh* pMesh)
+{
+    pMesh->mFaces = new aiFace[pMesh->mNumFaces];
+    for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces;++i)    {
+
+        aiFace& face = pMesh->mFaces[i];
+        face.mIndices = new unsigned int[face.mNumIndices = 3];
+        for (unsigned int o = 0; o < 3;++o,++p) {
+            face.mIndices[o] = p;
+        }
+    }
+}
+
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void STLImporter::InternReadFile( const std::string& pFile,
@@ -164,17 +192,8 @@ void STLImporter::InternReadFile( const std::string& pFile,
     // the default vertex color is light gray.
     clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = 0.6f;
 
-    // allocate one mesh
-    pScene->mNumMeshes = 1;
-    pScene->mMeshes = new aiMesh*[1];
-    aiMesh* pMesh = pScene->mMeshes[0] = new aiMesh();
-    pMesh->mMaterialIndex = 0;
-
     // allocate a single node
     pScene->mRootNode = new aiNode();
-    pScene->mRootNode->mNumMeshes = 1;
-    pScene->mRootNode->mMeshes = new unsigned int[1];
-    pScene->mRootNode->mMeshes[0] = 0;
 
     bool bMatClr = false;
 
@@ -186,16 +205,11 @@ void STLImporter::InternReadFile( const std::string& pFile,
         throw DeadlyImportError( "Failed to determine STL storage representation for " + pFile + ".");
     }
 
-    // now copy faces
-    pMesh->mFaces = new aiFace[pMesh->mNumFaces];
-    for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces;++i)   {
-
-        aiFace& face = pMesh->mFaces[i];
-        face.mIndices = new unsigned int[face.mNumIndices = 3];
-        for (unsigned int o = 0; o < 3;++o,++p) {
-            face.mIndices[o] = p;
-        }
-    }
+    // add all created meshes to the single node
+    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
+    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+    for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
+        pScene->mRootNode->mMeshes[i] = i;
 
     // create a single default material, using a light gray diffuse color for consistency with
     // other geometric types (e.g., PLY).
@@ -221,140 +235,171 @@ void STLImporter::InternReadFile( const std::string& pFile,
 // Read an ASCII STL file
 void STLImporter::LoadASCIIFile()
 {
-    aiMesh* pMesh = pScene->mMeshes[0];
-
+    std::vector<aiMesh*> meshes;
     const char* sz = mBuffer;
-    SkipSpaces(&sz);
-    ai_assert(!IsLineEnd(sz));
-
-    sz += 5; // skip the "solid"
-    SkipSpaces(&sz);
-    const char* szMe = sz;
-    while (!::IsSpaceOrNewLine(*sz)) {
-        sz++;
-    }
-
-    size_t temp;
-    // setup the name of the node
-    if ((temp = (size_t)(sz-szMe))) {
-        if (temp >= MAXLEN) {
-            throw DeadlyImportError( "STL: Node name too long" );
-        }
-
-        pScene->mRootNode->mName.length = temp;
-        memcpy(pScene->mRootNode->mName.data,szMe,temp);
-        pScene->mRootNode->mName.data[temp] = '\0';
-    }
-    else pScene->mRootNode->mName.Set("<STL_ASCII>");
+    const char* bufferEnd = mBuffer + fileSize;
+    std::vector<aiVector3D> positionBuffer;
+    std::vector<aiVector3D> normalBuffer;
 
     // try to guess how many vertices we could have
     // assume we'll need 160 bytes for each face
-    pMesh->mNumVertices = ( pMesh->mNumFaces = std::max(1u,fileSize / 160u )) * 3;
-    pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
-    pMesh->mNormals  = new aiVector3D[pMesh->mNumVertices];
+    size_t sizeEstimate = std::max(1u, fileSize / 160u ) * 3;
+    positionBuffer.reserve(sizeEstimate);
+    normalBuffer.reserve(sizeEstimate);
 
-    unsigned int curFace = 0, curVertex = 3;
-    for ( ;; )
+    while (IsAsciiSTL(sz, bufferEnd - sz))
     {
-        // go to the next token
-        if(!SkipSpacesAndLineEnd(&sz))
-        {
-            // seems we're finished although there was no end marker
-            DefaultLogger::get()->warn("STL: unexpected EOF. \'endsolid\' keyword was expected");
-            break;
+        aiMesh* pMesh = new aiMesh();
+        pMesh->mMaterialIndex = 0;
+        meshes.push_back(pMesh);
+
+        SkipSpaces(&sz);
+        ai_assert(!IsLineEnd(sz));
+
+        sz += 5; // skip the "solid"
+        SkipSpaces(&sz);
+        const char* szMe = sz;
+        while (!::IsSpaceOrNewLine(*sz)) {
+            sz++;
         }
-        // facet normal -0.13 -0.13 -0.98
-        if (!strncmp(sz,"facet",5) && IsSpaceOrNewLine(*(sz+5)))    {
 
-            if (3 != curVertex) {
-                DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete");
+        size_t temp;
+        // setup the name of the node
+        if ((temp = (size_t)(sz-szMe)))    {
+            if (temp >= MAXLEN) {
+                throw DeadlyImportError( "STL: Node name too long" );
             }
-            if (pMesh->mNumFaces == curFace)    {
-                ai_assert(pMesh->mNumFaces != 0);
-
-                // need to resize the arrays, our size estimate was wrong
-                unsigned int iNeededSize = (unsigned int)(sz-mBuffer) / pMesh->mNumFaces;
-                if (iNeededSize <= 160)iNeededSize >>= 1; // prevent endless looping
-                unsigned int add = (unsigned int)((mBuffer+fileSize)-sz) / iNeededSize;
-                add += add >> 3; // add 12.5% as buffer
-                iNeededSize = (pMesh->mNumFaces + add)*3;
-                aiVector3D* pv = new aiVector3D[iNeededSize];
-                memcpy(pv,pMesh->mVertices,pMesh->mNumVertices*sizeof(aiVector3D));
-                delete[] pMesh->mVertices;
-                pMesh->mVertices = pv;
-                pv = new aiVector3D[iNeededSize];
-                memcpy(pv,pMesh->mNormals,pMesh->mNumVertices*sizeof(aiVector3D));
-                delete[] pMesh->mNormals;
-                pMesh->mNormals = pv;
-
-                pMesh->mNumVertices = iNeededSize;
-                pMesh->mNumFaces += add;
+
+            pScene->mRootNode->mName.length = temp;
+            memcpy(pScene->mRootNode->mName.data,szMe,temp);
+            pScene->mRootNode->mName.data[temp] = '\0';
+        }
+        else pScene->mRootNode->mName.Set("<STL_ASCII>");
+
+        unsigned int faceVertexCounter = 0;
+        for ( ;; )
+        {
+            // go to the next token
+            if(!SkipSpacesAndLineEnd(&sz))
+            {
+                // seems we're finished although there was no end marker
+                DefaultLogger::get()->warn("STL: unexpected EOF. \'endsolid\' keyword was expected");
+                break;
             }
-            aiVector3D* vn = &pMesh->mNormals[curFace++*3];
+            // facet normal -0.13 -0.13 -0.98
+            if (!strncmp(sz,"facet",5) && IsSpaceOrNewLine(*(sz+5)) && *(sz + 5) != '\0')    {
 
-            sz += 6;
-            curVertex = 0;
-            SkipSpaces(&sz);
-            if (strncmp(sz,"normal",6)) {
-                DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found");
+                if (faceVertexCounter != 3) {
+                    DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete");
+                }
+                faceVertexCounter = 0;
+                normalBuffer.push_back(aiVector3D());
+                aiVector3D* vn = &normalBuffer.back();
+
+                sz += 6;
+                SkipSpaces(&sz);
+                if (strncmp(sz,"normal",6))    {
+                    DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found");
+                }
+                else
+                {
+                    if (sz[6] == '\0') {
+                        throw DeadlyImportError("STL: unexpected EOF while parsing facet");
+                    }
+                    sz += 7;
+                    SkipSpaces(&sz);
+                    sz = fast_atoreal_move<float>(sz, (float&)vn->x );
+                    SkipSpaces(&sz);
+                    sz = fast_atoreal_move<float>(sz, (float&)vn->y );
+                    SkipSpaces(&sz);
+                    sz = fast_atoreal_move<float>(sz, (float&)vn->z );
+                    normalBuffer.push_back(*vn);
+                    normalBuffer.push_back(*vn);
+                }
             }
-            else
+            // vertex 1.50000 1.50000 0.00000
+            else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6)))
             {
-                sz += 7;
-                SkipSpaces(&sz);
-                sz = fast_atoreal_move<float>(sz, (float&)vn->x );
-                SkipSpaces(&sz);
-                sz = fast_atoreal_move<float>(sz, (float&)vn->y );
-                SkipSpaces(&sz);
-                sz = fast_atoreal_move<float>(sz, (float&)vn->z );
-                *(vn+1) = *vn;
-                *(vn+2) = *vn;
+                if (faceVertexCounter >= 3) {
+                    DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found");
+                    ++sz;
+                }
+                else
+                {
+                    if (sz[6] == '\0') {
+                        throw DeadlyImportError("STL: unexpected EOF while parsing facet");
+                    }
+                    sz += 7;
+                    SkipSpaces(&sz);
+                    positionBuffer.push_back(aiVector3D());
+                    aiVector3D* vn = &positionBuffer.back();
+                    sz = fast_atoreal_move<float>(sz, (float&)vn->x );
+                    SkipSpaces(&sz);
+                    sz = fast_atoreal_move<float>(sz, (float&)vn->y );
+                    SkipSpaces(&sz);
+                    sz = fast_atoreal_move<float>(sz, (float&)vn->z );
+                    faceVertexCounter++;
+                }
             }
-        }
-        // vertex 1.50000 1.50000 0.00000
-        else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6)))
-        {
-            if (3 == curVertex) {
-                DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found");
-                ++sz;
+            else if (!::strncmp(sz,"endsolid",8))    {
+                do {
+                    ++sz;
+                } while (!::IsLineEnd(*sz));
+                SkipSpacesAndLineEnd(&sz);
+                // finished!
+                break;
             }
-            else
-            {
-                sz += 7;
-                SkipSpaces(&sz);
-                aiVector3D* vn = &pMesh->mVertices[(curFace-1)*3 + curVertex++];
-                sz = fast_atoreal_move<float>(sz, (float&)vn->x );
-                SkipSpaces(&sz);
-                sz = fast_atoreal_move<float>(sz, (float&)vn->y );
-                SkipSpaces(&sz);
-                sz = fast_atoreal_move<float>(sz, (float&)vn->z );
+            // else skip the whole identifier
+            else {
+                do {
+                    ++sz;
+                } while (!::IsSpaceOrNewLine(*sz));
             }
         }
-        else if (!::strncmp(sz,"endsolid",8))   {
-            // finished!
-            break;
+
+        if (positionBuffer.empty())    {
+            pMesh->mNumFaces = 0;
+            throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded");
+        }
+        if (positionBuffer.size() % 3 != 0)    {
+            pMesh->mNumFaces = 0;
+            throw DeadlyImportError("STL: Invalid number of vertices");
         }
-        // else skip the whole identifier
-        else {
-            do {
-                ++sz;
-            } while (!::IsSpaceOrNewLine(*sz));
+        if (normalBuffer.size() != positionBuffer.size())    {
+            pMesh->mNumFaces = 0;
+            throw DeadlyImportError("Normal buffer size does not match position buffer size");
         }
+        pMesh->mNumFaces = positionBuffer.size() / 3;
+        pMesh->mNumVertices = positionBuffer.size();
+        pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
+        memcpy(pMesh->mVertices, &positionBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+        positionBuffer.clear();
+        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
+        memcpy(pMesh->mNormals, &normalBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+        normalBuffer.clear();
+
+        // now copy faces
+        addFacesToMesh(pMesh);
     }
-
-    if (!curFace)   {
-        pMesh->mNumFaces = 0;
-        throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded");
+    // now add the loaded meshes
+    pScene->mNumMeshes = (unsigned int)meshes.size();
+    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+    for (size_t i = 0; i < meshes.size(); i++)
+    {
+        pScene->mMeshes[i] = meshes[i];
     }
-    pMesh->mNumFaces = curFace;
-    pMesh->mNumVertices = curFace*3;
-    // we are finished!
 }
 
 // ------------------------------------------------------------------------------------------------
 // Read a binary STL file
 bool STLImporter::LoadBinaryFile()
 {
+    // allocate one mesh
+    pScene->mNumMeshes = 1;
+    pScene->mMeshes = new aiMesh*[1];
+    aiMesh* pMesh = pScene->mMeshes[0] = new aiMesh();
+    pMesh->mMaterialIndex = 0;
+
     // skip the first 80 bytes
     if (fileSize < 84) {
         throw DeadlyImportError("STL: file is too small for the header");
@@ -382,7 +427,6 @@ bool STLImporter::LoadBinaryFile()
     const unsigned char* sz = (const unsigned char*)mBuffer + 80;
 
     // now read the number of facets
-    aiMesh* pMesh = pScene->mMeshes[0];
     pScene->mRootNode->mName.Set("<STL_BINARY>");
 
     pMesh->mNumFaces = *((uint32_t*)sz);
@@ -402,7 +446,7 @@ bool STLImporter::LoadBinaryFile()
     vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
     vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
 
-    for (unsigned int i = 0; i < pMesh->mNumFaces;++i)  {
+    for (unsigned int i = 0; i < pMesh->mNumFaces;++i) {
 
         // NOTE: Blender sometimes writes empty normals ... this is not
         // our fault ... the RemoveInvalidData helper step should fix that
@@ -455,6 +499,10 @@ bool STLImporter::LoadBinaryFile()
             *(clr+2) = *clr;
         }
     }
+
+    // now copy faces
+    addFacesToMesh(pMesh);
+
     if (bIsMaterialise && !pMesh->mColors[0])
     {
         // use the color as diffuse material color

+ 7 - 1
Source/ThirdParty/Assimp/code/SceneCombiner.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Declares a helper class, "SceneCombiner" providing various
  *  utilities to merge scenes.
  */
@@ -50,8 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <stddef.h>
 #include <set>
 #include <list>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
-//#include "../include/assimp/Compiler/pstdint.h"
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 #include <vector>
 

+ 7 - 0
Source/ThirdParty/Assimp/code/SmoothingGroups.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Defines the helper data structures for importing 3DS files.
 http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
 
@@ -45,7 +47,12 @@ http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
 #define AI_SMOOTHINGGROUPS_H_INC
 
 #include "../include/assimp/vector3.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <vector>
 
 // ---------------------------------------------------------------------------

+ 7 - 0
Source/ThirdParty/Assimp/code/StringComparison.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file Definition of platform independent string workers:
 
    ASSIMP_itoa10
@@ -54,7 +56,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "StringComparison.h"
 
 #include <string.h>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 #include <string>
 #include <cctype>
 

+ 5 - 1
Source/ThirdParty/Assimp/code/Subdivision.cpp

@@ -399,10 +399,14 @@ void CatmullClarkSubdivider::InternSubdivide (
                     bool haveit = false;
                     for (unsigned int i = 0; i < f.mNumIndices; ++i) {
                         if (maptbl[FLATTEN_VERTEX_IDX(n,f.mIndices[i])]==(unsigned int)t) {
-                            haveit = true; break;
+                            haveit = true;
+                            break;
                         }
                     }
                     ai_assert(haveit);
+                    if (!haveit) {
+                        DefaultLogger::get()->debug("Catmull-Clark Subdivider: Index not used");
+                    }
                     break;
                 }
             }

+ 7 - 0
Source/ThirdParty/Assimp/code/UnrealLoader.h

@@ -38,6 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /** @file  UnrealLoader.h
  *  @brief Declaration of the .3d (UNREAL) importer class.
  */
@@ -45,7 +47,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_3D_LOADER_H
 
 #include "BaseImporter.h"
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 namespace Assimp    {
 namespace Unreal {

+ 6 - 0
Source/ThirdParty/Assimp/code/XFileHelper.h

@@ -38,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
 
 /** @file Defines the helper data structures for importing XFiles */
 #ifndef AI_XFILEHELPER_H_INC
@@ -45,7 +46,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <string>
 #include <vector>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 #include "../include/assimp/types.h"
 #include "../include/assimp/quaternion.h"

+ 9 - 7
Source/ThirdParty/Assimp/code/fast_atof.h

@@ -11,24 +11,26 @@
 //     to ensure long numbers are handled correctly
 // ------------------------------------------------------------------------------------
 
+// Modified by Lasse Oorni for Urho3D
 
 #ifndef __FAST_A_TO_F_H_INCLUDED__
 #define __FAST_A_TO_F_H_INCLUDED__
 
 #include <cmath>
 #include <limits>
+// Urho3D: added include
+#include <limits.h>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
-#include <stdexcept>
-
-#include "StringComparison.h"
-
-
-#ifdef _MSC_VER
-#  include <stdint.h>
 #else
 #include "../include/assimp/Compiler/pstdint.h"
 #endif
 
+#include <stdexcept>
+
+#include "StringComparison.h"
+
 namespace Assimp
 {
 

+ 0 - 105
Source/ThirdParty/Assimp/code/makefile.mingw

@@ -1,105 +0,0 @@
-### USE OF THIS MAKEFILE IS NOT RECOMMENDED.
-### It is no longer maintained. Use CMAKE instead.
-
-# ---------------------------------------------------------------------------
-# Makefile for Open Asset Import Library (MinGW32-make)
-# [email protected]
-#   - just a quick'n'dirty one, could be buggy ...
-#
-# Usage: mingw32-make -f makefile.mingw <target> <macros>
-
-# TARGETS:
-#   all                  Build a shared so from the whole library
-#   clean                Cleanup object files, prepare for rebuild
-#   static               Build a static library (*.a)
-
-# MACROS: (make clean before you change one)
-#   NOBOOST=1            Build against boost workaround
-#   SINGLETHREADED=1     Build single-threaded library
-#   DEBUG=1              Build debug build of library
-# 
-# ---------------------------------------------------------------------------
-
-# C++ object files
-OBJECTS   := $(patsubst %.cpp,%.o,  $(wildcard *.cpp)) 
-OBJECTS   += $(patsubst %.cpp,%.o,  $(wildcard extra/*.cpp)) 
-OBJECTS   += $(patsubst %.cpp,%.o,  $(wildcard ./../contrib/irrXML/*.cpp)) 
-
-# C object files 
-OBJECTSC  := $(patsubst %.c,%.oc,   $(wildcard ./../contrib/zlib/*.c))
-OBJECTSC  += $(patsubst %.c,%.oc,   $(wildcard ./../contrib/ConvertUTF/*.c))
-OBJECTSC  += $(patsubst %.c,%.oc,   $(wildcard ./../contrib/unzip/*.c))
-
-# Include flags for gcc
-INCLUDEFLAGS =
-
-# Preprocessor defines for gcc
-DEFINEFLAGS = 
-
-# Suffix for the output binary, represents build type
-NAMESUFFIX = 
-
-# Output path for binaries
-BINPATH = ../bin/mingw/
-
-# GCC compiler flags 
-CPPFLAGS=-Wall 
-
-# Setup environment for noboost build
-ifeq ($(NOBOOST),1)
-	SINGLETHREADED = 1
-	INCLUDEFLAGS  += -I./BoostWorkaround/
-	DEFINEFLAGS   += -DASSIMP_BUILD_BOOST_WORKAROUND 
-#	NAMESUFFIX    += -noboost
-else
-	# adjust this manually if your boost is stored elsewhere
-	INCLUDEFLAGS  += -I"C:/Program Files/boost/boost_1_38"
-	#INCLUDEFLAGS  += -I"$(BOOST_DIR)"
-
-endif
-
-# Setup environment for st build
-ifeq ($(SINGLETHREADED),1)
-	DEFINEFLAGS   += -DASSIMP_BUILD_SINGLETHREADED
-#	NAMESUFFIX    += -st
-endif
-
-# Setup environment for debug build
-ifeq ($(DEBUG),1)
-	DEFINEFLAGS   += -D_DEBUG -DDEBUG
-	CPPFLAGS      += -g
-#	NAMESUFFIX    += -debug
-else
-	CPPFLAGS      += -O2 -s
-	DEFINEFLAGS   += -DNDEBUG -D_NDEBUG
-endif
-
-# Output name of shared library
-SHARED_TARGET = $(BINPATH)/libassimp$(NAMESUFFIX).so
-
-# Output name of static library
-STATIC = $(BINPATH)/libassimp$(NAMESUFFIX).a
-
-# target: all
-# usage : build a shared library (*.so)
-all:	$(SHARED_TARGET)
-
-$(SHARED_TARGET):  $(OBJECTS)  $(OBJECTSC)
-	gcc -o $@ $(OBJECTS) $(OBJECTSC) -shared -lstdc++ 
-%.o:%.cpp
-	$(CXX) -c  $(CPPFLAGS) $? -o $@ $(INCLUDEFLAGS) $(DEFINEFLAGS)
-%.oc:%.c
-	$(CXX) -x c -c -ansi $(CPPFLAGS) $? -o $@ 
-
-# target: clean
-# usage : cleanup all object files, prepare for a rebuild
-.PHONY: clean
-clean:
-	-del *.o .\..\contrib\irrXML\*.o .\..\contrib\zlib\*.oc .\..\contrib\unzip\*.oc .\..\contrib\ConvertUTF\*.oc
-
-# target: static
-# usage : build a static library (*.a)
-static:    $(STATIC) 
-$(STATIC):    $(OBJECTS) $(OBJECTSC)
-	ar rcs $@ $(OBJECTS) $(OBJECTSC)
-

+ 7 - 0
Source/ThirdParty/Assimp/code/qnan.h

@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
+// Modified by Lasse Oorni for Urho3D
+
 /**  @file  qnan.h
  *   @brief Some utilities for our dealings with qnans.
  *
@@ -54,7 +56,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "../include/assimp/defs.h"
 #include <limits>
+// Urho3D: VS2008 compatibility
+#if !defined(_MSC_VER) || (_MSC_VER >= 1600)
 #include <stdint.h>
+#else
+#include "../include/assimp/Compiler/pstdint.h"
+#endif
 
 // ---------------------------------------------------------------------------
 /** Data structure to represent the bit pattern of a 32 Bit

+ 14 - 14
Source/ThirdParty/Assimp/code/res/resource.h

@@ -1,14 +1,14 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by assimp.rc
-
-// Nächste Standardwerte für neue Objekte
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        101
-#define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1001
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by assimp.rc
+
+// Nächste Standardwerte für neue Objekte
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif

+ 1 - 1
Source/ThirdParty/Assimp/code/revision.h

@@ -1,7 +1,7 @@
 #ifndef ASSIMP_REVISION_H_INC
 #define ASSIMP_REVISION_H_INC
 
-#define GitVersion 0xb0853cc
+#define GitVersion 0xe159728
 #define GitBranch "master"
 
 #endif // ASSIMP_REVISION_H_INC

+ 29 - 29
Source/ThirdParty/Assimp/contrib/clipper/License.txt

@@ -1,29 +1,29 @@
-The Clipper code library, the "Software" (that includes Delphi, C++ & C# 
-source code, accompanying samples and documentation), has been released 
-under the following license, terms and conditions:
-
-Boost Software License - Version 1.0 - August 17th, 2003
-http://www.boost.org/LICENSE_1_0.txt
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
+The Clipper code library, the "Software" (that includes Delphi, C++ & C# 
+source code, accompanying samples and documentation), has been released 
+under the following license, terms and conditions:
+
+Boost Software License - Version 1.0 - August 17th, 2003
+http://www.boost.org/LICENSE_1_0.txt
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+

+ 3448 - 3448
Source/ThirdParty/Assimp/contrib/clipper/clipper.cpp

@@ -1,3448 +1,3448 @@
-/*******************************************************************************
-*                                                                              *
-* Author    :  Angus Johnson                                                   *
-* Version   :  4.8.8                                                           *
-* Date      :  30 August 2012                                                  *
-* Website   :  http://www.angusj.com                                           *
-* Copyright :  Angus Johnson 2010-2012                                         *
-*                                                                              *
-* License:                                                                     *
-* Use, modification & distribution is subject to Boost Software License Ver 1. *
-* http://www.boost.org/LICENSE_1_0.txt                                         *
-*                                                                              *
-* Attributions:                                                                *
-* The code in this library is an extension of Bala Vatti's clipping algorithm: *
-* "A generic solution to polygon clipping"                                     *
-* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
-* http://portal.acm.org/citation.cfm?id=129906                                 *
-*                                                                              *
-* Computer graphics and geometric modeling: implementation and algorithms      *
-* By Max K. Agoston                                                            *
-* Springer; 1 edition (January 4, 2005)                                        *
-* http://books.google.com/books?q=vatti+clipping+agoston                       *
-*                                                                              *
-* See also:                                                                    *
-* "Polygon Offsetting by Computing Winding Numbers"                            *
-* Paper no. DETC2005-85513 pp. 565-575                                         *
-* ASME 2005 International Design Engineering Technical Conferences             *
-* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
-* September 24–28, 2005 , Long Beach, California, USA                          *
-* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
-*                                                                              *
-*******************************************************************************/
-
-/*******************************************************************************
-*                                                                              *
-* This is a translation of the Delphi Clipper library and the naming style     *
-* used has retained a Delphi flavour.                                          *
-*                                                                              *
-*******************************************************************************/
-
-#include "clipper.hpp"
-#include <cmath>
-#include <vector>
-#include <algorithm>
-#include <stdexcept>
-#include <cstring>
-#include <cstdlib>
-#include <ostream>
-
-namespace ClipperLib {
-
-static long64 const loRange = 0x3FFFFFFF;
-static long64 const hiRange = 0x3FFFFFFFFFFFFFFFLL;
-static double const pi = 3.141592653589793238;
-enum Direction { dRightToLeft, dLeftToRight };
-
-#define HORIZONTAL (-1.0E+40)
-#define TOLERANCE (1.0e-20)
-#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
-#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b))
-
-inline long64 Abs(long64 val)
-{
-  return val < 0 ? -val : val;
-}
-//------------------------------------------------------------------------------
-
-//------------------------------------------------------------------------------
-// Int128 class (enables safe math on signed 64bit integers)
-// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
-//    Int128 val2((long64)9223372036854775807);
-//    Int128 val3 = val1 * val2;
-//    val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
-//------------------------------------------------------------------------------
-
-class Int128
-{
-  public:
-
-    Int128(long64 _lo = 0)
-    {
-      lo = _lo;
-      if (lo < 0) hi = -1; else hi = 0;
-    }
-
-    Int128(const Int128 &val): hi(val.hi), lo(val.lo){}
-
-    long64 operator = (const long64 &val)
-    {
-      lo = val;
-      if (lo < 0) hi = -1; else hi = 0;
-      return val;
-    }
-
-    bool operator == (const Int128 &val) const
-      {return (hi == val.hi && lo == val.lo);}
-
-    bool operator != (const Int128 &val) const
-      { return !(*this == val);}
-
-    bool operator > (const Int128 &val) const
-    {
-      if (hi != val.hi)
-        return hi > val.hi;
-      else
-        return lo > val.lo;
-    }
-
-    bool operator < (const Int128 &val) const
-    {
-      if (hi != val.hi)
-        return hi < val.hi;
-      else
-        return lo < val.lo;
-    }
-
-    bool operator >= (const Int128 &val) const
-      { return !(*this < val);}
-
-    bool operator <= (const Int128 &val) const
-      { return !(*this > val);}
-
-    Int128& operator += (const Int128 &rhs)
-    {
-      hi += rhs.hi;
-      lo += rhs.lo;
-      if (ulong64(lo) < ulong64(rhs.lo)) hi++;
-      return *this;
-    }
-
-    Int128 operator + (const Int128 &rhs) const
-    {
-      Int128 result(*this);
-      result+= rhs;
-      return result;
-    }
-
-    Int128& operator -= (const Int128 &rhs)
-    {
-      Int128 tmp(rhs);
-      Negate(tmp);
-      *this += tmp;
-      return *this;
-    }
-
-    //Int128 operator -() const
-    //{
-    //  Int128 result(*this);
-    //  if (result.lo == 0) {
-    //    if (result.hi != 0) result.hi = -1;
-    //  }
-    //  else {
-    //    result.lo = -result.lo;
-    //    result.hi = ~result.hi;
-    //  }
-    //  return result;
-    //}
-
-    Int128 operator - (const Int128 &rhs) const
-    {
-      Int128 result(*this);
-      result -= rhs;
-      return result;
-    }
-
-    Int128 operator * (const Int128 &rhs) const
-    {
-      if ( !(hi == 0 || hi == -1) || !(rhs.hi == 0 || rhs.hi == -1))
-        throw "Int128 operator*: overflow error";
-      bool negate = (hi < 0) != (rhs.hi < 0);
-
-      Int128 tmp(*this);
-      if (tmp.hi < 0) Negate(tmp);
-      ulong64 int1Hi = ulong64(tmp.lo) >> 32;
-      ulong64 int1Lo = ulong64(tmp.lo & 0xFFFFFFFF);
-
-      tmp = rhs;
-      if (tmp.hi < 0) Negate(tmp);
-      ulong64 int2Hi = ulong64(tmp.lo) >> 32;
-      ulong64 int2Lo = ulong64(tmp.lo & 0xFFFFFFFF);
-
-      //nb: see comments in clipper.pas
-      ulong64 a = int1Hi * int2Hi;
-      ulong64 b = int1Lo * int2Lo;
-      ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
-
-      tmp.hi = long64(a + (c >> 32));
-      tmp.lo = long64(c << 32);
-      tmp.lo += long64(b);
-      if (ulong64(tmp.lo) < b) tmp.hi++;
-      if (negate) Negate(tmp);
-      return tmp;
-    }
-
-    Int128 operator/ (const Int128 &rhs) const
-    {
-      if (rhs.lo == 0 && rhs.hi == 0)
-        throw "Int128 operator/: divide by zero";
-      bool negate = (rhs.hi < 0) != (hi < 0);
-      Int128 result(*this), denom(rhs);
-      if (result.hi < 0) Negate(result);
-      if (denom.hi < 0)  Negate(denom);
-      if (denom > result) return Int128(0); //result is only a fraction of 1
-      Negate(denom);
-
-      Int128 p(0);
-      for (int i = 0; i < 128; ++i)
-      {
-        p.hi = p.hi << 1;
-        if (p.lo < 0) p.hi++;
-        p.lo = long64(p.lo) << 1;
-        if (result.hi < 0) p.lo++;
-        result.hi = result.hi << 1;
-        if (result.lo < 0) result.hi++;
-        result.lo = long64(result.lo) << 1;
-        Int128 p2(p);
-        p += denom;
-        if (p.hi < 0) p = p2;
-        else result.lo++;
-      }
-      if (negate) Negate(result);
-      return result;
-    }
-
-    double AsDouble() const
-    {
-      const double shift64 = 18446744073709551616.0; //2^64
-      const double bit64 = 9223372036854775808.0;
-      if (hi < 0)
-      {
-        Int128 tmp(*this);
-        Negate(tmp);
-        if (tmp.lo < 0)
-          return (double)tmp.lo - bit64 - tmp.hi * shift64;
-        else
-          return -(double)tmp.lo - tmp.hi * shift64;
-      }
-      else if (lo < 0)
-        return -(double)lo + bit64 + hi * shift64;
-      else
-        return (double)lo + (double)hi * shift64;
-    }
-
-    //for bug testing ...
-    //std::string AsString() const
-    //{
-    //  std::string result;
-    //  unsigned char r = 0;
-    //  Int128 tmp(0), val(*this);
-    //  if (hi < 0) Negate(val);
-    //  result.resize(50);
-    //  std::string::size_type i = result.size() -1;
-    //  while (val.hi != 0 || val.lo != 0)
-    //  {
-    //    Div10(val, tmp, r);
-    //    result[i--] = char('0' + r);
-    //    val = tmp;
-    //  }
-    //  if (hi < 0) result[i--] = '-';
-    //  result.erase(0,i+1);
-    //  if (result.size() == 0) result = "0";
-    //  return result;
-    //}
-
-private:
-    long64 hi;
-    long64 lo;
-
-    static void Negate(Int128 &val)
-    {
-      if (val.lo == 0) {
-        if (val.hi != 0) val.hi = -val.hi;;
-      }
-      else {
-        val.lo = -val.lo;
-        val.hi = ~val.hi;
-      }
-    }
-
-    //debugging only ...
-    //void Div10(const Int128 val, Int128& result, unsigned char & remainder) const
-    //{
-    //  remainder = 0;
-    //  result = 0;
-    //  for (int i = 63; i >= 0; --i)
-    //  {
-    //    if ((val.hi & ((long64)1 << i)) != 0)
-    //      remainder = char((remainder * 2) + 1); else
-    //      remainder *= char(2);
-    //    if (remainder >= 10)
-    //    {
-    //      result.hi += ((long64)1 << i);
-    //      remainder -= char(10);
-    //    }
-    //  }
-    //  for (int i = 63; i >= 0; --i)
-    //  {
-    //    if ((val.lo & ((long64)1 << i)) != 0)
-    //      remainder = char((remainder * 2) + 1); else
-    //      remainder *= char(2);
-    //    if (remainder >= 10)
-    //    {
-    //      result.lo += ((long64)1 << i);
-    //      remainder -= char(10);
-    //    }
-    //  }
-    //}
-};
-
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------------------
-
-bool FullRangeNeeded(const Polygon &pts)
-{
-  bool result = false;
-  for (Polygon::size_type i = 0; i <  pts.size(); ++i)
-  {
-    if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange)
-        throw "Coordinate exceeds range bounds.";
-      else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange)
-        result = true;
-  }
-  return result;
-}
-//------------------------------------------------------------------------------
-  
-bool Orientation(const Polygon &poly)
-{
-  int highI = (int)poly.size() -1;
-  if (highI < 2) return false;
-
-  int j = 0, jplus, jminus;
-  for (int i = 0; i <= highI; ++i)
-  {
-    if (poly[i].Y < poly[j].Y) continue;
-    if ((poly[i].Y > poly[j].Y || poly[i].X < poly[j].X)) j = i;
-  };
-  if (j == highI) jplus = 0;
-  else jplus = j +1;
-  if (j == 0) jminus = highI;
-  else jminus = j -1;
-
-  IntPoint vec1, vec2;
-  //get cross product of vectors of the edges adjacent to highest point ...
-  vec1.X = poly[j].X - poly[jminus].X;
-  vec1.Y = poly[j].Y - poly[jminus].Y;
-  vec2.X = poly[jplus].X - poly[j].X;
-  vec2.Y = poly[jplus].Y - poly[j].Y;
-
-  if (Abs(vec1.X) > loRange || Abs(vec1.Y) > loRange ||
-    Abs(vec2.X) > loRange || Abs(vec2.Y) > loRange)
-  {
-    if (Abs(vec1.X) > hiRange || Abs(vec1.Y) > hiRange ||
-      Abs(vec2.X) > hiRange || Abs(vec2.Y) > hiRange)
-        throw "Coordinate exceeds range bounds.";
-    Int128 cross = Int128(vec1.X) * Int128(vec2.Y) -
-      Int128(vec2.X) * Int128(vec1.Y);
-    return cross >= 0;
-  }
-  else
-    return (vec1.X * vec2.Y - vec2.X * vec1.Y) >= 0;
-}
-//------------------------------------------------------------------------------
-
-inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2)
-{
-  return ( pt1.X == pt2.X && pt1.Y == pt2.Y );
-}
-//------------------------------------------------------------------------------
-
-bool Orientation(OutRec *outRec, bool UseFullInt64Range)
-{
-  //first make sure bottomPt is correctly assigned ...
-  OutPt *opBottom = outRec->pts, *op = outRec->pts->next;
-  while (op != outRec->pts)
-  {
-    if (op->pt.Y >= opBottom->pt.Y)
-    {
-      if (op->pt.Y > opBottom->pt.Y || op->pt.X < opBottom->pt.X)
-      opBottom = op;
-    }
-    op = op->next;
-  }
-  outRec->bottomPt = opBottom;
-  opBottom->idx = outRec->idx;
-
-  op = opBottom;
-  //find vertices either side of bottomPt (skipping duplicate points) ....
-  OutPt *opPrev = op->prev;
-  OutPt *opNext = op->next;
-  while (op != opPrev && PointsEqual(op->pt, opPrev->pt))
-    opPrev = opPrev->prev;
-  while (op != opNext && PointsEqual(op->pt, opNext->pt))
-    opNext = opNext->next;
-
-  IntPoint ip1, ip2;
-  ip1.X = op->pt.X - opPrev->pt.X;
-  ip1.Y = op->pt.Y - opPrev->pt.Y;
-  ip2.X = opNext->pt.X - op->pt.X;
-  ip2.Y = opNext->pt.Y - op->pt.Y;
-
-  if (UseFullInt64Range)
-    return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) >= 0;
-  else
-    return (ip1.X * ip2.Y - ip2.X * ip1.Y) >= 0;
-}
-//------------------------------------------------------------------------------
-
-double Area(const Polygon &poly)
-{
-  int highI = (int)poly.size() -1;
-  if (highI < 2) return 0;
-
-  if (FullRangeNeeded(poly)) {
-    Int128 a;
-    a = (Int128(poly[highI].X) * Int128(poly[0].Y)) -
-      Int128(poly[0].X) * Int128(poly[highI].Y);
-    for (int i = 0; i < highI; ++i)
-      a += Int128(poly[i].X) * Int128(poly[i+1].Y) -
-        Int128(poly[i+1].X) * Int128(poly[i].Y);
-    return a.AsDouble() / 2;
-  }
-  else
-  {
-    double a;
-    a = (double)poly[highI].X * poly[0].Y - (double)poly[0].X * poly[highI].Y;
-    for (int i = 0; i < highI; ++i)
-      a += (double)poly[i].X * poly[i+1].Y - (double)poly[i+1].X * poly[i].Y;
-    return a/2;
-  }
-}
-//------------------------------------------------------------------------------
-
-double Area(const OutRec &outRec, bool UseFullInt64Range)
-{
-  OutPt *op = outRec.pts;
-  if (UseFullInt64Range) {
-    Int128 a(0);
-    do {
-      a += (Int128(op->prev->pt.X) * Int128(op->pt.Y)) -
-        Int128(op->pt.X) * Int128(op->prev->pt.Y);
-      op = op->next;
-    } while (op != outRec.pts);
-    return a.AsDouble() / 2;
-  }
-  else
-  {
-    double a = 0;
-    do {
-      a += (op->prev->pt.X * op->pt.Y) - (op->pt.X * op->prev->pt.Y);
-      op = op->next;
-    } while (op != outRec.pts);
-    return a/2;
-  }
-}
-//------------------------------------------------------------------------------
-
-bool PointIsVertex(const IntPoint &pt, OutPt *pp)
-{
-  OutPt *pp2 = pp;
-  do
-  {
-    if (PointsEqual(pp2->pt, pt)) return true;
-    pp2 = pp2->next;
-  }
-  while (pp2 != pp);
-  return false;
-}
-//------------------------------------------------------------------------------
-
-bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range)
-{
-  OutPt *pp2 = pp;
-  bool result = false;
-  if (UseFullInt64Range) {
-    do
-    {
-      if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) ||
-          ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) &&
-          Int128(pt.X - pp2->pt.X) < (Int128(pp2->prev->pt.X - pp2->pt.X) *
-          Int128(pt.Y - pp2->pt.Y)) / Int128(pp2->prev->pt.Y - pp2->pt.Y))
-            result = !result;
-      pp2 = pp2->next;
-    }
-    while (pp2 != pp);
-  }
-  else
-  {
-    do
-    {
-      if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) ||
-        ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) &&
-        (pt.X < (pp2->prev->pt.X - pp2->pt.X) * (pt.Y - pp2->pt.Y) /
-        (pp2->prev->pt.Y - pp2->pt.Y) + pp2->pt.X )) result = !result;
-      pp2 = pp2->next;
-    }
-    while (pp2 != pp);
-  }
-  return result;
-}
-//------------------------------------------------------------------------------
-
-bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range)
-{
-  if (UseFullInt64Range)
-    return Int128(e1.ytop - e1.ybot) * Int128(e2.xtop - e2.xbot) ==
-      Int128(e1.xtop - e1.xbot) * Int128(e2.ytop - e2.ybot);
-  else return (e1.ytop - e1.ybot)*(e2.xtop - e2.xbot) ==
-      (e1.xtop - e1.xbot)*(e2.ytop - e2.ybot);
-}
-//------------------------------------------------------------------------------
-
-bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
-  const IntPoint pt3, bool UseFullInt64Range)
-{
-  if (UseFullInt64Range)
-    return Int128(pt1.Y-pt2.Y) * Int128(pt2.X-pt3.X) ==
-      Int128(pt1.X-pt2.X) * Int128(pt2.Y-pt3.Y);
-  else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y);
-}
-//------------------------------------------------------------------------------
-
-bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
-  const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range)
-{
-  if (UseFullInt64Range)
-    return Int128(pt1.Y-pt2.Y) * Int128(pt3.X-pt4.X) ==
-      Int128(pt1.X-pt2.X) * Int128(pt3.Y-pt4.Y);
-  else return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y);
-}
-//------------------------------------------------------------------------------
-
-double GetDx(const IntPoint pt1, const IntPoint pt2)
-{
-  return (pt1.Y == pt2.Y) ?
-    HORIZONTAL : (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y);
-}
-//---------------------------------------------------------------------------
-
-void SetDx(TEdge &e)
-{
-  if (e.ybot == e.ytop) e.dx = HORIZONTAL;
-  else e.dx = (double)(e.xtop - e.xbot) / (double)(e.ytop - e.ybot);
-}
-//---------------------------------------------------------------------------
-
-void SwapSides(TEdge &edge1, TEdge &edge2)
-{
-  EdgeSide side =  edge1.side;
-  edge1.side = edge2.side;
-  edge2.side = side;
-}
-//------------------------------------------------------------------------------
-
-void SwapPolyIndexes(TEdge &edge1, TEdge &edge2)
-{
-  int outIdx =  edge1.outIdx;
-  edge1.outIdx = edge2.outIdx;
-  edge2.outIdx = outIdx;
-}
-//------------------------------------------------------------------------------
-
-inline long64 Round(double val)
-{
-  return (val < 0) ?
-    static_cast<long64>(val - 0.5) : static_cast<long64>(val + 0.5);
-}
-//------------------------------------------------------------------------------
-
-long64 TopX(TEdge &edge, const long64 currentY)
-{
-  return ( currentY == edge.ytop ) ?
-    edge.xtop : edge.xbot + Round(edge.dx *(currentY - edge.ybot));
-}
-//------------------------------------------------------------------------------
-
-long64 TopX(const IntPoint pt1, const IntPoint pt2, const long64 currentY)
-{
-  //preconditions: pt1.Y <> pt2.Y and pt1.Y > pt2.Y
-  if (currentY >= pt1.Y) return pt1.X;
-  else if (currentY == pt2.Y) return pt2.X;
-  else if (pt1.X == pt2.X) return pt1.X;
-  else
-  {
-    double q = (double)(pt1.X-pt2.X)/(double)(pt1.Y-pt2.Y);
-    return Round(pt1.X + (currentY - pt1.Y) *q);
-  }
-}
-//------------------------------------------------------------------------------
-
-bool IntersectPoint(TEdge &edge1, TEdge &edge2,
-  IntPoint &ip, bool UseFullInt64Range)
-{
-  double b1, b2;
-  if (SlopesEqual(edge1, edge2, UseFullInt64Range)) return false;
-  else if (NEAR_ZERO(edge1.dx))
-  {
-    ip.X = edge1.xbot;
-    if (NEAR_EQUAL(edge2.dx, HORIZONTAL))
-    {
-      ip.Y = edge2.ybot;
-    } else
-    {
-      b2 = edge2.ybot - (edge2.xbot/edge2.dx);
-      ip.Y = Round(ip.X/edge2.dx + b2);
-    }
-  }
-  else if (NEAR_ZERO(edge2.dx))
-  {
-    ip.X = edge2.xbot;
-    if (NEAR_EQUAL(edge1.dx, HORIZONTAL))
-    {
-      ip.Y = edge1.ybot;
-    } else
-    {
-      b1 = edge1.ybot - (edge1.xbot/edge1.dx);
-      ip.Y = Round(ip.X/edge1.dx + b1);
-    }
-  } else
-  {
-    b1 = edge1.xbot - edge1.ybot * edge1.dx;
-    b2 = edge2.xbot - edge2.ybot * edge2.dx;
-    b2 = (b2-b1)/(edge1.dx - edge2.dx);
-    ip.Y = Round(b2);
-    ip.X = Round(edge1.dx * b2 + b1);
-  }
-
-  return
-    //can be *so close* to the top of one edge that the rounded Y equals one ytop ...
-    (ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) ||
-    (ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) ||
-    (ip.Y > edge1.ytop && ip.Y > edge2.ytop);
-}
-//------------------------------------------------------------------------------
-
-void ReversePolyPtLinks(OutPt &pp)
-{
-  OutPt *pp1, *pp2;
-  pp1 = &pp;
-  do {
-  pp2 = pp1->next;
-  pp1->next = pp1->prev;
-  pp1->prev = pp2;
-  pp1 = pp2;
-  } while( pp1 != &pp );
-}
-//------------------------------------------------------------------------------
-
-void DisposeOutPts(OutPt*& pp)
-{
-  if (pp == 0) return;
-  pp->prev->next = 0;
-  while( pp )
-  {
-    OutPt *tmpPp = pp;
-    pp = pp->next;
-    delete tmpPp ;
-  }
-}
-//------------------------------------------------------------------------------
-
-void InitEdge(TEdge *e, TEdge *eNext,
-  TEdge *ePrev, const IntPoint &pt, PolyType polyType)
-{
-  std::memset( e, 0, sizeof( TEdge ));
-
-  e->next = eNext;
-  e->prev = ePrev;
-  e->xcurr = pt.X;
-  e->ycurr = pt.Y;
-  if (e->ycurr >= e->next->ycurr)
-  {
-    e->xbot = e->xcurr;
-    e->ybot = e->ycurr;
-    e->xtop = e->next->xcurr;
-    e->ytop = e->next->ycurr;
-    e->windDelta = 1;
-  } else
-  {
-    e->xtop = e->xcurr;
-    e->ytop = e->ycurr;
-    e->xbot = e->next->xcurr;
-    e->ybot = e->next->ycurr;
-    e->windDelta = -1;
-  }
-  SetDx(*e);
-  e->polyType = polyType;
-  e->outIdx = -1;
-}
-//------------------------------------------------------------------------------
-
-inline void SwapX(TEdge &e)
-{
-  //swap horizontal edges' top and bottom x's so they follow the natural
-  //progression of the bounds - ie so their xbots will align with the
-  //adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
-  e.xcurr = e.xtop;
-  e.xtop = e.xbot;
-  e.xbot = e.xcurr;
-}
-//------------------------------------------------------------------------------
-
-void SwapPoints(IntPoint &pt1, IntPoint &pt2)
-{
-  IntPoint tmp = pt1;
-  pt1 = pt2;
-  pt2 = tmp;
-}
-//------------------------------------------------------------------------------
-
-bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
-  IntPoint pt2b, IntPoint &pt1, IntPoint &pt2)
-{
-  //precondition: segments are colinear.
-  if ( pt1a.Y == pt1b.Y || Abs((pt1a.X - pt1b.X)/(pt1a.Y - pt1b.Y)) > 1 )
-  {
-    if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b);
-    if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b);
-    if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a;
-    if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b;
-    return pt1.X < pt2.X;
-  } else
-  {
-    if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b);
-    if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b);
-    if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a;
-    if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b;
-    return pt1.Y > pt2.Y;
-  }
-}
-//------------------------------------------------------------------------------
-
-bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2)
-{
-  OutPt *p = btmPt1->prev;
-  while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->prev;
-  double dx1p = std::fabs(GetDx(btmPt1->pt, p->pt));
-  p = btmPt1->next;
-  while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->next;
-  double dx1n = std::fabs(GetDx(btmPt1->pt, p->pt));
-
-  p = btmPt2->prev;
-  while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->prev;
-  double dx2p = std::fabs(GetDx(btmPt2->pt, p->pt));
-  p = btmPt2->next;
-  while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->next;
-  double dx2n = std::fabs(GetDx(btmPt2->pt, p->pt));
-  return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
-}
-//------------------------------------------------------------------------------
-
-OutPt* GetBottomPt(OutPt *pp)
-{
-  OutPt* dups = 0;
-  OutPt* p = pp->next;
-  while (p != pp)
-  {
-    if (p->pt.Y > pp->pt.Y)
-    {
-      pp = p;
-      dups = 0;
-    }
-    else if (p->pt.Y == pp->pt.Y && p->pt.X <= pp->pt.X)
-    {
-      if (p->pt.X < pp->pt.X)
-      {
-        dups = 0;
-        pp = p;
-      } else
-      {
-        if (p->next != pp && p->prev != pp) dups = p;
-      }
-    }
-    p = p->next;
-  }
-  if (dups)
-  {
-    //there appears to be at least 2 vertices at bottomPt so ...
-    while (dups != p)
-    {
-      if (!FirstIsBottomPt(p, dups)) pp = dups;
-      dups = dups->next;
-      while (!PointsEqual(dups->pt, pp->pt)) dups = dups->next;
-    }
-  }
-  return pp;
-}
-//------------------------------------------------------------------------------
-
-bool FindSegment(OutPt* &pp, IntPoint &pt1, IntPoint &pt2)
-{
-  //outPt1 & outPt2 => the overlap segment (if the function returns true)
-  if (!pp) return false;
-  OutPt* pp2 = pp;
-  IntPoint pt1a = pt1, pt2a = pt2;
-  do
-  {
-    if (SlopesEqual(pt1a, pt2a, pp->pt, pp->prev->pt, true) &&
-      SlopesEqual(pt1a, pt2a, pp->pt, true) &&
-      GetOverlapSegment(pt1a, pt2a, pp->pt, pp->prev->pt, pt1, pt2))
-        return true;
-    pp = pp->next;
-  }
-  while (pp != pp2);
-  return false;
-}
-//------------------------------------------------------------------------------
-
-bool Pt3IsBetweenPt1AndPt2(const IntPoint pt1,
-  const IntPoint pt2, const IntPoint pt3)
-{
-  if (PointsEqual(pt1, pt3) || PointsEqual(pt2, pt3)) return true;
-  else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X);
-  else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y);
-}
-//------------------------------------------------------------------------------
-
-OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint pt)
-{
-  if (p1 == p2) throw "JoinError";
-  OutPt* result = new OutPt;
-  result->pt = pt;
-  if (p2 == p1->next)
-  {
-    p1->next = result;
-    p2->prev = result;
-    result->next = p2;
-    result->prev = p1;
-  } else
-  {
-    p2->next = result;
-    p1->prev = result;
-    result->next = p1;
-    result->prev = p2;
-  }
-  return result;
-}
-
-//------------------------------------------------------------------------------
-// ClipperBase class methods ...
-//------------------------------------------------------------------------------
-
-ClipperBase::ClipperBase() //constructor
-{
-  m_MinimaList = 0;
-  m_CurrentLM = 0;
-  m_UseFullRange = true;
-}
-//------------------------------------------------------------------------------
-
-ClipperBase::~ClipperBase() //destructor
-{
-  Clear();
-}
-//------------------------------------------------------------------------------
-
-bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType)
-{
-  int len = (int)pg.size();
-  if (len < 3) return false;
-  Polygon p(len);
-  p[0] = pg[0];
-  int j = 0;
-
-  long64 maxVal;
-  if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
-
-  for (int i = 0; i < len; ++i)
-  {
-    if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal)
-    {
-      if (Abs(pg[i].X) > hiRange || Abs(pg[i].Y) > hiRange)
-        throw "Coordinate exceeds range bounds";
-      maxVal = hiRange;
-      m_UseFullRange = true;
-    }
-
-    if (i == 0 || PointsEqual(p[j], pg[i])) continue;
-    else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange))
-    {
-      if (PointsEqual(p[j-1], pg[i])) j--;
-    } else j++;
-    p[j] = pg[i];
-  }
-  if (j < 2) return false;
-
-  len = j+1;
-  while (len > 2)
-  {
-    //nb: test for point equality before testing slopes ...
-    if (PointsEqual(p[j], p[0])) j--;
-    else if (PointsEqual(p[0], p[1]) ||
-      SlopesEqual(p[j], p[0], p[1], m_UseFullRange))
-      p[0] = p[j--];
-    else if (SlopesEqual(p[j-1], p[j], p[0], m_UseFullRange)) j--;
-    else if (SlopesEqual(p[0], p[1], p[2], m_UseFullRange))
-    {
-      for (int i = 2; i <= j; ++i) p[i-1] = p[i];
-      j--;
-    }
-    else break;
-    len--;
-  }
-  if (len < 3) return false;
-
-  //create a new edge array ...
-  TEdge *edges = new TEdge [len];
-  m_edges.push_back(edges);
-
-  //convert vertices to a double-linked-list of edges and initialize ...
-  edges[0].xcurr = p[0].X;
-  edges[0].ycurr = p[0].Y;
-  InitEdge(&edges[len-1], &edges[0], &edges[len-2], p[len-1], polyType);
-  for (int i = len-2; i > 0; --i)
-    InitEdge(&edges[i], &edges[i+1], &edges[i-1], p[i], polyType);
-  InitEdge(&edges[0], &edges[1], &edges[len-1], p[0], polyType);
-
-  //reset xcurr & ycurr and find 'eHighest' (given the Y axis coordinates
-  //increase downward so the 'highest' edge will have the smallest ytop) ...
-  TEdge *e = &edges[0];
-  TEdge *eHighest = e;
-  do
-  {
-    e->xcurr = e->xbot;
-    e->ycurr = e->ybot;
-    if (e->ytop < eHighest->ytop) eHighest = e;
-    e = e->next;
-  }
-  while ( e != &edges[0]);
-
-  //make sure eHighest is positioned so the following loop works safely ...
-  if (eHighest->windDelta > 0) eHighest = eHighest->next;
-  if (NEAR_EQUAL(eHighest->dx, HORIZONTAL)) eHighest = eHighest->next;
-
-  //finally insert each local minima ...
-  e = eHighest;
-  do {
-    e = AddBoundsToLML(e);
-  }
-  while( e != eHighest );
-  return true;
-}
-//------------------------------------------------------------------------------
-
-void ClipperBase::InsertLocalMinima(LocalMinima *newLm)
-{
-  if( ! m_MinimaList )
-  {
-    m_MinimaList = newLm;
-  }
-  else if( newLm->Y >= m_MinimaList->Y )
-  {
-    newLm->next = m_MinimaList;
-    m_MinimaList = newLm;
-  } else
-  {
-    LocalMinima* tmpLm = m_MinimaList;
-    while( tmpLm->next  && ( newLm->Y < tmpLm->next->Y ) )
-      tmpLm = tmpLm->next;
-    newLm->next = tmpLm->next;
-    tmpLm->next = newLm;
-  }
-}
-//------------------------------------------------------------------------------
-
-TEdge* ClipperBase::AddBoundsToLML(TEdge *e)
-{
-  //Starting at the top of one bound we progress to the bottom where there's
-  //a local minima. We then go to the top of the next bound. These two bounds
-  //form the left and right (or right and left) bounds of the local minima.
-  e->nextInLML = 0;
-  e = e->next;
-  for (;;)
-  {
-    if (NEAR_EQUAL(e->dx, HORIZONTAL))
-    {
-      //nb: proceed through horizontals when approaching from their right,
-      //    but break on horizontal minima if approaching from their left.
-      //    This ensures 'local minima' are always on the left of horizontals.
-      if (e->next->ytop < e->ytop && e->next->xbot > e->prev->xbot) break;
-      if (e->xtop != e->prev->xbot) SwapX(*e);
-      e->nextInLML = e->prev;
-    }
-    else if (e->ycurr == e->prev->ycurr) break;
-    else e->nextInLML = e->prev;
-    e = e->next;
-  }
-
-  //e and e.prev are now at a local minima ...
-  LocalMinima* newLm = new LocalMinima;
-  newLm->next = 0;
-  newLm->Y = e->prev->ybot;
-
-  if ( NEAR_EQUAL(e->dx, HORIZONTAL) ) //horizontal edges never start a left bound
-  {
-    if (e->xbot != e->prev->xbot) SwapX(*e);
-    newLm->leftBound = e->prev;
-    newLm->rightBound = e;
-  } else if (e->dx < e->prev->dx)
-  {
-    newLm->leftBound = e->prev;
-    newLm->rightBound = e;
-  } else
-  {
-    newLm->leftBound = e;
-    newLm->rightBound = e->prev;
-  }
-  newLm->leftBound->side = esLeft;
-  newLm->rightBound->side = esRight;
-  InsertLocalMinima( newLm );
-
-  for (;;)
-  {
-    if ( e->next->ytop == e->ytop && !NEAR_EQUAL(e->next->dx, HORIZONTAL) ) break;
-    e->nextInLML = e->next;
-    e = e->next;
-    if ( NEAR_EQUAL(e->dx, HORIZONTAL) && e->xbot != e->prev->xtop) SwapX(*e);
-  }
-  return e->next;
-}
-//------------------------------------------------------------------------------
-
-bool ClipperBase::AddPolygons(const Polygons &ppg, PolyType polyType)
-{
-  bool result = false;
-  for (Polygons::size_type i = 0; i < ppg.size(); ++i)
-    if (AddPolygon(ppg[i], polyType)) result = true;
-  return result;
-}
-//------------------------------------------------------------------------------
-
-void ClipperBase::Clear()
-{
-  DisposeLocalMinimaList();
-  for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) delete [] m_edges[i];
-  m_edges.clear();
-  m_UseFullRange = false;
-}
-//------------------------------------------------------------------------------
-
-void ClipperBase::Reset()
-{
-  m_CurrentLM = m_MinimaList;
-  if( !m_CurrentLM ) return; //ie nothing to process
-
-  //reset all edges ...
-  LocalMinima* lm = m_MinimaList;
-  while( lm )
-  {
-    TEdge* e = lm->leftBound;
-    while( e )
-    {
-      e->xcurr = e->xbot;
-      e->ycurr = e->ybot;
-      e->side = esLeft;
-      e->outIdx = -1;
-      e = e->nextInLML;
-    }
-    e = lm->rightBound;
-    while( e )
-    {
-      e->xcurr = e->xbot;
-      e->ycurr = e->ybot;
-      e->side = esRight;
-      e->outIdx = -1;
-      e = e->nextInLML;
-    }
-    lm = lm->next;
-  }
-}
-//------------------------------------------------------------------------------
-
-void ClipperBase::DisposeLocalMinimaList()
-{
-  while( m_MinimaList )
-  {
-    LocalMinima* tmpLm = m_MinimaList->next;
-    delete m_MinimaList;
-    m_MinimaList = tmpLm;
-  }
-  m_CurrentLM = 0;
-}
-//------------------------------------------------------------------------------
-
-void ClipperBase::PopLocalMinima()
-{
-  if( ! m_CurrentLM ) return;
-  m_CurrentLM = m_CurrentLM->next;
-}
-//------------------------------------------------------------------------------
-
-IntRect ClipperBase::GetBounds()
-{
-  IntRect result;
-  LocalMinima* lm = m_MinimaList;
-  if (!lm)
-  {
-    result.left = result.top = result.right = result.bottom = 0;
-    return result;
-  }
-  result.left = lm->leftBound->xbot;
-  result.top = lm->leftBound->ybot;
-  result.right = lm->leftBound->xbot;
-  result.bottom = lm->leftBound->ybot;
-  while (lm)
-  {
-    if (lm->leftBound->ybot > result.bottom)
-      result.bottom = lm->leftBound->ybot;
-    TEdge* e = lm->leftBound;
-    for (;;) {
-      TEdge* bottomE = e;
-      while (e->nextInLML)
-      {
-        if (e->xbot < result.left) result.left = e->xbot;
-        if (e->xbot > result.right) result.right = e->xbot;
-        e = e->nextInLML;
-      }
-      if (e->xbot < result.left) result.left = e->xbot;
-      if (e->xbot > result.right) result.right = e->xbot;
-      if (e->xtop < result.left) result.left = e->xtop;
-      if (e->xtop > result.right) result.right = e->xtop;
-      if (e->ytop < result.top) result.top = e->ytop;
-
-      if (bottomE == lm->leftBound) e = lm->rightBound;
-      else break;
-    }
-    lm = lm->next;
-  }
-  return result;
-}
-
-
-//------------------------------------------------------------------------------
-// TClipper methods ...
-//------------------------------------------------------------------------------
-
-Clipper::Clipper() : ClipperBase() //constructor
-{
-  m_Scanbeam = 0;
-  m_ActiveEdges = 0;
-  m_SortedEdges = 0;
-  m_IntersectNodes = 0;
-  m_ExecuteLocked = false;
-  m_UseFullRange = false;
-  m_ReverseOutput = false;
-}
-//------------------------------------------------------------------------------
-
-Clipper::~Clipper() //destructor
-{
-  Clear();
-  DisposeScanbeamList();
-}
-//------------------------------------------------------------------------------
-
-void Clipper::Clear()
-{
-  if (m_edges.size() == 0) return; //avoids problems with ClipperBase destructor
-  DisposeAllPolyPts();
-  ClipperBase::Clear();
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeScanbeamList()
-{
-  while ( m_Scanbeam ) {
-  Scanbeam* sb2 = m_Scanbeam->next;
-  delete m_Scanbeam;
-  m_Scanbeam = sb2;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::Reset()
-{
-  ClipperBase::Reset();
-  m_Scanbeam = 0;
-  m_ActiveEdges = 0;
-  m_SortedEdges = 0;
-  DisposeAllPolyPts();
-  LocalMinima* lm = m_MinimaList;
-  while (lm)
-  {
-    InsertScanbeam(lm->Y);
-    InsertScanbeam(lm->leftBound->ytop);
-    lm = lm->next;
-  }
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::Execute(ClipType clipType, Polygons &solution,
-    PolyFillType subjFillType, PolyFillType clipFillType)
-{
-  if( m_ExecuteLocked ) return false;
-  m_ExecuteLocked = true;
-  solution.resize(0);
-  m_SubjFillType = subjFillType;
-  m_ClipFillType = clipFillType;
-  m_ClipType = clipType;
-  bool succeeded = ExecuteInternal(false);
-  if (succeeded) BuildResult(solution);
-  m_ExecuteLocked = false;
-  return succeeded;
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::Execute(ClipType clipType, ExPolygons &solution,
-    PolyFillType subjFillType, PolyFillType clipFillType)
-{
-  if( m_ExecuteLocked ) return false;
-  m_ExecuteLocked = true;
-  solution.resize(0);
-  m_SubjFillType = subjFillType;
-  m_ClipFillType = clipFillType;
-  m_ClipType = clipType;
-  bool succeeded = ExecuteInternal(true);
-  if (succeeded) BuildResultEx(solution);
-  m_ExecuteLocked = false;
-  return succeeded;
-}
-//------------------------------------------------------------------------------
-
-bool PolySort(OutRec *or1, OutRec *or2)
-{
-  if (or1 == or2) return false;
-  if (!or1->pts || !or2->pts)
-  {
-    if (or1->pts != or2->pts)
-    {
-      return or1->pts ? true : false;
-    }
-    else return false;
-  }
-  int i1, i2;
-  if (or1->isHole)
-    i1 = or1->FirstLeft->idx; else
-    i1 = or1->idx;
-  if (or2->isHole)
-    i2 = or2->FirstLeft->idx; else
-    i2 = or2->idx;
-  int result = i1 - i2;
-  if (result == 0 && (or1->isHole != or2->isHole))
-  {
-    return or1->isHole ? false : true;
-  }
-  else return result < 0;
-}
-//------------------------------------------------------------------------------
-
-OutRec* FindAppendLinkEnd(OutRec *outRec)
-{
-  while (outRec->AppendLink) outRec = outRec->AppendLink;
-  return outRec;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::FixHoleLinkage(OutRec *outRec)
-{
-  OutRec *tmp;
-  if (outRec->bottomPt)
-    tmp = m_PolyOuts[outRec->bottomPt->idx]->FirstLeft;
-  else
-    tmp = outRec->FirstLeft;
-  if (outRec == tmp) throw clipperException("HoleLinkage error");
-
-  if (tmp)
-  {
-    if (tmp->AppendLink) tmp = FindAppendLinkEnd(tmp);
-    if (tmp == outRec) tmp = 0;
-    else if (tmp->isHole)
-    {
-      FixHoleLinkage(tmp);
-      tmp = tmp->FirstLeft;
-    }
-  }
-  outRec->FirstLeft = tmp;
-  if (!tmp) outRec->isHole = false;
-  outRec->AppendLink = 0;
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::ExecuteInternal(bool fixHoleLinkages)
-{
-  bool succeeded;
-  try {
-    Reset();
-    if (!m_CurrentLM ) return true;
-    long64 botY = PopScanbeam();
-    do {
-      InsertLocalMinimaIntoAEL(botY);
-      ClearHorzJoins();
-      ProcessHorizontals();
-      long64 topY = PopScanbeam();
-      succeeded = ProcessIntersections(botY, topY);
-      if (!succeeded) break;
-      ProcessEdgesAtTopOfScanbeam(topY);
-      botY = topY;
-    } while( m_Scanbeam );
-  }
-  catch(...) {
-    succeeded = false;
-  }
-
-  if (succeeded)
-  {
-    //tidy up output polygons and fix orientations where necessary ...
-    for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
-    {
-      OutRec *outRec = m_PolyOuts[i];
-      if (!outRec->pts) continue;
-      FixupOutPolygon(*outRec);
-      if (!outRec->pts) continue;
-      if (outRec->isHole && fixHoleLinkages) FixHoleLinkage(outRec);
-
-      if (outRec->bottomPt == outRec->bottomFlag &&
-        (Orientation(outRec, m_UseFullRange) != (Area(*outRec, m_UseFullRange) > 0)))
-          DisposeBottomPt(*outRec);
-
-      if (outRec->isHole ==
-        (m_ReverseOutput ^ Orientation(outRec, m_UseFullRange)))
-          ReversePolyPtLinks(*outRec->pts);
-    }
-
-    JoinCommonEdges(fixHoleLinkages);
-    if (fixHoleLinkages)
-      std::sort(m_PolyOuts.begin(), m_PolyOuts.end(), PolySort);
-  }
-
-  ClearJoins();
-  ClearHorzJoins();
-  return succeeded;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::InsertScanbeam(const long64 Y)
-{
-  if( !m_Scanbeam )
-  {
-    m_Scanbeam = new Scanbeam;
-    m_Scanbeam->next = 0;
-    m_Scanbeam->Y = Y;
-  }
-  else if(  Y > m_Scanbeam->Y )
-  {
-    Scanbeam* newSb = new Scanbeam;
-    newSb->Y = Y;
-    newSb->next = m_Scanbeam;
-    m_Scanbeam = newSb;
-  } else
-  {
-    Scanbeam* sb2 = m_Scanbeam;
-    while( sb2->next  && ( Y <= sb2->next->Y ) ) sb2 = sb2->next;
-    if(  Y == sb2->Y ) return; //ie ignores duplicates
-    Scanbeam* newSb = new Scanbeam;
-    newSb->Y = Y;
-    newSb->next = sb2->next;
-    sb2->next = newSb;
-  }
-}
-//------------------------------------------------------------------------------
-
-long64 Clipper::PopScanbeam()
-{
-  long64 Y = m_Scanbeam->Y;
-  Scanbeam* sb2 = m_Scanbeam;
-  m_Scanbeam = m_Scanbeam->next;
-  delete sb2;
-  return Y;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeAllPolyPts(){
-  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
-    DisposeOutRec(i);
-  m_PolyOuts.clear();
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeOutRec(PolyOutList::size_type index)
-{
-  OutRec *outRec = m_PolyOuts[index];
-  if (outRec->pts) DisposeOutPts(outRec->pts);
-  delete outRec;
-  m_PolyOuts[index] = 0;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::SetWindingCount(TEdge &edge)
-{
-  TEdge *e = edge.prevInAEL;
-  //find the edge of the same polytype that immediately preceeds 'edge' in AEL
-  while ( e  && e->polyType != edge.polyType ) e = e->prevInAEL;
-  if ( !e )
-  {
-    edge.windCnt = edge.windDelta;
-    edge.windCnt2 = 0;
-    e = m_ActiveEdges; //ie get ready to calc windCnt2
-  } else if ( IsEvenOddFillType(edge) )
-  {
-    //EvenOdd filling ...
-    edge.windCnt = 1;
-    edge.windCnt2 = e->windCnt2;
-    e = e->nextInAEL; //ie get ready to calc windCnt2
-  } else
-  {
-    //nonZero, Positive or Negative filling ...
-    if ( e->windCnt * e->windDelta < 0 )
-    {
-      if (Abs(e->windCnt) > 1)
-      {
-        if (e->windDelta * edge.windDelta < 0) edge.windCnt = e->windCnt;
-        else edge.windCnt = e->windCnt + edge.windDelta;
-      } else
-        edge.windCnt = e->windCnt + e->windDelta + edge.windDelta;
-    } else
-    {
-      if ( Abs(e->windCnt) > 1 && e->windDelta * edge.windDelta < 0)
-        edge.windCnt = e->windCnt;
-      else if ( e->windCnt + edge.windDelta == 0 )
-        edge.windCnt = e->windCnt;
-      else edge.windCnt = e->windCnt + edge.windDelta;
-    }
-    edge.windCnt2 = e->windCnt2;
-    e = e->nextInAEL; //ie get ready to calc windCnt2
-  }
-
-  //update windCnt2 ...
-  if ( IsEvenOddAltFillType(edge) )
-  {
-    //EvenOdd filling ...
-    while ( e != &edge )
-    {
-      edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0;
-      e = e->nextInAEL;
-    }
-  } else
-  {
-    //nonZero, Positive or Negative filling ...
-    while ( e != &edge )
-    {
-      edge.windCnt2 += e->windDelta;
-      e = e->nextInAEL;
-    }
-  }
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::IsEvenOddFillType(const TEdge& edge) const
-{
-  if (edge.polyType == ptSubject)
-    return m_SubjFillType == pftEvenOdd; else
-    return m_ClipFillType == pftEvenOdd;
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const
-{
-  if (edge.polyType == ptSubject)
-    return m_ClipFillType == pftEvenOdd; else
-    return m_SubjFillType == pftEvenOdd;
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::IsContributing(const TEdge& edge) const
-{
-  PolyFillType pft, pft2;
-  if (edge.polyType == ptSubject)
-  {
-    pft = m_SubjFillType;
-    pft2 = m_ClipFillType;
-  } else
-  {
-    pft = m_ClipFillType;
-    pft2 = m_SubjFillType;
-  }
-
-  switch(pft)
-  {
-    case pftEvenOdd: 
-    case pftNonZero:
-      if (Abs(edge.windCnt) != 1) return false;
-      break;
-    case pftPositive: 
-      if (edge.windCnt != 1) return false;
-      break;
-    default: //pftNegative
-      if (edge.windCnt != -1) return false;
-  }
-
-  switch(m_ClipType)
-  {
-    case ctIntersection:
-      switch(pft2)
-      {
-        case pftEvenOdd: 
-        case pftNonZero: 
-          return (edge.windCnt2 != 0);
-        case pftPositive: 
-          return (edge.windCnt2 > 0);
-        default: 
-          return (edge.windCnt2 < 0);
-      }
-    case ctUnion:
-      switch(pft2)
-      {
-        case pftEvenOdd: 
-        case pftNonZero: 
-          return (edge.windCnt2 == 0);
-        case pftPositive: 
-          return (edge.windCnt2 <= 0);
-        default: 
-          return (edge.windCnt2 >= 0);
-      }
-    case ctDifference:
-      if (edge.polyType == ptSubject)
-        switch(pft2)
-        {
-          case pftEvenOdd: 
-          case pftNonZero: 
-            return (edge.windCnt2 == 0);
-          case pftPositive: 
-            return (edge.windCnt2 <= 0);
-          default: 
-            return (edge.windCnt2 >= 0);
-        }
-      else
-        switch(pft2)
-        {
-          case pftEvenOdd: 
-          case pftNonZero: 
-            return (edge.windCnt2 != 0);
-          case pftPositive: 
-            return (edge.windCnt2 > 0);
-          default: 
-            return (edge.windCnt2 < 0);
-        }
-    default:
-      return true;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
-{
-  TEdge *e, *prevE;
-  if( NEAR_EQUAL(e2->dx, HORIZONTAL) || ( e1->dx > e2->dx ) )
-  {
-    AddOutPt( e1, pt );
-    e2->outIdx = e1->outIdx;
-    e1->side = esLeft;
-    e2->side = esRight;
-    e = e1;
-    if (e->prevInAEL == e2)
-      prevE = e2->prevInAEL; 
-    else
-      prevE = e->prevInAEL;
-  } else
-  {
-    AddOutPt( e2, pt );
-    e1->outIdx = e2->outIdx;
-    e1->side = esRight;
-    e2->side = esLeft;
-    e = e2;
-    if (e->prevInAEL == e1)
-        prevE = e1->prevInAEL;
-    else
-        prevE = e->prevInAEL;
-  }
-  if (prevE && prevE->outIdx >= 0 &&
-      (TopX(*prevE, pt.Y) == TopX(*e, pt.Y)) &&
-        SlopesEqual(*e, *prevE, m_UseFullRange))
-          AddJoin(e, prevE, -1, -1);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
-{
-  AddOutPt( e1, pt );
-  if( e1->outIdx == e2->outIdx )
-  {
-    e1->outIdx = -1;
-    e2->outIdx = -1;
-  }
-  else if (e1->outIdx < e2->outIdx) 
-    AppendPolygon(e1, e2); 
-  else 
-    AppendPolygon(e2, e1);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AddEdgeToSEL(TEdge *edge)
-{
-  //SEL pointers in PEdge are reused to build a list of horizontal edges.
-  //However, we don't need to worry about order with horizontal edge processing.
-  if( !m_SortedEdges )
-  {
-    m_SortedEdges = edge;
-    edge->prevInSEL = 0;
-    edge->nextInSEL = 0;
-  }
-  else
-  {
-    edge->nextInSEL = m_SortedEdges;
-    edge->prevInSEL = 0;
-    m_SortedEdges->prevInSEL = edge;
-    m_SortedEdges = edge;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::CopyAELToSEL()
-{
-  TEdge* e = m_ActiveEdges;
-  m_SortedEdges = e;
-  if (!m_ActiveEdges) return;
-  m_SortedEdges->prevInSEL = 0;
-  e = e->nextInAEL;
-  while ( e )
-  {
-    e->prevInSEL = e->prevInAEL;
-    e->prevInSEL->nextInSEL = e;
-    e->nextInSEL = 0;
-    e = e->nextInAEL;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx, int e2OutIdx)
-{
-  JoinRec* jr = new JoinRec;
-  if (e1OutIdx >= 0)
-    jr->poly1Idx = e1OutIdx; else
-    jr->poly1Idx = e1->outIdx;
-  jr->pt1a = IntPoint(e1->xcurr, e1->ycurr);
-  jr->pt1b = IntPoint(e1->xtop, e1->ytop);
-  if (e2OutIdx >= 0)
-    jr->poly2Idx = e2OutIdx; else
-    jr->poly2Idx = e2->outIdx;
-  jr->pt2a = IntPoint(e2->xcurr, e2->ycurr);
-  jr->pt2b = IntPoint(e2->xtop, e2->ytop);
-  m_Joins.push_back(jr);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::ClearJoins()
-{
-  for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
-    delete m_Joins[i];
-  m_Joins.resize(0);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AddHorzJoin(TEdge *e, int idx)
-{
-  HorzJoinRec* hj = new HorzJoinRec;
-  hj->edge = e;
-  hj->savedIdx = idx;
-  m_HorizJoins.push_back(hj);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::ClearHorzJoins()
-{
-  for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); i++)
-    delete m_HorizJoins[i];
-  m_HorizJoins.resize(0);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::InsertLocalMinimaIntoAEL( const long64 botY)
-{
-  while(  m_CurrentLM  && ( m_CurrentLM->Y == botY ) )
-  {
-    TEdge* lb = m_CurrentLM->leftBound;
-    TEdge* rb = m_CurrentLM->rightBound;
-
-    InsertEdgeIntoAEL( lb );
-    InsertScanbeam( lb->ytop );
-    InsertEdgeIntoAEL( rb );
-
-    if (IsEvenOddFillType(*lb))
-    {
-      lb->windDelta = 1;
-      rb->windDelta = 1;
-    }
-    else
-    {
-      rb->windDelta = -lb->windDelta;
-    }
-    SetWindingCount( *lb );
-    rb->windCnt = lb->windCnt;
-    rb->windCnt2 = lb->windCnt2;
-
-    if( NEAR_EQUAL(rb->dx, HORIZONTAL) )
-    {
-      //nb: only rightbounds can have a horizontal bottom edge
-      AddEdgeToSEL( rb );
-      InsertScanbeam( rb->nextInLML->ytop );
-    }
-    else
-      InsertScanbeam( rb->ytop );
-
-    if( IsContributing(*lb) )
-      AddLocalMinPoly( lb, rb, IntPoint(lb->xcurr, m_CurrentLM->Y) );
-
-    //if any output polygons share an edge, they'll need joining later ...
-    if (rb->outIdx >= 0)
-    {
-      if (NEAR_EQUAL(rb->dx, HORIZONTAL))
-      {
-        for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i)
-        {
-          IntPoint pt, pt2; //returned by GetOverlapSegment() but unused here.
-          HorzJoinRec* hj = m_HorizJoins[i];
-          //if horizontals rb and hj.edge overlap, flag for joining later ...
-          if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot),
-            IntPoint(hj->edge->xtop, hj->edge->ytop),
-            IntPoint(rb->xbot, rb->ybot),
-            IntPoint(rb->xtop, rb->ytop), pt, pt2))
-              AddJoin(hj->edge, rb, hj->savedIdx);
-        }
-      }
-    }
-
-    if( lb->nextInAEL != rb )
-    {
-      if (rb->outIdx >= 0 && rb->prevInAEL->outIdx >= 0 &&
-        SlopesEqual(*rb->prevInAEL, *rb, m_UseFullRange))
-          AddJoin(rb, rb->prevInAEL);
-
-      TEdge* e = lb->nextInAEL;
-      IntPoint pt = IntPoint(lb->xcurr, lb->ycurr);
-      while( e != rb )
-      {
-        if(!e) throw clipperException("InsertLocalMinimaIntoAEL: missing rightbound!");
-        //nb: For calculating winding counts etc, IntersectEdges() assumes
-        //that param1 will be to the right of param2 ABOVE the intersection ...
-        IntersectEdges( rb , e , pt , ipNone); //order important here
-        e = e->nextInAEL;
-      }
-    }
-    PopLocalMinima();
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DeleteFromAEL(TEdge *e)
-{
-  TEdge* AelPrev = e->prevInAEL;
-  TEdge* AelNext = e->nextInAEL;
-  if(  !AelPrev &&  !AelNext && (e != m_ActiveEdges) ) return; //already deleted
-  if( AelPrev ) AelPrev->nextInAEL = AelNext;
-  else m_ActiveEdges = AelNext;
-  if( AelNext ) AelNext->prevInAEL = AelPrev;
-  e->nextInAEL = 0;
-  e->prevInAEL = 0;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DeleteFromSEL(TEdge *e)
-{
-  TEdge* SelPrev = e->prevInSEL;
-  TEdge* SelNext = e->nextInSEL;
-  if( !SelPrev &&  !SelNext && (e != m_SortedEdges) ) return; //already deleted
-  if( SelPrev ) SelPrev->nextInSEL = SelNext;
-  else m_SortedEdges = SelNext;
-  if( SelNext ) SelNext->prevInSEL = SelPrev;
-  e->nextInSEL = 0;
-  e->prevInSEL = 0;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
-     const IntPoint &pt, IntersectProtects protects)
-{
-  //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before
-  //e2 in AEL except when e1 is being inserted at the intersection point ...
-  bool e1stops = !(ipLeft & protects) &&  !e1->nextInLML &&
-    e1->xtop == pt.X && e1->ytop == pt.Y;
-  bool e2stops = !(ipRight & protects) &&  !e2->nextInLML &&
-    e2->xtop == pt.X && e2->ytop == pt.Y;
-  bool e1Contributing = ( e1->outIdx >= 0 );
-  bool e2contributing = ( e2->outIdx >= 0 );
-
-  //update winding counts...
-  //assumes that e1 will be to the right of e2 ABOVE the intersection
-  if ( e1->polyType == e2->polyType )
-  {
-    if ( IsEvenOddFillType( *e1) )
-    {
-      int oldE1WindCnt = e1->windCnt;
-      e1->windCnt = e2->windCnt;
-      e2->windCnt = oldE1WindCnt;
-    } else
-    {
-      if (e1->windCnt + e2->windDelta == 0 ) e1->windCnt = -e1->windCnt;
-      else e1->windCnt += e2->windDelta;
-      if ( e2->windCnt - e1->windDelta == 0 ) e2->windCnt = -e2->windCnt;
-      else e2->windCnt -= e1->windDelta;
-    }
-  } else
-  {
-    if (!IsEvenOddFillType(*e2)) e1->windCnt2 += e2->windDelta;
-    else e1->windCnt2 = ( e1->windCnt2 == 0 ) ? 1 : 0;
-    if (!IsEvenOddFillType(*e1)) e2->windCnt2 -= e1->windDelta;
-    else e2->windCnt2 = ( e2->windCnt2 == 0 ) ? 1 : 0;
-  }
-
-  PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
-  if (e1->polyType == ptSubject)
-  {
-    e1FillType = m_SubjFillType;
-    e1FillType2 = m_ClipFillType;
-  } else
-  {
-    e1FillType = m_ClipFillType;
-    e1FillType2 = m_SubjFillType;
-  }
-  if (e2->polyType == ptSubject)
-  {
-    e2FillType = m_SubjFillType;
-    e2FillType2 = m_ClipFillType;
-  } else
-  {
-    e2FillType = m_ClipFillType;
-    e2FillType2 = m_SubjFillType;
-  }
-
-  long64 e1Wc, e2Wc;
-  switch (e1FillType)
-  {
-    case pftPositive: e1Wc = e1->windCnt; break;
-    case pftNegative: e1Wc = -e1->windCnt; break;
-    default: e1Wc = Abs(e1->windCnt);
-  }
-  switch(e2FillType)
-  {
-    case pftPositive: e2Wc = e2->windCnt; break;
-    case pftNegative: e2Wc = -e2->windCnt; break;
-    default: e2Wc = Abs(e2->windCnt);
-  }
-
-  if ( e1Contributing && e2contributing )
-  {
-    if ( e1stops || e2stops || 
-      (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
-      (e1->polyType != e2->polyType && m_ClipType != ctXor) )
-        AddLocalMaxPoly(e1, e2, pt); 
-    else
-        DoBothEdges( e1, e2, pt );
-  }
-  else if ( e1Contributing )
-  {
-    if ((e2Wc == 0 || e2Wc == 1) && 
-      (m_ClipType != ctIntersection || 
-      e2->polyType == ptSubject || (e2->windCnt2 != 0))) 
-        DoEdge1(e1, e2, pt);
-  }
-  else if ( e2contributing )
-  {
-    if ((e1Wc == 0 || e1Wc == 1) && 
-      (m_ClipType != ctIntersection || 
-      e1->polyType == ptSubject || (e1->windCnt2 != 0))) 
-        DoEdge2(e1, e2, pt);
-  } 
-  else if ( (e1Wc == 0 || e1Wc == 1) && 
-    (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
-  {
-    //neither edge is currently contributing ...
-
-    long64 e1Wc2, e2Wc2;
-    switch (e1FillType2)
-    {
-      case pftPositive: e1Wc2 = e1->windCnt2; break;
-      case pftNegative : e1Wc2 = -e1->windCnt2; break;
-      default: e1Wc2 = Abs(e1->windCnt2);
-    }
-    switch (e2FillType2)
-    {
-      case pftPositive: e2Wc2 = e2->windCnt2; break;
-      case pftNegative: e2Wc2 = -e2->windCnt2; break;
-      default: e2Wc2 = Abs(e2->windCnt2);
-    }
-
-    if (e1->polyType != e2->polyType)
-        AddLocalMinPoly(e1, e2, pt);
-    else if (e1Wc == 1 && e2Wc == 1)
-      switch( m_ClipType ) {
-        case ctIntersection:
-          if (e1Wc2 > 0 && e2Wc2 > 0)
-            AddLocalMinPoly(e1, e2, pt);
-          break;
-        case ctUnion:
-          if ( e1Wc2 <= 0 && e2Wc2 <= 0 )
-            AddLocalMinPoly(e1, e2, pt);
-          break;
-        case ctDifference:
-          if (((e1->polyType == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
-              ((e1->polyType == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
-                AddLocalMinPoly(e1, e2, pt);
-          break;
-        case ctXor:
-          AddLocalMinPoly(e1, e2, pt);
-      }
-    else
-      SwapSides( *e1, *e2 );
-  }
-
-  if(  (e1stops != e2stops) &&
-    ( (e1stops && (e1->outIdx >= 0)) || (e2stops && (e2->outIdx >= 0)) ) )
-  {
-    SwapSides( *e1, *e2 );
-    SwapPolyIndexes( *e1, *e2 );
-  }
-
-  //finally, delete any non-contributing maxima edges  ...
-  if( e1stops ) DeleteFromAEL( e1 );
-  if( e2stops ) DeleteFromAEL( e2 );
-}
-//------------------------------------------------------------------------------
-
-void Clipper::SetHoleState(TEdge *e, OutRec *outRec)
-{
-  bool isHole = false;
-  TEdge *e2 = e->prevInAEL;
-  while (e2)
-  {
-    if (e2->outIdx >= 0)
-    {
-      isHole = !isHole;
-      if (! outRec->FirstLeft)
-        outRec->FirstLeft = m_PolyOuts[e2->outIdx];
-    }
-    e2 = e2->prevInAEL;
-  }
-  if (isHole) outRec->isHole = true;
-}
-//------------------------------------------------------------------------------
-
-OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
-{
-  //work out which polygon fragment has the correct hole state ...
-  OutPt *outPt1 = outRec1->bottomPt;
-  OutPt *outPt2 = outRec2->bottomPt;
-  if (outPt1->pt.Y > outPt2->pt.Y) return outRec1;
-  else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2;
-  else if (outPt1->pt.X < outPt2->pt.X) return outRec1;
-  else if (outPt1->pt.X > outPt2->pt.X) return outRec2;
-  else if (outPt1->next == outPt1) return outRec2;
-  else if (outPt2->next == outPt2) return outRec1;
-  else if (FirstIsBottomPt(outPt1, outPt2)) return outRec1;
-  else return outRec2;
-}
-//------------------------------------------------------------------------------
-
-bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
-{
-  do
-  {
-    outRec1 = outRec1->FirstLeft;
-    if (outRec1 == outRec2) return true;
-  } while (outRec1);
-  return false;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
-{
-  //get the start and ends of both output polygons ...
-  OutRec *outRec1 = m_PolyOuts[e1->outIdx];
-  OutRec *outRec2 = m_PolyOuts[e2->outIdx];
-
-  OutRec *holeStateRec;
-  if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
-  else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
-  else holeStateRec = GetLowermostRec(outRec1, outRec2);
-
-  OutPt* p1_lft = outRec1->pts;
-  OutPt* p1_rt = p1_lft->prev;
-  OutPt* p2_lft = outRec2->pts;
-  OutPt* p2_rt = p2_lft->prev;
-
-  EdgeSide side;
-  //join e2 poly onto e1 poly and delete pointers to e2 ...
-  if(  e1->side == esLeft )
-  {
-    if(  e2->side == esLeft )
-    {
-      //z y x a b c
-      ReversePolyPtLinks(*p2_lft);
-      p2_lft->next = p1_lft;
-      p1_lft->prev = p2_lft;
-      p1_rt->next = p2_rt;
-      p2_rt->prev = p1_rt;
-      outRec1->pts = p2_rt;
-    } else
-    {
-      //x y z a b c
-      p2_rt->next = p1_lft;
-      p1_lft->prev = p2_rt;
-      p2_lft->prev = p1_rt;
-      p1_rt->next = p2_lft;
-      outRec1->pts = p2_lft;
-    }
-    side = esLeft;
-  } else
-  {
-    if(  e2->side == esRight )
-    {
-      //a b c z y x
-      ReversePolyPtLinks( *p2_lft );
-      p1_rt->next = p2_rt;
-      p2_rt->prev = p1_rt;
-      p2_lft->next = p1_lft;
-      p1_lft->prev = p2_lft;
-    } else
-    {
-      //a b c x y z
-      p1_rt->next = p2_lft;
-      p2_lft->prev = p1_rt;
-      p1_lft->prev = p2_rt;
-      p2_rt->next = p1_lft;
-    }
-    side = esRight;
-  }
-
-  if (holeStateRec == outRec2)
-  {
-    outRec1->bottomPt = outRec2->bottomPt;
-    outRec1->bottomPt->idx = outRec1->idx;
-    if (outRec2->FirstLeft != outRec1)
-      outRec1->FirstLeft = outRec2->FirstLeft;
-    outRec1->isHole = outRec2->isHole;
-  }
-  outRec2->pts = 0;
-  outRec2->bottomPt = 0;
-  outRec2->AppendLink = outRec1;
-  int OKIdx = e1->outIdx;
-  int ObsoleteIdx = e2->outIdx;
-
-  e1->outIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly
-  e2->outIdx = -1;
-
-  TEdge* e = m_ActiveEdges;
-  while( e )
-  {
-    if( e->outIdx == ObsoleteIdx )
-    {
-      e->outIdx = OKIdx;
-      e->side = side;
-      break;
-    }
-    e = e->nextInAEL;
-  }
-
-  for (JoinList::size_type i = 0; i < m_Joins.size(); ++i)
-  {
-      if (m_Joins[i]->poly1Idx == ObsoleteIdx) m_Joins[i]->poly1Idx = OKIdx;
-      if (m_Joins[i]->poly2Idx == ObsoleteIdx) m_Joins[i]->poly2Idx = OKIdx;
-  }
-
-  for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i)
-  {
-      if (m_HorizJoins[i]->savedIdx == ObsoleteIdx)
-        m_HorizJoins[i]->savedIdx = OKIdx;
-  }
-
-}
-//------------------------------------------------------------------------------
-
-OutRec* Clipper::CreateOutRec()
-{
-  OutRec* result = new OutRec;
-  result->isHole = false;
-  result->FirstLeft = 0;
-  result->AppendLink = 0;
-  result->pts = 0;
-  result->bottomPt = 0;
-  result->sides = esNeither;
-  result->bottomFlag = 0;
-
-  return result;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeBottomPt(OutRec &outRec)
-{
-  OutPt* next = outRec.bottomPt->next;
-  OutPt* prev = outRec.bottomPt->prev;
-  if (outRec.pts == outRec.bottomPt) outRec.pts = next;
-  delete outRec.bottomPt;
-  next->prev = prev;
-  prev->next = next;
-  outRec.bottomPt = next;
-  FixupOutPolygon(outRec);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
-{
-  bool ToFront = (e->side == esLeft);
-  if(  e->outIdx < 0 )
-  {
-    OutRec *outRec = CreateOutRec();
-    m_PolyOuts.push_back(outRec);
-    outRec->idx = (int)m_PolyOuts.size()-1;
-    e->outIdx = outRec->idx;
-    OutPt* op = new OutPt;
-    outRec->pts = op;
-    outRec->bottomPt = op;
-    op->pt = pt;
-    op->idx = outRec->idx;
-    op->next = op;
-    op->prev = op;
-    SetHoleState(e, outRec);
-  } else
-  {
-    OutRec *outRec = m_PolyOuts[e->outIdx];
-    OutPt* op = outRec->pts;
-    if ((ToFront && PointsEqual(pt, op->pt)) ||
-      (!ToFront && PointsEqual(pt, op->prev->pt))) return;
-
-    if ((e->side | outRec->sides) != outRec->sides)
-    {
-      //check for 'rounding' artefacts ...
-      if (outRec->sides == esNeither && pt.Y == op->pt.Y)
-      {
-        if (ToFront)
-        {
-          if (pt.X == op->pt.X +1) return;    //ie wrong side of bottomPt
-        }
-        else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt
-      }
-
-      outRec->sides = (EdgeSide)(outRec->sides | e->side);
-      if (outRec->sides == esBoth)
-      {
-        //A vertex from each side has now been added.
-        //Vertices of one side of an output polygon are quite commonly close to
-        //or even 'touching' edges of the other side of the output polygon.
-        //Very occasionally vertices from one side can 'cross' an edge on the
-        //the other side. The distance 'crossed' is always less that a unit
-        //and is purely an artefact of coordinate rounding. Nevertheless, this
-        //results in very tiny self-intersections. Because of the way
-        //orientation is calculated, even tiny self-intersections can cause
-        //the Orientation function to return the wrong result. Therefore, it's
-        //important to ensure that any self-intersections close to BottomPt are
-        //detected and removed before orientation is assigned.
-
-        OutPt *opBot, *op2;
-        if (ToFront)
-        {
-          opBot = outRec->pts;
-          op2 = opBot->next; //op2 == right side
-          if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y &&
-            ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) <
-            (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y)))
-               outRec->bottomFlag = opBot;
-        } else
-        {
-          opBot = outRec->pts->prev;
-          op2 = opBot->prev; //op2 == left side
-          if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y &&
-            ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) >
-            (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y)))
-               outRec->bottomFlag = opBot;
-        }
-      }
-    }
-
-    OutPt* op2 = new OutPt;
-    op2->pt = pt;
-    op2->idx = outRec->idx;
-    if (op2->pt.Y == outRec->bottomPt->pt.Y &&
-      op2->pt.X < outRec->bottomPt->pt.X)
-        outRec->bottomPt = op2;
-    op2->next = op;
-    op2->prev = op->prev;
-    op2->prev->next = op2;
-    op->prev = op2;
-    if (ToFront) outRec->pts = op2;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::ProcessHorizontals()
-{
-  TEdge* horzEdge = m_SortedEdges;
-  while( horzEdge )
-  {
-    DeleteFromSEL( horzEdge );
-    ProcessHorizontal( horzEdge );
-    horzEdge = m_SortedEdges;
-  }
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::IsTopHorz(const long64 XPos)
-{
-  TEdge* e = m_SortedEdges;
-  while( e )
-  {
-    if(  ( XPos >= std::min(e->xcurr, e->xtop) ) &&
-      ( XPos <= std::max(e->xcurr, e->xtop) ) ) return false;
-    e = e->nextInSEL;
-  }
-  return true;
-}
-//------------------------------------------------------------------------------
-
-bool IsMinima(TEdge *e)
-{
-  return e  && (e->prev->nextInLML != e) && (e->next->nextInLML != e);
-}
-//------------------------------------------------------------------------------
-
-bool IsMaxima(TEdge *e, const long64 Y)
-{
-  return e && e->ytop == Y && !e->nextInLML;
-}
-//------------------------------------------------------------------------------
-
-bool IsIntermediate(TEdge *e, const long64 Y)
-{
-  return e->ytop == Y && e->nextInLML;
-}
-//------------------------------------------------------------------------------
-
-TEdge *GetMaximaPair(TEdge *e)
-{
-  if( !IsMaxima(e->next, e->ytop) || e->next->xtop != e->xtop )
-    return e->prev; else
-    return e->next;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::SwapPositionsInAEL(TEdge *edge1, TEdge *edge2)
-{
-  if(  !edge1->nextInAEL &&  !edge1->prevInAEL ) return;
-  if(  !edge2->nextInAEL &&  !edge2->prevInAEL ) return;
-
-  if(  edge1->nextInAEL == edge2 )
-  {
-    TEdge* next = edge2->nextInAEL;
-    if( next ) next->prevInAEL = edge1;
-    TEdge* prev = edge1->prevInAEL;
-    if( prev ) prev->nextInAEL = edge2;
-    edge2->prevInAEL = prev;
-    edge2->nextInAEL = edge1;
-    edge1->prevInAEL = edge2;
-    edge1->nextInAEL = next;
-  }
-  else if(  edge2->nextInAEL == edge1 )
-  {
-    TEdge* next = edge1->nextInAEL;
-    if( next ) next->prevInAEL = edge2;
-    TEdge* prev = edge2->prevInAEL;
-    if( prev ) prev->nextInAEL = edge1;
-    edge1->prevInAEL = prev;
-    edge1->nextInAEL = edge2;
-    edge2->prevInAEL = edge1;
-    edge2->nextInAEL = next;
-  }
-  else
-  {
-    TEdge* next = edge1->nextInAEL;
-    TEdge* prev = edge1->prevInAEL;
-    edge1->nextInAEL = edge2->nextInAEL;
-    if( edge1->nextInAEL ) edge1->nextInAEL->prevInAEL = edge1;
-    edge1->prevInAEL = edge2->prevInAEL;
-    if( edge1->prevInAEL ) edge1->prevInAEL->nextInAEL = edge1;
-    edge2->nextInAEL = next;
-    if( edge2->nextInAEL ) edge2->nextInAEL->prevInAEL = edge2;
-    edge2->prevInAEL = prev;
-    if( edge2->prevInAEL ) edge2->prevInAEL->nextInAEL = edge2;
-  }
-
-  if( !edge1->prevInAEL ) m_ActiveEdges = edge1;
-  else if( !edge2->prevInAEL ) m_ActiveEdges = edge2;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::SwapPositionsInSEL(TEdge *edge1, TEdge *edge2)
-{
-  if(  !( edge1->nextInSEL ) &&  !( edge1->prevInSEL ) ) return;
-  if(  !( edge2->nextInSEL ) &&  !( edge2->prevInSEL ) ) return;
-
-  if(  edge1->nextInSEL == edge2 )
-  {
-    TEdge* next = edge2->nextInSEL;
-    if( next ) next->prevInSEL = edge1;
-    TEdge* prev = edge1->prevInSEL;
-    if( prev ) prev->nextInSEL = edge2;
-    edge2->prevInSEL = prev;
-    edge2->nextInSEL = edge1;
-    edge1->prevInSEL = edge2;
-    edge1->nextInSEL = next;
-  }
-  else if(  edge2->nextInSEL == edge1 )
-  {
-    TEdge* next = edge1->nextInSEL;
-    if( next ) next->prevInSEL = edge2;
-    TEdge* prev = edge2->prevInSEL;
-    if( prev ) prev->nextInSEL = edge1;
-    edge1->prevInSEL = prev;
-    edge1->nextInSEL = edge2;
-    edge2->prevInSEL = edge1;
-    edge2->nextInSEL = next;
-  }
-  else
-  {
-    TEdge* next = edge1->nextInSEL;
-    TEdge* prev = edge1->prevInSEL;
-    edge1->nextInSEL = edge2->nextInSEL;
-    if( edge1->nextInSEL ) edge1->nextInSEL->prevInSEL = edge1;
-    edge1->prevInSEL = edge2->prevInSEL;
-    if( edge1->prevInSEL ) edge1->prevInSEL->nextInSEL = edge1;
-    edge2->nextInSEL = next;
-    if( edge2->nextInSEL ) edge2->nextInSEL->prevInSEL = edge2;
-    edge2->prevInSEL = prev;
-    if( edge2->prevInSEL ) edge2->prevInSEL->nextInSEL = edge2;
-  }
-
-  if( !edge1->prevInSEL ) m_SortedEdges = edge1;
-  else if( !edge2->prevInSEL ) m_SortedEdges = edge2;
-}
-//------------------------------------------------------------------------------
-
-TEdge* GetNextInAEL(TEdge *e, Direction dir)
-{
-  return dir == dLeftToRight ? e->nextInAEL : e->prevInAEL;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::ProcessHorizontal(TEdge *horzEdge)
-{
-  Direction dir;
-  long64 horzLeft, horzRight;
-
-  if( horzEdge->xcurr < horzEdge->xtop )
-  {
-    horzLeft = horzEdge->xcurr;
-    horzRight = horzEdge->xtop;
-    dir = dLeftToRight;
-  } else
-  {
-    horzLeft = horzEdge->xtop;
-    horzRight = horzEdge->xcurr;
-    dir = dRightToLeft;
-  }
-
-  TEdge* eMaxPair;
-  if( horzEdge->nextInLML ) eMaxPair = 0;
-  else eMaxPair = GetMaximaPair(horzEdge);
-
-  TEdge* e = GetNextInAEL( horzEdge , dir );
-  while( e )
-  {
-    TEdge* eNext = GetNextInAEL( e, dir );
-
-    if (eMaxPair ||
-      ((dir == dLeftToRight) && (e->xcurr <= horzRight)) ||
-      ((dir == dRightToLeft) && (e->xcurr >= horzLeft)))
-    {
-      //ok, so far it looks like we're still in range of the horizontal edge
-      if ( e->xcurr == horzEdge->xtop && !eMaxPair )
-      {
-        if (SlopesEqual(*e, *horzEdge->nextInLML, m_UseFullRange))
-        {
-          //if output polygons share an edge, they'll need joining later ...
-          if (horzEdge->outIdx >= 0 && e->outIdx >= 0)
-            AddJoin(horzEdge->nextInLML, e, horzEdge->outIdx);
-          break; //we've reached the end of the horizontal line
-        }
-        else if (e->dx < horzEdge->nextInLML->dx)
-        //we really have got to the end of the intermediate horz edge so quit.
-        //nb: More -ve slopes follow more +ve slopes ABOVE the horizontal.
-          break;
-      }
-
-      if( e == eMaxPair )
-      {
-        //horzEdge is evidently a maxima horizontal and we've arrived at its end.
-        if (dir == dLeftToRight)
-          IntersectEdges(horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), ipNone);
-        else
-          IntersectEdges(e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), ipNone);
-        if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error");
-        return;
-      }
-      else if( NEAR_EQUAL(e->dx, HORIZONTAL) &&  !IsMinima(e) && !(e->xcurr > e->xtop) )
-      {
-        //An overlapping horizontal edge. Overlapping horizontal edges are
-        //processed as if layered with the current horizontal edge (horizEdge)
-        //being infinitesimally lower that the next (e). Therfore, we
-        //intersect with e only if e.xcurr is within the bounds of horzEdge ...
-        if( dir == dLeftToRight )
-          IntersectEdges( horzEdge , e, IntPoint(e->xcurr, horzEdge->ycurr),
-            (IsTopHorz( e->xcurr ))? ipLeft : ipBoth );
-        else
-          IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr),
-            (IsTopHorz( e->xcurr ))? ipRight : ipBoth );
-      }
-      else if( dir == dLeftToRight )
-      {
-        IntersectEdges( horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr),
-          (IsTopHorz( e->xcurr ))? ipLeft : ipBoth );
-      }
-      else
-      {
-        IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr),
-          (IsTopHorz( e->xcurr ))? ipRight : ipBoth );
-      }
-      SwapPositionsInAEL( horzEdge, e );
-    }
-    else if( (dir == dLeftToRight && e->xcurr > horzRight  && m_SortedEdges) ||
-     (dir == dRightToLeft && e->xcurr < horzLeft && m_SortedEdges) ) break;
-    e = eNext;
-  } //end while
-
-  if( horzEdge->nextInLML )
-  {
-    if( horzEdge->outIdx >= 0 )
-      AddOutPt( horzEdge, IntPoint(horzEdge->xtop, horzEdge->ytop));
-    UpdateEdgeIntoAEL( horzEdge );
-  }
-  else
-  {
-    if ( horzEdge->outIdx >= 0 )
-      IntersectEdges( horzEdge, eMaxPair,
-      IntPoint(horzEdge->xtop, horzEdge->ycurr), ipBoth);
-    if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error");
-    DeleteFromAEL(eMaxPair);
-    DeleteFromAEL(horzEdge);
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
-{
-  if( !e->nextInLML ) throw
-    clipperException("UpdateEdgeIntoAEL: invalid call");
-  TEdge* AelPrev = e->prevInAEL;
-  TEdge* AelNext = e->nextInAEL;
-  e->nextInLML->outIdx = e->outIdx;
-  if( AelPrev ) AelPrev->nextInAEL = e->nextInLML;
-  else m_ActiveEdges = e->nextInLML;
-  if( AelNext ) AelNext->prevInAEL = e->nextInLML;
-  e->nextInLML->side = e->side;
-  e->nextInLML->windDelta = e->windDelta;
-  e->nextInLML->windCnt = e->windCnt;
-  e->nextInLML->windCnt2 = e->windCnt2;
-  e = e->nextInLML;
-  e->prevInAEL = AelPrev;
-  e->nextInAEL = AelNext;
-  if( !NEAR_EQUAL(e->dx, HORIZONTAL) ) InsertScanbeam( e->ytop );
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::ProcessIntersections(const long64 botY, const long64 topY)
-{
-  if( !m_ActiveEdges ) return true;
-  try {
-    BuildIntersectList(botY, topY);
-    if ( !m_IntersectNodes) return true;
-    if ( FixupIntersections() ) ProcessIntersectList();
-    else return false;
-  }
-  catch(...) {
-    m_SortedEdges = 0;
-    DisposeIntersectNodes();
-    throw clipperException("ProcessIntersections error");
-  }
-  return true;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeIntersectNodes()
-{
-  while ( m_IntersectNodes )
-  {
-    IntersectNode* iNode = m_IntersectNodes->next;
-    delete m_IntersectNodes;
-    m_IntersectNodes = iNode;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
-{
-  if ( !m_ActiveEdges ) return;
-
-  //prepare for sorting ...
-  TEdge* e = m_ActiveEdges;
-  e->tmpX = TopX( *e, topY );
-  m_SortedEdges = e;
-  m_SortedEdges->prevInSEL = 0;
-  e = e->nextInAEL;
-  while( e )
-  {
-    e->prevInSEL = e->prevInAEL;
-    e->prevInSEL->nextInSEL = e;
-    e->nextInSEL = 0;
-    e->tmpX = TopX( *e, topY );
-    e = e->nextInAEL;
-  }
-
-  //bubblesort ...
-  bool isModified = true;
-  while( isModified && m_SortedEdges )
-  {
-    isModified = false;
-    e = m_SortedEdges;
-    while( e->nextInSEL )
-    {
-      TEdge *eNext = e->nextInSEL;
-      IntPoint pt;
-      if(e->tmpX > eNext->tmpX &&
-        IntersectPoint(*e, *eNext, pt, m_UseFullRange))
-      {
-        if (pt.Y > botY)
-        {
-            pt.Y = botY;
-            pt.X = TopX(*e, pt.Y);
-        }
-        AddIntersectNode( e, eNext, pt );
-        SwapPositionsInSEL(e, eNext);
-        isModified = true;
-      }
-      else
-        e = eNext;
-    }
-    if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0;
-    else break;
-  }
-  m_SortedEdges = 0;
-}
-//------------------------------------------------------------------------------
-
-bool ProcessParam1BeforeParam2(IntersectNode &node1, IntersectNode &node2)
-{
-  bool result;
-  if (node1.pt.Y == node2.pt.Y)
-  {
-    if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1)
-    {
-      result = node2.pt.X > node1.pt.X;
-      return node2.edge1->dx > 0 ? !result : result;
-    }
-    else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2)
-    {
-      result = node2.pt.X > node1.pt.X;
-      return node2.edge2->dx > 0 ? !result : result;
-    }
-    else return node2.pt.X > node1.pt.X;
-  }
-  else return node1.pt.Y > node2.pt.Y;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
-{
-  IntersectNode* newNode = new IntersectNode;
-  newNode->edge1 = e1;
-  newNode->edge2 = e2;
-  newNode->pt = pt;
-  newNode->next = 0;
-  if( !m_IntersectNodes ) m_IntersectNodes = newNode;
-  else if(  ProcessParam1BeforeParam2(*newNode, *m_IntersectNodes) )
-  {
-    newNode->next = m_IntersectNodes;
-    m_IntersectNodes = newNode;
-  }
-  else
-  {
-    IntersectNode* iNode = m_IntersectNodes;
-    while( iNode->next  && ProcessParam1BeforeParam2(*iNode->next, *newNode) )
-        iNode = iNode->next;
-    newNode->next = iNode->next;
-    iNode->next = newNode;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::ProcessIntersectList()
-{
-  while( m_IntersectNodes )
-  {
-    IntersectNode* iNode = m_IntersectNodes->next;
-    {
-      IntersectEdges( m_IntersectNodes->edge1 ,
-        m_IntersectNodes->edge2 , m_IntersectNodes->pt, ipBoth );
-      SwapPositionsInAEL( m_IntersectNodes->edge1 , m_IntersectNodes->edge2 );
-    }
-    delete m_IntersectNodes;
-    m_IntersectNodes = iNode;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DoMaxima(TEdge *e, long64 topY)
-{
-  TEdge* eMaxPair = GetMaximaPair(e);
-  long64 X = e->xtop;
-  TEdge* eNext = e->nextInAEL;
-  while( eNext != eMaxPair )
-  {
-    if (!eNext) throw clipperException("DoMaxima error");
-    IntersectEdges( e, eNext, IntPoint(X, topY), ipBoth );
-    eNext = eNext->nextInAEL;
-  }
-  if( e->outIdx < 0 && eMaxPair->outIdx < 0 )
-  {
-    DeleteFromAEL( e );
-    DeleteFromAEL( eMaxPair );
-  }
-  else if( e->outIdx >= 0 && eMaxPair->outIdx >= 0 )
-  {
-    IntersectEdges( e, eMaxPair, IntPoint(X, topY), ipNone );
-  }
-  else throw clipperException("DoMaxima error");
-}
-//------------------------------------------------------------------------------
-
-void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY)
-{
-  TEdge* e = m_ActiveEdges;
-  while( e )
-  {
-    //1. process maxima, treating them as if they're 'bent' horizontal edges,
-    //   but exclude maxima with horizontal edges. nb: e can't be a horizontal.
-    if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) )
-    {
-      //'e' might be removed from AEL, as may any following edges so ...
-      TEdge* ePrior = e->prevInAEL;
-      DoMaxima(e, topY);
-      if( !ePrior ) e = m_ActiveEdges;
-      else e = ePrior->nextInAEL;
-    }
-    else
-    {
-      //2. promote horizontal edges, otherwise update xcurr and ycurr ...
-      if(  IsIntermediate(e, topY) && NEAR_EQUAL(e->nextInLML->dx, HORIZONTAL) )
-      {
-        if (e->outIdx >= 0)
-        {
-          AddOutPt(e, IntPoint(e->xtop, e->ytop));
-
-          for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i)
-          {
-            IntPoint pt, pt2;
-            HorzJoinRec* hj = m_HorizJoins[i];
-            if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot),
-              IntPoint(hj->edge->xtop, hj->edge->ytop),
-              IntPoint(e->nextInLML->xbot, e->nextInLML->ybot),
-              IntPoint(e->nextInLML->xtop, e->nextInLML->ytop), pt, pt2))
-                AddJoin(hj->edge, e->nextInLML, hj->savedIdx, e->outIdx);
-          }
-
-          AddHorzJoin(e->nextInLML, e->outIdx);
-        }
-        UpdateEdgeIntoAEL(e);
-        AddEdgeToSEL(e);
-      } else
-      {
-        //this just simplifies horizontal processing ...
-        e->xcurr = TopX( *e, topY );
-        e->ycurr = topY;
-      }
-      e = e->nextInAEL;
-    }
-  }
-
-  //3. Process horizontals at the top of the scanbeam ...
-  ProcessHorizontals();
-
-  //4. Promote intermediate vertices ...
-  e = m_ActiveEdges;
-  while( e )
-  {
-    if( IsIntermediate( e, topY ) )
-    {
-      if( e->outIdx >= 0 ) AddOutPt(e, IntPoint(e->xtop,e->ytop));
-      UpdateEdgeIntoAEL(e);
-
-      //if output polygons share an edge, they'll need joining later ...
-      if (e->outIdx >= 0 && e->prevInAEL && e->prevInAEL->outIdx >= 0 &&
-        e->prevInAEL->xcurr == e->xbot && e->prevInAEL->ycurr == e->ybot &&
-        SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop),
-          IntPoint(e->xbot,e->ybot),
-          IntPoint(e->prevInAEL->xtop, e->prevInAEL->ytop), m_UseFullRange))
-      {
-        AddOutPt(e->prevInAEL, IntPoint(e->xbot, e->ybot));
-        AddJoin(e, e->prevInAEL);
-      }
-      else if (e->outIdx >= 0 && e->nextInAEL && e->nextInAEL->outIdx >= 0 &&
-        e->nextInAEL->ycurr > e->nextInAEL->ytop &&
-        e->nextInAEL->ycurr <= e->nextInAEL->ybot &&
-        e->nextInAEL->xcurr == e->xbot && e->nextInAEL->ycurr == e->ybot &&
-        SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop),
-          IntPoint(e->xbot,e->ybot),
-          IntPoint(e->nextInAEL->xtop, e->nextInAEL->ytop), m_UseFullRange))
-      {
-        AddOutPt(e->nextInAEL, IntPoint(e->xbot, e->ybot));
-        AddJoin(e, e->nextInAEL);
-      }
-    }
-    e = e->nextInAEL;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::FixupOutPolygon(OutRec &outRec)
-{
-  //FixupOutPolygon() - removes duplicate points and simplifies consecutive
-  //parallel edges by removing the middle vertex.
-  OutPt *lastOK = 0;
-  outRec.pts = outRec.bottomPt;
-  OutPt *pp = outRec.bottomPt;
-
-  for (;;)
-  {
-    if (pp->prev == pp || pp->prev == pp->next )
-    {
-      DisposeOutPts(pp);
-      outRec.pts = 0;
-      outRec.bottomPt = 0;
-      return;
-    }
-    //test for duplicate points and for same slope (cross-product) ...
-    if ( PointsEqual(pp->pt, pp->next->pt) ||
-      SlopesEqual(pp->prev->pt, pp->pt, pp->next->pt, m_UseFullRange) )
-    {
-      lastOK = 0;
-      OutPt *tmp = pp;
-      if (pp == outRec.bottomPt)
-        outRec.bottomPt = 0; //flags need for updating
-      pp->prev->next = pp->next;
-      pp->next->prev = pp->prev;
-      pp = pp->prev;
-      delete tmp;
-    }
-    else if (pp == lastOK) break;
-    else
-    {
-      if (!lastOK) lastOK = pp;
-      pp = pp->next;
-    }
-  }
-  if (!outRec.bottomPt) {
-    outRec.bottomPt = GetBottomPt(pp);
-    outRec.bottomPt->idx = outRec.idx;
-    outRec.pts = outRec.bottomPt;
-  }
-}
-//------------------------------------------------------------------------------
-
-void Clipper::BuildResult(Polygons &polys)
-{
-  int k = 0;
-  polys.resize(m_PolyOuts.size());
-  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
-  {
-    if (m_PolyOuts[i]->pts)
-    {
-      Polygon* pg = &polys[k];
-      pg->clear();
-      OutPt* p = m_PolyOuts[i]->pts;
-      do
-      {
-        pg->push_back(p->pt);
-        p = p->next;
-      } while (p != m_PolyOuts[i]->pts);
-      //make sure each polygon has at least 3 vertices ...
-      if (pg->size() < 3) pg->clear(); else k++;
-    }
-  }
-  polys.resize(k);
-}
-//------------------------------------------------------------------------------
-
-void Clipper::BuildResultEx(ExPolygons &polys)
-{
-  PolyOutList::size_type i = 0;
-  int k = 0;
-  polys.resize(0);
-  polys.reserve(m_PolyOuts.size());
-  while (i < m_PolyOuts.size() && m_PolyOuts[i]->pts)
-  {
-    ExPolygon epg;
-    OutPt* p = m_PolyOuts[i]->pts;
-    do {
-      epg.outer.push_back(p->pt);
-      p = p->next;
-    } while (p != m_PolyOuts[i]->pts);
-    i++;
-    //make sure polygons have at least 3 vertices ...
-    if (epg.outer.size() < 3) continue;
-    while (i < m_PolyOuts.size()
-      && m_PolyOuts[i]->pts && m_PolyOuts[i]->isHole)
-    {
-      Polygon pg;
-      p = m_PolyOuts[i]->pts;
-      do {
-        pg.push_back(p->pt);
-        p = p->next;
-      } while (p != m_PolyOuts[i]->pts);
-      epg.holes.push_back(pg);
-      i++;
-    }
-    polys.push_back(epg);
-    k++;
-  }
-  polys.resize(k);
-}
-//------------------------------------------------------------------------------
-
-void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2)
-{
-  TEdge *e1 = int1.edge1;
-  TEdge *e2 = int1.edge2;
-  IntPoint p = int1.pt;
-
-  int1.edge1 = int2.edge1;
-  int1.edge2 = int2.edge2;
-  int1.pt = int2.pt;
-
-  int2.edge1 = e1;
-  int2.edge2 = e2;
-  int2.pt = p;
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::FixupIntersections()
-{
-  if ( !m_IntersectNodes->next ) return true;
-
-  CopyAELToSEL();
-  IntersectNode *int1 = m_IntersectNodes;
-  IntersectNode *int2 = m_IntersectNodes->next;
-  while (int2)
-  {
-    TEdge *e1 = int1->edge1;
-    TEdge *e2;
-    if (e1->prevInSEL == int1->edge2) e2 = e1->prevInSEL;
-    else if (e1->nextInSEL == int1->edge2) e2 = e1->nextInSEL;
-    else
-    {
-      //The current intersection is out of order, so try and swap it with
-      //a subsequent intersection ...
-      while (int2)
-      {
-        if (int2->edge1->nextInSEL == int2->edge2 ||
-          int2->edge1->prevInSEL == int2->edge2) break;
-        else int2 = int2->next;
-      }
-      if ( !int2 ) return false; //oops!!!
-
-      //found an intersect node that can be swapped ...
-      SwapIntersectNodes(*int1, *int2);
-      e1 = int1->edge1;
-      e2 = int1->edge2;
-    }
-    SwapPositionsInSEL(e1, e2);
-    int1 = int1->next;
-    int2 = int1->next;
-  }
-
-  m_SortedEdges = 0;
-
-  //finally, check the last intersection too ...
-  return (int1->edge1->prevInSEL == int1->edge2 ||
-    int1->edge1->nextInSEL == int1->edge2);
-}
-//------------------------------------------------------------------------------
-
-bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
-{
-  return e2.xcurr == e1.xcurr ? e2.dx > e1.dx : e2.xcurr < e1.xcurr;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::InsertEdgeIntoAEL(TEdge *edge)
-{
-  edge->prevInAEL = 0;
-  edge->nextInAEL = 0;
-  if( !m_ActiveEdges )
-  {
-    m_ActiveEdges = edge;
-  }
-  else if( E2InsertsBeforeE1(*m_ActiveEdges, *edge) )
-  {
-    edge->nextInAEL = m_ActiveEdges;
-    m_ActiveEdges->prevInAEL = edge;
-    m_ActiveEdges = edge;
-  } else
-  {
-    TEdge* e = m_ActiveEdges;
-    while( e->nextInAEL  && !E2InsertsBeforeE1(*e->nextInAEL , *edge) )
-      e = e->nextInAEL;
-    edge->nextInAEL = e->nextInAEL;
-    if( e->nextInAEL ) e->nextInAEL->prevInAEL = edge;
-    edge->prevInAEL = e;
-    e->nextInAEL = edge;
-  }
-}
-//----------------------------------------------------------------------
-
-void Clipper::DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
-{
-  AddOutPt(edge1, pt);
-  SwapSides(*edge1, *edge2);
-  SwapPolyIndexes(*edge1, *edge2);
-}
-//----------------------------------------------------------------------
-
-void Clipper::DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
-{
-  AddOutPt(edge2, pt);
-  SwapSides(*edge1, *edge2);
-  SwapPolyIndexes(*edge1, *edge2);
-}
-//----------------------------------------------------------------------
-
-void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
-{
-  AddOutPt(edge1, pt);
-  AddOutPt(edge2, pt);
-  SwapSides( *edge1 , *edge2 );
-  SwapPolyIndexes( *edge1 , *edge2 );
-}
-//----------------------------------------------------------------------
-
-void Clipper::CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2)
-{
-  //when a polygon is split into 2 polygons, make sure any holes the original
-  //polygon contained link to the correct polygon ...
-  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
-  {
-    OutRec *orec = m_PolyOuts[i];
-    if (orec->isHole && orec->bottomPt && orec->FirstLeft == outRec1 &&
-      !PointInPolygon(orec->bottomPt->pt, outRec1->pts, m_UseFullRange))
-        orec->FirstLeft = outRec2;
-  }
-}
-//----------------------------------------------------------------------
-
-void Clipper::CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2)
-{
-  //if a hole is owned by outRec2 then make it owned by outRec1 ...
-  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
-    if (m_PolyOuts[i]->isHole && m_PolyOuts[i]->bottomPt &&
-      m_PolyOuts[i]->FirstLeft == outRec2)
-        m_PolyOuts[i]->FirstLeft = outRec1;
-}
-//----------------------------------------------------------------------
-
-void Clipper::JoinCommonEdges(bool fixHoleLinkages)
-{
-  for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
-  {
-    JoinRec* j = m_Joins[i];
-    OutRec *outRec1 = m_PolyOuts[j->poly1Idx];
-    OutPt *pp1a = outRec1->pts;
-    OutRec *outRec2 = m_PolyOuts[j->poly2Idx];
-    OutPt *pp2a = outRec2->pts;
-    IntPoint pt1 = j->pt2a, pt2 = j->pt2b;
-    IntPoint pt3 = j->pt1a, pt4 = j->pt1b;
-    if (!FindSegment(pp1a, pt1, pt2)) continue;
-    if (j->poly1Idx == j->poly2Idx)
-    {
-      //we're searching the same polygon for overlapping segments so
-      //segment 2 mustn't be the same as segment 1 ...
-      pp2a = pp1a->next;
-      if (!FindSegment(pp2a, pt3, pt4) || (pp2a == pp1a)) continue;
-    }
-    else if (!FindSegment(pp2a, pt3, pt4)) continue;
-
-    if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) continue;
-
-    OutPt *p1, *p2, *p3, *p4;
-    OutPt *prev = pp1a->prev;
-    //get p1 & p2 polypts - the overlap start & endpoints on poly1
-    if (PointsEqual(pp1a->pt, pt1)) p1 = pp1a;
-    else if (PointsEqual(prev->pt, pt1)) p1 = prev;
-    else p1 = InsertPolyPtBetween(pp1a, prev, pt1);
-
-    if (PointsEqual(pp1a->pt, pt2)) p2 = pp1a;
-    else if (PointsEqual(prev->pt, pt2)) p2 = prev;
-    else if ((p1 == pp1a) || (p1 == prev))
-      p2 = InsertPolyPtBetween(pp1a, prev, pt2);
-    else if (Pt3IsBetweenPt1AndPt2(pp1a->pt, p1->pt, pt2))
-      p2 = InsertPolyPtBetween(pp1a, p1, pt2); else
-      p2 = InsertPolyPtBetween(p1, prev, pt2);
-
-    //get p3 & p4 polypts - the overlap start & endpoints on poly2
-    prev = pp2a->prev;
-    if (PointsEqual(pp2a->pt, pt1)) p3 = pp2a;
-    else if (PointsEqual(prev->pt, pt1)) p3 = prev;
-    else p3 = InsertPolyPtBetween(pp2a, prev, pt1);
-
-    if (PointsEqual(pp2a->pt, pt2)) p4 = pp2a;
-    else if (PointsEqual(prev->pt, pt2)) p4 = prev;
-    else if ((p3 == pp2a) || (p3 == prev))
-      p4 = InsertPolyPtBetween(pp2a, prev, pt2);
-    else if (Pt3IsBetweenPt1AndPt2(pp2a->pt, p3->pt, pt2))
-      p4 = InsertPolyPtBetween(pp2a, p3, pt2); else
-      p4 = InsertPolyPtBetween(p3, prev, pt2);
-
-    //p1.pt == p3.pt and p2.pt == p4.pt so join p1 to p3 and p2 to p4 ...
-    if (p1->next == p2 && p3->prev == p4)
-    {
-      p1->next = p3;
-      p3->prev = p1;
-      p2->prev = p4;
-      p4->next = p2;
-    }
-    else if (p1->prev == p2 && p3->next == p4)
-    {
-      p1->prev = p3;
-      p3->next = p1;
-      p2->next = p4;
-      p4->prev = p2;
-    }
-    else
-      continue; //an orientation is probably wrong
-
-    if (j->poly2Idx == j->poly1Idx)
-    {
-      //instead of joining two polygons, we've just created a new one by
-      //splitting one polygon into two.
-      outRec1->pts = GetBottomPt(p1);
-      outRec1->bottomPt = outRec1->pts;
-      outRec1->bottomPt->idx = outRec1->idx;
-      outRec2 = CreateOutRec();
-      m_PolyOuts.push_back(outRec2);
-      outRec2->idx = (int)m_PolyOuts.size()-1;
-      j->poly2Idx = outRec2->idx;
-      outRec2->pts = GetBottomPt(p2);
-      outRec2->bottomPt = outRec2->pts;
-      outRec2->bottomPt->idx = outRec2->idx;
-
-      if (PointInPolygon(outRec2->pts->pt, outRec1->pts, m_UseFullRange))
-      {
-        //outRec2 is contained by outRec1 ...
-        outRec2->isHole = !outRec1->isHole;
-        outRec2->FirstLeft = outRec1;
-        if (outRec2->isHole ==
-          (m_ReverseOutput ^ Orientation(outRec2, m_UseFullRange)))
-            ReversePolyPtLinks(*outRec2->pts);
-      } else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRange))
-      {
-        //outRec1 is contained by outRec2 ...
-        outRec2->isHole = outRec1->isHole;
-        outRec1->isHole = !outRec2->isHole;
-        outRec2->FirstLeft = outRec1->FirstLeft;
-        outRec1->FirstLeft = outRec2;
-        if (outRec1->isHole ==
-          (m_ReverseOutput ^ Orientation(outRec1, m_UseFullRange)))
-            ReversePolyPtLinks(*outRec1->pts);
-        //make sure any contained holes now link to the correct polygon ...
-        if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
-      } else
-      {
-        outRec2->isHole = outRec1->isHole;
-        outRec2->FirstLeft = outRec1->FirstLeft;
-        //make sure any contained holes now link to the correct polygon ...
-        if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
-      }
-
-      //now fixup any subsequent joins that match this polygon
-      for (JoinList::size_type k = i+1; k < m_Joins.size(); k++)
-      {
-        JoinRec* j2 = m_Joins[k];
-        if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, p2))
-          j2->poly1Idx = j->poly2Idx;
-        if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, p2))
-          j2->poly2Idx = j->poly2Idx;
-      }
-
-      //now cleanup redundant edges too ...
-      FixupOutPolygon(*outRec1);
-      FixupOutPolygon(*outRec2);
-
-      if (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFullRange) > 0))
-          DisposeBottomPt(*outRec1);
-      if (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFullRange) > 0))
-          DisposeBottomPt(*outRec2);
-
-    } else
-    {
-      //joined 2 polygons together ...
-
-      //make sure any holes contained by outRec2 now link to outRec1 ...
-      if (fixHoleLinkages) CheckHoleLinkages2(outRec1, outRec2);
-
-      //now cleanup redundant edges too ...
-      FixupOutPolygon(*outRec1);
-
-      if (outRec1->pts)
-      {
-        outRec1->isHole = !Orientation(outRec1, m_UseFullRange);
-        if (outRec1->isHole && !outRec1->FirstLeft)
-          outRec1->FirstLeft = outRec2->FirstLeft;
-      }
-
-      //delete the obsolete pointer ...
-      int OKIdx = outRec1->idx;
-      int ObsoleteIdx = outRec2->idx;
-      outRec2->pts = 0;
-      outRec2->bottomPt = 0;
-      outRec2->AppendLink = outRec1;
-
-      //now fixup any subsequent Joins that match this polygon
-      for (JoinList::size_type k = i+1; k < m_Joins.size(); k++)
-      {
-        JoinRec* j2 = m_Joins[k];
-        if (j2->poly1Idx == ObsoleteIdx) j2->poly1Idx = OKIdx;
-        if (j2->poly2Idx == ObsoleteIdx) j2->poly2Idx = OKIdx;
-      }
-    }
-  }
-}
-//------------------------------------------------------------------------------
-
-void ReversePolygon(Polygon& p)
-{
-  std::reverse(p.begin(), p.end());
-}
-//------------------------------------------------------------------------------
-
-void ReversePolygons(Polygons& p)
-{
-  for (Polygons::size_type i = 0; i < p.size(); ++i)
-    ReversePolygon(p[i]);
-}
-
-//------------------------------------------------------------------------------
-// OffsetPolygon functions ...
-//------------------------------------------------------------------------------
-
-struct DoublePoint
-{
-  double X;
-  double Y;
-  DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
-};
-//------------------------------------------------------------------------------
-
-Polygon BuildArc(const IntPoint &pt,
-  const double a1, const double a2, const double r)
-{
-  long64 steps = std::max(6, int(std::sqrt(std::fabs(r)) * std::fabs(a2 - a1)));
-  if (steps > 0x100000) steps = 0x100000;
-  int n = (unsigned)steps;
-  Polygon result(n);
-  double da = (a2 - a1) / (n -1);
-  double a = a1;
-  for (int i = 0; i < n; ++i)
-  {
-    result[i].X = pt.X + Round(std::cos(a)*r);
-    result[i].Y = pt.Y + Round(std::sin(a)*r);
-    a += da;
-  }
-  return result;
-}
-//------------------------------------------------------------------------------
-
-DoublePoint GetUnitNormal( const IntPoint &pt1, const IntPoint &pt2)
-{
-  if(pt2.X == pt1.X && pt2.Y == pt1.Y) 
-    return DoublePoint(0, 0);
-
-  double dx = (double)(pt2.X - pt1.X);
-  double dy = (double)(pt2.Y - pt1.Y);
-  double f = 1 *1.0/ std::sqrt( dx*dx + dy*dy );
-  dx *= f;
-  dy *= f;
-  return DoublePoint(dy, -dx);
-}
-
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------------------
-
-class PolyOffsetBuilder
-{
-private:
-  Polygons m_p;
-  Polygon* m_curr_poly;
-  std::vector<DoublePoint> normals;
-  double m_delta, m_RMin, m_R;
-  size_t m_i, m_j, m_k;
-  static const int buffLength = 128;
-  JoinType m_jointype;
- 
-public:
-
-PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
-  double delta, JoinType jointype, double MiterLimit)
-{
-    //nb precondition - out_polys != ptsin_polys
-    if (NEAR_ZERO(delta))
-    {
-        out_polys = in_polys;
-        return;
-    }
-
-    this->m_p = in_polys;
-    this->m_delta = delta;
-    this->m_jointype = jointype;
-    if (MiterLimit <= 1) MiterLimit = 1;
-    m_RMin = 2/(MiterLimit*MiterLimit);
- 
-    double deltaSq = delta*delta;
-    out_polys.clear();
-    out_polys.resize(in_polys.size());
-    for (m_i = 0; m_i < in_polys.size(); m_i++)
-    {
-        m_curr_poly = &out_polys[m_i];
-        size_t len = in_polys[m_i].size();
-        if (len > 1 && m_p[m_i][0].X == m_p[m_i][len - 1].X &&
-            m_p[m_i][0].Y == m_p[m_i][len-1].Y) len--;
-
-        //when 'shrinking' polygons - to minimize artefacts
-        //strip those polygons that have an area < pi * delta^2 ...
-        double a1 = Area(in_polys[m_i]);
-        if (delta < 0) { if (a1 > 0 && a1 < deltaSq *pi) len = 0; }
-        else if (a1 < 0 && -a1 < deltaSq *pi) len = 0; //holes have neg. area
-
-        if (len == 0 || (len < 3 && delta <= 0))
-          continue;
-        else if (len == 1)
-        {
-            Polygon arc;
-            arc = BuildArc(in_polys[m_i][len-1], 0, 2 * pi, delta);
-            out_polys[m_i] = arc;
-            continue;
-        }
-
-        //build normals ...
-        normals.clear();
-        normals.resize(len);
-        normals[len-1] = GetUnitNormal(in_polys[m_i][len-1], in_polys[m_i][0]);
-        for (m_j = 0; m_j < len -1; ++m_j)
-            normals[m_j] = GetUnitNormal(in_polys[m_i][m_j], in_polys[m_i][m_j+1]);
-        
-        m_k = len -1;
-        for (m_j = 0; m_j < len; ++m_j)
-        {
-          switch (jointype)
-          {
-            case jtMiter:
-            {
-              m_R = 1 + (normals[m_j].X*normals[m_k].X + 
-                normals[m_j].Y*normals[m_k].Y);
-              if (m_R >= m_RMin) DoMiter(); else DoSquare(MiterLimit);
-              break;
-            }
-            case jtSquare: DoSquare(); break;
-            case jtRound: DoRound(); break;
-          }
-        m_k = m_j;
-        }
-    }
-
-    //finally, clean up untidy corners using Clipper ...
-    Clipper clpr;
-    clpr.AddPolygons(out_polys, ptSubject);
-    if (delta > 0)
-    {
-        if (!clpr.Execute(ctUnion, out_polys, pftPositive, pftPositive))
-            out_polys.clear();
-    }
-    else
-    {
-        IntRect r = clpr.GetBounds();
-        Polygon outer(4);
-        outer[0] = IntPoint(r.left - 10, r.bottom + 10);
-        outer[1] = IntPoint(r.right + 10, r.bottom + 10);
-        outer[2] = IntPoint(r.right + 10, r.top - 10);
-        outer[3] = IntPoint(r.left - 10, r.top - 10);
-
-        clpr.AddPolygon(outer, ptSubject);
-        if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
-        {
-            out_polys.erase(out_polys.begin());
-            ReversePolygons(out_polys);
-
-        } else
-            out_polys.clear();
-    }
-}
-//------------------------------------------------------------------------------
-
-private:
-
-void AddPoint(const IntPoint& pt)
-{
-    Polygon::size_type len = m_curr_poly->size();
-    if (len == m_curr_poly->capacity())
-        m_curr_poly->reserve(len + buffLength);
-    m_curr_poly->push_back(pt);
-}
-//------------------------------------------------------------------------------
-
-void DoSquare(double mul = 1.0)
-{
-    IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
-        (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
-    IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
-        (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
-    if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
-    {
-      double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
-      double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
-      a1 = std::fabs(a2 - a1);
-      if (a1 > pi) a1 = pi * 2 - a1;
-      double dx = std::tan((pi - a1)/4) * std::fabs(m_delta * mul);
-      pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
-        (long64)(pt1.Y + normals[m_k].X * dx));
-      AddPoint(pt1);
-      pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx),
-        (long64)(pt2.Y -normals[m_j].X * dx));
-      AddPoint(pt2);
-    }
-    else
-    {
-      AddPoint(pt1);
-      AddPoint(m_p[m_i][m_j]);
-      AddPoint(pt2);
-    }
-}
-//------------------------------------------------------------------------------
-
-void DoMiter()
-{
-    if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
-    {
-        double q = m_delta / m_R;
-        AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X + 
-            (normals[m_k].X + normals[m_j].X) * q),
-            (long64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
-    }
-    else
-    {
-        IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X *
-          m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
-        IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X *
-          m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
-        AddPoint(pt1);
-        AddPoint(m_p[m_i][m_j]);
-        AddPoint(pt2);
-    }
-}
-//------------------------------------------------------------------------------
-
-void DoRound()
-{
-    IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
-        (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
-    IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
-        (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
-    AddPoint(pt1);
-    //round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg).
-    if ((normals[m_k].X*normals[m_j].Y - normals[m_j].X*normals[m_k].Y) * m_delta >= 0)
-    {
-      if (normals[m_j].X * normals[m_k].X + normals[m_j].Y * normals[m_k].Y < 0.985)
-      {
-        double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
-        double a2 = std::atan2(normals[m_j].Y, normals[m_j].X);
-        if (m_delta > 0 && a2 < a1) a2 += pi *2;
-        else if (m_delta < 0 && a2 > a1) a2 -= pi *2;
-        Polygon arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta);
-        for (Polygon::size_type m = 0; m < arc.size(); m++)
-          AddPoint(arc[m]);
-      }
-    }
-    else
-      AddPoint(m_p[m_i][m_j]);
-    AddPoint(pt2);
-}
-//--------------------------------------------------------------------------
-
-}; //end PolyOffsetBuilder
-
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------------------
-
-void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
-  double delta, JoinType jointype, double MiterLimit)
-{
-  if (&out_polys == &in_polys)
-  {
-    Polygons poly2(in_polys);
-    PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit);
-  }
-  else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit);
-}
-//------------------------------------------------------------------------------
-
-void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType)
-{
-  Clipper c;
-  c.AddPolygon(in_poly, ptSubject);
-  c.Execute(ctUnion, out_polys, fillType, fillType);
-}
-//------------------------------------------------------------------------------
-
-void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType)
-{
-  Clipper c;
-  c.AddPolygons(in_polys, ptSubject);
-  c.Execute(ctUnion, out_polys, fillType, fillType);
-}
-//------------------------------------------------------------------------------
-
-void SimplifyPolygons(Polygons &polys, PolyFillType fillType)
-{
-  SimplifyPolygons(polys, polys, fillType);
-}
-//------------------------------------------------------------------------------
-
-std::ostream& operator <<(std::ostream &s, IntPoint& p)
-{
-  s << p.X << ' ' << p.Y << "\n";
-  return s;
-}
-//------------------------------------------------------------------------------
-
-std::ostream& operator <<(std::ostream &s, Polygon &p)
-{
-  for (Polygon::size_type i = 0; i < p.size(); i++)
-    s << p[i];
-  s << "\n";
-  return s;
-}
-//------------------------------------------------------------------------------
-
-std::ostream& operator <<(std::ostream &s, Polygons &p)
-{
-  for (Polygons::size_type i = 0; i < p.size(); i++)
-    s << p[i];
-  s << "\n";
-  return s;
-}
-//------------------------------------------------------------------------------
-
-} //ClipperLib namespace
+/*******************************************************************************
+*                                                                              *
+* Author    :  Angus Johnson                                                   *
+* Version   :  4.8.8                                                           *
+* Date      :  30 August 2012                                                  *
+* Website   :  http://www.angusj.com                                           *
+* Copyright :  Angus Johnson 2010-2012                                         *
+*                                                                              *
+* License:                                                                     *
+* Use, modification & distribution is subject to Boost Software License Ver 1. *
+* http://www.boost.org/LICENSE_1_0.txt                                         *
+*                                                                              *
+* Attributions:                                                                *
+* The code in this library is an extension of Bala Vatti's clipping algorithm: *
+* "A generic solution to polygon clipping"                                     *
+* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
+* http://portal.acm.org/citation.cfm?id=129906                                 *
+*                                                                              *
+* Computer graphics and geometric modeling: implementation and algorithms      *
+* By Max K. Agoston                                                            *
+* Springer; 1 edition (January 4, 2005)                                        *
+* http://books.google.com/books?q=vatti+clipping+agoston                       *
+*                                                                              *
+* See also:                                                                    *
+* "Polygon Offsetting by Computing Winding Numbers"                            *
+* Paper no. DETC2005-85513 pp. 565-575                                         *
+* ASME 2005 International Design Engineering Technical Conferences             *
+* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
+* September 24–28, 2005 , Long Beach, California, USA                          *
+* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
+*                                                                              *
+*******************************************************************************/
+
+/*******************************************************************************
+*                                                                              *
+* This is a translation of the Delphi Clipper library and the naming style     *
+* used has retained a Delphi flavour.                                          *
+*                                                                              *
+*******************************************************************************/
+
+#include "clipper.hpp"
+#include <cmath>
+#include <vector>
+#include <algorithm>
+#include <stdexcept>
+#include <cstring>
+#include <cstdlib>
+#include <ostream>
+
+namespace ClipperLib {
+
+static long64 const loRange = 0x3FFFFFFF;
+static long64 const hiRange = 0x3FFFFFFFFFFFFFFFLL;
+static double const pi = 3.141592653589793238;
+enum Direction { dRightToLeft, dLeftToRight };
+
+#define HORIZONTAL (-1.0E+40)
+#define TOLERANCE (1.0e-20)
+#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
+#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b))
+
+inline long64 Abs(long64 val)
+{
+  return val < 0 ? -val : val;
+}
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Int128 class (enables safe math on signed 64bit integers)
+// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
+//    Int128 val2((long64)9223372036854775807);
+//    Int128 val3 = val1 * val2;
+//    val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
+//------------------------------------------------------------------------------
+
+class Int128
+{
+  public:
+
+    Int128(long64 _lo = 0)
+    {
+      lo = _lo;
+      if (lo < 0) hi = -1; else hi = 0;
+    }
+
+    Int128(const Int128 &val): hi(val.hi), lo(val.lo){}
+
+    long64 operator = (const long64 &val)
+    {
+      lo = val;
+      if (lo < 0) hi = -1; else hi = 0;
+      return val;
+    }
+
+    bool operator == (const Int128 &val) const
+      {return (hi == val.hi && lo == val.lo);}
+
+    bool operator != (const Int128 &val) const
+      { return !(*this == val);}
+
+    bool operator > (const Int128 &val) const
+    {
+      if (hi != val.hi)
+        return hi > val.hi;
+      else
+        return lo > val.lo;
+    }
+
+    bool operator < (const Int128 &val) const
+    {
+      if (hi != val.hi)
+        return hi < val.hi;
+      else
+        return lo < val.lo;
+    }
+
+    bool operator >= (const Int128 &val) const
+      { return !(*this < val);}
+
+    bool operator <= (const Int128 &val) const
+      { return !(*this > val);}
+
+    Int128& operator += (const Int128 &rhs)
+    {
+      hi += rhs.hi;
+      lo += rhs.lo;
+      if (ulong64(lo) < ulong64(rhs.lo)) hi++;
+      return *this;
+    }
+
+    Int128 operator + (const Int128 &rhs) const
+    {
+      Int128 result(*this);
+      result+= rhs;
+      return result;
+    }
+
+    Int128& operator -= (const Int128 &rhs)
+    {
+      Int128 tmp(rhs);
+      Negate(tmp);
+      *this += tmp;
+      return *this;
+    }
+
+    //Int128 operator -() const
+    //{
+    //  Int128 result(*this);
+    //  if (result.lo == 0) {
+    //    if (result.hi != 0) result.hi = -1;
+    //  }
+    //  else {
+    //    result.lo = -result.lo;
+    //    result.hi = ~result.hi;
+    //  }
+    //  return result;
+    //}
+
+    Int128 operator - (const Int128 &rhs) const
+    {
+      Int128 result(*this);
+      result -= rhs;
+      return result;
+    }
+
+    Int128 operator * (const Int128 &rhs) const
+    {
+      if ( !(hi == 0 || hi == -1) || !(rhs.hi == 0 || rhs.hi == -1))
+        throw "Int128 operator*: overflow error";
+      bool negate = (hi < 0) != (rhs.hi < 0);
+
+      Int128 tmp(*this);
+      if (tmp.hi < 0) Negate(tmp);
+      ulong64 int1Hi = ulong64(tmp.lo) >> 32;
+      ulong64 int1Lo = ulong64(tmp.lo & 0xFFFFFFFF);
+
+      tmp = rhs;
+      if (tmp.hi < 0) Negate(tmp);
+      ulong64 int2Hi = ulong64(tmp.lo) >> 32;
+      ulong64 int2Lo = ulong64(tmp.lo & 0xFFFFFFFF);
+
+      //nb: see comments in clipper.pas
+      ulong64 a = int1Hi * int2Hi;
+      ulong64 b = int1Lo * int2Lo;
+      ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
+
+      tmp.hi = long64(a + (c >> 32));
+      tmp.lo = long64(c << 32);
+      tmp.lo += long64(b);
+      if (ulong64(tmp.lo) < b) tmp.hi++;
+      if (negate) Negate(tmp);
+      return tmp;
+    }
+
+    Int128 operator/ (const Int128 &rhs) const
+    {
+      if (rhs.lo == 0 && rhs.hi == 0)
+        throw "Int128 operator/: divide by zero";
+      bool negate = (rhs.hi < 0) != (hi < 0);
+      Int128 result(*this), denom(rhs);
+      if (result.hi < 0) Negate(result);
+      if (denom.hi < 0)  Negate(denom);
+      if (denom > result) return Int128(0); //result is only a fraction of 1
+      Negate(denom);
+
+      Int128 p(0);
+      for (int i = 0; i < 128; ++i)
+      {
+        p.hi = p.hi << 1;
+        if (p.lo < 0) p.hi++;
+        p.lo = long64(p.lo) << 1;
+        if (result.hi < 0) p.lo++;
+        result.hi = result.hi << 1;
+        if (result.lo < 0) result.hi++;
+        result.lo = long64(result.lo) << 1;
+        Int128 p2(p);
+        p += denom;
+        if (p.hi < 0) p = p2;
+        else result.lo++;
+      }
+      if (negate) Negate(result);
+      return result;
+    }
+
+    double AsDouble() const
+    {
+      const double shift64 = 18446744073709551616.0; //2^64
+      const double bit64 = 9223372036854775808.0;
+      if (hi < 0)
+      {
+        Int128 tmp(*this);
+        Negate(tmp);
+        if (tmp.lo < 0)
+          return (double)tmp.lo - bit64 - tmp.hi * shift64;
+        else
+          return -(double)tmp.lo - tmp.hi * shift64;
+      }
+      else if (lo < 0)
+        return -(double)lo + bit64 + hi * shift64;
+      else
+        return (double)lo + (double)hi * shift64;
+    }
+
+    //for bug testing ...
+    //std::string AsString() const
+    //{
+    //  std::string result;
+    //  unsigned char r = 0;
+    //  Int128 tmp(0), val(*this);
+    //  if (hi < 0) Negate(val);
+    //  result.resize(50);
+    //  std::string::size_type i = result.size() -1;
+    //  while (val.hi != 0 || val.lo != 0)
+    //  {
+    //    Div10(val, tmp, r);
+    //    result[i--] = char('0' + r);
+    //    val = tmp;
+    //  }
+    //  if (hi < 0) result[i--] = '-';
+    //  result.erase(0,i+1);
+    //  if (result.size() == 0) result = "0";
+    //  return result;
+    //}
+
+private:
+    long64 hi;
+    long64 lo;
+
+    static void Negate(Int128 &val)
+    {
+      if (val.lo == 0) {
+        if (val.hi != 0) val.hi = -val.hi;;
+      }
+      else {
+        val.lo = -val.lo;
+        val.hi = ~val.hi;
+      }
+    }
+
+    //debugging only ...
+    //void Div10(const Int128 val, Int128& result, unsigned char & remainder) const
+    //{
+    //  remainder = 0;
+    //  result = 0;
+    //  for (int i = 63; i >= 0; --i)
+    //  {
+    //    if ((val.hi & ((long64)1 << i)) != 0)
+    //      remainder = char((remainder * 2) + 1); else
+    //      remainder *= char(2);
+    //    if (remainder >= 10)
+    //    {
+    //      result.hi += ((long64)1 << i);
+    //      remainder -= char(10);
+    //    }
+    //  }
+    //  for (int i = 63; i >= 0; --i)
+    //  {
+    //    if ((val.lo & ((long64)1 << i)) != 0)
+    //      remainder = char((remainder * 2) + 1); else
+    //      remainder *= char(2);
+    //    if (remainder >= 10)
+    //    {
+    //      result.lo += ((long64)1 << i);
+    //      remainder -= char(10);
+    //    }
+    //  }
+    //}
+};
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+bool FullRangeNeeded(const Polygon &pts)
+{
+  bool result = false;
+  for (Polygon::size_type i = 0; i <  pts.size(); ++i)
+  {
+    if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange)
+        throw "Coordinate exceeds range bounds.";
+      else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange)
+        result = true;
+  }
+  return result;
+}
+//------------------------------------------------------------------------------
+  
+bool Orientation(const Polygon &poly)
+{
+  int highI = (int)poly.size() -1;
+  if (highI < 2) return false;
+
+  int j = 0, jplus, jminus;
+  for (int i = 0; i <= highI; ++i)
+  {
+    if (poly[i].Y < poly[j].Y) continue;
+    if ((poly[i].Y > poly[j].Y || poly[i].X < poly[j].X)) j = i;
+  };
+  if (j == highI) jplus = 0;
+  else jplus = j +1;
+  if (j == 0) jminus = highI;
+  else jminus = j -1;
+
+  IntPoint vec1, vec2;
+  //get cross product of vectors of the edges adjacent to highest point ...
+  vec1.X = poly[j].X - poly[jminus].X;
+  vec1.Y = poly[j].Y - poly[jminus].Y;
+  vec2.X = poly[jplus].X - poly[j].X;
+  vec2.Y = poly[jplus].Y - poly[j].Y;
+
+  if (Abs(vec1.X) > loRange || Abs(vec1.Y) > loRange ||
+    Abs(vec2.X) > loRange || Abs(vec2.Y) > loRange)
+  {
+    if (Abs(vec1.X) > hiRange || Abs(vec1.Y) > hiRange ||
+      Abs(vec2.X) > hiRange || Abs(vec2.Y) > hiRange)
+        throw "Coordinate exceeds range bounds.";
+    Int128 cross = Int128(vec1.X) * Int128(vec2.Y) -
+      Int128(vec2.X) * Int128(vec1.Y);
+    return cross >= 0;
+  }
+  else
+    return (vec1.X * vec2.Y - vec2.X * vec1.Y) >= 0;
+}
+//------------------------------------------------------------------------------
+
+inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2)
+{
+  return ( pt1.X == pt2.X && pt1.Y == pt2.Y );
+}
+//------------------------------------------------------------------------------
+
+bool Orientation(OutRec *outRec, bool UseFullInt64Range)
+{
+  //first make sure bottomPt is correctly assigned ...
+  OutPt *opBottom = outRec->pts, *op = outRec->pts->next;
+  while (op != outRec->pts)
+  {
+    if (op->pt.Y >= opBottom->pt.Y)
+    {
+      if (op->pt.Y > opBottom->pt.Y || op->pt.X < opBottom->pt.X)
+      opBottom = op;
+    }
+    op = op->next;
+  }
+  outRec->bottomPt = opBottom;
+  opBottom->idx = outRec->idx;
+
+  op = opBottom;
+  //find vertices either side of bottomPt (skipping duplicate points) ....
+  OutPt *opPrev = op->prev;
+  OutPt *opNext = op->next;
+  while (op != opPrev && PointsEqual(op->pt, opPrev->pt))
+    opPrev = opPrev->prev;
+  while (op != opNext && PointsEqual(op->pt, opNext->pt))
+    opNext = opNext->next;
+
+  IntPoint ip1, ip2;
+  ip1.X = op->pt.X - opPrev->pt.X;
+  ip1.Y = op->pt.Y - opPrev->pt.Y;
+  ip2.X = opNext->pt.X - op->pt.X;
+  ip2.Y = opNext->pt.Y - op->pt.Y;
+
+  if (UseFullInt64Range)
+    return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) >= 0;
+  else
+    return (ip1.X * ip2.Y - ip2.X * ip1.Y) >= 0;
+}
+//------------------------------------------------------------------------------
+
+double Area(const Polygon &poly)
+{
+  int highI = (int)poly.size() -1;
+  if (highI < 2) return 0;
+
+  if (FullRangeNeeded(poly)) {
+    Int128 a;
+    a = (Int128(poly[highI].X) * Int128(poly[0].Y)) -
+      Int128(poly[0].X) * Int128(poly[highI].Y);
+    for (int i = 0; i < highI; ++i)
+      a += Int128(poly[i].X) * Int128(poly[i+1].Y) -
+        Int128(poly[i+1].X) * Int128(poly[i].Y);
+    return a.AsDouble() / 2;
+  }
+  else
+  {
+    double a;
+    a = (double)poly[highI].X * poly[0].Y - (double)poly[0].X * poly[highI].Y;
+    for (int i = 0; i < highI; ++i)
+      a += (double)poly[i].X * poly[i+1].Y - (double)poly[i+1].X * poly[i].Y;
+    return a/2;
+  }
+}
+//------------------------------------------------------------------------------
+
+double Area(const OutRec &outRec, bool UseFullInt64Range)
+{
+  OutPt *op = outRec.pts;
+  if (UseFullInt64Range) {
+    Int128 a(0);
+    do {
+      a += (Int128(op->prev->pt.X) * Int128(op->pt.Y)) -
+        Int128(op->pt.X) * Int128(op->prev->pt.Y);
+      op = op->next;
+    } while (op != outRec.pts);
+    return a.AsDouble() / 2;
+  }
+  else
+  {
+    double a = 0;
+    do {
+      a += (op->prev->pt.X * op->pt.Y) - (op->pt.X * op->prev->pt.Y);
+      op = op->next;
+    } while (op != outRec.pts);
+    return a/2;
+  }
+}
+//------------------------------------------------------------------------------
+
+bool PointIsVertex(const IntPoint &pt, OutPt *pp)
+{
+  OutPt *pp2 = pp;
+  do
+  {
+    if (PointsEqual(pp2->pt, pt)) return true;
+    pp2 = pp2->next;
+  }
+  while (pp2 != pp);
+  return false;
+}
+//------------------------------------------------------------------------------
+
+bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range)
+{
+  OutPt *pp2 = pp;
+  bool result = false;
+  if (UseFullInt64Range) {
+    do
+    {
+      if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) ||
+          ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) &&
+          Int128(pt.X - pp2->pt.X) < (Int128(pp2->prev->pt.X - pp2->pt.X) *
+          Int128(pt.Y - pp2->pt.Y)) / Int128(pp2->prev->pt.Y - pp2->pt.Y))
+            result = !result;
+      pp2 = pp2->next;
+    }
+    while (pp2 != pp);
+  }
+  else
+  {
+    do
+    {
+      if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) ||
+        ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) &&
+        (pt.X < (pp2->prev->pt.X - pp2->pt.X) * (pt.Y - pp2->pt.Y) /
+        (pp2->prev->pt.Y - pp2->pt.Y) + pp2->pt.X )) result = !result;
+      pp2 = pp2->next;
+    }
+    while (pp2 != pp);
+  }
+  return result;
+}
+//------------------------------------------------------------------------------
+
+bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range)
+{
+  if (UseFullInt64Range)
+    return Int128(e1.ytop - e1.ybot) * Int128(e2.xtop - e2.xbot) ==
+      Int128(e1.xtop - e1.xbot) * Int128(e2.ytop - e2.ybot);
+  else return (e1.ytop - e1.ybot)*(e2.xtop - e2.xbot) ==
+      (e1.xtop - e1.xbot)*(e2.ytop - e2.ybot);
+}
+//------------------------------------------------------------------------------
+
+bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
+  const IntPoint pt3, bool UseFullInt64Range)
+{
+  if (UseFullInt64Range)
+    return Int128(pt1.Y-pt2.Y) * Int128(pt2.X-pt3.X) ==
+      Int128(pt1.X-pt2.X) * Int128(pt2.Y-pt3.Y);
+  else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y);
+}
+//------------------------------------------------------------------------------
+
+bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
+  const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range)
+{
+  if (UseFullInt64Range)
+    return Int128(pt1.Y-pt2.Y) * Int128(pt3.X-pt4.X) ==
+      Int128(pt1.X-pt2.X) * Int128(pt3.Y-pt4.Y);
+  else return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y);
+}
+//------------------------------------------------------------------------------
+
+double GetDx(const IntPoint pt1, const IntPoint pt2)
+{
+  return (pt1.Y == pt2.Y) ?
+    HORIZONTAL : (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y);
+}
+//---------------------------------------------------------------------------
+
+void SetDx(TEdge &e)
+{
+  if (e.ybot == e.ytop) e.dx = HORIZONTAL;
+  else e.dx = (double)(e.xtop - e.xbot) / (double)(e.ytop - e.ybot);
+}
+//---------------------------------------------------------------------------
+
+void SwapSides(TEdge &edge1, TEdge &edge2)
+{
+  EdgeSide side =  edge1.side;
+  edge1.side = edge2.side;
+  edge2.side = side;
+}
+//------------------------------------------------------------------------------
+
+void SwapPolyIndexes(TEdge &edge1, TEdge &edge2)
+{
+  int outIdx =  edge1.outIdx;
+  edge1.outIdx = edge2.outIdx;
+  edge2.outIdx = outIdx;
+}
+//------------------------------------------------------------------------------
+
+inline long64 Round(double val)
+{
+  return (val < 0) ?
+    static_cast<long64>(val - 0.5) : static_cast<long64>(val + 0.5);
+}
+//------------------------------------------------------------------------------
+
+long64 TopX(TEdge &edge, const long64 currentY)
+{
+  return ( currentY == edge.ytop ) ?
+    edge.xtop : edge.xbot + Round(edge.dx *(currentY - edge.ybot));
+}
+//------------------------------------------------------------------------------
+
+long64 TopX(const IntPoint pt1, const IntPoint pt2, const long64 currentY)
+{
+  //preconditions: pt1.Y <> pt2.Y and pt1.Y > pt2.Y
+  if (currentY >= pt1.Y) return pt1.X;
+  else if (currentY == pt2.Y) return pt2.X;
+  else if (pt1.X == pt2.X) return pt1.X;
+  else
+  {
+    double q = (double)(pt1.X-pt2.X)/(double)(pt1.Y-pt2.Y);
+    return Round(pt1.X + (currentY - pt1.Y) *q);
+  }
+}
+//------------------------------------------------------------------------------
+
+bool IntersectPoint(TEdge &edge1, TEdge &edge2,
+  IntPoint &ip, bool UseFullInt64Range)
+{
+  double b1, b2;
+  if (SlopesEqual(edge1, edge2, UseFullInt64Range)) return false;
+  else if (NEAR_ZERO(edge1.dx))
+  {
+    ip.X = edge1.xbot;
+    if (NEAR_EQUAL(edge2.dx, HORIZONTAL))
+    {
+      ip.Y = edge2.ybot;
+    } else
+    {
+      b2 = edge2.ybot - (edge2.xbot/edge2.dx);
+      ip.Y = Round(ip.X/edge2.dx + b2);
+    }
+  }
+  else if (NEAR_ZERO(edge2.dx))
+  {
+    ip.X = edge2.xbot;
+    if (NEAR_EQUAL(edge1.dx, HORIZONTAL))
+    {
+      ip.Y = edge1.ybot;
+    } else
+    {
+      b1 = edge1.ybot - (edge1.xbot/edge1.dx);
+      ip.Y = Round(ip.X/edge1.dx + b1);
+    }
+  } else
+  {
+    b1 = edge1.xbot - edge1.ybot * edge1.dx;
+    b2 = edge2.xbot - edge2.ybot * edge2.dx;
+    b2 = (b2-b1)/(edge1.dx - edge2.dx);
+    ip.Y = Round(b2);
+    ip.X = Round(edge1.dx * b2 + b1);
+  }
+
+  return
+    //can be *so close* to the top of one edge that the rounded Y equals one ytop ...
+    (ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) ||
+    (ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) ||
+    (ip.Y > edge1.ytop && ip.Y > edge2.ytop);
+}
+//------------------------------------------------------------------------------
+
+void ReversePolyPtLinks(OutPt &pp)
+{
+  OutPt *pp1, *pp2;
+  pp1 = &pp;
+  do {
+  pp2 = pp1->next;
+  pp1->next = pp1->prev;
+  pp1->prev = pp2;
+  pp1 = pp2;
+  } while( pp1 != &pp );
+}
+//------------------------------------------------------------------------------
+
+void DisposeOutPts(OutPt*& pp)
+{
+  if (pp == 0) return;
+  pp->prev->next = 0;
+  while( pp )
+  {
+    OutPt *tmpPp = pp;
+    pp = pp->next;
+    delete tmpPp ;
+  }
+}
+//------------------------------------------------------------------------------
+
+void InitEdge(TEdge *e, TEdge *eNext,
+  TEdge *ePrev, const IntPoint &pt, PolyType polyType)
+{
+  std::memset( e, 0, sizeof( TEdge ));
+
+  e->next = eNext;
+  e->prev = ePrev;
+  e->xcurr = pt.X;
+  e->ycurr = pt.Y;
+  if (e->ycurr >= e->next->ycurr)
+  {
+    e->xbot = e->xcurr;
+    e->ybot = e->ycurr;
+    e->xtop = e->next->xcurr;
+    e->ytop = e->next->ycurr;
+    e->windDelta = 1;
+  } else
+  {
+    e->xtop = e->xcurr;
+    e->ytop = e->ycurr;
+    e->xbot = e->next->xcurr;
+    e->ybot = e->next->ycurr;
+    e->windDelta = -1;
+  }
+  SetDx(*e);
+  e->polyType = polyType;
+  e->outIdx = -1;
+}
+//------------------------------------------------------------------------------
+
+inline void SwapX(TEdge &e)
+{
+  //swap horizontal edges' top and bottom x's so they follow the natural
+  //progression of the bounds - ie so their xbots will align with the
+  //adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
+  e.xcurr = e.xtop;
+  e.xtop = e.xbot;
+  e.xbot = e.xcurr;
+}
+//------------------------------------------------------------------------------
+
+void SwapPoints(IntPoint &pt1, IntPoint &pt2)
+{
+  IntPoint tmp = pt1;
+  pt1 = pt2;
+  pt2 = tmp;
+}
+//------------------------------------------------------------------------------
+
+bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
+  IntPoint pt2b, IntPoint &pt1, IntPoint &pt2)
+{
+  //precondition: segments are colinear.
+  if ( pt1a.Y == pt1b.Y || Abs((pt1a.X - pt1b.X)/(pt1a.Y - pt1b.Y)) > 1 )
+  {
+    if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b);
+    if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b);
+    if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a;
+    if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b;
+    return pt1.X < pt2.X;
+  } else
+  {
+    if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b);
+    if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b);
+    if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a;
+    if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b;
+    return pt1.Y > pt2.Y;
+  }
+}
+//------------------------------------------------------------------------------
+
+bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2)
+{
+  OutPt *p = btmPt1->prev;
+  while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->prev;
+  double dx1p = std::fabs(GetDx(btmPt1->pt, p->pt));
+  p = btmPt1->next;
+  while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->next;
+  double dx1n = std::fabs(GetDx(btmPt1->pt, p->pt));
+
+  p = btmPt2->prev;
+  while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->prev;
+  double dx2p = std::fabs(GetDx(btmPt2->pt, p->pt));
+  p = btmPt2->next;
+  while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->next;
+  double dx2n = std::fabs(GetDx(btmPt2->pt, p->pt));
+  return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
+}
+//------------------------------------------------------------------------------
+
+OutPt* GetBottomPt(OutPt *pp)
+{
+  OutPt* dups = 0;
+  OutPt* p = pp->next;
+  while (p != pp)
+  {
+    if (p->pt.Y > pp->pt.Y)
+    {
+      pp = p;
+      dups = 0;
+    }
+    else if (p->pt.Y == pp->pt.Y && p->pt.X <= pp->pt.X)
+    {
+      if (p->pt.X < pp->pt.X)
+      {
+        dups = 0;
+        pp = p;
+      } else
+      {
+        if (p->next != pp && p->prev != pp) dups = p;
+      }
+    }
+    p = p->next;
+  }
+  if (dups)
+  {
+    //there appears to be at least 2 vertices at bottomPt so ...
+    while (dups != p)
+    {
+      if (!FirstIsBottomPt(p, dups)) pp = dups;
+      dups = dups->next;
+      while (!PointsEqual(dups->pt, pp->pt)) dups = dups->next;
+    }
+  }
+  return pp;
+}
+//------------------------------------------------------------------------------
+
+bool FindSegment(OutPt* &pp, IntPoint &pt1, IntPoint &pt2)
+{
+  //outPt1 & outPt2 => the overlap segment (if the function returns true)
+  if (!pp) return false;
+  OutPt* pp2 = pp;
+  IntPoint pt1a = pt1, pt2a = pt2;
+  do
+  {
+    if (SlopesEqual(pt1a, pt2a, pp->pt, pp->prev->pt, true) &&
+      SlopesEqual(pt1a, pt2a, pp->pt, true) &&
+      GetOverlapSegment(pt1a, pt2a, pp->pt, pp->prev->pt, pt1, pt2))
+        return true;
+    pp = pp->next;
+  }
+  while (pp != pp2);
+  return false;
+}
+//------------------------------------------------------------------------------
+
+bool Pt3IsBetweenPt1AndPt2(const IntPoint pt1,
+  const IntPoint pt2, const IntPoint pt3)
+{
+  if (PointsEqual(pt1, pt3) || PointsEqual(pt2, pt3)) return true;
+  else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X);
+  else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y);
+}
+//------------------------------------------------------------------------------
+
+OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint pt)
+{
+  if (p1 == p2) throw "JoinError";
+  OutPt* result = new OutPt;
+  result->pt = pt;
+  if (p2 == p1->next)
+  {
+    p1->next = result;
+    p2->prev = result;
+    result->next = p2;
+    result->prev = p1;
+  } else
+  {
+    p2->next = result;
+    p1->prev = result;
+    result->next = p1;
+    result->prev = p2;
+  }
+  return result;
+}
+
+//------------------------------------------------------------------------------
+// ClipperBase class methods ...
+//------------------------------------------------------------------------------
+
+ClipperBase::ClipperBase() //constructor
+{
+  m_MinimaList = 0;
+  m_CurrentLM = 0;
+  m_UseFullRange = true;
+}
+//------------------------------------------------------------------------------
+
+ClipperBase::~ClipperBase() //destructor
+{
+  Clear();
+}
+//------------------------------------------------------------------------------
+
+bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType)
+{
+  int len = (int)pg.size();
+  if (len < 3) return false;
+  Polygon p(len);
+  p[0] = pg[0];
+  int j = 0;
+
+  long64 maxVal;
+  if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
+
+  for (int i = 0; i < len; ++i)
+  {
+    if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal)
+    {
+      if (Abs(pg[i].X) > hiRange || Abs(pg[i].Y) > hiRange)
+        throw "Coordinate exceeds range bounds";
+      maxVal = hiRange;
+      m_UseFullRange = true;
+    }
+
+    if (i == 0 || PointsEqual(p[j], pg[i])) continue;
+    else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange))
+    {
+      if (PointsEqual(p[j-1], pg[i])) j--;
+    } else j++;
+    p[j] = pg[i];
+  }
+  if (j < 2) return false;
+
+  len = j+1;
+  while (len > 2)
+  {
+    //nb: test for point equality before testing slopes ...
+    if (PointsEqual(p[j], p[0])) j--;
+    else if (PointsEqual(p[0], p[1]) ||
+      SlopesEqual(p[j], p[0], p[1], m_UseFullRange))
+      p[0] = p[j--];
+    else if (SlopesEqual(p[j-1], p[j], p[0], m_UseFullRange)) j--;
+    else if (SlopesEqual(p[0], p[1], p[2], m_UseFullRange))
+    {
+      for (int i = 2; i <= j; ++i) p[i-1] = p[i];
+      j--;
+    }
+    else break;
+    len--;
+  }
+  if (len < 3) return false;
+
+  //create a new edge array ...
+  TEdge *edges = new TEdge [len];
+  m_edges.push_back(edges);
+
+  //convert vertices to a double-linked-list of edges and initialize ...
+  edges[0].xcurr = p[0].X;
+  edges[0].ycurr = p[0].Y;
+  InitEdge(&edges[len-1], &edges[0], &edges[len-2], p[len-1], polyType);
+  for (int i = len-2; i > 0; --i)
+    InitEdge(&edges[i], &edges[i+1], &edges[i-1], p[i], polyType);
+  InitEdge(&edges[0], &edges[1], &edges[len-1], p[0], polyType);
+
+  //reset xcurr & ycurr and find 'eHighest' (given the Y axis coordinates
+  //increase downward so the 'highest' edge will have the smallest ytop) ...
+  TEdge *e = &edges[0];
+  TEdge *eHighest = e;
+  do
+  {
+    e->xcurr = e->xbot;
+    e->ycurr = e->ybot;
+    if (e->ytop < eHighest->ytop) eHighest = e;
+    e = e->next;
+  }
+  while ( e != &edges[0]);
+
+  //make sure eHighest is positioned so the following loop works safely ...
+  if (eHighest->windDelta > 0) eHighest = eHighest->next;
+  if (NEAR_EQUAL(eHighest->dx, HORIZONTAL)) eHighest = eHighest->next;
+
+  //finally insert each local minima ...
+  e = eHighest;
+  do {
+    e = AddBoundsToLML(e);
+  }
+  while( e != eHighest );
+  return true;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::InsertLocalMinima(LocalMinima *newLm)
+{
+  if( ! m_MinimaList )
+  {
+    m_MinimaList = newLm;
+  }
+  else if( newLm->Y >= m_MinimaList->Y )
+  {
+    newLm->next = m_MinimaList;
+    m_MinimaList = newLm;
+  } else
+  {
+    LocalMinima* tmpLm = m_MinimaList;
+    while( tmpLm->next  && ( newLm->Y < tmpLm->next->Y ) )
+      tmpLm = tmpLm->next;
+    newLm->next = tmpLm->next;
+    tmpLm->next = newLm;
+  }
+}
+//------------------------------------------------------------------------------
+
+TEdge* ClipperBase::AddBoundsToLML(TEdge *e)
+{
+  //Starting at the top of one bound we progress to the bottom where there's
+  //a local minima. We then go to the top of the next bound. These two bounds
+  //form the left and right (or right and left) bounds of the local minima.
+  e->nextInLML = 0;
+  e = e->next;
+  for (;;)
+  {
+    if (NEAR_EQUAL(e->dx, HORIZONTAL))
+    {
+      //nb: proceed through horizontals when approaching from their right,
+      //    but break on horizontal minima if approaching from their left.
+      //    This ensures 'local minima' are always on the left of horizontals.
+      if (e->next->ytop < e->ytop && e->next->xbot > e->prev->xbot) break;
+      if (e->xtop != e->prev->xbot) SwapX(*e);
+      e->nextInLML = e->prev;
+    }
+    else if (e->ycurr == e->prev->ycurr) break;
+    else e->nextInLML = e->prev;
+    e = e->next;
+  }
+
+  //e and e.prev are now at a local minima ...
+  LocalMinima* newLm = new LocalMinima;
+  newLm->next = 0;
+  newLm->Y = e->prev->ybot;
+
+  if ( NEAR_EQUAL(e->dx, HORIZONTAL) ) //horizontal edges never start a left bound
+  {
+    if (e->xbot != e->prev->xbot) SwapX(*e);
+    newLm->leftBound = e->prev;
+    newLm->rightBound = e;
+  } else if (e->dx < e->prev->dx)
+  {
+    newLm->leftBound = e->prev;
+    newLm->rightBound = e;
+  } else
+  {
+    newLm->leftBound = e;
+    newLm->rightBound = e->prev;
+  }
+  newLm->leftBound->side = esLeft;
+  newLm->rightBound->side = esRight;
+  InsertLocalMinima( newLm );
+
+  for (;;)
+  {
+    if ( e->next->ytop == e->ytop && !NEAR_EQUAL(e->next->dx, HORIZONTAL) ) break;
+    e->nextInLML = e->next;
+    e = e->next;
+    if ( NEAR_EQUAL(e->dx, HORIZONTAL) && e->xbot != e->prev->xtop) SwapX(*e);
+  }
+  return e->next;
+}
+//------------------------------------------------------------------------------
+
+bool ClipperBase::AddPolygons(const Polygons &ppg, PolyType polyType)
+{
+  bool result = false;
+  for (Polygons::size_type i = 0; i < ppg.size(); ++i)
+    if (AddPolygon(ppg[i], polyType)) result = true;
+  return result;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::Clear()
+{
+  DisposeLocalMinimaList();
+  for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) delete [] m_edges[i];
+  m_edges.clear();
+  m_UseFullRange = false;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::Reset()
+{
+  m_CurrentLM = m_MinimaList;
+  if( !m_CurrentLM ) return; //ie nothing to process
+
+  //reset all edges ...
+  LocalMinima* lm = m_MinimaList;
+  while( lm )
+  {
+    TEdge* e = lm->leftBound;
+    while( e )
+    {
+      e->xcurr = e->xbot;
+      e->ycurr = e->ybot;
+      e->side = esLeft;
+      e->outIdx = -1;
+      e = e->nextInLML;
+    }
+    e = lm->rightBound;
+    while( e )
+    {
+      e->xcurr = e->xbot;
+      e->ycurr = e->ybot;
+      e->side = esRight;
+      e->outIdx = -1;
+      e = e->nextInLML;
+    }
+    lm = lm->next;
+  }
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::DisposeLocalMinimaList()
+{
+  while( m_MinimaList )
+  {
+    LocalMinima* tmpLm = m_MinimaList->next;
+    delete m_MinimaList;
+    m_MinimaList = tmpLm;
+  }
+  m_CurrentLM = 0;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::PopLocalMinima()
+{
+  if( ! m_CurrentLM ) return;
+  m_CurrentLM = m_CurrentLM->next;
+}
+//------------------------------------------------------------------------------
+
+IntRect ClipperBase::GetBounds()
+{
+  IntRect result;
+  LocalMinima* lm = m_MinimaList;
+  if (!lm)
+  {
+    result.left = result.top = result.right = result.bottom = 0;
+    return result;
+  }
+  result.left = lm->leftBound->xbot;
+  result.top = lm->leftBound->ybot;
+  result.right = lm->leftBound->xbot;
+  result.bottom = lm->leftBound->ybot;
+  while (lm)
+  {
+    if (lm->leftBound->ybot > result.bottom)
+      result.bottom = lm->leftBound->ybot;
+    TEdge* e = lm->leftBound;
+    for (;;) {
+      TEdge* bottomE = e;
+      while (e->nextInLML)
+      {
+        if (e->xbot < result.left) result.left = e->xbot;
+        if (e->xbot > result.right) result.right = e->xbot;
+        e = e->nextInLML;
+      }
+      if (e->xbot < result.left) result.left = e->xbot;
+      if (e->xbot > result.right) result.right = e->xbot;
+      if (e->xtop < result.left) result.left = e->xtop;
+      if (e->xtop > result.right) result.right = e->xtop;
+      if (e->ytop < result.top) result.top = e->ytop;
+
+      if (bottomE == lm->leftBound) e = lm->rightBound;
+      else break;
+    }
+    lm = lm->next;
+  }
+  return result;
+}
+
+
+//------------------------------------------------------------------------------
+// TClipper methods ...
+//------------------------------------------------------------------------------
+
+Clipper::Clipper() : ClipperBase() //constructor
+{
+  m_Scanbeam = 0;
+  m_ActiveEdges = 0;
+  m_SortedEdges = 0;
+  m_IntersectNodes = 0;
+  m_ExecuteLocked = false;
+  m_UseFullRange = false;
+  m_ReverseOutput = false;
+}
+//------------------------------------------------------------------------------
+
+Clipper::~Clipper() //destructor
+{
+  Clear();
+  DisposeScanbeamList();
+}
+//------------------------------------------------------------------------------
+
+void Clipper::Clear()
+{
+  if (m_edges.size() == 0) return; //avoids problems with ClipperBase destructor
+  DisposeAllPolyPts();
+  ClipperBase::Clear();
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DisposeScanbeamList()
+{
+  while ( m_Scanbeam ) {
+  Scanbeam* sb2 = m_Scanbeam->next;
+  delete m_Scanbeam;
+  m_Scanbeam = sb2;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::Reset()
+{
+  ClipperBase::Reset();
+  m_Scanbeam = 0;
+  m_ActiveEdges = 0;
+  m_SortedEdges = 0;
+  DisposeAllPolyPts();
+  LocalMinima* lm = m_MinimaList;
+  while (lm)
+  {
+    InsertScanbeam(lm->Y);
+    InsertScanbeam(lm->leftBound->ytop);
+    lm = lm->next;
+  }
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::Execute(ClipType clipType, Polygons &solution,
+    PolyFillType subjFillType, PolyFillType clipFillType)
+{
+  if( m_ExecuteLocked ) return false;
+  m_ExecuteLocked = true;
+  solution.resize(0);
+  m_SubjFillType = subjFillType;
+  m_ClipFillType = clipFillType;
+  m_ClipType = clipType;
+  bool succeeded = ExecuteInternal(false);
+  if (succeeded) BuildResult(solution);
+  m_ExecuteLocked = false;
+  return succeeded;
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::Execute(ClipType clipType, ExPolygons &solution,
+    PolyFillType subjFillType, PolyFillType clipFillType)
+{
+  if( m_ExecuteLocked ) return false;
+  m_ExecuteLocked = true;
+  solution.resize(0);
+  m_SubjFillType = subjFillType;
+  m_ClipFillType = clipFillType;
+  m_ClipType = clipType;
+  bool succeeded = ExecuteInternal(true);
+  if (succeeded) BuildResultEx(solution);
+  m_ExecuteLocked = false;
+  return succeeded;
+}
+//------------------------------------------------------------------------------
+
+bool PolySort(OutRec *or1, OutRec *or2)
+{
+  if (or1 == or2) return false;
+  if (!or1->pts || !or2->pts)
+  {
+    if (or1->pts != or2->pts)
+    {
+      return or1->pts ? true : false;
+    }
+    else return false;
+  }
+  int i1, i2;
+  if (or1->isHole)
+    i1 = or1->FirstLeft->idx; else
+    i1 = or1->idx;
+  if (or2->isHole)
+    i2 = or2->FirstLeft->idx; else
+    i2 = or2->idx;
+  int result = i1 - i2;
+  if (result == 0 && (or1->isHole != or2->isHole))
+  {
+    return or1->isHole ? false : true;
+  }
+  else return result < 0;
+}
+//------------------------------------------------------------------------------
+
+OutRec* FindAppendLinkEnd(OutRec *outRec)
+{
+  while (outRec->AppendLink) outRec = outRec->AppendLink;
+  return outRec;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::FixHoleLinkage(OutRec *outRec)
+{
+  OutRec *tmp;
+  if (outRec->bottomPt)
+    tmp = m_PolyOuts[outRec->bottomPt->idx]->FirstLeft;
+  else
+    tmp = outRec->FirstLeft;
+  if (outRec == tmp) throw clipperException("HoleLinkage error");
+
+  if (tmp)
+  {
+    if (tmp->AppendLink) tmp = FindAppendLinkEnd(tmp);
+    if (tmp == outRec) tmp = 0;
+    else if (tmp->isHole)
+    {
+      FixHoleLinkage(tmp);
+      tmp = tmp->FirstLeft;
+    }
+  }
+  outRec->FirstLeft = tmp;
+  if (!tmp) outRec->isHole = false;
+  outRec->AppendLink = 0;
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::ExecuteInternal(bool fixHoleLinkages)
+{
+  bool succeeded;
+  try {
+    Reset();
+    if (!m_CurrentLM ) return true;
+    long64 botY = PopScanbeam();
+    do {
+      InsertLocalMinimaIntoAEL(botY);
+      ClearHorzJoins();
+      ProcessHorizontals();
+      long64 topY = PopScanbeam();
+      succeeded = ProcessIntersections(botY, topY);
+      if (!succeeded) break;
+      ProcessEdgesAtTopOfScanbeam(topY);
+      botY = topY;
+    } while( m_Scanbeam );
+  }
+  catch(...) {
+    succeeded = false;
+  }
+
+  if (succeeded)
+  {
+    //tidy up output polygons and fix orientations where necessary ...
+    for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+    {
+      OutRec *outRec = m_PolyOuts[i];
+      if (!outRec->pts) continue;
+      FixupOutPolygon(*outRec);
+      if (!outRec->pts) continue;
+      if (outRec->isHole && fixHoleLinkages) FixHoleLinkage(outRec);
+
+      if (outRec->bottomPt == outRec->bottomFlag &&
+        (Orientation(outRec, m_UseFullRange) != (Area(*outRec, m_UseFullRange) > 0)))
+          DisposeBottomPt(*outRec);
+
+      if (outRec->isHole ==
+        (m_ReverseOutput ^ Orientation(outRec, m_UseFullRange)))
+          ReversePolyPtLinks(*outRec->pts);
+    }
+
+    JoinCommonEdges(fixHoleLinkages);
+    if (fixHoleLinkages)
+      std::sort(m_PolyOuts.begin(), m_PolyOuts.end(), PolySort);
+  }
+
+  ClearJoins();
+  ClearHorzJoins();
+  return succeeded;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::InsertScanbeam(const long64 Y)
+{
+  if( !m_Scanbeam )
+  {
+    m_Scanbeam = new Scanbeam;
+    m_Scanbeam->next = 0;
+    m_Scanbeam->Y = Y;
+  }
+  else if(  Y > m_Scanbeam->Y )
+  {
+    Scanbeam* newSb = new Scanbeam;
+    newSb->Y = Y;
+    newSb->next = m_Scanbeam;
+    m_Scanbeam = newSb;
+  } else
+  {
+    Scanbeam* sb2 = m_Scanbeam;
+    while( sb2->next  && ( Y <= sb2->next->Y ) ) sb2 = sb2->next;
+    if(  Y == sb2->Y ) return; //ie ignores duplicates
+    Scanbeam* newSb = new Scanbeam;
+    newSb->Y = Y;
+    newSb->next = sb2->next;
+    sb2->next = newSb;
+  }
+}
+//------------------------------------------------------------------------------
+
+long64 Clipper::PopScanbeam()
+{
+  long64 Y = m_Scanbeam->Y;
+  Scanbeam* sb2 = m_Scanbeam;
+  m_Scanbeam = m_Scanbeam->next;
+  delete sb2;
+  return Y;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DisposeAllPolyPts(){
+  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+    DisposeOutRec(i);
+  m_PolyOuts.clear();
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DisposeOutRec(PolyOutList::size_type index)
+{
+  OutRec *outRec = m_PolyOuts[index];
+  if (outRec->pts) DisposeOutPts(outRec->pts);
+  delete outRec;
+  m_PolyOuts[index] = 0;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::SetWindingCount(TEdge &edge)
+{
+  TEdge *e = edge.prevInAEL;
+  //find the edge of the same polytype that immediately preceeds 'edge' in AEL
+  while ( e  && e->polyType != edge.polyType ) e = e->prevInAEL;
+  if ( !e )
+  {
+    edge.windCnt = edge.windDelta;
+    edge.windCnt2 = 0;
+    e = m_ActiveEdges; //ie get ready to calc windCnt2
+  } else if ( IsEvenOddFillType(edge) )
+  {
+    //EvenOdd filling ...
+    edge.windCnt = 1;
+    edge.windCnt2 = e->windCnt2;
+    e = e->nextInAEL; //ie get ready to calc windCnt2
+  } else
+  {
+    //nonZero, Positive or Negative filling ...
+    if ( e->windCnt * e->windDelta < 0 )
+    {
+      if (Abs(e->windCnt) > 1)
+      {
+        if (e->windDelta * edge.windDelta < 0) edge.windCnt = e->windCnt;
+        else edge.windCnt = e->windCnt + edge.windDelta;
+      } else
+        edge.windCnt = e->windCnt + e->windDelta + edge.windDelta;
+    } else
+    {
+      if ( Abs(e->windCnt) > 1 && e->windDelta * edge.windDelta < 0)
+        edge.windCnt = e->windCnt;
+      else if ( e->windCnt + edge.windDelta == 0 )
+        edge.windCnt = e->windCnt;
+      else edge.windCnt = e->windCnt + edge.windDelta;
+    }
+    edge.windCnt2 = e->windCnt2;
+    e = e->nextInAEL; //ie get ready to calc windCnt2
+  }
+
+  //update windCnt2 ...
+  if ( IsEvenOddAltFillType(edge) )
+  {
+    //EvenOdd filling ...
+    while ( e != &edge )
+    {
+      edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0;
+      e = e->nextInAEL;
+    }
+  } else
+  {
+    //nonZero, Positive or Negative filling ...
+    while ( e != &edge )
+    {
+      edge.windCnt2 += e->windDelta;
+      e = e->nextInAEL;
+    }
+  }
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::IsEvenOddFillType(const TEdge& edge) const
+{
+  if (edge.polyType == ptSubject)
+    return m_SubjFillType == pftEvenOdd; else
+    return m_ClipFillType == pftEvenOdd;
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const
+{
+  if (edge.polyType == ptSubject)
+    return m_ClipFillType == pftEvenOdd; else
+    return m_SubjFillType == pftEvenOdd;
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::IsContributing(const TEdge& edge) const
+{
+  PolyFillType pft, pft2;
+  if (edge.polyType == ptSubject)
+  {
+    pft = m_SubjFillType;
+    pft2 = m_ClipFillType;
+  } else
+  {
+    pft = m_ClipFillType;
+    pft2 = m_SubjFillType;
+  }
+
+  switch(pft)
+  {
+    case pftEvenOdd: 
+    case pftNonZero:
+      if (Abs(edge.windCnt) != 1) return false;
+      break;
+    case pftPositive: 
+      if (edge.windCnt != 1) return false;
+      break;
+    default: //pftNegative
+      if (edge.windCnt != -1) return false;
+  }
+
+  switch(m_ClipType)
+  {
+    case ctIntersection:
+      switch(pft2)
+      {
+        case pftEvenOdd: 
+        case pftNonZero: 
+          return (edge.windCnt2 != 0);
+        case pftPositive: 
+          return (edge.windCnt2 > 0);
+        default: 
+          return (edge.windCnt2 < 0);
+      }
+    case ctUnion:
+      switch(pft2)
+      {
+        case pftEvenOdd: 
+        case pftNonZero: 
+          return (edge.windCnt2 == 0);
+        case pftPositive: 
+          return (edge.windCnt2 <= 0);
+        default: 
+          return (edge.windCnt2 >= 0);
+      }
+    case ctDifference:
+      if (edge.polyType == ptSubject)
+        switch(pft2)
+        {
+          case pftEvenOdd: 
+          case pftNonZero: 
+            return (edge.windCnt2 == 0);
+          case pftPositive: 
+            return (edge.windCnt2 <= 0);
+          default: 
+            return (edge.windCnt2 >= 0);
+        }
+      else
+        switch(pft2)
+        {
+          case pftEvenOdd: 
+          case pftNonZero: 
+            return (edge.windCnt2 != 0);
+          case pftPositive: 
+            return (edge.windCnt2 > 0);
+          default: 
+            return (edge.windCnt2 < 0);
+        }
+    default:
+      return true;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
+{
+  TEdge *e, *prevE;
+  if( NEAR_EQUAL(e2->dx, HORIZONTAL) || ( e1->dx > e2->dx ) )
+  {
+    AddOutPt( e1, pt );
+    e2->outIdx = e1->outIdx;
+    e1->side = esLeft;
+    e2->side = esRight;
+    e = e1;
+    if (e->prevInAEL == e2)
+      prevE = e2->prevInAEL; 
+    else
+      prevE = e->prevInAEL;
+  } else
+  {
+    AddOutPt( e2, pt );
+    e1->outIdx = e2->outIdx;
+    e1->side = esRight;
+    e2->side = esLeft;
+    e = e2;
+    if (e->prevInAEL == e1)
+        prevE = e1->prevInAEL;
+    else
+        prevE = e->prevInAEL;
+  }
+  if (prevE && prevE->outIdx >= 0 &&
+      (TopX(*prevE, pt.Y) == TopX(*e, pt.Y)) &&
+        SlopesEqual(*e, *prevE, m_UseFullRange))
+          AddJoin(e, prevE, -1, -1);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
+{
+  AddOutPt( e1, pt );
+  if( e1->outIdx == e2->outIdx )
+  {
+    e1->outIdx = -1;
+    e2->outIdx = -1;
+  }
+  else if (e1->outIdx < e2->outIdx) 
+    AppendPolygon(e1, e2); 
+  else 
+    AppendPolygon(e2, e1);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AddEdgeToSEL(TEdge *edge)
+{
+  //SEL pointers in PEdge are reused to build a list of horizontal edges.
+  //However, we don't need to worry about order with horizontal edge processing.
+  if( !m_SortedEdges )
+  {
+    m_SortedEdges = edge;
+    edge->prevInSEL = 0;
+    edge->nextInSEL = 0;
+  }
+  else
+  {
+    edge->nextInSEL = m_SortedEdges;
+    edge->prevInSEL = 0;
+    m_SortedEdges->prevInSEL = edge;
+    m_SortedEdges = edge;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::CopyAELToSEL()
+{
+  TEdge* e = m_ActiveEdges;
+  m_SortedEdges = e;
+  if (!m_ActiveEdges) return;
+  m_SortedEdges->prevInSEL = 0;
+  e = e->nextInAEL;
+  while ( e )
+  {
+    e->prevInSEL = e->prevInAEL;
+    e->prevInSEL->nextInSEL = e;
+    e->nextInSEL = 0;
+    e = e->nextInAEL;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx, int e2OutIdx)
+{
+  JoinRec* jr = new JoinRec;
+  if (e1OutIdx >= 0)
+    jr->poly1Idx = e1OutIdx; else
+    jr->poly1Idx = e1->outIdx;
+  jr->pt1a = IntPoint(e1->xcurr, e1->ycurr);
+  jr->pt1b = IntPoint(e1->xtop, e1->ytop);
+  if (e2OutIdx >= 0)
+    jr->poly2Idx = e2OutIdx; else
+    jr->poly2Idx = e2->outIdx;
+  jr->pt2a = IntPoint(e2->xcurr, e2->ycurr);
+  jr->pt2b = IntPoint(e2->xtop, e2->ytop);
+  m_Joins.push_back(jr);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ClearJoins()
+{
+  for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
+    delete m_Joins[i];
+  m_Joins.resize(0);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AddHorzJoin(TEdge *e, int idx)
+{
+  HorzJoinRec* hj = new HorzJoinRec;
+  hj->edge = e;
+  hj->savedIdx = idx;
+  m_HorizJoins.push_back(hj);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ClearHorzJoins()
+{
+  for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); i++)
+    delete m_HorizJoins[i];
+  m_HorizJoins.resize(0);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::InsertLocalMinimaIntoAEL( const long64 botY)
+{
+  while(  m_CurrentLM  && ( m_CurrentLM->Y == botY ) )
+  {
+    TEdge* lb = m_CurrentLM->leftBound;
+    TEdge* rb = m_CurrentLM->rightBound;
+
+    InsertEdgeIntoAEL( lb );
+    InsertScanbeam( lb->ytop );
+    InsertEdgeIntoAEL( rb );
+
+    if (IsEvenOddFillType(*lb))
+    {
+      lb->windDelta = 1;
+      rb->windDelta = 1;
+    }
+    else
+    {
+      rb->windDelta = -lb->windDelta;
+    }
+    SetWindingCount( *lb );
+    rb->windCnt = lb->windCnt;
+    rb->windCnt2 = lb->windCnt2;
+
+    if( NEAR_EQUAL(rb->dx, HORIZONTAL) )
+    {
+      //nb: only rightbounds can have a horizontal bottom edge
+      AddEdgeToSEL( rb );
+      InsertScanbeam( rb->nextInLML->ytop );
+    }
+    else
+      InsertScanbeam( rb->ytop );
+
+    if( IsContributing(*lb) )
+      AddLocalMinPoly( lb, rb, IntPoint(lb->xcurr, m_CurrentLM->Y) );
+
+    //if any output polygons share an edge, they'll need joining later ...
+    if (rb->outIdx >= 0)
+    {
+      if (NEAR_EQUAL(rb->dx, HORIZONTAL))
+      {
+        for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i)
+        {
+          IntPoint pt, pt2; //returned by GetOverlapSegment() but unused here.
+          HorzJoinRec* hj = m_HorizJoins[i];
+          //if horizontals rb and hj.edge overlap, flag for joining later ...
+          if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot),
+            IntPoint(hj->edge->xtop, hj->edge->ytop),
+            IntPoint(rb->xbot, rb->ybot),
+            IntPoint(rb->xtop, rb->ytop), pt, pt2))
+              AddJoin(hj->edge, rb, hj->savedIdx);
+        }
+      }
+    }
+
+    if( lb->nextInAEL != rb )
+    {
+      if (rb->outIdx >= 0 && rb->prevInAEL->outIdx >= 0 &&
+        SlopesEqual(*rb->prevInAEL, *rb, m_UseFullRange))
+          AddJoin(rb, rb->prevInAEL);
+
+      TEdge* e = lb->nextInAEL;
+      IntPoint pt = IntPoint(lb->xcurr, lb->ycurr);
+      while( e != rb )
+      {
+        if(!e) throw clipperException("InsertLocalMinimaIntoAEL: missing rightbound!");
+        //nb: For calculating winding counts etc, IntersectEdges() assumes
+        //that param1 will be to the right of param2 ABOVE the intersection ...
+        IntersectEdges( rb , e , pt , ipNone); //order important here
+        e = e->nextInAEL;
+      }
+    }
+    PopLocalMinima();
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DeleteFromAEL(TEdge *e)
+{
+  TEdge* AelPrev = e->prevInAEL;
+  TEdge* AelNext = e->nextInAEL;
+  if(  !AelPrev &&  !AelNext && (e != m_ActiveEdges) ) return; //already deleted
+  if( AelPrev ) AelPrev->nextInAEL = AelNext;
+  else m_ActiveEdges = AelNext;
+  if( AelNext ) AelNext->prevInAEL = AelPrev;
+  e->nextInAEL = 0;
+  e->prevInAEL = 0;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DeleteFromSEL(TEdge *e)
+{
+  TEdge* SelPrev = e->prevInSEL;
+  TEdge* SelNext = e->nextInSEL;
+  if( !SelPrev &&  !SelNext && (e != m_SortedEdges) ) return; //already deleted
+  if( SelPrev ) SelPrev->nextInSEL = SelNext;
+  else m_SortedEdges = SelNext;
+  if( SelNext ) SelNext->prevInSEL = SelPrev;
+  e->nextInSEL = 0;
+  e->prevInSEL = 0;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
+     const IntPoint &pt, IntersectProtects protects)
+{
+  //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before
+  //e2 in AEL except when e1 is being inserted at the intersection point ...
+  bool e1stops = !(ipLeft & protects) &&  !e1->nextInLML &&
+    e1->xtop == pt.X && e1->ytop == pt.Y;
+  bool e2stops = !(ipRight & protects) &&  !e2->nextInLML &&
+    e2->xtop == pt.X && e2->ytop == pt.Y;
+  bool e1Contributing = ( e1->outIdx >= 0 );
+  bool e2contributing = ( e2->outIdx >= 0 );
+
+  //update winding counts...
+  //assumes that e1 will be to the right of e2 ABOVE the intersection
+  if ( e1->polyType == e2->polyType )
+  {
+    if ( IsEvenOddFillType( *e1) )
+    {
+      int oldE1WindCnt = e1->windCnt;
+      e1->windCnt = e2->windCnt;
+      e2->windCnt = oldE1WindCnt;
+    } else
+    {
+      if (e1->windCnt + e2->windDelta == 0 ) e1->windCnt = -e1->windCnt;
+      else e1->windCnt += e2->windDelta;
+      if ( e2->windCnt - e1->windDelta == 0 ) e2->windCnt = -e2->windCnt;
+      else e2->windCnt -= e1->windDelta;
+    }
+  } else
+  {
+    if (!IsEvenOddFillType(*e2)) e1->windCnt2 += e2->windDelta;
+    else e1->windCnt2 = ( e1->windCnt2 == 0 ) ? 1 : 0;
+    if (!IsEvenOddFillType(*e1)) e2->windCnt2 -= e1->windDelta;
+    else e2->windCnt2 = ( e2->windCnt2 == 0 ) ? 1 : 0;
+  }
+
+  PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
+  if (e1->polyType == ptSubject)
+  {
+    e1FillType = m_SubjFillType;
+    e1FillType2 = m_ClipFillType;
+  } else
+  {
+    e1FillType = m_ClipFillType;
+    e1FillType2 = m_SubjFillType;
+  }
+  if (e2->polyType == ptSubject)
+  {
+    e2FillType = m_SubjFillType;
+    e2FillType2 = m_ClipFillType;
+  } else
+  {
+    e2FillType = m_ClipFillType;
+    e2FillType2 = m_SubjFillType;
+  }
+
+  long64 e1Wc, e2Wc;
+  switch (e1FillType)
+  {
+    case pftPositive: e1Wc = e1->windCnt; break;
+    case pftNegative: e1Wc = -e1->windCnt; break;
+    default: e1Wc = Abs(e1->windCnt);
+  }
+  switch(e2FillType)
+  {
+    case pftPositive: e2Wc = e2->windCnt; break;
+    case pftNegative: e2Wc = -e2->windCnt; break;
+    default: e2Wc = Abs(e2->windCnt);
+  }
+
+  if ( e1Contributing && e2contributing )
+  {
+    if ( e1stops || e2stops || 
+      (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
+      (e1->polyType != e2->polyType && m_ClipType != ctXor) )
+        AddLocalMaxPoly(e1, e2, pt); 
+    else
+        DoBothEdges( e1, e2, pt );
+  }
+  else if ( e1Contributing )
+  {
+    if ((e2Wc == 0 || e2Wc == 1) && 
+      (m_ClipType != ctIntersection || 
+      e2->polyType == ptSubject || (e2->windCnt2 != 0))) 
+        DoEdge1(e1, e2, pt);
+  }
+  else if ( e2contributing )
+  {
+    if ((e1Wc == 0 || e1Wc == 1) && 
+      (m_ClipType != ctIntersection || 
+      e1->polyType == ptSubject || (e1->windCnt2 != 0))) 
+        DoEdge2(e1, e2, pt);
+  } 
+  else if ( (e1Wc == 0 || e1Wc == 1) && 
+    (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
+  {
+    //neither edge is currently contributing ...
+
+    long64 e1Wc2, e2Wc2;
+    switch (e1FillType2)
+    {
+      case pftPositive: e1Wc2 = e1->windCnt2; break;
+      case pftNegative : e1Wc2 = -e1->windCnt2; break;
+      default: e1Wc2 = Abs(e1->windCnt2);
+    }
+    switch (e2FillType2)
+    {
+      case pftPositive: e2Wc2 = e2->windCnt2; break;
+      case pftNegative: e2Wc2 = -e2->windCnt2; break;
+      default: e2Wc2 = Abs(e2->windCnt2);
+    }
+
+    if (e1->polyType != e2->polyType)
+        AddLocalMinPoly(e1, e2, pt);
+    else if (e1Wc == 1 && e2Wc == 1)
+      switch( m_ClipType ) {
+        case ctIntersection:
+          if (e1Wc2 > 0 && e2Wc2 > 0)
+            AddLocalMinPoly(e1, e2, pt);
+          break;
+        case ctUnion:
+          if ( e1Wc2 <= 0 && e2Wc2 <= 0 )
+            AddLocalMinPoly(e1, e2, pt);
+          break;
+        case ctDifference:
+          if (((e1->polyType == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
+              ((e1->polyType == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
+                AddLocalMinPoly(e1, e2, pt);
+          break;
+        case ctXor:
+          AddLocalMinPoly(e1, e2, pt);
+      }
+    else
+      SwapSides( *e1, *e2 );
+  }
+
+  if(  (e1stops != e2stops) &&
+    ( (e1stops && (e1->outIdx >= 0)) || (e2stops && (e2->outIdx >= 0)) ) )
+  {
+    SwapSides( *e1, *e2 );
+    SwapPolyIndexes( *e1, *e2 );
+  }
+
+  //finally, delete any non-contributing maxima edges  ...
+  if( e1stops ) DeleteFromAEL( e1 );
+  if( e2stops ) DeleteFromAEL( e2 );
+}
+//------------------------------------------------------------------------------
+
+void Clipper::SetHoleState(TEdge *e, OutRec *outRec)
+{
+  bool isHole = false;
+  TEdge *e2 = e->prevInAEL;
+  while (e2)
+  {
+    if (e2->outIdx >= 0)
+    {
+      isHole = !isHole;
+      if (! outRec->FirstLeft)
+        outRec->FirstLeft = m_PolyOuts[e2->outIdx];
+    }
+    e2 = e2->prevInAEL;
+  }
+  if (isHole) outRec->isHole = true;
+}
+//------------------------------------------------------------------------------
+
+OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
+{
+  //work out which polygon fragment has the correct hole state ...
+  OutPt *outPt1 = outRec1->bottomPt;
+  OutPt *outPt2 = outRec2->bottomPt;
+  if (outPt1->pt.Y > outPt2->pt.Y) return outRec1;
+  else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2;
+  else if (outPt1->pt.X < outPt2->pt.X) return outRec1;
+  else if (outPt1->pt.X > outPt2->pt.X) return outRec2;
+  else if (outPt1->next == outPt1) return outRec2;
+  else if (outPt2->next == outPt2) return outRec1;
+  else if (FirstIsBottomPt(outPt1, outPt2)) return outRec1;
+  else return outRec2;
+}
+//------------------------------------------------------------------------------
+
+bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
+{
+  do
+  {
+    outRec1 = outRec1->FirstLeft;
+    if (outRec1 == outRec2) return true;
+  } while (outRec1);
+  return false;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
+{
+  //get the start and ends of both output polygons ...
+  OutRec *outRec1 = m_PolyOuts[e1->outIdx];
+  OutRec *outRec2 = m_PolyOuts[e2->outIdx];
+
+  OutRec *holeStateRec;
+  if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
+  else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
+  else holeStateRec = GetLowermostRec(outRec1, outRec2);
+
+  OutPt* p1_lft = outRec1->pts;
+  OutPt* p1_rt = p1_lft->prev;
+  OutPt* p2_lft = outRec2->pts;
+  OutPt* p2_rt = p2_lft->prev;
+
+  EdgeSide side;
+  //join e2 poly onto e1 poly and delete pointers to e2 ...
+  if(  e1->side == esLeft )
+  {
+    if(  e2->side == esLeft )
+    {
+      //z y x a b c
+      ReversePolyPtLinks(*p2_lft);
+      p2_lft->next = p1_lft;
+      p1_lft->prev = p2_lft;
+      p1_rt->next = p2_rt;
+      p2_rt->prev = p1_rt;
+      outRec1->pts = p2_rt;
+    } else
+    {
+      //x y z a b c
+      p2_rt->next = p1_lft;
+      p1_lft->prev = p2_rt;
+      p2_lft->prev = p1_rt;
+      p1_rt->next = p2_lft;
+      outRec1->pts = p2_lft;
+    }
+    side = esLeft;
+  } else
+  {
+    if(  e2->side == esRight )
+    {
+      //a b c z y x
+      ReversePolyPtLinks( *p2_lft );
+      p1_rt->next = p2_rt;
+      p2_rt->prev = p1_rt;
+      p2_lft->next = p1_lft;
+      p1_lft->prev = p2_lft;
+    } else
+    {
+      //a b c x y z
+      p1_rt->next = p2_lft;
+      p2_lft->prev = p1_rt;
+      p1_lft->prev = p2_rt;
+      p2_rt->next = p1_lft;
+    }
+    side = esRight;
+  }
+
+  if (holeStateRec == outRec2)
+  {
+    outRec1->bottomPt = outRec2->bottomPt;
+    outRec1->bottomPt->idx = outRec1->idx;
+    if (outRec2->FirstLeft != outRec1)
+      outRec1->FirstLeft = outRec2->FirstLeft;
+    outRec1->isHole = outRec2->isHole;
+  }
+  outRec2->pts = 0;
+  outRec2->bottomPt = 0;
+  outRec2->AppendLink = outRec1;
+  int OKIdx = e1->outIdx;
+  int ObsoleteIdx = e2->outIdx;
+
+  e1->outIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly
+  e2->outIdx = -1;
+
+  TEdge* e = m_ActiveEdges;
+  while( e )
+  {
+    if( e->outIdx == ObsoleteIdx )
+    {
+      e->outIdx = OKIdx;
+      e->side = side;
+      break;
+    }
+    e = e->nextInAEL;
+  }
+
+  for (JoinList::size_type i = 0; i < m_Joins.size(); ++i)
+  {
+      if (m_Joins[i]->poly1Idx == ObsoleteIdx) m_Joins[i]->poly1Idx = OKIdx;
+      if (m_Joins[i]->poly2Idx == ObsoleteIdx) m_Joins[i]->poly2Idx = OKIdx;
+  }
+
+  for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i)
+  {
+      if (m_HorizJoins[i]->savedIdx == ObsoleteIdx)
+        m_HorizJoins[i]->savedIdx = OKIdx;
+  }
+
+}
+//------------------------------------------------------------------------------
+
+OutRec* Clipper::CreateOutRec()
+{
+  OutRec* result = new OutRec;
+  result->isHole = false;
+  result->FirstLeft = 0;
+  result->AppendLink = 0;
+  result->pts = 0;
+  result->bottomPt = 0;
+  result->sides = esNeither;
+  result->bottomFlag = 0;
+
+  return result;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DisposeBottomPt(OutRec &outRec)
+{
+  OutPt* next = outRec.bottomPt->next;
+  OutPt* prev = outRec.bottomPt->prev;
+  if (outRec.pts == outRec.bottomPt) outRec.pts = next;
+  delete outRec.bottomPt;
+  next->prev = prev;
+  prev->next = next;
+  outRec.bottomPt = next;
+  FixupOutPolygon(outRec);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
+{
+  bool ToFront = (e->side == esLeft);
+  if(  e->outIdx < 0 )
+  {
+    OutRec *outRec = CreateOutRec();
+    m_PolyOuts.push_back(outRec);
+    outRec->idx = (int)m_PolyOuts.size()-1;
+    e->outIdx = outRec->idx;
+    OutPt* op = new OutPt;
+    outRec->pts = op;
+    outRec->bottomPt = op;
+    op->pt = pt;
+    op->idx = outRec->idx;
+    op->next = op;
+    op->prev = op;
+    SetHoleState(e, outRec);
+  } else
+  {
+    OutRec *outRec = m_PolyOuts[e->outIdx];
+    OutPt* op = outRec->pts;
+    if ((ToFront && PointsEqual(pt, op->pt)) ||
+      (!ToFront && PointsEqual(pt, op->prev->pt))) return;
+
+    if ((e->side | outRec->sides) != outRec->sides)
+    {
+      //check for 'rounding' artefacts ...
+      if (outRec->sides == esNeither && pt.Y == op->pt.Y)
+      {
+        if (ToFront)
+        {
+          if (pt.X == op->pt.X +1) return;    //ie wrong side of bottomPt
+        }
+        else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt
+      }
+
+      outRec->sides = (EdgeSide)(outRec->sides | e->side);
+      if (outRec->sides == esBoth)
+      {
+        //A vertex from each side has now been added.
+        //Vertices of one side of an output polygon are quite commonly close to
+        //or even 'touching' edges of the other side of the output polygon.
+        //Very occasionally vertices from one side can 'cross' an edge on the
+        //the other side. The distance 'crossed' is always less that a unit
+        //and is purely an artefact of coordinate rounding. Nevertheless, this
+        //results in very tiny self-intersections. Because of the way
+        //orientation is calculated, even tiny self-intersections can cause
+        //the Orientation function to return the wrong result. Therefore, it's
+        //important to ensure that any self-intersections close to BottomPt are
+        //detected and removed before orientation is assigned.
+
+        OutPt *opBot, *op2;
+        if (ToFront)
+        {
+          opBot = outRec->pts;
+          op2 = opBot->next; //op2 == right side
+          if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y &&
+            ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) <
+            (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y)))
+               outRec->bottomFlag = opBot;
+        } else
+        {
+          opBot = outRec->pts->prev;
+          op2 = opBot->prev; //op2 == left side
+          if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y &&
+            ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) >
+            (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y)))
+               outRec->bottomFlag = opBot;
+        }
+      }
+    }
+
+    OutPt* op2 = new OutPt;
+    op2->pt = pt;
+    op2->idx = outRec->idx;
+    if (op2->pt.Y == outRec->bottomPt->pt.Y &&
+      op2->pt.X < outRec->bottomPt->pt.X)
+        outRec->bottomPt = op2;
+    op2->next = op;
+    op2->prev = op->prev;
+    op2->prev->next = op2;
+    op->prev = op2;
+    if (ToFront) outRec->pts = op2;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ProcessHorizontals()
+{
+  TEdge* horzEdge = m_SortedEdges;
+  while( horzEdge )
+  {
+    DeleteFromSEL( horzEdge );
+    ProcessHorizontal( horzEdge );
+    horzEdge = m_SortedEdges;
+  }
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::IsTopHorz(const long64 XPos)
+{
+  TEdge* e = m_SortedEdges;
+  while( e )
+  {
+    if(  ( XPos >= std::min(e->xcurr, e->xtop) ) &&
+      ( XPos <= std::max(e->xcurr, e->xtop) ) ) return false;
+    e = e->nextInSEL;
+  }
+  return true;
+}
+//------------------------------------------------------------------------------
+
+bool IsMinima(TEdge *e)
+{
+  return e  && (e->prev->nextInLML != e) && (e->next->nextInLML != e);
+}
+//------------------------------------------------------------------------------
+
+bool IsMaxima(TEdge *e, const long64 Y)
+{
+  return e && e->ytop == Y && !e->nextInLML;
+}
+//------------------------------------------------------------------------------
+
+bool IsIntermediate(TEdge *e, const long64 Y)
+{
+  return e->ytop == Y && e->nextInLML;
+}
+//------------------------------------------------------------------------------
+
+TEdge *GetMaximaPair(TEdge *e)
+{
+  if( !IsMaxima(e->next, e->ytop) || e->next->xtop != e->xtop )
+    return e->prev; else
+    return e->next;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::SwapPositionsInAEL(TEdge *edge1, TEdge *edge2)
+{
+  if(  !edge1->nextInAEL &&  !edge1->prevInAEL ) return;
+  if(  !edge2->nextInAEL &&  !edge2->prevInAEL ) return;
+
+  if(  edge1->nextInAEL == edge2 )
+  {
+    TEdge* next = edge2->nextInAEL;
+    if( next ) next->prevInAEL = edge1;
+    TEdge* prev = edge1->prevInAEL;
+    if( prev ) prev->nextInAEL = edge2;
+    edge2->prevInAEL = prev;
+    edge2->nextInAEL = edge1;
+    edge1->prevInAEL = edge2;
+    edge1->nextInAEL = next;
+  }
+  else if(  edge2->nextInAEL == edge1 )
+  {
+    TEdge* next = edge1->nextInAEL;
+    if( next ) next->prevInAEL = edge2;
+    TEdge* prev = edge2->prevInAEL;
+    if( prev ) prev->nextInAEL = edge1;
+    edge1->prevInAEL = prev;
+    edge1->nextInAEL = edge2;
+    edge2->prevInAEL = edge1;
+    edge2->nextInAEL = next;
+  }
+  else
+  {
+    TEdge* next = edge1->nextInAEL;
+    TEdge* prev = edge1->prevInAEL;
+    edge1->nextInAEL = edge2->nextInAEL;
+    if( edge1->nextInAEL ) edge1->nextInAEL->prevInAEL = edge1;
+    edge1->prevInAEL = edge2->prevInAEL;
+    if( edge1->prevInAEL ) edge1->prevInAEL->nextInAEL = edge1;
+    edge2->nextInAEL = next;
+    if( edge2->nextInAEL ) edge2->nextInAEL->prevInAEL = edge2;
+    edge2->prevInAEL = prev;
+    if( edge2->prevInAEL ) edge2->prevInAEL->nextInAEL = edge2;
+  }
+
+  if( !edge1->prevInAEL ) m_ActiveEdges = edge1;
+  else if( !edge2->prevInAEL ) m_ActiveEdges = edge2;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::SwapPositionsInSEL(TEdge *edge1, TEdge *edge2)
+{
+  if(  !( edge1->nextInSEL ) &&  !( edge1->prevInSEL ) ) return;
+  if(  !( edge2->nextInSEL ) &&  !( edge2->prevInSEL ) ) return;
+
+  if(  edge1->nextInSEL == edge2 )
+  {
+    TEdge* next = edge2->nextInSEL;
+    if( next ) next->prevInSEL = edge1;
+    TEdge* prev = edge1->prevInSEL;
+    if( prev ) prev->nextInSEL = edge2;
+    edge2->prevInSEL = prev;
+    edge2->nextInSEL = edge1;
+    edge1->prevInSEL = edge2;
+    edge1->nextInSEL = next;
+  }
+  else if(  edge2->nextInSEL == edge1 )
+  {
+    TEdge* next = edge1->nextInSEL;
+    if( next ) next->prevInSEL = edge2;
+    TEdge* prev = edge2->prevInSEL;
+    if( prev ) prev->nextInSEL = edge1;
+    edge1->prevInSEL = prev;
+    edge1->nextInSEL = edge2;
+    edge2->prevInSEL = edge1;
+    edge2->nextInSEL = next;
+  }
+  else
+  {
+    TEdge* next = edge1->nextInSEL;
+    TEdge* prev = edge1->prevInSEL;
+    edge1->nextInSEL = edge2->nextInSEL;
+    if( edge1->nextInSEL ) edge1->nextInSEL->prevInSEL = edge1;
+    edge1->prevInSEL = edge2->prevInSEL;
+    if( edge1->prevInSEL ) edge1->prevInSEL->nextInSEL = edge1;
+    edge2->nextInSEL = next;
+    if( edge2->nextInSEL ) edge2->nextInSEL->prevInSEL = edge2;
+    edge2->prevInSEL = prev;
+    if( edge2->prevInSEL ) edge2->prevInSEL->nextInSEL = edge2;
+  }
+
+  if( !edge1->prevInSEL ) m_SortedEdges = edge1;
+  else if( !edge2->prevInSEL ) m_SortedEdges = edge2;
+}
+//------------------------------------------------------------------------------
+
+TEdge* GetNextInAEL(TEdge *e, Direction dir)
+{
+  return dir == dLeftToRight ? e->nextInAEL : e->prevInAEL;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ProcessHorizontal(TEdge *horzEdge)
+{
+  Direction dir;
+  long64 horzLeft, horzRight;
+
+  if( horzEdge->xcurr < horzEdge->xtop )
+  {
+    horzLeft = horzEdge->xcurr;
+    horzRight = horzEdge->xtop;
+    dir = dLeftToRight;
+  } else
+  {
+    horzLeft = horzEdge->xtop;
+    horzRight = horzEdge->xcurr;
+    dir = dRightToLeft;
+  }
+
+  TEdge* eMaxPair;
+  if( horzEdge->nextInLML ) eMaxPair = 0;
+  else eMaxPair = GetMaximaPair(horzEdge);
+
+  TEdge* e = GetNextInAEL( horzEdge , dir );
+  while( e )
+  {
+    TEdge* eNext = GetNextInAEL( e, dir );
+
+    if (eMaxPair ||
+      ((dir == dLeftToRight) && (e->xcurr <= horzRight)) ||
+      ((dir == dRightToLeft) && (e->xcurr >= horzLeft)))
+    {
+      //ok, so far it looks like we're still in range of the horizontal edge
+      if ( e->xcurr == horzEdge->xtop && !eMaxPair )
+      {
+        if (SlopesEqual(*e, *horzEdge->nextInLML, m_UseFullRange))
+        {
+          //if output polygons share an edge, they'll need joining later ...
+          if (horzEdge->outIdx >= 0 && e->outIdx >= 0)
+            AddJoin(horzEdge->nextInLML, e, horzEdge->outIdx);
+          break; //we've reached the end of the horizontal line
+        }
+        else if (e->dx < horzEdge->nextInLML->dx)
+        //we really have got to the end of the intermediate horz edge so quit.
+        //nb: More -ve slopes follow more +ve slopes ABOVE the horizontal.
+          break;
+      }
+
+      if( e == eMaxPair )
+      {
+        //horzEdge is evidently a maxima horizontal and we've arrived at its end.
+        if (dir == dLeftToRight)
+          IntersectEdges(horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), ipNone);
+        else
+          IntersectEdges(e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), ipNone);
+        if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error");
+        return;
+      }
+      else if( NEAR_EQUAL(e->dx, HORIZONTAL) &&  !IsMinima(e) && !(e->xcurr > e->xtop) )
+      {
+        //An overlapping horizontal edge. Overlapping horizontal edges are
+        //processed as if layered with the current horizontal edge (horizEdge)
+        //being infinitesimally lower that the next (e). Therfore, we
+        //intersect with e only if e.xcurr is within the bounds of horzEdge ...
+        if( dir == dLeftToRight )
+          IntersectEdges( horzEdge , e, IntPoint(e->xcurr, horzEdge->ycurr),
+            (IsTopHorz( e->xcurr ))? ipLeft : ipBoth );
+        else
+          IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr),
+            (IsTopHorz( e->xcurr ))? ipRight : ipBoth );
+      }
+      else if( dir == dLeftToRight )
+      {
+        IntersectEdges( horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr),
+          (IsTopHorz( e->xcurr ))? ipLeft : ipBoth );
+      }
+      else
+      {
+        IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr),
+          (IsTopHorz( e->xcurr ))? ipRight : ipBoth );
+      }
+      SwapPositionsInAEL( horzEdge, e );
+    }
+    else if( (dir == dLeftToRight && e->xcurr > horzRight  && m_SortedEdges) ||
+     (dir == dRightToLeft && e->xcurr < horzLeft && m_SortedEdges) ) break;
+    e = eNext;
+  } //end while
+
+  if( horzEdge->nextInLML )
+  {
+    if( horzEdge->outIdx >= 0 )
+      AddOutPt( horzEdge, IntPoint(horzEdge->xtop, horzEdge->ytop));
+    UpdateEdgeIntoAEL( horzEdge );
+  }
+  else
+  {
+    if ( horzEdge->outIdx >= 0 )
+      IntersectEdges( horzEdge, eMaxPair,
+      IntPoint(horzEdge->xtop, horzEdge->ycurr), ipBoth);
+    if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error");
+    DeleteFromAEL(eMaxPair);
+    DeleteFromAEL(horzEdge);
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
+{
+  if( !e->nextInLML ) throw
+    clipperException("UpdateEdgeIntoAEL: invalid call");
+  TEdge* AelPrev = e->prevInAEL;
+  TEdge* AelNext = e->nextInAEL;
+  e->nextInLML->outIdx = e->outIdx;
+  if( AelPrev ) AelPrev->nextInAEL = e->nextInLML;
+  else m_ActiveEdges = e->nextInLML;
+  if( AelNext ) AelNext->prevInAEL = e->nextInLML;
+  e->nextInLML->side = e->side;
+  e->nextInLML->windDelta = e->windDelta;
+  e->nextInLML->windCnt = e->windCnt;
+  e->nextInLML->windCnt2 = e->windCnt2;
+  e = e->nextInLML;
+  e->prevInAEL = AelPrev;
+  e->nextInAEL = AelNext;
+  if( !NEAR_EQUAL(e->dx, HORIZONTAL) ) InsertScanbeam( e->ytop );
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::ProcessIntersections(const long64 botY, const long64 topY)
+{
+  if( !m_ActiveEdges ) return true;
+  try {
+    BuildIntersectList(botY, topY);
+    if ( !m_IntersectNodes) return true;
+    if ( FixupIntersections() ) ProcessIntersectList();
+    else return false;
+  }
+  catch(...) {
+    m_SortedEdges = 0;
+    DisposeIntersectNodes();
+    throw clipperException("ProcessIntersections error");
+  }
+  return true;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DisposeIntersectNodes()
+{
+  while ( m_IntersectNodes )
+  {
+    IntersectNode* iNode = m_IntersectNodes->next;
+    delete m_IntersectNodes;
+    m_IntersectNodes = iNode;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
+{
+  if ( !m_ActiveEdges ) return;
+
+  //prepare for sorting ...
+  TEdge* e = m_ActiveEdges;
+  e->tmpX = TopX( *e, topY );
+  m_SortedEdges = e;
+  m_SortedEdges->prevInSEL = 0;
+  e = e->nextInAEL;
+  while( e )
+  {
+    e->prevInSEL = e->prevInAEL;
+    e->prevInSEL->nextInSEL = e;
+    e->nextInSEL = 0;
+    e->tmpX = TopX( *e, topY );
+    e = e->nextInAEL;
+  }
+
+  //bubblesort ...
+  bool isModified = true;
+  while( isModified && m_SortedEdges )
+  {
+    isModified = false;
+    e = m_SortedEdges;
+    while( e->nextInSEL )
+    {
+      TEdge *eNext = e->nextInSEL;
+      IntPoint pt;
+      if(e->tmpX > eNext->tmpX &&
+        IntersectPoint(*e, *eNext, pt, m_UseFullRange))
+      {
+        if (pt.Y > botY)
+        {
+            pt.Y = botY;
+            pt.X = TopX(*e, pt.Y);
+        }
+        AddIntersectNode( e, eNext, pt );
+        SwapPositionsInSEL(e, eNext);
+        isModified = true;
+      }
+      else
+        e = eNext;
+    }
+    if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0;
+    else break;
+  }
+  m_SortedEdges = 0;
+}
+//------------------------------------------------------------------------------
+
+bool ProcessParam1BeforeParam2(IntersectNode &node1, IntersectNode &node2)
+{
+  bool result;
+  if (node1.pt.Y == node2.pt.Y)
+  {
+    if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1)
+    {
+      result = node2.pt.X > node1.pt.X;
+      return node2.edge1->dx > 0 ? !result : result;
+    }
+    else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2)
+    {
+      result = node2.pt.X > node1.pt.X;
+      return node2.edge2->dx > 0 ? !result : result;
+    }
+    else return node2.pt.X > node1.pt.X;
+  }
+  else return node1.pt.Y > node2.pt.Y;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
+{
+  IntersectNode* newNode = new IntersectNode;
+  newNode->edge1 = e1;
+  newNode->edge2 = e2;
+  newNode->pt = pt;
+  newNode->next = 0;
+  if( !m_IntersectNodes ) m_IntersectNodes = newNode;
+  else if(  ProcessParam1BeforeParam2(*newNode, *m_IntersectNodes) )
+  {
+    newNode->next = m_IntersectNodes;
+    m_IntersectNodes = newNode;
+  }
+  else
+  {
+    IntersectNode* iNode = m_IntersectNodes;
+    while( iNode->next  && ProcessParam1BeforeParam2(*iNode->next, *newNode) )
+        iNode = iNode->next;
+    newNode->next = iNode->next;
+    iNode->next = newNode;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ProcessIntersectList()
+{
+  while( m_IntersectNodes )
+  {
+    IntersectNode* iNode = m_IntersectNodes->next;
+    {
+      IntersectEdges( m_IntersectNodes->edge1 ,
+        m_IntersectNodes->edge2 , m_IntersectNodes->pt, ipBoth );
+      SwapPositionsInAEL( m_IntersectNodes->edge1 , m_IntersectNodes->edge2 );
+    }
+    delete m_IntersectNodes;
+    m_IntersectNodes = iNode;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::DoMaxima(TEdge *e, long64 topY)
+{
+  TEdge* eMaxPair = GetMaximaPair(e);
+  long64 X = e->xtop;
+  TEdge* eNext = e->nextInAEL;
+  while( eNext != eMaxPair )
+  {
+    if (!eNext) throw clipperException("DoMaxima error");
+    IntersectEdges( e, eNext, IntPoint(X, topY), ipBoth );
+    eNext = eNext->nextInAEL;
+  }
+  if( e->outIdx < 0 && eMaxPair->outIdx < 0 )
+  {
+    DeleteFromAEL( e );
+    DeleteFromAEL( eMaxPair );
+  }
+  else if( e->outIdx >= 0 && eMaxPair->outIdx >= 0 )
+  {
+    IntersectEdges( e, eMaxPair, IntPoint(X, topY), ipNone );
+  }
+  else throw clipperException("DoMaxima error");
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY)
+{
+  TEdge* e = m_ActiveEdges;
+  while( e )
+  {
+    //1. process maxima, treating them as if they're 'bent' horizontal edges,
+    //   but exclude maxima with horizontal edges. nb: e can't be a horizontal.
+    if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) )
+    {
+      //'e' might be removed from AEL, as may any following edges so ...
+      TEdge* ePrior = e->prevInAEL;
+      DoMaxima(e, topY);
+      if( !ePrior ) e = m_ActiveEdges;
+      else e = ePrior->nextInAEL;
+    }
+    else
+    {
+      //2. promote horizontal edges, otherwise update xcurr and ycurr ...
+      if(  IsIntermediate(e, topY) && NEAR_EQUAL(e->nextInLML->dx, HORIZONTAL) )
+      {
+        if (e->outIdx >= 0)
+        {
+          AddOutPt(e, IntPoint(e->xtop, e->ytop));
+
+          for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i)
+          {
+            IntPoint pt, pt2;
+            HorzJoinRec* hj = m_HorizJoins[i];
+            if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot),
+              IntPoint(hj->edge->xtop, hj->edge->ytop),
+              IntPoint(e->nextInLML->xbot, e->nextInLML->ybot),
+              IntPoint(e->nextInLML->xtop, e->nextInLML->ytop), pt, pt2))
+                AddJoin(hj->edge, e->nextInLML, hj->savedIdx, e->outIdx);
+          }
+
+          AddHorzJoin(e->nextInLML, e->outIdx);
+        }
+        UpdateEdgeIntoAEL(e);
+        AddEdgeToSEL(e);
+      } else
+      {
+        //this just simplifies horizontal processing ...
+        e->xcurr = TopX( *e, topY );
+        e->ycurr = topY;
+      }
+      e = e->nextInAEL;
+    }
+  }
+
+  //3. Process horizontals at the top of the scanbeam ...
+  ProcessHorizontals();
+
+  //4. Promote intermediate vertices ...
+  e = m_ActiveEdges;
+  while( e )
+  {
+    if( IsIntermediate( e, topY ) )
+    {
+      if( e->outIdx >= 0 ) AddOutPt(e, IntPoint(e->xtop,e->ytop));
+      UpdateEdgeIntoAEL(e);
+
+      //if output polygons share an edge, they'll need joining later ...
+      if (e->outIdx >= 0 && e->prevInAEL && e->prevInAEL->outIdx >= 0 &&
+        e->prevInAEL->xcurr == e->xbot && e->prevInAEL->ycurr == e->ybot &&
+        SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop),
+          IntPoint(e->xbot,e->ybot),
+          IntPoint(e->prevInAEL->xtop, e->prevInAEL->ytop), m_UseFullRange))
+      {
+        AddOutPt(e->prevInAEL, IntPoint(e->xbot, e->ybot));
+        AddJoin(e, e->prevInAEL);
+      }
+      else if (e->outIdx >= 0 && e->nextInAEL && e->nextInAEL->outIdx >= 0 &&
+        e->nextInAEL->ycurr > e->nextInAEL->ytop &&
+        e->nextInAEL->ycurr <= e->nextInAEL->ybot &&
+        e->nextInAEL->xcurr == e->xbot && e->nextInAEL->ycurr == e->ybot &&
+        SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop),
+          IntPoint(e->xbot,e->ybot),
+          IntPoint(e->nextInAEL->xtop, e->nextInAEL->ytop), m_UseFullRange))
+      {
+        AddOutPt(e->nextInAEL, IntPoint(e->xbot, e->ybot));
+        AddJoin(e, e->nextInAEL);
+      }
+    }
+    e = e->nextInAEL;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::FixupOutPolygon(OutRec &outRec)
+{
+  //FixupOutPolygon() - removes duplicate points and simplifies consecutive
+  //parallel edges by removing the middle vertex.
+  OutPt *lastOK = 0;
+  outRec.pts = outRec.bottomPt;
+  OutPt *pp = outRec.bottomPt;
+
+  for (;;)
+  {
+    if (pp->prev == pp || pp->prev == pp->next )
+    {
+      DisposeOutPts(pp);
+      outRec.pts = 0;
+      outRec.bottomPt = 0;
+      return;
+    }
+    //test for duplicate points and for same slope (cross-product) ...
+    if ( PointsEqual(pp->pt, pp->next->pt) ||
+      SlopesEqual(pp->prev->pt, pp->pt, pp->next->pt, m_UseFullRange) )
+    {
+      lastOK = 0;
+      OutPt *tmp = pp;
+      if (pp == outRec.bottomPt)
+        outRec.bottomPt = 0; //flags need for updating
+      pp->prev->next = pp->next;
+      pp->next->prev = pp->prev;
+      pp = pp->prev;
+      delete tmp;
+    }
+    else if (pp == lastOK) break;
+    else
+    {
+      if (!lastOK) lastOK = pp;
+      pp = pp->next;
+    }
+  }
+  if (!outRec.bottomPt) {
+    outRec.bottomPt = GetBottomPt(pp);
+    outRec.bottomPt->idx = outRec.idx;
+    outRec.pts = outRec.bottomPt;
+  }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::BuildResult(Polygons &polys)
+{
+  int k = 0;
+  polys.resize(m_PolyOuts.size());
+  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+  {
+    if (m_PolyOuts[i]->pts)
+    {
+      Polygon* pg = &polys[k];
+      pg->clear();
+      OutPt* p = m_PolyOuts[i]->pts;
+      do
+      {
+        pg->push_back(p->pt);
+        p = p->next;
+      } while (p != m_PolyOuts[i]->pts);
+      //make sure each polygon has at least 3 vertices ...
+      if (pg->size() < 3) pg->clear(); else k++;
+    }
+  }
+  polys.resize(k);
+}
+//------------------------------------------------------------------------------
+
+void Clipper::BuildResultEx(ExPolygons &polys)
+{
+  PolyOutList::size_type i = 0;
+  int k = 0;
+  polys.resize(0);
+  polys.reserve(m_PolyOuts.size());
+  while (i < m_PolyOuts.size() && m_PolyOuts[i]->pts)
+  {
+    ExPolygon epg;
+    OutPt* p = m_PolyOuts[i]->pts;
+    do {
+      epg.outer.push_back(p->pt);
+      p = p->next;
+    } while (p != m_PolyOuts[i]->pts);
+    i++;
+    //make sure polygons have at least 3 vertices ...
+    if (epg.outer.size() < 3) continue;
+    while (i < m_PolyOuts.size()
+      && m_PolyOuts[i]->pts && m_PolyOuts[i]->isHole)
+    {
+      Polygon pg;
+      p = m_PolyOuts[i]->pts;
+      do {
+        pg.push_back(p->pt);
+        p = p->next;
+      } while (p != m_PolyOuts[i]->pts);
+      epg.holes.push_back(pg);
+      i++;
+    }
+    polys.push_back(epg);
+    k++;
+  }
+  polys.resize(k);
+}
+//------------------------------------------------------------------------------
+
+void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2)
+{
+  TEdge *e1 = int1.edge1;
+  TEdge *e2 = int1.edge2;
+  IntPoint p = int1.pt;
+
+  int1.edge1 = int2.edge1;
+  int1.edge2 = int2.edge2;
+  int1.pt = int2.pt;
+
+  int2.edge1 = e1;
+  int2.edge2 = e2;
+  int2.pt = p;
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::FixupIntersections()
+{
+  if ( !m_IntersectNodes->next ) return true;
+
+  CopyAELToSEL();
+  IntersectNode *int1 = m_IntersectNodes;
+  IntersectNode *int2 = m_IntersectNodes->next;
+  while (int2)
+  {
+    TEdge *e1 = int1->edge1;
+    TEdge *e2;
+    if (e1->prevInSEL == int1->edge2) e2 = e1->prevInSEL;
+    else if (e1->nextInSEL == int1->edge2) e2 = e1->nextInSEL;
+    else
+    {
+      //The current intersection is out of order, so try and swap it with
+      //a subsequent intersection ...
+      while (int2)
+      {
+        if (int2->edge1->nextInSEL == int2->edge2 ||
+          int2->edge1->prevInSEL == int2->edge2) break;
+        else int2 = int2->next;
+      }
+      if ( !int2 ) return false; //oops!!!
+
+      //found an intersect node that can be swapped ...
+      SwapIntersectNodes(*int1, *int2);
+      e1 = int1->edge1;
+      e2 = int1->edge2;
+    }
+    SwapPositionsInSEL(e1, e2);
+    int1 = int1->next;
+    int2 = int1->next;
+  }
+
+  m_SortedEdges = 0;
+
+  //finally, check the last intersection too ...
+  return (int1->edge1->prevInSEL == int1->edge2 ||
+    int1->edge1->nextInSEL == int1->edge2);
+}
+//------------------------------------------------------------------------------
+
+bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
+{
+  return e2.xcurr == e1.xcurr ? e2.dx > e1.dx : e2.xcurr < e1.xcurr;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::InsertEdgeIntoAEL(TEdge *edge)
+{
+  edge->prevInAEL = 0;
+  edge->nextInAEL = 0;
+  if( !m_ActiveEdges )
+  {
+    m_ActiveEdges = edge;
+  }
+  else if( E2InsertsBeforeE1(*m_ActiveEdges, *edge) )
+  {
+    edge->nextInAEL = m_ActiveEdges;
+    m_ActiveEdges->prevInAEL = edge;
+    m_ActiveEdges = edge;
+  } else
+  {
+    TEdge* e = m_ActiveEdges;
+    while( e->nextInAEL  && !E2InsertsBeforeE1(*e->nextInAEL , *edge) )
+      e = e->nextInAEL;
+    edge->nextInAEL = e->nextInAEL;
+    if( e->nextInAEL ) e->nextInAEL->prevInAEL = edge;
+    edge->prevInAEL = e;
+    e->nextInAEL = edge;
+  }
+}
+//----------------------------------------------------------------------
+
+void Clipper::DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
+{
+  AddOutPt(edge1, pt);
+  SwapSides(*edge1, *edge2);
+  SwapPolyIndexes(*edge1, *edge2);
+}
+//----------------------------------------------------------------------
+
+void Clipper::DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
+{
+  AddOutPt(edge2, pt);
+  SwapSides(*edge1, *edge2);
+  SwapPolyIndexes(*edge1, *edge2);
+}
+//----------------------------------------------------------------------
+
+void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
+{
+  AddOutPt(edge1, pt);
+  AddOutPt(edge2, pt);
+  SwapSides( *edge1 , *edge2 );
+  SwapPolyIndexes( *edge1 , *edge2 );
+}
+//----------------------------------------------------------------------
+
+void Clipper::CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2)
+{
+  //when a polygon is split into 2 polygons, make sure any holes the original
+  //polygon contained link to the correct polygon ...
+  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+  {
+    OutRec *orec = m_PolyOuts[i];
+    if (orec->isHole && orec->bottomPt && orec->FirstLeft == outRec1 &&
+      !PointInPolygon(orec->bottomPt->pt, outRec1->pts, m_UseFullRange))
+        orec->FirstLeft = outRec2;
+  }
+}
+//----------------------------------------------------------------------
+
+void Clipper::CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2)
+{
+  //if a hole is owned by outRec2 then make it owned by outRec1 ...
+  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+    if (m_PolyOuts[i]->isHole && m_PolyOuts[i]->bottomPt &&
+      m_PolyOuts[i]->FirstLeft == outRec2)
+        m_PolyOuts[i]->FirstLeft = outRec1;
+}
+//----------------------------------------------------------------------
+
+void Clipper::JoinCommonEdges(bool fixHoleLinkages)
+{
+  for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
+  {
+    JoinRec* j = m_Joins[i];
+    OutRec *outRec1 = m_PolyOuts[j->poly1Idx];
+    OutPt *pp1a = outRec1->pts;
+    OutRec *outRec2 = m_PolyOuts[j->poly2Idx];
+    OutPt *pp2a = outRec2->pts;
+    IntPoint pt1 = j->pt2a, pt2 = j->pt2b;
+    IntPoint pt3 = j->pt1a, pt4 = j->pt1b;
+    if (!FindSegment(pp1a, pt1, pt2)) continue;
+    if (j->poly1Idx == j->poly2Idx)
+    {
+      //we're searching the same polygon for overlapping segments so
+      //segment 2 mustn't be the same as segment 1 ...
+      pp2a = pp1a->next;
+      if (!FindSegment(pp2a, pt3, pt4) || (pp2a == pp1a)) continue;
+    }
+    else if (!FindSegment(pp2a, pt3, pt4)) continue;
+
+    if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) continue;
+
+    OutPt *p1, *p2, *p3, *p4;
+    OutPt *prev = pp1a->prev;
+    //get p1 & p2 polypts - the overlap start & endpoints on poly1
+    if (PointsEqual(pp1a->pt, pt1)) p1 = pp1a;
+    else if (PointsEqual(prev->pt, pt1)) p1 = prev;
+    else p1 = InsertPolyPtBetween(pp1a, prev, pt1);
+
+    if (PointsEqual(pp1a->pt, pt2)) p2 = pp1a;
+    else if (PointsEqual(prev->pt, pt2)) p2 = prev;
+    else if ((p1 == pp1a) || (p1 == prev))
+      p2 = InsertPolyPtBetween(pp1a, prev, pt2);
+    else if (Pt3IsBetweenPt1AndPt2(pp1a->pt, p1->pt, pt2))
+      p2 = InsertPolyPtBetween(pp1a, p1, pt2); else
+      p2 = InsertPolyPtBetween(p1, prev, pt2);
+
+    //get p3 & p4 polypts - the overlap start & endpoints on poly2
+    prev = pp2a->prev;
+    if (PointsEqual(pp2a->pt, pt1)) p3 = pp2a;
+    else if (PointsEqual(prev->pt, pt1)) p3 = prev;
+    else p3 = InsertPolyPtBetween(pp2a, prev, pt1);
+
+    if (PointsEqual(pp2a->pt, pt2)) p4 = pp2a;
+    else if (PointsEqual(prev->pt, pt2)) p4 = prev;
+    else if ((p3 == pp2a) || (p3 == prev))
+      p4 = InsertPolyPtBetween(pp2a, prev, pt2);
+    else if (Pt3IsBetweenPt1AndPt2(pp2a->pt, p3->pt, pt2))
+      p4 = InsertPolyPtBetween(pp2a, p3, pt2); else
+      p4 = InsertPolyPtBetween(p3, prev, pt2);
+
+    //p1.pt == p3.pt and p2.pt == p4.pt so join p1 to p3 and p2 to p4 ...
+    if (p1->next == p2 && p3->prev == p4)
+    {
+      p1->next = p3;
+      p3->prev = p1;
+      p2->prev = p4;
+      p4->next = p2;
+    }
+    else if (p1->prev == p2 && p3->next == p4)
+    {
+      p1->prev = p3;
+      p3->next = p1;
+      p2->next = p4;
+      p4->prev = p2;
+    }
+    else
+      continue; //an orientation is probably wrong
+
+    if (j->poly2Idx == j->poly1Idx)
+    {
+      //instead of joining two polygons, we've just created a new one by
+      //splitting one polygon into two.
+      outRec1->pts = GetBottomPt(p1);
+      outRec1->bottomPt = outRec1->pts;
+      outRec1->bottomPt->idx = outRec1->idx;
+      outRec2 = CreateOutRec();
+      m_PolyOuts.push_back(outRec2);
+      outRec2->idx = (int)m_PolyOuts.size()-1;
+      j->poly2Idx = outRec2->idx;
+      outRec2->pts = GetBottomPt(p2);
+      outRec2->bottomPt = outRec2->pts;
+      outRec2->bottomPt->idx = outRec2->idx;
+
+      if (PointInPolygon(outRec2->pts->pt, outRec1->pts, m_UseFullRange))
+      {
+        //outRec2 is contained by outRec1 ...
+        outRec2->isHole = !outRec1->isHole;
+        outRec2->FirstLeft = outRec1;
+        if (outRec2->isHole ==
+          (m_ReverseOutput ^ Orientation(outRec2, m_UseFullRange)))
+            ReversePolyPtLinks(*outRec2->pts);
+      } else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRange))
+      {
+        //outRec1 is contained by outRec2 ...
+        outRec2->isHole = outRec1->isHole;
+        outRec1->isHole = !outRec2->isHole;
+        outRec2->FirstLeft = outRec1->FirstLeft;
+        outRec1->FirstLeft = outRec2;
+        if (outRec1->isHole ==
+          (m_ReverseOutput ^ Orientation(outRec1, m_UseFullRange)))
+            ReversePolyPtLinks(*outRec1->pts);
+        //make sure any contained holes now link to the correct polygon ...
+        if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
+      } else
+      {
+        outRec2->isHole = outRec1->isHole;
+        outRec2->FirstLeft = outRec1->FirstLeft;
+        //make sure any contained holes now link to the correct polygon ...
+        if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
+      }
+
+      //now fixup any subsequent joins that match this polygon
+      for (JoinList::size_type k = i+1; k < m_Joins.size(); k++)
+      {
+        JoinRec* j2 = m_Joins[k];
+        if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, p2))
+          j2->poly1Idx = j->poly2Idx;
+        if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, p2))
+          j2->poly2Idx = j->poly2Idx;
+      }
+
+      //now cleanup redundant edges too ...
+      FixupOutPolygon(*outRec1);
+      FixupOutPolygon(*outRec2);
+
+      if (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFullRange) > 0))
+          DisposeBottomPt(*outRec1);
+      if (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFullRange) > 0))
+          DisposeBottomPt(*outRec2);
+
+    } else
+    {
+      //joined 2 polygons together ...
+
+      //make sure any holes contained by outRec2 now link to outRec1 ...
+      if (fixHoleLinkages) CheckHoleLinkages2(outRec1, outRec2);
+
+      //now cleanup redundant edges too ...
+      FixupOutPolygon(*outRec1);
+
+      if (outRec1->pts)
+      {
+        outRec1->isHole = !Orientation(outRec1, m_UseFullRange);
+        if (outRec1->isHole && !outRec1->FirstLeft)
+          outRec1->FirstLeft = outRec2->FirstLeft;
+      }
+
+      //delete the obsolete pointer ...
+      int OKIdx = outRec1->idx;
+      int ObsoleteIdx = outRec2->idx;
+      outRec2->pts = 0;
+      outRec2->bottomPt = 0;
+      outRec2->AppendLink = outRec1;
+
+      //now fixup any subsequent Joins that match this polygon
+      for (JoinList::size_type k = i+1; k < m_Joins.size(); k++)
+      {
+        JoinRec* j2 = m_Joins[k];
+        if (j2->poly1Idx == ObsoleteIdx) j2->poly1Idx = OKIdx;
+        if (j2->poly2Idx == ObsoleteIdx) j2->poly2Idx = OKIdx;
+      }
+    }
+  }
+}
+//------------------------------------------------------------------------------
+
+void ReversePolygon(Polygon& p)
+{
+  std::reverse(p.begin(), p.end());
+}
+//------------------------------------------------------------------------------
+
+void ReversePolygons(Polygons& p)
+{
+  for (Polygons::size_type i = 0; i < p.size(); ++i)
+    ReversePolygon(p[i]);
+}
+
+//------------------------------------------------------------------------------
+// OffsetPolygon functions ...
+//------------------------------------------------------------------------------
+
+struct DoublePoint
+{
+  double X;
+  double Y;
+  DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
+};
+//------------------------------------------------------------------------------
+
+Polygon BuildArc(const IntPoint &pt,
+  const double a1, const double a2, const double r)
+{
+  long64 steps = std::max(6, int(std::sqrt(std::fabs(r)) * std::fabs(a2 - a1)));
+  if (steps > 0x100000) steps = 0x100000;
+  int n = (unsigned)steps;
+  Polygon result(n);
+  double da = (a2 - a1) / (n -1);
+  double a = a1;
+  for (int i = 0; i < n; ++i)
+  {
+    result[i].X = pt.X + Round(std::cos(a)*r);
+    result[i].Y = pt.Y + Round(std::sin(a)*r);
+    a += da;
+  }
+  return result;
+}
+//------------------------------------------------------------------------------
+
+DoublePoint GetUnitNormal( const IntPoint &pt1, const IntPoint &pt2)
+{
+  if(pt2.X == pt1.X && pt2.Y == pt1.Y) 
+    return DoublePoint(0, 0);
+
+  double dx = (double)(pt2.X - pt1.X);
+  double dy = (double)(pt2.Y - pt1.Y);
+  double f = 1 *1.0/ std::sqrt( dx*dx + dy*dy );
+  dx *= f;
+  dy *= f;
+  return DoublePoint(dy, -dx);
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+class PolyOffsetBuilder
+{
+private:
+  Polygons m_p;
+  Polygon* m_curr_poly;
+  std::vector<DoublePoint> normals;
+  double m_delta, m_RMin, m_R;
+  size_t m_i, m_j, m_k;
+  static const int buffLength = 128;
+  JoinType m_jointype;
+ 
+public:
+
+PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
+  double delta, JoinType jointype, double MiterLimit)
+{
+    //nb precondition - out_polys != ptsin_polys
+    if (NEAR_ZERO(delta))
+    {
+        out_polys = in_polys;
+        return;
+    }
+
+    this->m_p = in_polys;
+    this->m_delta = delta;
+    this->m_jointype = jointype;
+    if (MiterLimit <= 1) MiterLimit = 1;
+    m_RMin = 2/(MiterLimit*MiterLimit);
+ 
+    double deltaSq = delta*delta;
+    out_polys.clear();
+    out_polys.resize(in_polys.size());
+    for (m_i = 0; m_i < in_polys.size(); m_i++)
+    {
+        m_curr_poly = &out_polys[m_i];
+        size_t len = in_polys[m_i].size();
+        if (len > 1 && m_p[m_i][0].X == m_p[m_i][len - 1].X &&
+            m_p[m_i][0].Y == m_p[m_i][len-1].Y) len--;
+
+        //when 'shrinking' polygons - to minimize artefacts
+        //strip those polygons that have an area < pi * delta^2 ...
+        double a1 = Area(in_polys[m_i]);
+        if (delta < 0) { if (a1 > 0 && a1 < deltaSq *pi) len = 0; }
+        else if (a1 < 0 && -a1 < deltaSq *pi) len = 0; //holes have neg. area
+
+        if (len == 0 || (len < 3 && delta <= 0))
+          continue;
+        else if (len == 1)
+        {
+            Polygon arc;
+            arc = BuildArc(in_polys[m_i][len-1], 0, 2 * pi, delta);
+            out_polys[m_i] = arc;
+            continue;
+        }
+
+        //build normals ...
+        normals.clear();
+        normals.resize(len);
+        normals[len-1] = GetUnitNormal(in_polys[m_i][len-1], in_polys[m_i][0]);
+        for (m_j = 0; m_j < len -1; ++m_j)
+            normals[m_j] = GetUnitNormal(in_polys[m_i][m_j], in_polys[m_i][m_j+1]);
+        
+        m_k = len -1;
+        for (m_j = 0; m_j < len; ++m_j)
+        {
+          switch (jointype)
+          {
+            case jtMiter:
+            {
+              m_R = 1 + (normals[m_j].X*normals[m_k].X + 
+                normals[m_j].Y*normals[m_k].Y);
+              if (m_R >= m_RMin) DoMiter(); else DoSquare(MiterLimit);
+              break;
+            }
+            case jtSquare: DoSquare(); break;
+            case jtRound: DoRound(); break;
+          }
+        m_k = m_j;
+        }
+    }
+
+    //finally, clean up untidy corners using Clipper ...
+    Clipper clpr;
+    clpr.AddPolygons(out_polys, ptSubject);
+    if (delta > 0)
+    {
+        if (!clpr.Execute(ctUnion, out_polys, pftPositive, pftPositive))
+            out_polys.clear();
+    }
+    else
+    {
+        IntRect r = clpr.GetBounds();
+        Polygon outer(4);
+        outer[0] = IntPoint(r.left - 10, r.bottom + 10);
+        outer[1] = IntPoint(r.right + 10, r.bottom + 10);
+        outer[2] = IntPoint(r.right + 10, r.top - 10);
+        outer[3] = IntPoint(r.left - 10, r.top - 10);
+
+        clpr.AddPolygon(outer, ptSubject);
+        if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
+        {
+            out_polys.erase(out_polys.begin());
+            ReversePolygons(out_polys);
+
+        } else
+            out_polys.clear();
+    }
+}
+//------------------------------------------------------------------------------
+
+private:
+
+void AddPoint(const IntPoint& pt)
+{
+    Polygon::size_type len = m_curr_poly->size();
+    if (len == m_curr_poly->capacity())
+        m_curr_poly->reserve(len + buffLength);
+    m_curr_poly->push_back(pt);
+}
+//------------------------------------------------------------------------------
+
+void DoSquare(double mul = 1.0)
+{
+    IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
+        (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
+    IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
+        (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
+    if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
+    {
+      double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
+      double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
+      a1 = std::fabs(a2 - a1);
+      if (a1 > pi) a1 = pi * 2 - a1;
+      double dx = std::tan((pi - a1)/4) * std::fabs(m_delta * mul);
+      pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
+        (long64)(pt1.Y + normals[m_k].X * dx));
+      AddPoint(pt1);
+      pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx),
+        (long64)(pt2.Y -normals[m_j].X * dx));
+      AddPoint(pt2);
+    }
+    else
+    {
+      AddPoint(pt1);
+      AddPoint(m_p[m_i][m_j]);
+      AddPoint(pt2);
+    }
+}
+//------------------------------------------------------------------------------
+
+void DoMiter()
+{
+    if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
+    {
+        double q = m_delta / m_R;
+        AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X + 
+            (normals[m_k].X + normals[m_j].X) * q),
+            (long64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
+    }
+    else
+    {
+        IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X *
+          m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
+        IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X *
+          m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
+        AddPoint(pt1);
+        AddPoint(m_p[m_i][m_j]);
+        AddPoint(pt2);
+    }
+}
+//------------------------------------------------------------------------------
+
+void DoRound()
+{
+    IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
+        (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
+    IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
+        (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
+    AddPoint(pt1);
+    //round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg).
+    if ((normals[m_k].X*normals[m_j].Y - normals[m_j].X*normals[m_k].Y) * m_delta >= 0)
+    {
+      if (normals[m_j].X * normals[m_k].X + normals[m_j].Y * normals[m_k].Y < 0.985)
+      {
+        double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
+        double a2 = std::atan2(normals[m_j].Y, normals[m_j].X);
+        if (m_delta > 0 && a2 < a1) a2 += pi *2;
+        else if (m_delta < 0 && a2 > a1) a2 -= pi *2;
+        Polygon arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta);
+        for (Polygon::size_type m = 0; m < arc.size(); m++)
+          AddPoint(arc[m]);
+      }
+    }
+    else
+      AddPoint(m_p[m_i][m_j]);
+    AddPoint(pt2);
+}
+//--------------------------------------------------------------------------
+
+}; //end PolyOffsetBuilder
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
+  double delta, JoinType jointype, double MiterLimit)
+{
+  if (&out_polys == &in_polys)
+  {
+    Polygons poly2(in_polys);
+    PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit);
+  }
+  else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit);
+}
+//------------------------------------------------------------------------------
+
+void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType)
+{
+  Clipper c;
+  c.AddPolygon(in_poly, ptSubject);
+  c.Execute(ctUnion, out_polys, fillType, fillType);
+}
+//------------------------------------------------------------------------------
+
+void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType)
+{
+  Clipper c;
+  c.AddPolygons(in_polys, ptSubject);
+  c.Execute(ctUnion, out_polys, fillType, fillType);
+}
+//------------------------------------------------------------------------------
+
+void SimplifyPolygons(Polygons &polys, PolyFillType fillType)
+{
+  SimplifyPolygons(polys, polys, fillType);
+}
+//------------------------------------------------------------------------------
+
+std::ostream& operator <<(std::ostream &s, IntPoint& p)
+{
+  s << p.X << ' ' << p.Y << "\n";
+  return s;
+}
+//------------------------------------------------------------------------------
+
+std::ostream& operator <<(std::ostream &s, Polygon &p)
+{
+  for (Polygon::size_type i = 0; i < p.size(); i++)
+    s << p[i];
+  s << "\n";
+  return s;
+}
+//------------------------------------------------------------------------------
+
+std::ostream& operator <<(std::ostream &s, Polygons &p)
+{
+  for (Polygons::size_type i = 0; i < p.size(); i++)
+    s << p[i];
+  s << "\n";
+  return s;
+}
+//------------------------------------------------------------------------------
+
+} //ClipperLib namespace

+ 306 - 306
Source/ThirdParty/Assimp/contrib/clipper/clipper.hpp

@@ -1,306 +1,306 @@
-/*******************************************************************************
-*                                                                              *
-* Author    :  Angus Johnson                                                   *
-* Version   :  4.8.8                                                           *
-* Date      :  30 August 2012                                                  *
-* Website   :  http://www.angusj.com                                           *
-* Copyright :  Angus Johnson 2010-2012                                         *
-*                                                                              *
-* License:                                                                     *
-* Use, modification & distribution is subject to Boost Software License Ver 1. *
-* http://www.boost.org/LICENSE_1_0.txt                                         *
-*                                                                              *
-* Attributions:                                                                *
-* The code in this library is an extension of Bala Vatti's clipping algorithm: *
-* "A generic solution to polygon clipping"                                     *
-* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
-* http://portal.acm.org/citation.cfm?id=129906                                 *
-*                                                                              *
-* Computer graphics and geometric modeling: implementation and algorithms      *
-* By Max K. Agoston                                                            *
-* Springer; 1 edition (January 4, 2005)                                        *
-* http://books.google.com/books?q=vatti+clipping+agoston                       *
-*                                                                              *
-* See also:                                                                    *
-* "Polygon Offsetting by Computing Winding Numbers"                            *
-* Paper no. DETC2005-85513 pp. 565-575                                         *
-* ASME 2005 International Design Engineering Technical Conferences             *
-* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
-* September 24–28, 2005 , Long Beach, California, USA                          *
-* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
-*                                                                              *
-*******************************************************************************/
-
-#ifndef clipper_hpp
-#define clipper_hpp
-
-#include <vector>
-#include <stdexcept>
-#include <cstring>
-#include <cstdlib>
-#include <ostream>
-
-namespace ClipperLib {
-
-enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
-enum PolyType { ptSubject, ptClip };
-//By far the most widely used winding rules for polygon filling are
-//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
-//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
-//see http://glprogramming.com/red/chapter11.html
-enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
-
-typedef signed long long long64;
-typedef unsigned long long ulong64;
-
-struct IntPoint {
-public:
-  long64 X;
-  long64 Y;
-  IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {};
-  friend std::ostream& operator <<(std::ostream &s, IntPoint &p);
-};
-
-typedef std::vector< IntPoint > Polygon;
-typedef std::vector< Polygon > Polygons;
-
-std::ostream& operator <<(std::ostream &s, Polygon &p);
-std::ostream& operator <<(std::ostream &s, Polygons &p);
-
-struct ExPolygon {
-  Polygon  outer;
-  Polygons holes;
-};
-typedef std::vector< ExPolygon > ExPolygons;
-
-enum JoinType { jtSquare, jtRound, jtMiter };
-
-bool Orientation(const Polygon &poly);
-double Area(const Polygon &poly);
-void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
-  double delta, JoinType jointype = jtSquare, double MiterLimit = 2);
-void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
-void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
-void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd);
-
-void ReversePolygon(Polygon& p);
-void ReversePolygons(Polygons& p);
-
-//used internally ...
-enum EdgeSide { esNeither = 0, esLeft = 1, esRight = 2, esBoth = 3 };
-enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
-
-struct TEdge {
-  long64 xbot;
-  long64 ybot;
-  long64 xcurr;
-  long64 ycurr;
-  long64 xtop;
-  long64 ytop;
-  double dx;
-  long64 tmpX;
-  PolyType polyType;
-  EdgeSide side;
-  int windDelta; //1 or -1 depending on winding direction
-  int windCnt;
-  int windCnt2; //winding count of the opposite polytype
-  int outIdx;
-  TEdge *next;
-  TEdge *prev;
-  TEdge *nextInLML;
-  TEdge *nextInAEL;
-  TEdge *prevInAEL;
-  TEdge *nextInSEL;
-  TEdge *prevInSEL;
-};
-
-struct IntersectNode {
-  TEdge          *edge1;
-  TEdge          *edge2;
-  IntPoint        pt;
-  IntersectNode  *next;
-};
-
-struct LocalMinima {
-  long64        Y;
-  TEdge        *leftBound;
-  TEdge        *rightBound;
-  LocalMinima  *next;
-};
-
-struct Scanbeam {
-  long64    Y;
-  Scanbeam *next;
-};
-
-struct OutPt; //forward declaration
-
-struct OutRec {
-  int     idx;
-  bool    isHole;
-  OutRec *FirstLeft;
-  OutRec *AppendLink;
-  OutPt  *pts;
-  OutPt  *bottomPt;
-  OutPt  *bottomFlag;
-  EdgeSide sides;
-};
-
-struct OutPt {
-  int     idx;
-  IntPoint pt;
-  OutPt   *next;
-  OutPt   *prev;
-};
-
-struct JoinRec {
-  IntPoint  pt1a;
-  IntPoint  pt1b;
-  int       poly1Idx;
-  IntPoint  pt2a;
-  IntPoint  pt2b;
-  int       poly2Idx;
-};
-
-struct HorzJoinRec {
-  TEdge    *edge;
-  int       savedIdx;
-};
-
-struct IntRect { long64 left; long64 top; long64 right; long64 bottom; };
-
-typedef std::vector < OutRec* > PolyOutList;
-typedef std::vector < TEdge* > EdgeList;
-typedef std::vector < JoinRec* > JoinList;
-typedef std::vector < HorzJoinRec* > HorzJoinList;
-
-//ClipperBase is the ancestor to the Clipper class. It should not be
-//instantiated directly. This class simply abstracts the conversion of sets of
-//polygon coordinates into edge objects that are stored in a LocalMinima list.
-class ClipperBase
-{
-public:
-  ClipperBase();
-  virtual ~ClipperBase();
-  bool AddPolygon(const Polygon &pg, PolyType polyType);
-  bool AddPolygons( const Polygons &ppg, PolyType polyType);
-  virtual void Clear();
-  IntRect GetBounds();
-protected:
-  void DisposeLocalMinimaList();
-  TEdge* AddBoundsToLML(TEdge *e);
-  void PopLocalMinima();
-  virtual void Reset();
-  void InsertLocalMinima(LocalMinima *newLm);
-  LocalMinima      *m_CurrentLM;
-  LocalMinima      *m_MinimaList;
-  bool              m_UseFullRange;
-  EdgeList          m_edges;
-};
-
-class Clipper : public virtual ClipperBase
-{
-public:
-  Clipper();
-  ~Clipper();
-  bool Execute(ClipType clipType,
-  Polygons &solution,
-  PolyFillType subjFillType = pftEvenOdd,
-  PolyFillType clipFillType = pftEvenOdd);
-  bool Execute(ClipType clipType,
-  ExPolygons &solution,
-  PolyFillType subjFillType = pftEvenOdd,
-  PolyFillType clipFillType = pftEvenOdd);
-  void Clear();
-  bool ReverseSolution() {return m_ReverseOutput;};
-  void ReverseSolution(bool value) {m_ReverseOutput = value;};
-protected:
-  void Reset();
-  virtual bool ExecuteInternal(bool fixHoleLinkages);
-private:
-  PolyOutList       m_PolyOuts;
-  JoinList          m_Joins;
-  HorzJoinList      m_HorizJoins;
-  ClipType          m_ClipType;
-  Scanbeam         *m_Scanbeam;
-  TEdge           *m_ActiveEdges;
-  TEdge           *m_SortedEdges;
-  IntersectNode    *m_IntersectNodes;
-  bool              m_ExecuteLocked;
-  PolyFillType      m_ClipFillType;
-  PolyFillType      m_SubjFillType;
-  bool              m_ReverseOutput;
-  void DisposeScanbeamList();
-  void SetWindingCount(TEdge& edge);
-  bool IsEvenOddFillType(const TEdge& edge) const;
-  bool IsEvenOddAltFillType(const TEdge& edge) const;
-  void InsertScanbeam(const long64 Y);
-  long64 PopScanbeam();
-  void InsertLocalMinimaIntoAEL(const long64 botY);
-  void InsertEdgeIntoAEL(TEdge *edge);
-  void AddEdgeToSEL(TEdge *edge);
-  void CopyAELToSEL();
-  void DeleteFromSEL(TEdge *e);
-  void DeleteFromAEL(TEdge *e);
-  void UpdateEdgeIntoAEL(TEdge *&e);
-  void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
-  bool IsContributing(const TEdge& edge) const;
-  bool IsTopHorz(const long64 XPos);
-  void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
-  void DoMaxima(TEdge *e, long64 topY);
-  void ProcessHorizontals();
-  void ProcessHorizontal(TEdge *horzEdge);
-  void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
-  void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
-  void AppendPolygon(TEdge *e1, TEdge *e2);
-  void DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
-  void DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
-  void DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
-  void IntersectEdges(TEdge *e1, TEdge *e2,
-    const IntPoint &pt, IntersectProtects protects);
-  OutRec* CreateOutRec();
-  void AddOutPt(TEdge *e, const IntPoint &pt);
-  void DisposeBottomPt(OutRec &outRec);
-  void DisposeAllPolyPts();
-  void DisposeOutRec(PolyOutList::size_type index);
-  bool ProcessIntersections(const long64 botY, const long64 topY);
-  void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
-  void BuildIntersectList(const long64 botY, const long64 topY);
-  void ProcessIntersectList();
-  void ProcessEdgesAtTopOfScanbeam(const long64 topY);
-  void BuildResult(Polygons& polys);
-  void BuildResultEx(ExPolygons& polys);
-  void SetHoleState(TEdge *e, OutRec *OutRec);
-  void DisposeIntersectNodes();
-  bool FixupIntersections();
-  void FixupOutPolygon(OutRec &outRec);
-  bool IsHole(TEdge *e);
-  void FixHoleLinkage(OutRec *outRec);
-  void CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2);
-  void CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2);
-  void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1);
-  void ClearJoins();
-  void AddHorzJoin(TEdge *e, int idx);
-  void ClearHorzJoins();
-  void JoinCommonEdges(bool fixHoleLinkages);
-};
-
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------------------
-
-class clipperException : public std::exception
-{
-  public:
-    clipperException(const char* description): m_descr(description) {}
-    virtual ~clipperException() throw() {}
-    virtual const char* what() const throw() {return m_descr.c_str();}
-  private:
-    std::string m_descr;
-};
-//------------------------------------------------------------------------------
-
-} //ClipperLib namespace
-
-#endif //clipper_hpp
-
-
+/*******************************************************************************
+*                                                                              *
+* Author    :  Angus Johnson                                                   *
+* Version   :  4.8.8                                                           *
+* Date      :  30 August 2012                                                  *
+* Website   :  http://www.angusj.com                                           *
+* Copyright :  Angus Johnson 2010-2012                                         *
+*                                                                              *
+* License:                                                                     *
+* Use, modification & distribution is subject to Boost Software License Ver 1. *
+* http://www.boost.org/LICENSE_1_0.txt                                         *
+*                                                                              *
+* Attributions:                                                                *
+* The code in this library is an extension of Bala Vatti's clipping algorithm: *
+* "A generic solution to polygon clipping"                                     *
+* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
+* http://portal.acm.org/citation.cfm?id=129906                                 *
+*                                                                              *
+* Computer graphics and geometric modeling: implementation and algorithms      *
+* By Max K. Agoston                                                            *
+* Springer; 1 edition (January 4, 2005)                                        *
+* http://books.google.com/books?q=vatti+clipping+agoston                       *
+*                                                                              *
+* See also:                                                                    *
+* "Polygon Offsetting by Computing Winding Numbers"                            *
+* Paper no. DETC2005-85513 pp. 565-575                                         *
+* ASME 2005 International Design Engineering Technical Conferences             *
+* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
+* September 24–28, 2005 , Long Beach, California, USA                          *
+* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
+*                                                                              *
+*******************************************************************************/
+
+#ifndef clipper_hpp
+#define clipper_hpp
+
+#include <vector>
+#include <stdexcept>
+#include <cstring>
+#include <cstdlib>
+#include <ostream>
+
+namespace ClipperLib {
+
+enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
+enum PolyType { ptSubject, ptClip };
+//By far the most widely used winding rules for polygon filling are
+//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
+//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
+//see http://glprogramming.com/red/chapter11.html
+enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
+
+typedef signed long long long64;
+typedef unsigned long long ulong64;
+
+struct IntPoint {
+public:
+  long64 X;
+  long64 Y;
+  IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {};
+  friend std::ostream& operator <<(std::ostream &s, IntPoint &p);
+};
+
+typedef std::vector< IntPoint > Polygon;
+typedef std::vector< Polygon > Polygons;
+
+std::ostream& operator <<(std::ostream &s, Polygon &p);
+std::ostream& operator <<(std::ostream &s, Polygons &p);
+
+struct ExPolygon {
+  Polygon  outer;
+  Polygons holes;
+};
+typedef std::vector< ExPolygon > ExPolygons;
+
+enum JoinType { jtSquare, jtRound, jtMiter };
+
+bool Orientation(const Polygon &poly);
+double Area(const Polygon &poly);
+void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
+  double delta, JoinType jointype = jtSquare, double MiterLimit = 2);
+void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
+void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
+void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd);
+
+void ReversePolygon(Polygon& p);
+void ReversePolygons(Polygons& p);
+
+//used internally ...
+enum EdgeSide { esNeither = 0, esLeft = 1, esRight = 2, esBoth = 3 };
+enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
+
+struct TEdge {
+  long64 xbot;
+  long64 ybot;
+  long64 xcurr;
+  long64 ycurr;
+  long64 xtop;
+  long64 ytop;
+  double dx;
+  long64 tmpX;
+  PolyType polyType;
+  EdgeSide side;
+  int windDelta; //1 or -1 depending on winding direction
+  int windCnt;
+  int windCnt2; //winding count of the opposite polytype
+  int outIdx;
+  TEdge *next;
+  TEdge *prev;
+  TEdge *nextInLML;
+  TEdge *nextInAEL;
+  TEdge *prevInAEL;
+  TEdge *nextInSEL;
+  TEdge *prevInSEL;
+};
+
+struct IntersectNode {
+  TEdge          *edge1;
+  TEdge          *edge2;
+  IntPoint        pt;
+  IntersectNode  *next;
+};
+
+struct LocalMinima {
+  long64        Y;
+  TEdge        *leftBound;
+  TEdge        *rightBound;
+  LocalMinima  *next;
+};
+
+struct Scanbeam {
+  long64    Y;
+  Scanbeam *next;
+};
+
+struct OutPt; //forward declaration
+
+struct OutRec {
+  int     idx;
+  bool    isHole;
+  OutRec *FirstLeft;
+  OutRec *AppendLink;
+  OutPt  *pts;
+  OutPt  *bottomPt;
+  OutPt  *bottomFlag;
+  EdgeSide sides;
+};
+
+struct OutPt {
+  int     idx;
+  IntPoint pt;
+  OutPt   *next;
+  OutPt   *prev;
+};
+
+struct JoinRec {
+  IntPoint  pt1a;
+  IntPoint  pt1b;
+  int       poly1Idx;
+  IntPoint  pt2a;
+  IntPoint  pt2b;
+  int       poly2Idx;
+};
+
+struct HorzJoinRec {
+  TEdge    *edge;
+  int       savedIdx;
+};
+
+struct IntRect { long64 left; long64 top; long64 right; long64 bottom; };
+
+typedef std::vector < OutRec* > PolyOutList;
+typedef std::vector < TEdge* > EdgeList;
+typedef std::vector < JoinRec* > JoinList;
+typedef std::vector < HorzJoinRec* > HorzJoinList;
+
+//ClipperBase is the ancestor to the Clipper class. It should not be
+//instantiated directly. This class simply abstracts the conversion of sets of
+//polygon coordinates into edge objects that are stored in a LocalMinima list.
+class ClipperBase
+{
+public:
+  ClipperBase();
+  virtual ~ClipperBase();
+  bool AddPolygon(const Polygon &pg, PolyType polyType);
+  bool AddPolygons( const Polygons &ppg, PolyType polyType);
+  virtual void Clear();
+  IntRect GetBounds();
+protected:
+  void DisposeLocalMinimaList();
+  TEdge* AddBoundsToLML(TEdge *e);
+  void PopLocalMinima();
+  virtual void Reset();
+  void InsertLocalMinima(LocalMinima *newLm);
+  LocalMinima      *m_CurrentLM;
+  LocalMinima      *m_MinimaList;
+  bool              m_UseFullRange;
+  EdgeList          m_edges;
+};
+
+class Clipper : public virtual ClipperBase
+{
+public:
+  Clipper();
+  ~Clipper();
+  bool Execute(ClipType clipType,
+  Polygons &solution,
+  PolyFillType subjFillType = pftEvenOdd,
+  PolyFillType clipFillType = pftEvenOdd);
+  bool Execute(ClipType clipType,
+  ExPolygons &solution,
+  PolyFillType subjFillType = pftEvenOdd,
+  PolyFillType clipFillType = pftEvenOdd);
+  void Clear();
+  bool ReverseSolution() {return m_ReverseOutput;};
+  void ReverseSolution(bool value) {m_ReverseOutput = value;};
+protected:
+  void Reset();
+  virtual bool ExecuteInternal(bool fixHoleLinkages);
+private:
+  PolyOutList       m_PolyOuts;
+  JoinList          m_Joins;
+  HorzJoinList      m_HorizJoins;
+  ClipType          m_ClipType;
+  Scanbeam         *m_Scanbeam;
+  TEdge           *m_ActiveEdges;
+  TEdge           *m_SortedEdges;
+  IntersectNode    *m_IntersectNodes;
+  bool              m_ExecuteLocked;
+  PolyFillType      m_ClipFillType;
+  PolyFillType      m_SubjFillType;
+  bool              m_ReverseOutput;
+  void DisposeScanbeamList();
+  void SetWindingCount(TEdge& edge);
+  bool IsEvenOddFillType(const TEdge& edge) const;
+  bool IsEvenOddAltFillType(const TEdge& edge) const;
+  void InsertScanbeam(const long64 Y);
+  long64 PopScanbeam();
+  void InsertLocalMinimaIntoAEL(const long64 botY);
+  void InsertEdgeIntoAEL(TEdge *edge);
+  void AddEdgeToSEL(TEdge *edge);
+  void CopyAELToSEL();
+  void DeleteFromSEL(TEdge *e);
+  void DeleteFromAEL(TEdge *e);
+  void UpdateEdgeIntoAEL(TEdge *&e);
+  void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
+  bool IsContributing(const TEdge& edge) const;
+  bool IsTopHorz(const long64 XPos);
+  void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
+  void DoMaxima(TEdge *e, long64 topY);
+  void ProcessHorizontals();
+  void ProcessHorizontal(TEdge *horzEdge);
+  void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
+  void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
+  void AppendPolygon(TEdge *e1, TEdge *e2);
+  void DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
+  void DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
+  void DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
+  void IntersectEdges(TEdge *e1, TEdge *e2,
+    const IntPoint &pt, IntersectProtects protects);
+  OutRec* CreateOutRec();
+  void AddOutPt(TEdge *e, const IntPoint &pt);
+  void DisposeBottomPt(OutRec &outRec);
+  void DisposeAllPolyPts();
+  void DisposeOutRec(PolyOutList::size_type index);
+  bool ProcessIntersections(const long64 botY, const long64 topY);
+  void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
+  void BuildIntersectList(const long64 botY, const long64 topY);
+  void ProcessIntersectList();
+  void ProcessEdgesAtTopOfScanbeam(const long64 topY);
+  void BuildResult(Polygons& polys);
+  void BuildResultEx(ExPolygons& polys);
+  void SetHoleState(TEdge *e, OutRec *OutRec);
+  void DisposeIntersectNodes();
+  bool FixupIntersections();
+  void FixupOutPolygon(OutRec &outRec);
+  bool IsHole(TEdge *e);
+  void FixHoleLinkage(OutRec *outRec);
+  void CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2);
+  void CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2);
+  void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1);
+  void ClearJoins();
+  void AddHorzJoin(TEdge *e, int idx);
+  void ClearHorzJoins();
+  void JoinCommonEdges(bool fixHoleLinkages);
+};
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+class clipperException : public std::exception
+{
+  public:
+    clipperException(const char* description): m_descr(description) {}
+    virtual ~clipperException() throw() {}
+    virtual const char* what() const throw() {return m_descr.c_str();}
+  private:
+    std::string m_descr;
+};
+//------------------------------------------------------------------------------
+
+} //ClipperLib namespace
+
+#endif //clipper_hpp
+
+

+ 8 - 0
Source/ThirdParty/Assimp/contrib/cppunit_note.txt

@@ -0,0 +1,8 @@
+This is a "slim" version of CPPunit. It contains everything we need, but nothing more.
+
+- Tools have been removed
+- x64-Build configs have been added
+- VC6 build & headers have been removed (Assimp can't be compiled with vc6)
+- vc9 solution has been added, vc8 solution uses Assimp 'FastSTL' settings
+
+--- Alex

+ 809 - 809
Source/ThirdParty/Assimp/contrib/irrXML/CXMLReaderImpl.h

@@ -1,809 +1,809 @@
-// Copyright (C) 2002-2005 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine" and the "irrXML" project.
-// For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h
-
-#ifndef __ICXML_READER_IMPL_H_INCLUDED__
-#define __ICXML_READER_IMPL_H_INCLUDED__
-
-#include "irrXML.h"
-#include "irrString.h"
-#include "irrArray.h"
-
-using namespace Assimp;
-
-#ifdef _DEBUG
-#define IRR_DEBUGPRINT(x) printf((x));
-#else // _DEBUG 
-#define IRR_DEBUGPRINT(x)
-#endif // _DEBUG
-
-
-namespace irr
-{
-namespace io
-{
-
-
-//! implementation of the IrrXMLReader
-template<class char_type, class superclass>
-class CXMLReaderImpl : public IIrrXMLReader<char_type, superclass>
-{
-public:
-
-	//! Constructor
-	CXMLReaderImpl(IFileReadCallBack* callback, bool deleteCallBack = true)
-		: TextData(0), P(0), TextBegin(0), TextSize(0), CurrentNodeType(EXN_NONE),
-		SourceFormat(ETF_ASCII), TargetFormat(ETF_ASCII)
-	{
-		if (!callback)
-			return;
-
-		storeTargetFormat();
-
-		// read whole xml file
-
-		readFile(callback);
-		
-		// clean up
-
-		if (deleteCallBack)
-			delete callback;
-
-		// create list with special characters
-
-		createSpecialCharacterList();
-
-		// set pointer to text begin
-		P = TextBegin;
-	}
-    	
-
-	//! Destructor
-	virtual ~CXMLReaderImpl()
-	{
-		delete [] TextData;
-	}
-
-
-	//! Reads forward to the next xml node. 
-	//! \return Returns false, if there was no further node. 
-	virtual bool read()
-	{
-		// if not end reached, parse the node
-		if (P && (unsigned int)(P - TextBegin) < TextSize - 1 && *P != 0)
-		{
-			parseCurrentNode();
-			return true;
-		}
-
-		_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
-		return false;
-	}
-
-
-	//! Returns the type of the current XML node.
-	virtual EXML_NODE getNodeType() const
-	{
-		return CurrentNodeType;
-	}
-
-
-	//! Returns attribute count of the current XML node.
-	virtual int getAttributeCount() const
-	{
-		return Attributes.size();
-	}
-
-
-	//! Returns name of an attribute.
-	virtual const char_type* getAttributeName(int idx) const
-	{
-		if (idx < 0 || idx >= (int)Attributes.size())
-			return 0;
-
-		return Attributes[idx].Name.c_str();
-	}
-
-
-	//! Returns the value of an attribute. 
-	virtual const char_type* getAttributeValue(int idx) const
-	{
-		if (idx < 0 || idx >= (int)Attributes.size())
-			return 0;
-
-		return Attributes[idx].Value.c_str();
-	}
-
-
-	//! Returns the value of an attribute. 
-	virtual const char_type* getAttributeValue(const char_type* name) const
-	{
-		const SAttribute* attr = getAttributeByName(name);
-		if (!attr)
-			return 0;
-
-		return attr->Value.c_str();
-	}
-
-
-	//! Returns the value of an attribute
-	virtual const char_type* getAttributeValueSafe(const char_type* name) const
-	{
-		const SAttribute* attr = getAttributeByName(name);
-		if (!attr)
-			return EmptyString.c_str();
-
-		return attr->Value.c_str();
-	}
-
-
-
-	//! Returns the value of an attribute as integer. 
-	int getAttributeValueAsInt(const char_type* name) const
-	{
-		return (int)getAttributeValueAsFloat(name);
-	}
-
-
-	//! Returns the value of an attribute as integer. 
-	int getAttributeValueAsInt(int idx) const
-	{
-		return (int)getAttributeValueAsFloat(idx);
-	}
-
-
-	//! Returns the value of an attribute as float. 
-	float getAttributeValueAsFloat(const char_type* name) const
-	{
-		const SAttribute* attr = getAttributeByName(name);
-		if (!attr)
-			return 0;
-
-		core::stringc c = attr->Value.c_str();
-		return fast_atof(c.c_str());
-	}
-
-
-	//! Returns the value of an attribute as float. 
-	float getAttributeValueAsFloat(int idx) const
-	{
-		const char_type* attrvalue = getAttributeValue(idx);
-		if (!attrvalue)
-			return 0;
-
-		core::stringc c = attrvalue;
-		return fast_atof(c.c_str());
-	}
-
-
-	//! Returns the name of the current node.
-	virtual const char_type* getNodeName() const
-	{
-		return NodeName.c_str();
-	}
-
-
-	//! Returns data of the current node.
-	virtual const char_type* getNodeData() const
-	{
-		return NodeName.c_str();
-	}
-
-
-	//! Returns if an element is an empty element, like <foo />
-	virtual bool isEmptyElement() const
-	{
-		return IsEmptyElement;
-	}
-
-	//! Returns format of the source xml file.
-	virtual ETEXT_FORMAT getSourceFormat() const
-	{
-		return SourceFormat;
-	}
-
-	//! Returns format of the strings returned by the parser.
-	virtual ETEXT_FORMAT getParserFormat() const
-	{
-		return TargetFormat;
-	}
-
-private:
-
-	// Reads the current xml node
-	void parseCurrentNode()
-	{
-		char_type* start = P;
-
-		// move forward until '<' found
-		while(*P != L'<' && *P)
-			++P;
-
-		if (!*P)
-			return;
-
-		if (P - start > 0)
-		{
-			// we found some text, store it
-			if (setText(start, P))
-				return;
-		}
-
-		++P;
-
-		// based on current token, parse and report next element
-		switch(*P)
-		{
-		case L'/':
-			parseClosingXMLElement(); 
-			break;
-		case L'?':
-			ignoreDefinition();	
-			break;
-		case L'!':
-			if (!parseCDATA())
-				parseComment();	
-			break;
-		default:
-			parseOpeningXMLElement();
-			break;
-		}
-	}
-
-
-	//! sets the state that text was found. Returns true if set should be set
-	bool setText(char_type* start, char_type* end)
-	{
-		// check if text is more than 2 characters, and if not, check if there is 
-		// only white space, so that this text won't be reported
-		if (end - start < 3)
-		{
-			char_type* p = start;
-			for(; p != end; ++p)
-				if (!isWhiteSpace(*p))
-					break;
-
-			if (p == end)
-				return false;
-		}
-
-		// set current text to the parsed text, and replace xml special characters
-		core::string<char_type> s(start, (int)(end - start));
-		NodeName = replaceSpecialCharacters(s);
-
-		// current XML node type is text
-		CurrentNodeType = EXN_TEXT;
-
-		return true;
-	}
-
-
-
-	//! ignores an xml definition like <?xml something />
-	void ignoreDefinition()
-	{
-		CurrentNodeType = EXN_UNKNOWN;
-
-		// move until end marked with '>' reached
-		while(*P != L'>')
-			++P;
-
-		++P;
-	}
-
-
-	//! parses a comment
-	void parseComment()
-	{
-		CurrentNodeType = EXN_COMMENT;
-		P += 1;
-
-		char_type *pCommentBegin = P;
-
-		int count = 1;
-
-		// move until end of comment reached
-		while(count)
-		{
-			if (*P == L'>')
-				--count;
-			else
-			if (*P == L'<')
-				++count;
-
-			++P;
-		}
-
-		P -= 3;
-		NodeName = core::string<char_type>(pCommentBegin+2, (int)(P - pCommentBegin-2));
-		P += 3;
-	}
-
-
-	//! parses an opening xml element and reads attributes
-	void parseOpeningXMLElement()
-	{
-		CurrentNodeType = EXN_ELEMENT;
-		IsEmptyElement = false;
-		Attributes.clear();
-
-		// find name
-		const char_type* startName = P;
-
-		// find end of element
-		while(*P != L'>' && !isWhiteSpace(*P))
-			++P;
-
-		const char_type* endName = P;
-
-		// find Attributes
-		while(*P != L'>')
-		{
-			if (isWhiteSpace(*P))
-				++P;
-			else
-			{
-				if (*P != L'/')
-				{
-					// we've got an attribute
-
-					// read the attribute names
-					const char_type* attributeNameBegin = P;
-
-					while(!isWhiteSpace(*P) && *P != L'=')
-						++P;
-
-					const char_type* attributeNameEnd = P;
-					++P;
-
-					// read the attribute value
-					// check for quotes and single quotes, thx to murphy
-					while( (*P != L'\"') && (*P != L'\'') && *P) 
-						++P;
-
-					if (!*P) // malformatted xml file
-						return;
-
-					const char_type attributeQuoteChar = *P;
-
-					++P;
-					const char_type* attributeValueBegin = P;
-					
-					while(*P != attributeQuoteChar && *P)
-						++P;
-
-					if (!*P) // malformatted xml file
-						return;
-
-					const char_type* attributeValueEnd = P;
-					++P;
-
-					SAttribute attr;
-					attr.Name = core::string<char_type>(attributeNameBegin, 
-						(int)(attributeNameEnd - attributeNameBegin));
-
-					core::string<char_type> s(attributeValueBegin, 
-						(int)(attributeValueEnd - attributeValueBegin));
-
-					attr.Value = replaceSpecialCharacters(s);
-					Attributes.push_back(attr);
-				}
-				else
-				{
-					// tag is closed directly
-					++P;
-					IsEmptyElement = true;
-					break;
-				}
-			}
-		}
-
-		// check if this tag is closing directly
-		if (endName > startName && *(endName-1) == L'/')
-		{
-			// directly closing tag
-			IsEmptyElement = true;
-			endName--;
-		}
-		
-		NodeName = core::string<char_type>(startName, (int)(endName - startName));
-
-		++P;
-	}
-
-
-	//! parses an closing xml tag
-	void parseClosingXMLElement()
-	{
-		CurrentNodeType = EXN_ELEMENT_END;
-		IsEmptyElement = false;
-		Attributes.clear();
-
-		++P;
-		const char_type* pBeginClose = P;
-
-		while(*P != L'>')
-			++P;
-
-    // remove trailing whitespace, if any
-    while( isspace( P[-1]))
-      --P;
-
-		NodeName = core::string<char_type>(pBeginClose, (int)(P - pBeginClose));
-		++P;
-	}
-
-	//! parses a possible CDATA section, returns false if begin was not a CDATA section
-	bool parseCDATA()
-	{
-		if (*(P+1) != L'[')
-			return false;
-
-		CurrentNodeType = EXN_CDATA;
-
-		// skip '<![CDATA['
-		int count=0;
-		while( *P && count<8 )
-		{
-			++P;
-			++count;
-		}
-
-		if (!*P)
-			return true;
-
-		char_type *cDataBegin = P;
-		char_type *cDataEnd = 0;
-
-		// find end of CDATA
-		while(*P && !cDataEnd)
-		{
-			if (*P == L'>' && 
-			   (*(P-1) == L']') &&
-			   (*(P-2) == L']'))
-			{
-				cDataEnd = P - 2;
-			}
-
-			++P;
-		}
-
-		if ( cDataEnd )
-			NodeName = core::string<char_type>(cDataBegin, (int)(cDataEnd - cDataBegin));
-		else
-			NodeName = "";
-
-		return true;
-	}
-
-
-	// structure for storing attribute-name pairs
-	struct SAttribute
-	{
-		core::string<char_type> Name;
-		core::string<char_type> Value;
-	};
-
-	// finds a current attribute by name, returns 0 if not found
-	const SAttribute* getAttributeByName(const char_type* name) const
-	{
-		if (!name)
-			return 0;
-
-		core::string<char_type> n = name;
-
-		for (int i=0; i<(int)Attributes.size(); ++i)
-			if (Attributes[i].Name == n)
-				return &Attributes[i];
-
-		return 0;
-	}
-
-	// replaces xml special characters in a string and creates a new one
-	core::string<char_type> replaceSpecialCharacters(
-		core::string<char_type>& origstr)
-	{
-		int pos = origstr.findFirst(L'&');
-		int oldPos = 0;
-
-		if (pos == -1)
-			return origstr;
-
-		core::string<char_type> newstr;
-
-		while(pos != -1 && pos < origstr.size()-2)
-		{
-			// check if it is one of the special characters
-
-			int specialChar = -1;
-			for (int i=0; i<(int)SpecialCharacters.size(); ++i)
-			{
-				const char_type* p = &origstr.c_str()[pos]+1;
-
-				if (equalsn(&SpecialCharacters[i][1], p, SpecialCharacters[i].size()-1))
-				{
-					specialChar = i;
-					break;
-				}
-			}
-
-			if (specialChar != -1)
-			{
-				newstr.append(origstr.subString(oldPos, pos - oldPos));
-				newstr.append(SpecialCharacters[specialChar][0]);
-				pos += SpecialCharacters[specialChar].size();
-			}
-			else
-			{
-				newstr.append(origstr.subString(oldPos, pos - oldPos + 1));
-				pos += 1;
-			}
-
-			// find next &
-			oldPos = pos;
-			pos = origstr.findNext(L'&', pos);		
-		}
-
-		if (oldPos < origstr.size()-1)
-			newstr.append(origstr.subString(oldPos, origstr.size()-oldPos));
-
-		return newstr;
-	}
-
-
-
-	//! reads the xml file and converts it into the wanted character format.
-	bool readFile(IFileReadCallBack* callback)
-	{
-		int size = callback->getSize();		
-		size += 4; // We need two terminating 0's at the end.
-		           // For ASCII we need 1 0's, for UTF-16 2, for UTF-32 4.
-
-		char* data8 = new char[size];
-
-		if (!callback->read(data8, size-4))
-		{
-			delete [] data8;
-			return false;
-		}
-
-		// add zeros at end
-
-		data8[size-1] = 0;
-		data8[size-2] = 0;
-		data8[size-3] = 0;
-		data8[size-4] = 0;
-
-		char16* data16 = reinterpret_cast<char16*>(data8);
-		char32* data32 = reinterpret_cast<char32*>(data8);	
-
-		// now we need to convert the data to the desired target format
-		// based on the byte order mark.
-
-		const unsigned char UTF8[] = {0xEF, 0xBB, 0xBF}; // 0xEFBBBF;
-		const int UTF16_BE = 0xFFFE;
-		const int UTF16_LE = 0xFEFF;
-		const int UTF32_BE = 0xFFFE0000;
-		const int UTF32_LE = 0x0000FEFF;
-
-		// check source for all utf versions and convert to target data format
-		
-		if (size >= 4 && data32[0] == (char32)UTF32_BE)
-		{
-			// UTF-32, big endian
-			SourceFormat = ETF_UTF32_BE;
-			convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header
-		}
-		else
-		if (size >= 4 && data32[0] == (char32)UTF32_LE)
-		{
-			// UTF-32, little endian
-			SourceFormat = ETF_UTF32_LE;
-			convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header
-		}
-		else
-		if (size >= 2 && data16[0] == UTF16_BE)
-		{
-			// UTF-16, big endian
-			SourceFormat = ETF_UTF16_BE;
-			convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header
-		}
-		else
-		if (size >= 2 && data16[0] == UTF16_LE)
-		{
-			// UTF-16, little endian
-			SourceFormat = ETF_UTF16_LE;
-			convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header
-		}
-		else
-		if (size >= 3 && data8[0] == UTF8[0] && data8[1] == UTF8[1] && data8[2] == UTF8[2])
-		{
-			// UTF-8
-			SourceFormat = ETF_UTF8;
-			convertTextData(data8+3, data8, size); // data8+3 because we need to skip the header
-		}
-		else
-		{
-			// ASCII
-			SourceFormat = ETF_ASCII;
-			convertTextData(data8, data8, size);
-		}
-
-		return true;
-	}
-
-
-	//! converts the text file into the desired format.
-	//! \param source: begin of the text (without byte order mark)
-	//! \param pointerToStore: pointer to text data block which can be
-	//! stored or deleted based on the nesessary conversion.
-	//! \param sizeWithoutHeader: Text size in characters without header
-	template<class src_char_type>
-	void convertTextData(src_char_type* source, char* pointerToStore, int sizeWithoutHeader)
-	{
-		// convert little to big endian if necessary
-		if (sizeof(src_char_type) > 1 && 
-			isLittleEndian(TargetFormat) != isLittleEndian(SourceFormat))
-			convertToLittleEndian(source);
-
-		// check if conversion is necessary:
-		if (sizeof(src_char_type) == sizeof(char_type))
-		{
-			// no need to convert
-			TextBegin = (char_type*)source;
-			TextData = (char_type*)pointerToStore;
-			TextSize = sizeWithoutHeader;
-		}
-		else
-		{
-			// convert source into target data format. 
-			// TODO: implement a real conversion. This one just 
-			// copies bytes. This is a problem when there are 
-			// unicode symbols using more than one character.
-
-			TextData = new char_type[sizeWithoutHeader];
-
-			// MSVC debugger complains here about loss of data ...
-
-
-			// FIXME - gcc complains about 'shift width larger than width of type'
-			// for T == unsigned long. Avoid it by messing around volatile ..
-			volatile unsigned int c = 3;
-			const src_char_type cc = (src_char_type)((((uint64_t)1u << (sizeof( char_type)<<c)) - 1));
-			for (int i=0; i<sizeWithoutHeader; ++i)
-				TextData[i] = char_type( source[i] & cc); 
-
-			TextBegin = TextData;
-			TextSize = sizeWithoutHeader;
-
-			// delete original data because no longer needed
-			delete [] pointerToStore;
-		}
-	}
-
-	//! converts whole text buffer to little endian
-	template<class src_char_type>
-	void convertToLittleEndian(src_char_type* t)
-	{
-		if (sizeof(src_char_type) == 4) 
-		{
-			// 32 bit
-
-			while(*t)
-			{
-				*t = ((*t & 0xff000000) >> 24) |
-				     ((*t & 0x00ff0000) >> 8)  |
-				     ((*t & 0x0000ff00) << 8)  |
-				     ((*t & 0x000000ff) << 24);
-				++t;
-			}
-		}
-		else
-		{
-			// 16 bit 
-
-			while(*t)
-			{
-				*t = (*t >> 8) | (*t << 8);
-				++t;
-			}
-		}
-	}
-
-	//! returns if a format is little endian
-	inline bool isLittleEndian(ETEXT_FORMAT f)
-	{
-		return f == ETF_ASCII ||
-		       f == ETF_UTF8 ||
-		       f == ETF_UTF16_LE ||
-		       f == ETF_UTF32_LE;
-	}
-
-
-	//! returns true if a character is whitespace
-	inline bool isWhiteSpace(char_type c)
-	{
-		return (c==' ' || c=='\t' || c=='\n' || c=='\r');
-	}
-
-
-	//! generates a list with xml special characters
-	void createSpecialCharacterList()
-	{
-		// list of strings containing special symbols, 
-		// the first character is the special character,
-		// the following is the symbol string without trailing &.
-
-		SpecialCharacters.push_back("&amp;");
-		SpecialCharacters.push_back("<lt;");
-		SpecialCharacters.push_back(">gt;");
-		SpecialCharacters.push_back("\"quot;");
-		SpecialCharacters.push_back("'apos;");
-		
-	}
-
-
-	//! compares the first n characters of the strings
-	bool equalsn(const char_type* str1, const char_type* str2, int len)
-	{
-		int i;
-		for(i=0; str1[i] && str2[i] && i < len; ++i)
-			if (str1[i] != str2[i])
-				return false;
-
-		// if one (or both) of the strings was smaller then they
-		// are only equal if they have the same lenght
-		return (i == len) || (str1[i] == 0 && str2[i] == 0);
-	}
-
-
-	//! stores the target text format
-	void storeTargetFormat()
-	{
-		// get target format. We could have done this using template specialization,
-		// but VisualStudio 6 don't like it and we want to support it.
-
-		switch(sizeof(char_type))
-		{
-		case 1: 
-			TargetFormat = ETF_UTF8;
-			break;
-		case 2: 
-			TargetFormat = ETF_UTF16_LE;
-			break;
-		case 4: 
-			TargetFormat = ETF_UTF32_LE;
-			break;
-		default:
-			TargetFormat = ETF_ASCII; // should never happen.
-		}
-	}
-
-
-	// instance variables:
-
-	char_type* TextData;         // data block of the text file
-	char_type* P;                // current point in text to parse
-	char_type* TextBegin;        // start of text to parse
-	unsigned int TextSize;       // size of text to parse in characters, not bytes
-
-	EXML_NODE CurrentNodeType;   // type of the currently parsed node
-	ETEXT_FORMAT SourceFormat;   // source format of the xml file
-	ETEXT_FORMAT TargetFormat;   // output format of this parser
-
-	core::string<char_type> NodeName;    // name of the node currently in
-	core::string<char_type> EmptyString; // empty string to be returned by getSafe() methods
-
-	bool IsEmptyElement;       // is the currently parsed node empty?
-
-	core::array< core::string<char_type> > SpecialCharacters; // see createSpecialCharacterList()
-
-	core::array<SAttribute> Attributes; // attributes of current element
-	
-}; // end CXMLReaderImpl
-
-
-} // end namespace
-} // end namespace
-
-#endif
+// Copyright (C) 2002-2005 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine" and the "irrXML" project.
+// For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h
+
+#ifndef __ICXML_READER_IMPL_H_INCLUDED__
+#define __ICXML_READER_IMPL_H_INCLUDED__
+
+#include "irrXML.h"
+#include "irrString.h"
+#include "irrArray.h"
+
+using namespace Assimp;
+
+#ifdef _DEBUG
+#define IRR_DEBUGPRINT(x) printf((x));
+#else // _DEBUG 
+#define IRR_DEBUGPRINT(x)
+#endif // _DEBUG
+
+
+namespace irr
+{
+namespace io
+{
+
+
+//! implementation of the IrrXMLReader
+template<class char_type, class superclass>
+class CXMLReaderImpl : public IIrrXMLReader<char_type, superclass>
+{
+public:
+
+	//! Constructor
+	CXMLReaderImpl(IFileReadCallBack* callback, bool deleteCallBack = true)
+		: TextData(0), P(0), TextBegin(0), TextSize(0), CurrentNodeType(EXN_NONE),
+		SourceFormat(ETF_ASCII), TargetFormat(ETF_ASCII)
+	{
+		if (!callback)
+			return;
+
+		storeTargetFormat();
+
+		// read whole xml file
+
+		readFile(callback);
+		
+		// clean up
+
+		if (deleteCallBack)
+			delete callback;
+
+		// create list with special characters
+
+		createSpecialCharacterList();
+
+		// set pointer to text begin
+		P = TextBegin;
+	}
+    	
+
+	//! Destructor
+	virtual ~CXMLReaderImpl()
+	{
+		delete [] TextData;
+	}
+
+
+	//! Reads forward to the next xml node. 
+	//! \return Returns false, if there was no further node. 
+	virtual bool read()
+	{
+		// if not end reached, parse the node
+		if (P && (unsigned int)(P - TextBegin) < TextSize - 1 && *P != 0)
+		{
+			parseCurrentNode();
+			return true;
+		}
+
+		_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+		return false;
+	}
+
+
+	//! Returns the type of the current XML node.
+	virtual EXML_NODE getNodeType() const
+	{
+		return CurrentNodeType;
+	}
+
+
+	//! Returns attribute count of the current XML node.
+	virtual int getAttributeCount() const
+	{
+		return Attributes.size();
+	}
+
+
+	//! Returns name of an attribute.
+	virtual const char_type* getAttributeName(int idx) const
+	{
+		if (idx < 0 || idx >= (int)Attributes.size())
+			return 0;
+
+		return Attributes[idx].Name.c_str();
+	}
+
+
+	//! Returns the value of an attribute. 
+	virtual const char_type* getAttributeValue(int idx) const
+	{
+		if (idx < 0 || idx >= (int)Attributes.size())
+			return 0;
+
+		return Attributes[idx].Value.c_str();
+	}
+
+
+	//! Returns the value of an attribute. 
+	virtual const char_type* getAttributeValue(const char_type* name) const
+	{
+		const SAttribute* attr = getAttributeByName(name);
+		if (!attr)
+			return 0;
+
+		return attr->Value.c_str();
+	}
+
+
+	//! Returns the value of an attribute
+	virtual const char_type* getAttributeValueSafe(const char_type* name) const
+	{
+		const SAttribute* attr = getAttributeByName(name);
+		if (!attr)
+			return EmptyString.c_str();
+
+		return attr->Value.c_str();
+	}
+
+
+
+	//! Returns the value of an attribute as integer. 
+	int getAttributeValueAsInt(const char_type* name) const
+	{
+		return (int)getAttributeValueAsFloat(name);
+	}
+
+
+	//! Returns the value of an attribute as integer. 
+	int getAttributeValueAsInt(int idx) const
+	{
+		return (int)getAttributeValueAsFloat(idx);
+	}
+
+
+	//! Returns the value of an attribute as float. 
+	float getAttributeValueAsFloat(const char_type* name) const
+	{
+		const SAttribute* attr = getAttributeByName(name);
+		if (!attr)
+			return 0;
+
+		core::stringc c = attr->Value.c_str();
+		return fast_atof(c.c_str());
+	}
+
+
+	//! Returns the value of an attribute as float. 
+	float getAttributeValueAsFloat(int idx) const
+	{
+		const char_type* attrvalue = getAttributeValue(idx);
+		if (!attrvalue)
+			return 0;
+
+		core::stringc c = attrvalue;
+		return fast_atof(c.c_str());
+	}
+
+
+	//! Returns the name of the current node.
+	virtual const char_type* getNodeName() const
+	{
+		return NodeName.c_str();
+	}
+
+
+	//! Returns data of the current node.
+	virtual const char_type* getNodeData() const
+	{
+		return NodeName.c_str();
+	}
+
+
+	//! Returns if an element is an empty element, like <foo />
+	virtual bool isEmptyElement() const
+	{
+		return IsEmptyElement;
+	}
+
+	//! Returns format of the source xml file.
+	virtual ETEXT_FORMAT getSourceFormat() const
+	{
+		return SourceFormat;
+	}
+
+	//! Returns format of the strings returned by the parser.
+	virtual ETEXT_FORMAT getParserFormat() const
+	{
+		return TargetFormat;
+	}
+
+private:
+
+	// Reads the current xml node
+	void parseCurrentNode()
+	{
+		char_type* start = P;
+
+		// move forward until '<' found
+		while(*P != L'<' && *P)
+			++P;
+
+		if (!*P)
+			return;
+
+		if (P - start > 0)
+		{
+			// we found some text, store it
+			if (setText(start, P))
+				return;
+		}
+
+		++P;
+
+		// based on current token, parse and report next element
+		switch(*P)
+		{
+		case L'/':
+			parseClosingXMLElement(); 
+			break;
+		case L'?':
+			ignoreDefinition();	
+			break;
+		case L'!':
+			if (!parseCDATA())
+				parseComment();	
+			break;
+		default:
+			parseOpeningXMLElement();
+			break;
+		}
+	}
+
+
+	//! sets the state that text was found. Returns true if set should be set
+	bool setText(char_type* start, char_type* end)
+	{
+		// check if text is more than 2 characters, and if not, check if there is 
+		// only white space, so that this text won't be reported
+		if (end - start < 3)
+		{
+			char_type* p = start;
+			for(; p != end; ++p)
+				if (!isWhiteSpace(*p))
+					break;
+
+			if (p == end)
+				return false;
+		}
+
+		// set current text to the parsed text, and replace xml special characters
+		core::string<char_type> s(start, (int)(end - start));
+		NodeName = replaceSpecialCharacters(s);
+
+		// current XML node type is text
+		CurrentNodeType = EXN_TEXT;
+
+		return true;
+	}
+
+
+
+	//! ignores an xml definition like <?xml something />
+	void ignoreDefinition()
+	{
+		CurrentNodeType = EXN_UNKNOWN;
+
+		// move until end marked with '>' reached
+		while(*P != L'>')
+			++P;
+
+		++P;
+	}
+
+
+	//! parses a comment
+	void parseComment()
+	{
+		CurrentNodeType = EXN_COMMENT;
+		P += 1;
+
+		char_type *pCommentBegin = P;
+
+		int count = 1;
+
+		// move until end of comment reached
+		while(count)
+		{
+			if (*P == L'>')
+				--count;
+			else
+			if (*P == L'<')
+				++count;
+
+			++P;
+		}
+
+		P -= 3;
+		NodeName = core::string<char_type>(pCommentBegin+2, (int)(P - pCommentBegin-2));
+		P += 3;
+	}
+
+
+	//! parses an opening xml element and reads attributes
+	void parseOpeningXMLElement()
+	{
+		CurrentNodeType = EXN_ELEMENT;
+		IsEmptyElement = false;
+		Attributes.clear();
+
+		// find name
+		const char_type* startName = P;
+
+		// find end of element
+		while(*P != L'>' && !isWhiteSpace(*P))
+			++P;
+
+		const char_type* endName = P;
+
+		// find Attributes
+		while(*P != L'>')
+		{
+			if (isWhiteSpace(*P))
+				++P;
+			else
+			{
+				if (*P != L'/')
+				{
+					// we've got an attribute
+
+					// read the attribute names
+					const char_type* attributeNameBegin = P;
+
+					while(!isWhiteSpace(*P) && *P != L'=')
+						++P;
+
+					const char_type* attributeNameEnd = P;
+					++P;
+
+					// read the attribute value
+					// check for quotes and single quotes, thx to murphy
+					while( (*P != L'\"') && (*P != L'\'') && *P) 
+						++P;
+
+					if (!*P) // malformatted xml file
+						return;
+
+					const char_type attributeQuoteChar = *P;
+
+					++P;
+					const char_type* attributeValueBegin = P;
+					
+					while(*P != attributeQuoteChar && *P)
+						++P;
+
+					if (!*P) // malformatted xml file
+						return;
+
+					const char_type* attributeValueEnd = P;
+					++P;
+
+					SAttribute attr;
+					attr.Name = core::string<char_type>(attributeNameBegin, 
+						(int)(attributeNameEnd - attributeNameBegin));
+
+					core::string<char_type> s(attributeValueBegin, 
+						(int)(attributeValueEnd - attributeValueBegin));
+
+					attr.Value = replaceSpecialCharacters(s);
+					Attributes.push_back(attr);
+				}
+				else
+				{
+					// tag is closed directly
+					++P;
+					IsEmptyElement = true;
+					break;
+				}
+			}
+		}
+
+		// check if this tag is closing directly
+		if (endName > startName && *(endName-1) == L'/')
+		{
+			// directly closing tag
+			IsEmptyElement = true;
+			endName--;
+		}
+		
+		NodeName = core::string<char_type>(startName, (int)(endName - startName));
+
+		++P;
+	}
+
+
+	//! parses an closing xml tag
+	void parseClosingXMLElement()
+	{
+		CurrentNodeType = EXN_ELEMENT_END;
+		IsEmptyElement = false;
+		Attributes.clear();
+
+		++P;
+		const char_type* pBeginClose = P;
+
+		while(*P != L'>')
+			++P;
+
+    // remove trailing whitespace, if any
+    while( isspace( P[-1]))
+      --P;
+
+		NodeName = core::string<char_type>(pBeginClose, (int)(P - pBeginClose));
+		++P;
+	}
+
+	//! parses a possible CDATA section, returns false if begin was not a CDATA section
+	bool parseCDATA()
+	{
+		if (*(P+1) != L'[')
+			return false;
+
+		CurrentNodeType = EXN_CDATA;
+
+		// skip '<![CDATA['
+		int count=0;
+		while( *P && count<8 )
+		{
+			++P;
+			++count;
+		}
+
+		if (!*P)
+			return true;
+
+		char_type *cDataBegin = P;
+		char_type *cDataEnd = 0;
+
+		// find end of CDATA
+		while(*P && !cDataEnd)
+		{
+			if (*P == L'>' && 
+			   (*(P-1) == L']') &&
+			   (*(P-2) == L']'))
+			{
+				cDataEnd = P - 2;
+			}
+
+			++P;
+		}
+
+		if ( cDataEnd )
+			NodeName = core::string<char_type>(cDataBegin, (int)(cDataEnd - cDataBegin));
+		else
+			NodeName = "";
+
+		return true;
+	}
+
+
+	// structure for storing attribute-name pairs
+	struct SAttribute
+	{
+		core::string<char_type> Name;
+		core::string<char_type> Value;
+	};
+
+	// finds a current attribute by name, returns 0 if not found
+	const SAttribute* getAttributeByName(const char_type* name) const
+	{
+		if (!name)
+			return 0;
+
+		core::string<char_type> n = name;
+
+		for (int i=0; i<(int)Attributes.size(); ++i)
+			if (Attributes[i].Name == n)
+				return &Attributes[i];
+
+		return 0;
+	}
+
+	// replaces xml special characters in a string and creates a new one
+	core::string<char_type> replaceSpecialCharacters(
+		core::string<char_type>& origstr)
+	{
+		int pos = origstr.findFirst(L'&');
+		int oldPos = 0;
+
+		if (pos == -1)
+			return origstr;
+
+		core::string<char_type> newstr;
+
+		while(pos != -1 && pos < origstr.size()-2)
+		{
+			// check if it is one of the special characters
+
+			int specialChar = -1;
+			for (int i=0; i<(int)SpecialCharacters.size(); ++i)
+			{
+				const char_type* p = &origstr.c_str()[pos]+1;
+
+				if (equalsn(&SpecialCharacters[i][1], p, SpecialCharacters[i].size()-1))
+				{
+					specialChar = i;
+					break;
+				}
+			}
+
+			if (specialChar != -1)
+			{
+				newstr.append(origstr.subString(oldPos, pos - oldPos));
+				newstr.append(SpecialCharacters[specialChar][0]);
+				pos += SpecialCharacters[specialChar].size();
+			}
+			else
+			{
+				newstr.append(origstr.subString(oldPos, pos - oldPos + 1));
+				pos += 1;
+			}
+
+			// find next &
+			oldPos = pos;
+			pos = origstr.findNext(L'&', pos);		
+		}
+
+		if (oldPos < origstr.size()-1)
+			newstr.append(origstr.subString(oldPos, origstr.size()-oldPos));
+
+		return newstr;
+	}
+
+
+
+	//! reads the xml file and converts it into the wanted character format.
+	bool readFile(IFileReadCallBack* callback)
+	{
+		int size = callback->getSize();		
+		size += 4; // We need two terminating 0's at the end.
+		           // For ASCII we need 1 0's, for UTF-16 2, for UTF-32 4.
+
+		char* data8 = new char[size];
+
+		if (!callback->read(data8, size-4))
+		{
+			delete [] data8;
+			return false;
+		}
+
+		// add zeros at end
+
+		data8[size-1] = 0;
+		data8[size-2] = 0;
+		data8[size-3] = 0;
+		data8[size-4] = 0;
+
+		char16* data16 = reinterpret_cast<char16*>(data8);
+		char32* data32 = reinterpret_cast<char32*>(data8);	
+
+		// now we need to convert the data to the desired target format
+		// based on the byte order mark.
+
+		const unsigned char UTF8[] = {0xEF, 0xBB, 0xBF}; // 0xEFBBBF;
+		const int UTF16_BE = 0xFFFE;
+		const int UTF16_LE = 0xFEFF;
+		const int UTF32_BE = 0xFFFE0000;
+		const int UTF32_LE = 0x0000FEFF;
+
+		// check source for all utf versions and convert to target data format
+		
+		if (size >= 4 && data32[0] == (char32)UTF32_BE)
+		{
+			// UTF-32, big endian
+			SourceFormat = ETF_UTF32_BE;
+			convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header
+		}
+		else
+		if (size >= 4 && data32[0] == (char32)UTF32_LE)
+		{
+			// UTF-32, little endian
+			SourceFormat = ETF_UTF32_LE;
+			convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header
+		}
+		else
+		if (size >= 2 && data16[0] == UTF16_BE)
+		{
+			// UTF-16, big endian
+			SourceFormat = ETF_UTF16_BE;
+			convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header
+		}
+		else
+		if (size >= 2 && data16[0] == UTF16_LE)
+		{
+			// UTF-16, little endian
+			SourceFormat = ETF_UTF16_LE;
+			convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header
+		}
+		else
+		if (size >= 3 && data8[0] == UTF8[0] && data8[1] == UTF8[1] && data8[2] == UTF8[2])
+		{
+			// UTF-8
+			SourceFormat = ETF_UTF8;
+			convertTextData(data8+3, data8, size); // data8+3 because we need to skip the header
+		}
+		else
+		{
+			// ASCII
+			SourceFormat = ETF_ASCII;
+			convertTextData(data8, data8, size);
+		}
+
+		return true;
+	}
+
+
+	//! converts the text file into the desired format.
+	//! \param source: begin of the text (without byte order mark)
+	//! \param pointerToStore: pointer to text data block which can be
+	//! stored or deleted based on the nesessary conversion.
+	//! \param sizeWithoutHeader: Text size in characters without header
+	template<class src_char_type>
+	void convertTextData(src_char_type* source, char* pointerToStore, int sizeWithoutHeader)
+	{
+		// convert little to big endian if necessary
+		if (sizeof(src_char_type) > 1 && 
+			isLittleEndian(TargetFormat) != isLittleEndian(SourceFormat))
+			convertToLittleEndian(source);
+
+		// check if conversion is necessary:
+		if (sizeof(src_char_type) == sizeof(char_type))
+		{
+			// no need to convert
+			TextBegin = (char_type*)source;
+			TextData = (char_type*)pointerToStore;
+			TextSize = sizeWithoutHeader;
+		}
+		else
+		{
+			// convert source into target data format. 
+			// TODO: implement a real conversion. This one just 
+			// copies bytes. This is a problem when there are 
+			// unicode symbols using more than one character.
+
+			TextData = new char_type[sizeWithoutHeader];
+
+			// MSVC debugger complains here about loss of data ...
+
+
+			// FIXME - gcc complains about 'shift width larger than width of type'
+			// for T == unsigned long. Avoid it by messing around volatile ..
+			volatile unsigned int c = 3;
+			const src_char_type cc = (src_char_type)((((uint64_t)1u << (sizeof( char_type)<<c)) - 1));
+			for (int i=0; i<sizeWithoutHeader; ++i)
+				TextData[i] = char_type( source[i] & cc); 
+
+			TextBegin = TextData;
+			TextSize = sizeWithoutHeader;
+
+			// delete original data because no longer needed
+			delete [] pointerToStore;
+		}
+	}
+
+	//! converts whole text buffer to little endian
+	template<class src_char_type>
+	void convertToLittleEndian(src_char_type* t)
+	{
+		if (sizeof(src_char_type) == 4) 
+		{
+			// 32 bit
+
+			while(*t)
+			{
+				*t = ((*t & 0xff000000) >> 24) |
+				     ((*t & 0x00ff0000) >> 8)  |
+				     ((*t & 0x0000ff00) << 8)  |
+				     ((*t & 0x000000ff) << 24);
+				++t;
+			}
+		}
+		else
+		{
+			// 16 bit 
+
+			while(*t)
+			{
+				*t = (*t >> 8) | (*t << 8);
+				++t;
+			}
+		}
+	}
+
+	//! returns if a format is little endian
+	inline bool isLittleEndian(ETEXT_FORMAT f)
+	{
+		return f == ETF_ASCII ||
+		       f == ETF_UTF8 ||
+		       f == ETF_UTF16_LE ||
+		       f == ETF_UTF32_LE;
+	}
+
+
+	//! returns true if a character is whitespace
+	inline bool isWhiteSpace(char_type c)
+	{
+		return (c==' ' || c=='\t' || c=='\n' || c=='\r');
+	}
+
+
+	//! generates a list with xml special characters
+	void createSpecialCharacterList()
+	{
+		// list of strings containing special symbols, 
+		// the first character is the special character,
+		// the following is the symbol string without trailing &.
+
+		SpecialCharacters.push_back("&amp;");
+		SpecialCharacters.push_back("<lt;");
+		SpecialCharacters.push_back(">gt;");
+		SpecialCharacters.push_back("\"quot;");
+		SpecialCharacters.push_back("'apos;");
+		
+	}
+
+
+	//! compares the first n characters of the strings
+	bool equalsn(const char_type* str1, const char_type* str2, int len)
+	{
+		int i;
+		for(i=0; str1[i] && str2[i] && i < len; ++i)
+			if (str1[i] != str2[i])
+				return false;
+
+		// if one (or both) of the strings was smaller then they
+		// are only equal if they have the same lenght
+		return (i == len) || (str1[i] == 0 && str2[i] == 0);
+	}
+
+
+	//! stores the target text format
+	void storeTargetFormat()
+	{
+		// get target format. We could have done this using template specialization,
+		// but VisualStudio 6 don't like it and we want to support it.
+
+		switch(sizeof(char_type))
+		{
+		case 1: 
+			TargetFormat = ETF_UTF8;
+			break;
+		case 2: 
+			TargetFormat = ETF_UTF16_LE;
+			break;
+		case 4: 
+			TargetFormat = ETF_UTF32_LE;
+			break;
+		default:
+			TargetFormat = ETF_ASCII; // should never happen.
+		}
+	}
+
+
+	// instance variables:
+
+	char_type* TextData;         // data block of the text file
+	char_type* P;                // current point in text to parse
+	char_type* TextBegin;        // start of text to parse
+	unsigned int TextSize;       // size of text to parse in characters, not bytes
+
+	EXML_NODE CurrentNodeType;   // type of the currently parsed node
+	ETEXT_FORMAT SourceFormat;   // source format of the xml file
+	ETEXT_FORMAT TargetFormat;   // output format of this parser
+
+	core::string<char_type> NodeName;    // name of the node currently in
+	core::string<char_type> EmptyString; // empty string to be returned by getSafe() methods
+
+	bool IsEmptyElement;       // is the currently parsed node empty?
+
+	core::array< core::string<char_type> > SpecialCharacters; // see createSpecialCharacterList()
+
+	core::array<SAttribute> Attributes; // attributes of current element
+	
+}; // end CXMLReaderImpl
+
+
+} // end namespace
+} // end namespace
+
+#endif

+ 73 - 73
Source/ThirdParty/Assimp/contrib/irrXML/heapsort.h

@@ -1,73 +1,73 @@
-// Copyright (C) 2002-2005 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#ifndef __IRR_HEAPSORT_H_INCLUDED__
-#define __IRR_HEAPSORT_H_INCLUDED__
-
-#include "irrTypes.h"
-
-namespace irr
-{
-namespace core
-{
-
-//! Sinks an element into the heap.
-template<class T>
-inline void heapsink(T*array, s32 element, s32 max)
-{
-	while ((element<<1) < max)	// there is a left child
-	{
-		s32 j = (element<<1);
-	
-		if (j+1 < max && array[j] < array[j+1])
-			j = j+1;							// take right child
-
-		if (array[element] < array[j])
-		{
-			T t = array[j];						// swap elements
-			array[j] = array[element];
-			array[element] = t;
-			element = j;
-		}
-		else
-			return;
-	}
-}
-
-
-//! Sorts an array with size 'size' using heapsort.
-template<class T>
-inline void heapsort(T* array_, s32 size)
-{
-	// for heapsink we pretent this is not c++, where
-	// arrays start with index 0. So we decrease the array pointer,
-	// the maximum always +2 and the element always +1
-
-	T* virtualArray = array_ - 1;
-	s32 virtualSize = size + 2;
-	s32 i;
-
-	// build heap
-
-	for (i=((size-1)/2); i>=0; --i)	
-		heapsink(virtualArray, i+1, virtualSize-1);
-
-	// sort array
-
-	for (i=size-1; i>=0; --i)	
-	{
-		T t = array_[0];
-		array_[0] = array_[i];
-		array_[i] = t;
-		heapsink(virtualArray, 1, i + 1);
-	}
-}
-
-} // end namespace core
-} // end namespace irr
-
-
-
-#endif
-
+// Copyright (C) 2002-2005 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#ifndef __IRR_HEAPSORT_H_INCLUDED__
+#define __IRR_HEAPSORT_H_INCLUDED__
+
+#include "irrTypes.h"
+
+namespace irr
+{
+namespace core
+{
+
+//! Sinks an element into the heap.
+template<class T>
+inline void heapsink(T*array, s32 element, s32 max)
+{
+	while ((element<<1) < max)	// there is a left child
+	{
+		s32 j = (element<<1);
+	
+		if (j+1 < max && array[j] < array[j+1])
+			j = j+1;							// take right child
+
+		if (array[element] < array[j])
+		{
+			T t = array[j];						// swap elements
+			array[j] = array[element];
+			array[element] = t;
+			element = j;
+		}
+		else
+			return;
+	}
+}
+
+
+//! Sorts an array with size 'size' using heapsort.
+template<class T>
+inline void heapsort(T* array_, s32 size)
+{
+	// for heapsink we pretent this is not c++, where
+	// arrays start with index 0. So we decrease the array pointer,
+	// the maximum always +2 and the element always +1
+
+	T* virtualArray = array_ - 1;
+	s32 virtualSize = size + 2;
+	s32 i;
+
+	// build heap
+
+	for (i=((size-1)/2); i>=0; --i)	
+		heapsink(virtualArray, i+1, virtualSize-1);
+
+	// sort array
+
+	for (i=size-1; i>=0; --i)	
+	{
+		T t = array_[0];
+		array_[0] = array_[i];
+		array_[i] = t;
+		heapsink(virtualArray, 1, i + 1);
+	}
+}
+
+} // end namespace core
+} // end namespace irr
+
+
+
+#endif
+

+ 444 - 444
Source/ThirdParty/Assimp/contrib/irrXML/irrArray.h

@@ -1,444 +1,444 @@
-// Copyright (C) 2002-2005 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine" and the "irrXML" project.
-// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
-
-#ifndef __IRR_ARRAY_H_INCLUDED__
-#define __IRR_ARRAY_H_INCLUDED__
-
-#include "irrTypes.h"
-#include "heapsort.h"
-
-namespace irr
-{
-namespace core
-{
-
-//!	Self reallocating template array (like stl vector) with additional features.
-/** Some features are: Heap sorting, binary search methods, easier debugging.
-*/
-template <class T>
-class array
-{
-
-public:
-
-	array()
-		: data(0), allocated(0), used(0),
-			free_when_destroyed(true), is_sorted(true)
-	{
-	}
-
-	//! Constructs a array and allocates an initial chunk of memory.
-	//! \param start_count: Amount of elements to allocate.
-	array(u32 start_count)
-		: data(0), allocated(0), used(0),
-			free_when_destroyed(true),	is_sorted(true)
-	{
-		reallocate(start_count);
-	}
-
-
-	//! Copy constructor
-	array(const array<T>& other)
-		: data(0)
-	{
-		*this = other;
-	}
-
-
-
-	//! Destructor. Frees allocated memory, if set_free_when_destroyed
-	//! was not set to false by the user before.
-	~array()
-	{
-		if (free_when_destroyed)
-			delete [] data;
-	}
-
-
-
-	//! Reallocates the array, make it bigger or smaller.
-	//! \param new_size: New size of array.
-	void reallocate(u32 new_size)
-	{
-		T* old_data = data;
-
-		data = new T[new_size];
-		allocated = new_size;
-		
-		s32 end = used < new_size ? used : new_size;
-		for (s32 i=0; i<end; ++i)
-			data[i] = old_data[i];
-
-		if (allocated < used)
-			used = allocated;
-		
-		delete [] old_data;
-	}
-
-	//! Adds an element at back of array. If the array is to small to 
-	//! add this new element, the array is made bigger.
-	//! \param element: Element to add at the back of the array.
-	void push_back(const T& element)
-	{
-		if (used + 1 > allocated)
-		{
-			// reallocate(used * 2 +1);
-			// this doesn't work if the element is in the same array. So
-			// we'll copy the element first to be sure we'll get no data
-			// corruption
-
-			T e;
-			e = element;           // copy element
-			reallocate(used * 2 +1); // increase data block
-			data[used++] = e;        // push_back
-			is_sorted = false; 
-			return;
-		}
-
-		data[used++] = element;
-		is_sorted = false;
-	}
-
-
-	//! Adds an element at the front of the array. If the array is to small to 
-	//! add this new element, the array is made bigger. Please note that this
-	//! is slow, because the whole array needs to be copied for this.
-	//! \param element: Element to add at the back of the array.
-	void push_front(const T& element)
-	{
-		if (used + 1 > allocated)
-			reallocate(used * 2 +1);
-
-		for (int i=(int)used; i>0; --i)
-			data[i] = data[i-1];
-
-		data[0] = element;
-		is_sorted = false;
-		++used;
-	}
-
-	
-	//! Insert item into array at specified position. Please use this
-	//! only if you know what you are doing (possible performance loss). 
-	//! The preferred method of adding elements should be push_back().
-	//! \param element: Element to be inserted
-	//! \param index: Where position to insert the new element.
-	void insert(const T& element, u32 index=0) 
-	{
-		_IRR_DEBUG_BREAK_IF(index>used) // access violation
-
-		if (used + 1 > allocated)
-			reallocate(used * 2 +1);
-
-		for (u32 i=used++; i>index; i--) 
-			data[i] = data[i-1];
-
-		data[index] = element;
-		is_sorted = false;
-	}
-
-
-
-
-	//! Clears the array and deletes all allocated memory.
-	void clear()
-	{
-		delete [] data;
-		data = 0;
-		used = 0;
-		allocated = 0;
-		is_sorted = true;
-	}
-
-
-
-	//! Sets pointer to new array, using this as new workspace.
-	//! \param newPointer: Pointer to new array of elements.
-	//! \param size: Size of the new array.
-	void set_pointer(T* newPointer, u32 size)
-	{
-		delete [] data;
-		data = newPointer;
-		allocated = size;
-		used = size;
-		is_sorted = false;
-	}
-
-
-
-	//! Sets if the array should delete the memory it used.
-	//! \param f: If true, the array frees the allocated memory in its
-	//! destructor, otherwise not. The default is true.
-	void set_free_when_destroyed(bool f)
-	{
-		free_when_destroyed = f;
-	}
-
-
-
-	//! Sets the size of the array.
-	//! \param usedNow: Amount of elements now used.
-	void set_used(u32 usedNow)
-	{
-		if (allocated < usedNow)
-			reallocate(usedNow);
-
-		used = usedNow;
-	}
-
-
-
-	//! Assignement operator
-	void operator=(const array<T>& other)
-	{
-		if (data)
-			delete [] data;
-
-		//if (allocated < other.allocated)
-		if (other.allocated == 0)
-			data = 0;
-		else
-			data = new T[other.allocated];
-
-		used = other.used;
-		free_when_destroyed = other.free_when_destroyed;
-		is_sorted = other.is_sorted;
-		allocated = other.allocated;
-
-		for (u32 i=0; i<other.used; ++i)
-			data[i] = other.data[i];
-	}
-
-
-	//! Direct access operator
-	T& operator [](u32 index)
-	{
-		_IRR_DEBUG_BREAK_IF(index>=used) // access violation
-
-		return data[index];
-	}
-
-
-
-	//! Direct access operator
-	const T& operator [](u32 index) const
-	{
-		_IRR_DEBUG_BREAK_IF(index>=used) // access violation
-
-		return data[index];
-	}
-
-    //! Gets last frame
-	const T& getLast() const
-	{
-		_IRR_DEBUG_BREAK_IF(!used) // access violation
-
-		return data[used-1];
-	}
-
-    //! Gets last frame
-	T& getLast()
-	{
-		_IRR_DEBUG_BREAK_IF(!used) // access violation
-
-		return data[used-1];
-	}
-    
-
-	//! Returns a pointer to the array.
-	//! \return Pointer to the array.
-	T* pointer()
-	{
-		return data;
-	}
-
-
-
-	//! Returns a const pointer to the array.
-	//! \return Pointer to the array.
-	const T* const_pointer() const
-	{
-		return data;
-	}
-
-
-
-	//! Returns size of used array.
-	//! \return Size of elements in the array.
-	u32 size() const
-	{
-		return used;
-	}
-
-
-
-	//! Returns amount memory allocated.
-	//! \return Returns amount of memory allocated. The amount of bytes
-	//! allocated would  be allocated_size() * sizeof(ElementsUsed);
-	u32 allocated_size() const
-	{
-		return allocated;
-	}
-
-
-
-	//! Returns true if array is empty
-	//! \return True if the array is empty, false if not.
-	bool empty() const
-	{
-		return used == 0;
-	}
-
-
-
-	//! Sorts the array using heapsort. There is no additional memory waste and
-	//! the algorithm performs (O) n log n in worst case.
-	void sort()
-	{
-		if (is_sorted || used<2)
-			return;
-
-		heapsort(data, used);
-		is_sorted = true;
-	}
-
-
-
-	//! Performs a binary search for an element, returns -1 if not found.
-	//! The array will be sorted before the binary search if it is not
-	//! already sorted.
-	//! \param element: Element to search for.
-	//! \return Returns position of the searched element if it was found,
-	//! otherwise -1 is returned.
-	s32 binary_search(const T& element)
-	{
-		return binary_search(element, 0, used-1);
-	}
-
-
-
-	//! Performs a binary search for an element, returns -1 if not found.
-	//! The array will be sorted before the binary search if it is not
-	//! already sorted.
-	//! \param element: Element to search for.
-	//! \param left: First left index
-	//! \param right: Last right index.
-	//! \return Returns position of the searched element if it was found,
-	//! otherwise -1 is returned.
-	s32 binary_search(const T& element, s32 left, s32 right)
-	{
-		if (!used)
-			return -1;
-
-		sort();
-
-		s32 m;
-
-		do
-		{
-			m = (left+right)>>1;
-
-			if (element < data[m])
-				right = m - 1;
-			else
-				left = m + 1;
-
-		} while((element < data[m] || data[m] < element) && left<=right);
-
-		// this last line equals to:
-		// " while((element != array[m]) && left<=right);"
-		// but we only want to use the '<' operator.
-		// the same in next line, it is "(element == array[m])"
-
-		if (!(element < data[m]) && !(data[m] < element))
-			return m;
-
-		return -1;
-	}
-
-
-	//! Finds an element in linear time, which is very slow. Use
-	//! binary_search for faster finding. Only works if =operator is implemented.
-	//! \param element: Element to search for.
-	//! \return Returns position of the searched element if it was found,
-	//! otherwise -1 is returned.
-	s32 linear_search(T& element)
-	{
-		for (u32 i=0; i<used; ++i)
-			if (!(element < data[i]) && !(data[i] < element))
-				return (s32)i;
-
-		return -1;
-	}
-
-
-	//! Finds an element in linear time, which is very slow. Use
-	//! binary_search for faster finding. Only works if =operator is implemented.
-	//! \param element: Element to search for.
-	//! \return Returns position of the searched element if it was found,
-	//! otherwise -1 is returned.
-	s32 linear_reverse_search(T& element)
-	{
-		for (s32 i=used-1; i>=0; --i)
-			if (data[i] == element)
-				return (s32)i;
-
-		return -1;
-	}
-
-
-
-	//! Erases an element from the array. May be slow, because all elements 
-	//! following after the erased element have to be copied.
-	//! \param index: Index of element to be erased.
-	void erase(u32 index)
-	{
-		_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
-
-		for (u32 i=index+1; i<used; ++i)
-			data[i-1] = data[i];
-
-		--used;
-	}
-
-
-	//! Erases some elements from the array. may be slow, because all elements 
-	//! following after the erased element have to be copied.
-	//! \param index: Index of the first element to be erased.
-	//! \param count: Amount of elements to be erased.
-	void erase(u32 index, s32 count)
-	{
-		_IRR_DEBUG_BREAK_IF(index>=used || index<0 || count<1 || index+count>used) // access violation
-
-		for (u32 i=index+count; i<used; ++i)
-			data[i-count] = data[i];
-
-		used-= count;
-	}
-
-
-	//! Sets if the array is sorted
-	void set_sorted(bool _is_sorted)
-	{
-		is_sorted = _is_sorted;
-	}
-
-			
-	private:
-
-		T* data;
-		u32 allocated;
-		u32 used;
-		bool free_when_destroyed;
-		bool is_sorted;
-};
-
-
-} // end namespace core
-} // end namespace irr
-
-
-
-#endif
-
+// Copyright (C) 2002-2005 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine" and the "irrXML" project.
+// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
+
+#ifndef __IRR_ARRAY_H_INCLUDED__
+#define __IRR_ARRAY_H_INCLUDED__
+
+#include "irrTypes.h"
+#include "heapsort.h"
+
+namespace irr
+{
+namespace core
+{
+
+//!	Self reallocating template array (like stl vector) with additional features.
+/** Some features are: Heap sorting, binary search methods, easier debugging.
+*/
+template <class T>
+class array
+{
+
+public:
+
+	array()
+		: data(0), allocated(0), used(0),
+			free_when_destroyed(true), is_sorted(true)
+	{
+	}
+
+	//! Constructs a array and allocates an initial chunk of memory.
+	//! \param start_count: Amount of elements to allocate.
+	array(u32 start_count)
+		: data(0), allocated(0), used(0),
+			free_when_destroyed(true),	is_sorted(true)
+	{
+		reallocate(start_count);
+	}
+
+
+	//! Copy constructor
+	array(const array<T>& other)
+		: data(0)
+	{
+		*this = other;
+	}
+
+
+
+	//! Destructor. Frees allocated memory, if set_free_when_destroyed
+	//! was not set to false by the user before.
+	~array()
+	{
+		if (free_when_destroyed)
+			delete [] data;
+	}
+
+
+
+	//! Reallocates the array, make it bigger or smaller.
+	//! \param new_size: New size of array.
+	void reallocate(u32 new_size)
+	{
+		T* old_data = data;
+
+		data = new T[new_size];
+		allocated = new_size;
+		
+		s32 end = used < new_size ? used : new_size;
+		for (s32 i=0; i<end; ++i)
+			data[i] = old_data[i];
+
+		if (allocated < used)
+			used = allocated;
+		
+		delete [] old_data;
+	}
+
+	//! Adds an element at back of array. If the array is to small to 
+	//! add this new element, the array is made bigger.
+	//! \param element: Element to add at the back of the array.
+	void push_back(const T& element)
+	{
+		if (used + 1 > allocated)
+		{
+			// reallocate(used * 2 +1);
+			// this doesn't work if the element is in the same array. So
+			// we'll copy the element first to be sure we'll get no data
+			// corruption
+
+			T e;
+			e = element;           // copy element
+			reallocate(used * 2 +1); // increase data block
+			data[used++] = e;        // push_back
+			is_sorted = false; 
+			return;
+		}
+
+		data[used++] = element;
+		is_sorted = false;
+	}
+
+
+	//! Adds an element at the front of the array. If the array is to small to 
+	//! add this new element, the array is made bigger. Please note that this
+	//! is slow, because the whole array needs to be copied for this.
+	//! \param element: Element to add at the back of the array.
+	void push_front(const T& element)
+	{
+		if (used + 1 > allocated)
+			reallocate(used * 2 +1);
+
+		for (int i=(int)used; i>0; --i)
+			data[i] = data[i-1];
+
+		data[0] = element;
+		is_sorted = false;
+		++used;
+	}
+
+	
+	//! Insert item into array at specified position. Please use this
+	//! only if you know what you are doing (possible performance loss). 
+	//! The preferred method of adding elements should be push_back().
+	//! \param element: Element to be inserted
+	//! \param index: Where position to insert the new element.
+	void insert(const T& element, u32 index=0) 
+	{
+		_IRR_DEBUG_BREAK_IF(index>used) // access violation
+
+		if (used + 1 > allocated)
+			reallocate(used * 2 +1);
+
+		for (u32 i=used++; i>index; i--) 
+			data[i] = data[i-1];
+
+		data[index] = element;
+		is_sorted = false;
+	}
+
+
+
+
+	//! Clears the array and deletes all allocated memory.
+	void clear()
+	{
+		delete [] data;
+		data = 0;
+		used = 0;
+		allocated = 0;
+		is_sorted = true;
+	}
+
+
+
+	//! Sets pointer to new array, using this as new workspace.
+	//! \param newPointer: Pointer to new array of elements.
+	//! \param size: Size of the new array.
+	void set_pointer(T* newPointer, u32 size)
+	{
+		delete [] data;
+		data = newPointer;
+		allocated = size;
+		used = size;
+		is_sorted = false;
+	}
+
+
+
+	//! Sets if the array should delete the memory it used.
+	//! \param f: If true, the array frees the allocated memory in its
+	//! destructor, otherwise not. The default is true.
+	void set_free_when_destroyed(bool f)
+	{
+		free_when_destroyed = f;
+	}
+
+
+
+	//! Sets the size of the array.
+	//! \param usedNow: Amount of elements now used.
+	void set_used(u32 usedNow)
+	{
+		if (allocated < usedNow)
+			reallocate(usedNow);
+
+		used = usedNow;
+	}
+
+
+
+	//! Assignement operator
+	void operator=(const array<T>& other)
+	{
+		if (data)
+			delete [] data;
+
+		//if (allocated < other.allocated)
+		if (other.allocated == 0)
+			data = 0;
+		else
+			data = new T[other.allocated];
+
+		used = other.used;
+		free_when_destroyed = other.free_when_destroyed;
+		is_sorted = other.is_sorted;
+		allocated = other.allocated;
+
+		for (u32 i=0; i<other.used; ++i)
+			data[i] = other.data[i];
+	}
+
+
+	//! Direct access operator
+	T& operator [](u32 index)
+	{
+		_IRR_DEBUG_BREAK_IF(index>=used) // access violation
+
+		return data[index];
+	}
+
+
+
+	//! Direct access operator
+	const T& operator [](u32 index) const
+	{
+		_IRR_DEBUG_BREAK_IF(index>=used) // access violation
+
+		return data[index];
+	}
+
+    //! Gets last frame
+	const T& getLast() const
+	{
+		_IRR_DEBUG_BREAK_IF(!used) // access violation
+
+		return data[used-1];
+	}
+
+    //! Gets last frame
+	T& getLast()
+	{
+		_IRR_DEBUG_BREAK_IF(!used) // access violation
+
+		return data[used-1];
+	}
+    
+
+	//! Returns a pointer to the array.
+	//! \return Pointer to the array.
+	T* pointer()
+	{
+		return data;
+	}
+
+
+
+	//! Returns a const pointer to the array.
+	//! \return Pointer to the array.
+	const T* const_pointer() const
+	{
+		return data;
+	}
+
+
+
+	//! Returns size of used array.
+	//! \return Size of elements in the array.
+	u32 size() const
+	{
+		return used;
+	}
+
+
+
+	//! Returns amount memory allocated.
+	//! \return Returns amount of memory allocated. The amount of bytes
+	//! allocated would  be allocated_size() * sizeof(ElementsUsed);
+	u32 allocated_size() const
+	{
+		return allocated;
+	}
+
+
+
+	//! Returns true if array is empty
+	//! \return True if the array is empty, false if not.
+	bool empty() const
+	{
+		return used == 0;
+	}
+
+
+
+	//! Sorts the array using heapsort. There is no additional memory waste and
+	//! the algorithm performs (O) n log n in worst case.
+	void sort()
+	{
+		if (is_sorted || used<2)
+			return;
+
+		heapsort(data, used);
+		is_sorted = true;
+	}
+
+
+
+	//! Performs a binary search for an element, returns -1 if not found.
+	//! The array will be sorted before the binary search if it is not
+	//! already sorted.
+	//! \param element: Element to search for.
+	//! \return Returns position of the searched element if it was found,
+	//! otherwise -1 is returned.
+	s32 binary_search(const T& element)
+	{
+		return binary_search(element, 0, used-1);
+	}
+
+
+
+	//! Performs a binary search for an element, returns -1 if not found.
+	//! The array will be sorted before the binary search if it is not
+	//! already sorted.
+	//! \param element: Element to search for.
+	//! \param left: First left index
+	//! \param right: Last right index.
+	//! \return Returns position of the searched element if it was found,
+	//! otherwise -1 is returned.
+	s32 binary_search(const T& element, s32 left, s32 right)
+	{
+		if (!used)
+			return -1;
+
+		sort();
+
+		s32 m;
+
+		do
+		{
+			m = (left+right)>>1;
+
+			if (element < data[m])
+				right = m - 1;
+			else
+				left = m + 1;
+
+		} while((element < data[m] || data[m] < element) && left<=right);
+
+		// this last line equals to:
+		// " while((element != array[m]) && left<=right);"
+		// but we only want to use the '<' operator.
+		// the same in next line, it is "(element == array[m])"
+
+		if (!(element < data[m]) && !(data[m] < element))
+			return m;
+
+		return -1;
+	}
+
+
+	//! Finds an element in linear time, which is very slow. Use
+	//! binary_search for faster finding. Only works if =operator is implemented.
+	//! \param element: Element to search for.
+	//! \return Returns position of the searched element if it was found,
+	//! otherwise -1 is returned.
+	s32 linear_search(T& element)
+	{
+		for (u32 i=0; i<used; ++i)
+			if (!(element < data[i]) && !(data[i] < element))
+				return (s32)i;
+
+		return -1;
+	}
+
+
+	//! Finds an element in linear time, which is very slow. Use
+	//! binary_search for faster finding. Only works if =operator is implemented.
+	//! \param element: Element to search for.
+	//! \return Returns position of the searched element if it was found,
+	//! otherwise -1 is returned.
+	s32 linear_reverse_search(T& element)
+	{
+		for (s32 i=used-1; i>=0; --i)
+			if (data[i] == element)
+				return (s32)i;
+
+		return -1;
+	}
+
+
+
+	//! Erases an element from the array. May be slow, because all elements 
+	//! following after the erased element have to be copied.
+	//! \param index: Index of element to be erased.
+	void erase(u32 index)
+	{
+		_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
+
+		for (u32 i=index+1; i<used; ++i)
+			data[i-1] = data[i];
+
+		--used;
+	}
+
+
+	//! Erases some elements from the array. may be slow, because all elements 
+	//! following after the erased element have to be copied.
+	//! \param index: Index of the first element to be erased.
+	//! \param count: Amount of elements to be erased.
+	void erase(u32 index, s32 count)
+	{
+		_IRR_DEBUG_BREAK_IF(index>=used || index<0 || count<1 || index+count>used) // access violation
+
+		for (u32 i=index+count; i<used; ++i)
+			data[i-count] = data[i];
+
+		used-= count;
+	}
+
+
+	//! Sets if the array is sorted
+	void set_sorted(bool _is_sorted)
+	{
+		is_sorted = _is_sorted;
+	}
+
+			
+	private:
+
+		T* data;
+		u32 allocated;
+		u32 used;
+		bool free_when_destroyed;
+		bool is_sorted;
+};
+
+
+} // end namespace core
+} // end namespace irr
+
+
+
+#endif
+

+ 664 - 664
Source/ThirdParty/Assimp/contrib/irrXML/irrString.h

@@ -1,664 +1,664 @@
-// Copyright (C) 2002-2005 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine" and the "irrXML" project.
-// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
-
-#ifndef __IRR_STRING_H_INCLUDED__
-#define __IRR_STRING_H_INCLUDED__
-
-#include "irrTypes.h"
-
-namespace irr
-{
-namespace core
-{
-
-//!	Very simple string class with some useful features.
-/**	string<c8> and string<wchar_t> work both with unicode AND ascii,
-so you can assign unicode to string<c8> and ascii to string<wchar_t> 
-(and the other way round) if your ever would want to. 
-Note that the conversation between both is not done using an encoding.
-
-Known bugs:
-Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the
-methods make_upper, make_lower and equals_ignore_case.
-*/
-template <class T>
-class string
-{
-public:
-
-	//! Default constructor
-	string()
-	: array(0), allocated(1), used(1)
-	{
-		array = new T[1];
-		array[0] = 0x0;
-	}
-
-
-
-	//! Constructor
-	string(const string<T>& other)
-	: array(0), allocated(0), used(0)
-	{
-		*this = other;
-	}
-
-
-	//! Constructs a string from an int
-	string(int number)
-	: array(0), allocated(0), used(0)
-	{
-		// store if negative and make positive
-
-		bool negative = false;
-		if (number < 0)
-		{
-			number *= -1;
-			negative = true;
-		}
-
-		// temporary buffer for 16 numbers
-
-		c8 tmpbuf[16];
-		tmpbuf[15] = 0;
-		s32 idx = 15;	
-
-		// special case '0'
-
-		if (!number) 
-		{
-			tmpbuf[14] = '0';
-			*this = &tmpbuf[14];
-			return;
-		}
-
-		// add numbers
-
-		while(number && idx)
-		{
-			idx--;	
-			tmpbuf[idx] = (c8)('0' + (number % 10));
-			number = number / 10;					
-		}
-
-		// add sign
-
-		if (negative)
-		{
-			idx--;
-			tmpbuf[idx] = '-';			
-		}
-
-		*this = &tmpbuf[idx];
-	}
-
-
-
-	//! Constructor for copying a string from a pointer with a given lenght
-	template <class B>
-	string(const B* c, s32 lenght)
-	: array(0), allocated(0), used(0)
-	{
-		if (!c)
-			return;
-
-        allocated = used = lenght+1;
-		array = new T[used];
-
-		for (s32 l = 0; l<lenght; ++l)
-			array[l] = (T)c[l];
-
-		array[lenght] = 0;
-	}
-
-
-
-	//! Constructor for unicode and ascii strings
-	template <class B>
-	string(const B* c)
-	: array(0),allocated(0), used(0)
-	{
-		*this = c;
-	}
-
-
-
-	//! destructor
-	~string()
-	{
-		delete [] array;
-	}
-
-
-
-	//! Assignment operator
-	string<T>& operator=(const string<T>& other) 
-	{
-		if (this == &other)
-			return *this;
-
-		delete [] array;
-		allocated = used = other.size()+1;
-		array = new T[used];
-
-		const T* p = other.c_str();
-		for (s32 i=0; i<used; ++i, ++p)
-			array[i] = *p;
-
-		return *this;
-	}
-
-
-
-	//! Assignment operator for strings, ascii and unicode
-	template <class B>
-	string<T>& operator=(const B* c) 
-	{
-		if (!c)
-		{
-			if (!array)
-			{
-				array = new T[1];
-				allocated = 1;
-				used = 1;
-			}
-			array[0] = 0x0;
-			return *this;
-		}
-
-		if ((void*)c == (void*)array)
-			return *this;
-
-		s32 len = 0;
-		const B* p = c;
-		while(*p)
-		{
-			++len;
-			++p;
-		}
-
-		// we'll take the old string for a while, because the new string could be
-		// a part of the current string.
-		T* oldArray = array;
-
-        allocated = used = len+1;
-		array = new T[used];
-
-		for (s32 l = 0; l<len+1; ++l)
-			array[l] = (T)c[l];
-
-		delete [] oldArray;
-		return *this;
-	}
-
-	//! Add operator for other strings
-	string<T> operator+(const string<T>& other) 
-	{ 
-		string<T> str(*this); 
-		str.append(other); 
-
-		return str; 
-	} 
-
-	//! Add operator for strings, ascii and unicode 
-	template <class B> 
-	string<T> operator+(const B* c) 
-	{ 
-		string<T> str(*this); 
-		str.append(c); 
-
-		return str; 
-	}
-
-
-
-	//! Direct access operator
-	T& operator [](const s32 index)  const
-	{
-		_IRR_DEBUG_BREAK_IF(index>=used) // bad index
-
-		return array[index];
-	}
-
-
-	//! Comparison operator
-	bool operator ==(const T* str) const
-	{
-		int i;
-		for(i=0; array[i] && str[i]; ++i)
-			if (array[i] != str[i])
-				return false;
-
-		return !array[i] && !str[i];
-	}
-
-
-
-	//! Comparison operator
-	bool operator ==(const string<T>& other) const
-	{
-		for(s32 i=0; array[i] && other.array[i]; ++i)
-			if (array[i] != other.array[i])
-				return false;
-
-		return used == other.used;
-	}
-
-
-
-	//! Is smaller operator
-	bool operator <(const string<T>& other) const
-	{
-		for(s32 i=0; array[i] && other.array[i]; ++i)
-			if (array[i] != other.array[i])
-				return (array[i] < other.array[i]);
-
-		return used < other.used;
-	}
-
-
-
-	//! Equals not operator
-	bool operator !=(const string<T>& other) const
-	{
-		return !(*this == other);
-	}
-
-
-    
-	//! Returns length of string
-	/** \return Returns length of the string in characters. */
-	s32 size() const
-	{
-		return used-1;
-	}
-
-
-
-	//! Returns character string
-	/** \return Returns pointer to C-style zero terminated string. */
-	const T* c_str() const
-	{
-		return array;
-	}
-
-
-
-	//! Makes the string lower case.
-	void make_lower()
-	{
-		const T A = (T)'A';
-		const T Z = (T)'Z';
-		const T diff = (T)'a' - A;
-
-		for (s32 i=0; i<used; ++i)
-		{
-			if (array[i]>=A && array[i]<=Z)
-				array[i] += diff;
-		}
-	}
-
-
-
-	//! Makes the string upper case.
-	void make_upper()
-	{
-		const T a = (T)'a';
-		const T z = (T)'z';
-		const T diff = (T)'A' - a;
-
-		for (s32 i=0; i<used; ++i)
-		{
-			if (array[i]>=a && array[i]<=z)
-				array[i] += diff;
-		}
-	}
-
-
-
-	//! Compares the string ignoring case.
-	/** \param other: Other string to compare.
-	\return Returns true if the string are equal ignoring case. */
-	bool equals_ignore_case(const string<T>& other) const
-	{
-		for(s32 i=0; array[i] && other[i]; ++i)
-			if (toLower(array[i]) != toLower(other[i]))
-				return false;
-
-		return used == other.used;
-	}
-
-
-	//! compares the first n characters of the strings
-	bool equalsn(const string<T>& other, int len)
-	{
-		int i;
-		for(i=0; array[i] && other[i] && i < len; ++i)
-			if (array[i] != other[i])
-				return false;
-
-		// if one (or both) of the strings was smaller then they
-		// are only equal if they have the same lenght
-		return (i == len) || (used == other.used);
-	}
-
-
-	//! compares the first n characters of the strings
-	bool equalsn(const T* str, int len)
-	{
-		int i;	
-		for(i=0; array[i] && str[i] && i < len; ++i)
-			if (array[i] != str[i])
-				return false;
-
-		// if one (or both) of the strings was smaller then they
-		// are only equal if they have the same lenght
-		return (i == len) || (array[i] == 0 && str[i] == 0);
-	}
-
-
-	//! Appends a character to this string
-	/** \param character: Character to append. */
-	void append(T character)
-	{
-		if (used + 1 > allocated)
-			reallocate((s32)used + 1);
-
-		used += 1;
-
-		array[used-2] = character;
-		array[used-1] = 0;
-	}
-
-	//! Appends a string to this string
-	/** \param other: String to append. */
-	void append(const string<T>& other)
-	{
-		--used;
-
-		s32 len = other.size();
-		
-		if (used + len + 1 > allocated)
-			reallocate((s32)used + (s32)len + 1);
-
-		for (s32 l=0; l<len+1; ++l)
-			array[l+used] = other[l];
-
-		used = used + len + 1;
-	}
-
-
-	//! Appends a string of the length l to this string.
-	/** \param other: other String to append to this string.
-	 \param length: How much characters of the other string to add to this one. */
-	void append(const string<T>& other, s32 length)
-	{
-		s32 len = other.size();
-
-		if (len < length)
-		{
-			append(other);
-			return;
-		}
-
-		len = length;
-		--used;
-		
-		if (used + len > allocated)
-			reallocate((s32)used + (s32)len);
-
-		for (s32 l=0; l<len; ++l)
-			array[l+used] = other[l];
-
-		used = used + len;
-	}
-
-
-	//! Reserves some memory.
-	/** \param count: Amount of characters to reserve. */
-	void reserve(s32 count)
-	{
-		if (count < allocated)
-			return;
-
-		reallocate(count);
-	}
-
-
-	//! finds first occurrence of character in string
-	/** \param c: Character to search for.
-	\return Returns position where the character has been found,
-	or -1 if not found. */
-	s32 findFirst(T c) const
-	{
-		for (s32 i=0; i<used; ++i)
-			if (array[i] == c)
-				return i;
-
-		return -1;
-	}
-
-	//! finds first occurrence of a character of a list in string
-	/** \param c: List of strings to find. For example if the method
-	should find the first occurance of 'a' or 'b', this parameter should be "ab".
-	\param count: Amount of characters in the list. Ususally, 
-	this should be strlen(ofParameter1)
-	\return Returns position where one of the character has been found,
-	or -1 if not found. */
-	s32 findFirstChar(T* c, int count) const
-	{
-		for (s32 i=0; i<used; ++i)
-			for (int j=0; j<count; ++j)
-				if (array[i] == c[j])
-					return i;
-
-		return -1;
-	}
-
-
-	//! Finds first position of a character not in a given list.
-	/** \param c: List of characters not to find. For example if the method
-	 should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
-	\param count: Amount of characters in the list. Ususally, 
-	this should be strlen(ofParameter1)
-	\return Returns position where the character has been found,
-	or -1 if not found. */
-	template <class B> 
-	s32 findFirstCharNotInList(B* c, int count) const
-	{
-		for (int i=0; i<used; ++i)
-		{
-            int j;
-			for (j=0; j<count; ++j)
-				if (array[i] == c[j])
-					break;
-
-			if (j==count)
-				return i;
-		}
-
-		return -1;
-	}
-
-	//! Finds last position of a character not in a given list.
-	/** \param c: List of characters not to find. For example if the method
-	 should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
-	\param count: Amount of characters in the list. Ususally, 
-	this should be strlen(ofParameter1)
-	\return Returns position where the character has been found,
-	or -1 if not found. */
-	template <class B> 
-	s32 findLastCharNotInList(B* c, int count) const
-	{
-		for (int i=used-2; i>=0; --i)
-		{
-            int j;
-			for (j=0; j<count; ++j)
-				if (array[i] == c[j])
-					break;
-
-			if (j==count)
-				return i;
-		}
-
-		return -1;
-	}
-
-	//! finds next occurrence of character in string
-	/** \param c: Character to search for.
-	\param startPos: Position in string to start searching. 
-	\return Returns position where the character has been found,
-	or -1 if not found. */
-	s32 findNext(T c, s32 startPos) const
-	{
-		for (s32 i=startPos; i<used; ++i)
-			if (array[i] == c)
-				return i;
-
-		return -1;
-	}
-
-
-	//! finds last occurrence of character in string
-	//! \param c: Character to search for.
-	//! \return Returns position where the character has been found,
-	//! or -1 if not found.
-	s32 findLast(T c) const
-	{
-		for (s32 i=used-1; i>=0; --i)
-			if (array[i] == c)
-				return i;
-
-		return -1;
-	}
-
-
-	//! Returns a substring
-	//! \param begin: Start of substring.
-	//! \param length: Length of substring.
-	string<T> subString(s32 begin, s32 length)
-	{
-		if (length <= 0)
-			return string<T>("");
-
-		string<T> o;
-		o.reserve(length+1);
-
-		for (s32 i=0; i<length; ++i)
-			o.array[i] = array[i+begin];
-
-		o.array[length] = 0;
-		o.used = o.allocated;
-
-		return o;
-	}
-
-
-	void operator += (T c)
-	{
-		append(c);
-	}
-
-	void operator += (const string<T>& other)
-	{
-		append(other);
-	}
-
-	void operator += (int i)
-	{
-		append(string<T>(i));
-	}
-
-	//! replaces all characters of a special type with another one
-	void replace(T toReplace, T replaceWith)
-	{
-		for (s32 i=0; i<used; ++i)
-			if (array[i] == toReplace)
-				array[i] = replaceWith;
-	}
-
-	//! trims the string.
-	/** Removes whitespace from begin and end of the string. */
-	void trim()
-	{
-		const char whitespace[] = " \t\n";
-		const int whitespacecount = 3;
-
-		// find start and end of real string without whitespace
-		int begin = findFirstCharNotInList(whitespace, whitespacecount);
-		if (begin == -1)
-			return;
-
-		int end = findLastCharNotInList(whitespace, whitespacecount);
-		if (end == -1)
-			return;
-
-		*this = subString(begin, (end +1) - begin);
-	}
-
-
-	//! Erases a character from the string. May be slow, because all elements 
-	//! following after the erased element have to be copied.
-	//! \param index: Index of element to be erased.
-	void erase(int index)
-	{
-		_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
-
-		for (int i=index+1; i<used; ++i)
-			array[i-1] = array[i];
-
-		--used;
-	}
-
-    	
-
-private:
-
-	//! Returns a character converted to lower case
-	T toLower(const T& t) const
-	{
-		if (t>=(T)'A' && t<=(T)'Z')
-			return t + ((T)'a' - (T)'A');
-		else
-			return t;
-	}
-
-	//! Reallocate the array, make it bigger or smaler
-	void reallocate(s32 new_size)
-	{
-		T* old_array = array;
-
-		array = new T[new_size];
-		allocated = new_size;
-		
-		s32 amount = used < new_size ? used : new_size;
-		for (s32 i=0; i<amount; ++i)
-			array[i] = old_array[i];
-
-		if (allocated < used)
-			used = allocated;
-		
-		delete [] old_array;
-	}
-
-
-	//--- member variables
-
-	T* array;
-	s32 allocated;
-	s32 used;
-};
-
-
-//! Typedef for character strings
-typedef string<irr::c8> stringc;
-
-//! Typedef for wide character strings
-typedef string<wchar_t> stringw;
-
-} // end namespace core
-} // end namespace irr
-
-#endif
-
+// Copyright (C) 2002-2005 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine" and the "irrXML" project.
+// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
+
+#ifndef __IRR_STRING_H_INCLUDED__
+#define __IRR_STRING_H_INCLUDED__
+
+#include "irrTypes.h"
+
+namespace irr
+{
+namespace core
+{
+
+//!	Very simple string class with some useful features.
+/**	string<c8> and string<wchar_t> work both with unicode AND ascii,
+so you can assign unicode to string<c8> and ascii to string<wchar_t> 
+(and the other way round) if your ever would want to. 
+Note that the conversation between both is not done using an encoding.
+
+Known bugs:
+Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the
+methods make_upper, make_lower and equals_ignore_case.
+*/
+template <class T>
+class string
+{
+public:
+
+	//! Default constructor
+	string()
+	: array(0), allocated(1), used(1)
+	{
+		array = new T[1];
+		array[0] = 0x0;
+	}
+
+
+
+	//! Constructor
+	string(const string<T>& other)
+	: array(0), allocated(0), used(0)
+	{
+		*this = other;
+	}
+
+
+	//! Constructs a string from an int
+	string(int number)
+	: array(0), allocated(0), used(0)
+	{
+		// store if negative and make positive
+
+		bool negative = false;
+		if (number < 0)
+		{
+			number *= -1;
+			negative = true;
+		}
+
+		// temporary buffer for 16 numbers
+
+		c8 tmpbuf[16];
+		tmpbuf[15] = 0;
+		s32 idx = 15;	
+
+		// special case '0'
+
+		if (!number) 
+		{
+			tmpbuf[14] = '0';
+			*this = &tmpbuf[14];
+			return;
+		}
+
+		// add numbers
+
+		while(number && idx)
+		{
+			idx--;	
+			tmpbuf[idx] = (c8)('0' + (number % 10));
+			number = number / 10;					
+		}
+
+		// add sign
+
+		if (negative)
+		{
+			idx--;
+			tmpbuf[idx] = '-';			
+		}
+
+		*this = &tmpbuf[idx];
+	}
+
+
+
+	//! Constructor for copying a string from a pointer with a given lenght
+	template <class B>
+	string(const B* c, s32 lenght)
+	: array(0), allocated(0), used(0)
+	{
+		if (!c)
+			return;
+
+        allocated = used = lenght+1;
+		array = new T[used];
+
+		for (s32 l = 0; l<lenght; ++l)
+			array[l] = (T)c[l];
+
+		array[lenght] = 0;
+	}
+
+
+
+	//! Constructor for unicode and ascii strings
+	template <class B>
+	string(const B* c)
+	: array(0),allocated(0), used(0)
+	{
+		*this = c;
+	}
+
+
+
+	//! destructor
+	~string()
+	{
+		delete [] array;
+	}
+
+
+
+	//! Assignment operator
+	string<T>& operator=(const string<T>& other) 
+	{
+		if (this == &other)
+			return *this;
+
+		delete [] array;
+		allocated = used = other.size()+1;
+		array = new T[used];
+
+		const T* p = other.c_str();
+		for (s32 i=0; i<used; ++i, ++p)
+			array[i] = *p;
+
+		return *this;
+	}
+
+
+
+	//! Assignment operator for strings, ascii and unicode
+	template <class B>
+	string<T>& operator=(const B* c) 
+	{
+		if (!c)
+		{
+			if (!array)
+			{
+				array = new T[1];
+				allocated = 1;
+				used = 1;
+			}
+			array[0] = 0x0;
+			return *this;
+		}
+
+		if ((void*)c == (void*)array)
+			return *this;
+
+		s32 len = 0;
+		const B* p = c;
+		while(*p)
+		{
+			++len;
+			++p;
+		}
+
+		// we'll take the old string for a while, because the new string could be
+		// a part of the current string.
+		T* oldArray = array;
+
+        allocated = used = len+1;
+		array = new T[used];
+
+		for (s32 l = 0; l<len+1; ++l)
+			array[l] = (T)c[l];
+
+		delete [] oldArray;
+		return *this;
+	}
+
+	//! Add operator for other strings
+	string<T> operator+(const string<T>& other) 
+	{ 
+		string<T> str(*this); 
+		str.append(other); 
+
+		return str; 
+	} 
+
+	//! Add operator for strings, ascii and unicode 
+	template <class B> 
+	string<T> operator+(const B* c) 
+	{ 
+		string<T> str(*this); 
+		str.append(c); 
+
+		return str; 
+	}
+
+
+
+	//! Direct access operator
+	T& operator [](const s32 index)  const
+	{
+		_IRR_DEBUG_BREAK_IF(index>=used) // bad index
+
+		return array[index];
+	}
+
+
+	//! Comparison operator
+	bool operator ==(const T* str) const
+	{
+		int i;
+		for(i=0; array[i] && str[i]; ++i)
+			if (array[i] != str[i])
+				return false;
+
+		return !array[i] && !str[i];
+	}
+
+
+
+	//! Comparison operator
+	bool operator ==(const string<T>& other) const
+	{
+		for(s32 i=0; array[i] && other.array[i]; ++i)
+			if (array[i] != other.array[i])
+				return false;
+
+		return used == other.used;
+	}
+
+
+
+	//! Is smaller operator
+	bool operator <(const string<T>& other) const
+	{
+		for(s32 i=0; array[i] && other.array[i]; ++i)
+			if (array[i] != other.array[i])
+				return (array[i] < other.array[i]);
+
+		return used < other.used;
+	}
+
+
+
+	//! Equals not operator
+	bool operator !=(const string<T>& other) const
+	{
+		return !(*this == other);
+	}
+
+
+    
+	//! Returns length of string
+	/** \return Returns length of the string in characters. */
+	s32 size() const
+	{
+		return used-1;
+	}
+
+
+
+	//! Returns character string
+	/** \return Returns pointer to C-style zero terminated string. */
+	const T* c_str() const
+	{
+		return array;
+	}
+
+
+
+	//! Makes the string lower case.
+	void make_lower()
+	{
+		const T A = (T)'A';
+		const T Z = (T)'Z';
+		const T diff = (T)'a' - A;
+
+		for (s32 i=0; i<used; ++i)
+		{
+			if (array[i]>=A && array[i]<=Z)
+				array[i] += diff;
+		}
+	}
+
+
+
+	//! Makes the string upper case.
+	void make_upper()
+	{
+		const T a = (T)'a';
+		const T z = (T)'z';
+		const T diff = (T)'A' - a;
+
+		for (s32 i=0; i<used; ++i)
+		{
+			if (array[i]>=a && array[i]<=z)
+				array[i] += diff;
+		}
+	}
+
+
+
+	//! Compares the string ignoring case.
+	/** \param other: Other string to compare.
+	\return Returns true if the string are equal ignoring case. */
+	bool equals_ignore_case(const string<T>& other) const
+	{
+		for(s32 i=0; array[i] && other[i]; ++i)
+			if (toLower(array[i]) != toLower(other[i]))
+				return false;
+
+		return used == other.used;
+	}
+
+
+	//! compares the first n characters of the strings
+	bool equalsn(const string<T>& other, int len)
+	{
+		int i;
+		for(i=0; array[i] && other[i] && i < len; ++i)
+			if (array[i] != other[i])
+				return false;
+
+		// if one (or both) of the strings was smaller then they
+		// are only equal if they have the same lenght
+		return (i == len) || (used == other.used);
+	}
+
+
+	//! compares the first n characters of the strings
+	bool equalsn(const T* str, int len)
+	{
+		int i;	
+		for(i=0; array[i] && str[i] && i < len; ++i)
+			if (array[i] != str[i])
+				return false;
+
+		// if one (or both) of the strings was smaller then they
+		// are only equal if they have the same lenght
+		return (i == len) || (array[i] == 0 && str[i] == 0);
+	}
+
+
+	//! Appends a character to this string
+	/** \param character: Character to append. */
+	void append(T character)
+	{
+		if (used + 1 > allocated)
+			reallocate((s32)used + 1);
+
+		used += 1;
+
+		array[used-2] = character;
+		array[used-1] = 0;
+	}
+
+	//! Appends a string to this string
+	/** \param other: String to append. */
+	void append(const string<T>& other)
+	{
+		--used;
+
+		s32 len = other.size();
+		
+		if (used + len + 1 > allocated)
+			reallocate((s32)used + (s32)len + 1);
+
+		for (s32 l=0; l<len+1; ++l)
+			array[l+used] = other[l];
+
+		used = used + len + 1;
+	}
+
+
+	//! Appends a string of the length l to this string.
+	/** \param other: other String to append to this string.
+	 \param length: How much characters of the other string to add to this one. */
+	void append(const string<T>& other, s32 length)
+	{
+		s32 len = other.size();
+
+		if (len < length)
+		{
+			append(other);
+			return;
+		}
+
+		len = length;
+		--used;
+		
+		if (used + len > allocated)
+			reallocate((s32)used + (s32)len);
+
+		for (s32 l=0; l<len; ++l)
+			array[l+used] = other[l];
+
+		used = used + len;
+	}
+
+
+	//! Reserves some memory.
+	/** \param count: Amount of characters to reserve. */
+	void reserve(s32 count)
+	{
+		if (count < allocated)
+			return;
+
+		reallocate(count);
+	}
+
+
+	//! finds first occurrence of character in string
+	/** \param c: Character to search for.
+	\return Returns position where the character has been found,
+	or -1 if not found. */
+	s32 findFirst(T c) const
+	{
+		for (s32 i=0; i<used; ++i)
+			if (array[i] == c)
+				return i;
+
+		return -1;
+	}
+
+	//! finds first occurrence of a character of a list in string
+	/** \param c: List of strings to find. For example if the method
+	should find the first occurance of 'a' or 'b', this parameter should be "ab".
+	\param count: Amount of characters in the list. Ususally, 
+	this should be strlen(ofParameter1)
+	\return Returns position where one of the character has been found,
+	or -1 if not found. */
+	s32 findFirstChar(T* c, int count) const
+	{
+		for (s32 i=0; i<used; ++i)
+			for (int j=0; j<count; ++j)
+				if (array[i] == c[j])
+					return i;
+
+		return -1;
+	}
+
+
+	//! Finds first position of a character not in a given list.
+	/** \param c: List of characters not to find. For example if the method
+	 should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
+	\param count: Amount of characters in the list. Ususally, 
+	this should be strlen(ofParameter1)
+	\return Returns position where the character has been found,
+	or -1 if not found. */
+	template <class B> 
+	s32 findFirstCharNotInList(B* c, int count) const
+	{
+		for (int i=0; i<used; ++i)
+		{
+            int j;
+			for (j=0; j<count; ++j)
+				if (array[i] == c[j])
+					break;
+
+			if (j==count)
+				return i;
+		}
+
+		return -1;
+	}
+
+	//! Finds last position of a character not in a given list.
+	/** \param c: List of characters not to find. For example if the method
+	 should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
+	\param count: Amount of characters in the list. Ususally, 
+	this should be strlen(ofParameter1)
+	\return Returns position where the character has been found,
+	or -1 if not found. */
+	template <class B> 
+	s32 findLastCharNotInList(B* c, int count) const
+	{
+		for (int i=used-2; i>=0; --i)
+		{
+            int j;
+			for (j=0; j<count; ++j)
+				if (array[i] == c[j])
+					break;
+
+			if (j==count)
+				return i;
+		}
+
+		return -1;
+	}
+
+	//! finds next occurrence of character in string
+	/** \param c: Character to search for.
+	\param startPos: Position in string to start searching. 
+	\return Returns position where the character has been found,
+	or -1 if not found. */
+	s32 findNext(T c, s32 startPos) const
+	{
+		for (s32 i=startPos; i<used; ++i)
+			if (array[i] == c)
+				return i;
+
+		return -1;
+	}
+
+
+	//! finds last occurrence of character in string
+	//! \param c: Character to search for.
+	//! \return Returns position where the character has been found,
+	//! or -1 if not found.
+	s32 findLast(T c) const
+	{
+		for (s32 i=used-1; i>=0; --i)
+			if (array[i] == c)
+				return i;
+
+		return -1;
+	}
+
+
+	//! Returns a substring
+	//! \param begin: Start of substring.
+	//! \param length: Length of substring.
+	string<T> subString(s32 begin, s32 length)
+	{
+		if (length <= 0)
+			return string<T>("");
+
+		string<T> o;
+		o.reserve(length+1);
+
+		for (s32 i=0; i<length; ++i)
+			o.array[i] = array[i+begin];
+
+		o.array[length] = 0;
+		o.used = o.allocated;
+
+		return o;
+	}
+
+
+	void operator += (T c)
+	{
+		append(c);
+	}
+
+	void operator += (const string<T>& other)
+	{
+		append(other);
+	}
+
+	void operator += (int i)
+	{
+		append(string<T>(i));
+	}
+
+	//! replaces all characters of a special type with another one
+	void replace(T toReplace, T replaceWith)
+	{
+		for (s32 i=0; i<used; ++i)
+			if (array[i] == toReplace)
+				array[i] = replaceWith;
+	}
+
+	//! trims the string.
+	/** Removes whitespace from begin and end of the string. */
+	void trim()
+	{
+		const char whitespace[] = " \t\n";
+		const int whitespacecount = 3;
+
+		// find start and end of real string without whitespace
+		int begin = findFirstCharNotInList(whitespace, whitespacecount);
+		if (begin == -1)
+			return;
+
+		int end = findLastCharNotInList(whitespace, whitespacecount);
+		if (end == -1)
+			return;
+
+		*this = subString(begin, (end +1) - begin);
+	}
+
+
+	//! Erases a character from the string. May be slow, because all elements 
+	//! following after the erased element have to be copied.
+	//! \param index: Index of element to be erased.
+	void erase(int index)
+	{
+		_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
+
+		for (int i=index+1; i<used; ++i)
+			array[i-1] = array[i];
+
+		--used;
+	}
+
+    	
+
+private:
+
+	//! Returns a character converted to lower case
+	T toLower(const T& t) const
+	{
+		if (t>=(T)'A' && t<=(T)'Z')
+			return t + ((T)'a' - (T)'A');
+		else
+			return t;
+	}
+
+	//! Reallocate the array, make it bigger or smaler
+	void reallocate(s32 new_size)
+	{
+		T* old_array = array;
+
+		array = new T[new_size];
+		allocated = new_size;
+		
+		s32 amount = used < new_size ? used : new_size;
+		for (s32 i=0; i<amount; ++i)
+			array[i] = old_array[i];
+
+		if (allocated < used)
+			used = allocated;
+		
+		delete [] old_array;
+	}
+
+
+	//--- member variables
+
+	T* array;
+	s32 allocated;
+	s32 used;
+};
+
+
+//! Typedef for character strings
+typedef string<irr::c8> stringc;
+
+//! Typedef for wide character strings
+typedef string<wchar_t> stringw;
+
+} // end namespace core
+} // end namespace irr
+
+#endif
+

+ 108 - 108
Source/ThirdParty/Assimp/contrib/irrXML/irrTypes.h

@@ -1,108 +1,108 @@
-// Copyright (C) 2002-2005 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#ifndef __IRR_TYPES_H_INCLUDED__
-#define __IRR_TYPES_H_INCLUDED__
-
-namespace irr
-{
-
-//! 8 bit unsigned variable.
-/** This is a typedef for unsigned char, it ensures portability of the engine. */
-typedef unsigned char		u8; 
-
-//! 8 bit signed variable.
-/** This is a typedef for signed char, it ensures portability of the engine. */
-typedef signed char			s8; 
-
-//! 8 bit character variable.
-/** This is a typedef for char, it ensures portability of the engine. */
-typedef char				c8; 
-
-
-
-//! 16 bit unsigned variable.
-/** This is a typedef for unsigned short, it ensures portability of the engine. */
-typedef unsigned short		u16;
-
-//! 16 bit signed variable.
-/** This is a typedef for signed short, it ensures portability of the engine. */
-typedef signed short		s16; 
-
-
-
-//! 32 bit unsigned variable.
-/** This is a typedef for unsigned int, it ensures portability of the engine. */
-typedef unsigned int		u32;
-
-//! 32 bit signed variable.
-/** This is a typedef for signed int, it ensures portability of the engine. */
-typedef signed int			s32; 
-
-
-
-// 64 bit signed variable.
-// This is a typedef for __int64, it ensures portability of the engine. 
-// This type is currently not used by the engine and not supported by compilers
-// other than Microsoft Compilers, so it is outcommented.
-//typedef __int64				s64; 
-
-
-
-//! 32 bit floating point variable.
-/** This is a typedef for float, it ensures portability of the engine. */
-typedef float				f32; 
-
-//! 64 bit floating point variable.
-/** This is a typedef for double, it ensures portability of the engine. */
-typedef double				f64; 
-
-
-} // end namespace
-
-
-// define the wchar_t type if not already built in.
-#ifdef _MSC_VER 
-#ifndef _WCHAR_T_DEFINED
-//! A 16 bit wide character type.
-/**
-	Defines the wchar_t-type.
-	In VS6, its not possible to tell
-	the standard compiler to treat wchar_t as a built-in type, and 
-	sometimes we just don't want to include the huge stdlib.h or wchar.h,
-	so we'll use this.
-*/
-typedef unsigned short wchar_t;
-#define _WCHAR_T_DEFINED
-#endif // wchar is not defined
-#endif // microsoft compiler
-
-//! define a break macro for debugging only in Win32 mode.
-// WORKAROUND (assimp): remove __asm
-#if defined(WIN32) && defined(_MSC_VER) && defined(_DEBUG)
-#if defined(_M_IX86)
-#define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) /*if (_CONDITION_) {_asm int 3}*/
-#else
-#define _IRR_DEBUG_BREAK_IF( _CONDITION_ )
-#endif
-#else 
-#define _IRR_DEBUG_BREAK_IF( _CONDITION_ )
-#endif
-
-//! Defines a small statement to work around a microsoft compiler bug.
-/** The microsft compiler 7.0 - 7.1 has a bug:
-When you call unmanaged code that returns a bool type value of false from managed code, 
-the return value may appear as true. See 
-http://support.microsoft.com/default.aspx?kbid=823071 for details. 
-Compiler version defines: VC6.0 : 1200, VC7.0 : 1300, VC7.1 : 1310, VC8.0 : 1400*/
-
-// WORKAROUND (assimp): remove __asm 
-#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER > 1299) && (_MSC_VER < 1400)
-#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX /*__asm mov eax,100*/
-#else
-#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
-#endif // _IRR_MANAGED_MARSHALLING_BUGFIX
-
-#endif // __IRR_TYPES_H_INCLUDED__
-
+// Copyright (C) 2002-2005 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#ifndef __IRR_TYPES_H_INCLUDED__
+#define __IRR_TYPES_H_INCLUDED__
+
+namespace irr
+{
+
+//! 8 bit unsigned variable.
+/** This is a typedef for unsigned char, it ensures portability of the engine. */
+typedef unsigned char		u8; 
+
+//! 8 bit signed variable.
+/** This is a typedef for signed char, it ensures portability of the engine. */
+typedef signed char			s8; 
+
+//! 8 bit character variable.
+/** This is a typedef for char, it ensures portability of the engine. */
+typedef char				c8; 
+
+
+
+//! 16 bit unsigned variable.
+/** This is a typedef for unsigned short, it ensures portability of the engine. */
+typedef unsigned short		u16;
+
+//! 16 bit signed variable.
+/** This is a typedef for signed short, it ensures portability of the engine. */
+typedef signed short		s16; 
+
+
+
+//! 32 bit unsigned variable.
+/** This is a typedef for unsigned int, it ensures portability of the engine. */
+typedef unsigned int		u32;
+
+//! 32 bit signed variable.
+/** This is a typedef for signed int, it ensures portability of the engine. */
+typedef signed int			s32; 
+
+
+
+// 64 bit signed variable.
+// This is a typedef for __int64, it ensures portability of the engine. 
+// This type is currently not used by the engine and not supported by compilers
+// other than Microsoft Compilers, so it is outcommented.
+//typedef __int64				s64; 
+
+
+
+//! 32 bit floating point variable.
+/** This is a typedef for float, it ensures portability of the engine. */
+typedef float				f32; 
+
+//! 64 bit floating point variable.
+/** This is a typedef for double, it ensures portability of the engine. */
+typedef double				f64; 
+
+
+} // end namespace
+
+
+// define the wchar_t type if not already built in.
+#ifdef _MSC_VER 
+#ifndef _WCHAR_T_DEFINED
+//! A 16 bit wide character type.
+/**
+	Defines the wchar_t-type.
+	In VS6, its not possible to tell
+	the standard compiler to treat wchar_t as a built-in type, and 
+	sometimes we just don't want to include the huge stdlib.h or wchar.h,
+	so we'll use this.
+*/
+typedef unsigned short wchar_t;
+#define _WCHAR_T_DEFINED
+#endif // wchar is not defined
+#endif // microsoft compiler
+
+//! define a break macro for debugging only in Win32 mode.
+// WORKAROUND (assimp): remove __asm
+#if defined(WIN32) && defined(_MSC_VER) && defined(_DEBUG)
+#if defined(_M_IX86)
+#define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) /*if (_CONDITION_) {_asm int 3}*/
+#else
+#define _IRR_DEBUG_BREAK_IF( _CONDITION_ )
+#endif
+#else 
+#define _IRR_DEBUG_BREAK_IF( _CONDITION_ )
+#endif
+
+//! Defines a small statement to work around a microsoft compiler bug.
+/** The microsft compiler 7.0 - 7.1 has a bug:
+When you call unmanaged code that returns a bool type value of false from managed code, 
+the return value may appear as true. See 
+http://support.microsoft.com/default.aspx?kbid=823071 for details. 
+Compiler version defines: VC6.0 : 1200, VC7.0 : 1300, VC7.1 : 1310, VC8.0 : 1400*/
+
+// WORKAROUND (assimp): remove __asm 
+#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER > 1299) && (_MSC_VER < 1400)
+#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX /*__asm mov eax,100*/
+#else
+#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
+#endif // _IRR_MANAGED_MARSHALLING_BUGFIX
+
+#endif // __IRR_TYPES_H_INCLUDED__
+

Some files were not shown because too many files changed in this diff