Parcourir la source

Merge branch 'master' into coverity_scan

Kim Kulling il y a 9 ans
Parent
commit
91f24db739
67 fichiers modifiés avec 3119 ajouts et 620 suppressions
  1. 78 42
      CMakeLists.txt
  2. 2 2
      CREDITS
  3. 1 3
      Readme.md
  4. 21 22
      code/ASEParser.cpp
  5. 35 37
      code/BlenderDNA.h
  6. 17 1
      code/BlenderDNA.inl
  7. 4 2
      code/BlenderIntermediate.h
  8. 5 4
      code/BlenderLoader.cpp
  9. 1 1
      code/BlenderScene.h
  10. 1 0
      code/CMakeLists.txt
  11. 10 6
      code/DefaultIOStream.cpp
  12. 7 7
      code/DefaultIOStream.h
  13. 84 73
      code/FBXConverter.cpp
  14. 8 7
      code/FBXDocument.h
  15. 2 3
      code/FBXMaterial.cpp
  16. 1 1
      code/IFCGeometry.cpp
  17. 3 0
      code/MDLMaterialLoader.cpp
  18. 1 1
      code/MakeVerboseFormat.cpp
  19. 0 2
      code/ObjFileImporter.cpp
  20. 7 1
      code/ObjFileParser.cpp
  21. 5 5
      code/PlyExporter.cpp
  22. 43 40
      code/XGLLoader.cpp
  23. 3 6
      code/XGLLoader.h
  24. 2 0
      code/glTFAsset.inl
  25. 3 3
      code/glTFAssetWriter.inl
  26. 3 3
      code/glTFExporter.cpp
  27. 2 3
      code/glTFExporter.h
  28. 1 1
      code/glTFImporter.cpp
  29. 1 1
      contrib/openddlparser/code/OpenDDLExport.cpp
  30. 3 3
      contrib/rapidjson/include/rapidjson/allocators.h
  31. 6 128
      contrib/rapidjson/include/rapidjson/document.h
  32. 5 5
      contrib/rapidjson/include/rapidjson/encodedstream.h
  33. 1 5
      contrib/rapidjson/include/rapidjson/filewritestream.h
  34. 2 12
      contrib/rapidjson/include/rapidjson/internal/biginteger.h
  35. 2 3
      contrib/rapidjson/include/rapidjson/internal/diyfp.h
  36. 5 5
      contrib/rapidjson/include/rapidjson/internal/dtoa.h
  37. 1 1
      contrib/rapidjson/include/rapidjson/internal/ieee754.h
  38. 1 18
      contrib/rapidjson/include/rapidjson/internal/stack.h
  39. 11 11
      contrib/rapidjson/include/rapidjson/internal/strtod.h
  40. 4 4
      contrib/rapidjson/include/rapidjson/rapidjson.h
  41. 25 83
      contrib/rapidjson/include/rapidjson/reader.h
  42. 5 5
      contrib/rapidjson/include/rapidjson/writer.h
  43. 1 1
      contrib/rapidjson/license.txt
  44. 7 7
      contrib/rapidjson/readme.md
  45. 37 10
      doc/dox_cmd.h
  46. 31 25
      include/assimp/material.h
  47. 1 1
      include/assimp/types.h
  48. 1 0
      test/CMakeLists.txt
  49. 1 1
      test/regression/ai_regression_ui.py
  50. BIN
      test/regression/db.zip
  51. 67 0
      test/unit/utBlenderIntermediate.cpp
  52. 15 3
      test/unit/utDefaultIOStream.cpp
  53. 0 1
      tools/assimp_cmd/Main.cpp
  54. 44 0
      tools/assimp_qt_viewer/CMakeLists.txt
  55. BIN
      tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt
  56. BIN
      tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt
  57. 1043 0
      tools/assimp_qt_viewer/glview.cpp
  58. 382 0
      tools/assimp_qt_viewer/glview.hpp
  59. 19 0
      tools/assimp_qt_viewer/loggerview.cpp
  60. 33 0
      tools/assimp_qt_viewer/loggerview.hpp
  61. 21 0
      tools/assimp_qt_viewer/main.cpp
  62. 344 0
      tools/assimp_qt_viewer/mainwindow.cpp
  63. 131 0
      tools/assimp_qt_viewer/mainwindow.hpp
  64. 516 0
      tools/assimp_qt_viewer/mainwindow.ui
  65. 1 0
      tools/assimp_view/CMakeLists.txt
  66. 1 2
      tools/assimp_view/assimp_view.cpp
  67. 1 9
      tools/assimp_view/assimp_view.h

+ 78 - 42
CMakeLists.txt

@@ -39,7 +39,50 @@ SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
 cmake_minimum_required( VERSION 2.8 )
 PROJECT( Assimp )
 
-OPTION(BUILD_SHARED_LIBS "Build package with shared libraries." ON)
+# All supported options ###############################################
+OPTION( BUILD_SHARED_LIBS 
+  "Build package with shared libraries." 
+  ON
+)
+OPTION( ASSIMP_DOUBLE_PRECISION
+  "Set to ON to enable double precision processing"
+  OFF
+)
+OPTION( ASSIMP_OPT_BUILD_PACKAGES 
+  "Set to ON to generate CPack configuration files and packaging targets" 
+  OFF
+)
+OPTION( ASSIMP_ANDROID_JNIIOSYSTEM 
+  "Android JNI IOSystem support is active" 
+  OFF
+)
+OPTION( ASSIMP_NO_EXPORT
+  "Disable Assimp's export functionality."
+  OFF
+)
+OPTION( ASSIMP_BUILD_ZLIB
+  "Build your own zlib"
+  OFF
+)
+option( ASSIMP_BUILD_ASSIMP_TOOLS
+  "If the supplementary tools for Assimp are built in addition to the library."
+  ON
+)
+option ( ASSIMP_BUILD_SAMPLES
+  "If the official samples are built as well (needs Glut)."
+  OFF
+)
+OPTION ( ASSIMP_BUILD_TESTS
+  "If the test suite for Assimp is built in addition to the library."
+  ON
+)
+IF(MSVC)
+  OPTION( ASSIMP_INSTALL_PDB
+    "Install MSVC debug files."
+    ON
+  )
+ENDIF(MSVC)
+
 IF(NOT BUILD_SHARED_LIBS)
   SET(LINK_SEARCH_START_STATIC TRUE)
 ENDIF(NOT BUILD_SHARED_LIBS)
@@ -80,18 +123,12 @@ IF(NOT GIT_COMMIT_HASH)
   SET(GIT_COMMIT_HASH 0)
 ENDIF(NOT GIT_COMMIT_HASH)
 
-OPTION(ASSIMP_DOUBLE_PRECISION
-    "Set to ON to enable double precision processing"
-    OFF
-)
-
 IF(ASSIMP_DOUBLE_PRECISION)
   ADD_DEFINITIONS(-DAI_DOUBLE_PRECISION)
 ENDIF(ASSIMP_DOUBLE_PRECISION)
 
 configure_file(
   ${CMAKE_CURRENT_LIST_DIR}/revision.h.in
-#  ${CMAKE_CURRENT_SOURCE_DIR}/revision.h.in
   ${CMAKE_CURRENT_BINARY_DIR}/revision.h
 )
 
@@ -106,23 +143,28 @@ include_directories(
     ${CMAKE_CURRENT_BINARY_DIR}/include
 )
 
-OPTION(ASSIMP_OPT_BUILD_PACKAGES "Set to ON to generate CPack configuration files and packaging targets" OFF)
 SET(CMAKE_MODULE_PATH       "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
 SET(LIBASSIMP_COMPONENT     "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}" )
 SET(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}-dev" )
 SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev)
 SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 
-OPTION(ASSIMP_ANDROID_JNIIOSYSTEM "Android JNI IOSystem support is active" OFF)
-
 # Workaround to be able to deal with compiler bug "Too many sections" with mingw.
 IF( CMAKE_COMPILER_IS_MINGW )
   ADD_DEFINITIONS(-DASSIMP_BUILD_NO_IFC_IMPORTER )
 ENDIF()
 
+# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
+IF( UNIX )
+  IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
+    ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
+  ENDIF()
+ENDIF()
+
 IF((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW)
   IF (BUILD_SHARED_LIBS AND CMAKE_SIZEOF_VOID_P EQUAL 8) # -fPIC is only required for shared libs on 64 bit
      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
   ENDIF()
   # hide all not-exported symbols
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -std=c++0x" )
@@ -171,8 +213,6 @@ IF (NOT TARGET uninstall)
   add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
 ENDIF()
 
-
-
 # cmake configuration files
 configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
 configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
@@ -180,22 +220,12 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"             "${C
 
 FIND_PACKAGE( DirectX )
 
-OPTION ( ASSIMP_NO_EXPORT
-  "Disable Assimp's export functionality."
-  OFF
-)
-
 IF( CMAKE_COMPILER_IS_GNUCXX )
   SET(LIBSTDC++_LIBRARIES -lstdc++)
 ENDIF( CMAKE_COMPILER_IS_GNUCXX )
 
 # Search for external dependencies, and build them from source if not found
 # Search for zlib
-OPTION(ASSIMP_BUILD_ZLIB
-    "Build your own zlib"
-    OFF
-)
-
 IF ( NOT ASSIMP_BUILD_ZLIB )
     find_package(ZLIB)
 ENDIF( NOT ASSIMP_BUILD_ZLIB )
@@ -293,10 +323,6 @@ ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 
 
 ADD_SUBDIRECTORY( code/ )
-option ( ASSIMP_BUILD_ASSIMP_TOOLS
-  "If the supplementary tools for Assimp are built in addition to the library."
-  ON
-)
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   IF ( WIN32 )
     option ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
@@ -306,12 +332,34 @@ IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   ENDIF ( WIN32 )
 
   ADD_SUBDIRECTORY( tools/assimp_cmd/ )
+
+  # Check dependencies for assimp_qt_viewer.
+  # Why here? Maybe user do not want Qt viewer and have no Qt.
+  # Why assimp_qt_viewer/CMakeLists.txt still contain similar check?
+  # Because viewer can be build independently of Assimp.
+  FIND_PACKAGE(Qt4 QUIET)
+  FIND_PACKAGE(DevIL QUIET)
+  FIND_PACKAGE(OpenGL QUIET)
+  IF ( Qt4_FOUND AND IL_FOUND AND OPENGL_FOUND)
+    ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
+  ELSE()
+    SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "")
+    IF (NOT Qt4_FOUND)
+      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt4")
+    ENDIF (NOT Qt4_FOUND)
+
+    IF (NOT IL_FOUND)
+      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} DevIL")
+    ENDIF (NOT IL_FOUND)
+
+    IF (NOT OPENGL_FOUND)
+      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL")
+    ENDIF (NOT OPENGL_FOUND)
+
+    MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}")
+  ENDIF ( Qt4_FOUND AND IL_FOUND AND OPENGL_FOUND)
 ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
 
-option ( ASSIMP_BUILD_SAMPLES
-  "If the official samples are built as well (needs Glut)."
-  OFF
-)
 
 IF ( ASSIMP_BUILD_SAMPLES)
   IF ( WIN32 )
@@ -320,22 +368,10 @@ IF ( ASSIMP_BUILD_SAMPLES)
   ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
 ENDIF ( ASSIMP_BUILD_SAMPLES )
 
-OPTION ( ASSIMP_BUILD_TESTS
-  "If the test suite for Assimp is built in addition to the library."
-  ON
-)
-
 IF ( ASSIMP_BUILD_TESTS )
   ADD_SUBDIRECTORY( test/ )
 ENDIF ( ASSIMP_BUILD_TESTS )
 
-IF(MSVC)
-  OPTION ( ASSIMP_INSTALL_PDB
-    "Install MSVC debug files."
-    ON
-  )
-ENDIF(MSVC)
-
 # Generate a pkg-config .pc for the Assimp library.
 CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
 INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})

+ 2 - 2
CREDITS

@@ -7,13 +7,13 @@ The following is a non-exhaustive list of all constributors over the years.
 If you think your name should be listed here, drop us a line and we'll add you.
 
 - Alexander Gessler,
-3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Admin and Design).
+3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design).
 
 - Thomas Schulze,
 X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation.
 
 - Kim Kulling,
-Obj-Loader, Logging system, Scons-build environment, CMake build environment, Linux build.
+Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ).
 
 - R.Schmidt,
 Linux build, eclipse support.

+ 1 - 3
Readme.md

@@ -14,7 +14,6 @@ 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>
-Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 <br>
 __[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__
 
@@ -117,8 +116,7 @@ For development discussions, there is also a (very low-volume) mailing list, _as
 
 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.
 
-And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type
-> /join #assetimporterlib
+And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)<br>
 
 ### Contributing ###
 Contributions to assimp are highly appreciated. The easiest way to get involved is to submit

+ 21 - 22
code/ASEParser.cpp

@@ -25,8 +25,8 @@ conditions are met:
   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
+  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,
@@ -1463,30 +1463,29 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh)
                 continue;
             }
             // another mesh UV channel ...
-            if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19))
-            {
-
-                unsigned int iIndex = 0;
+            if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19)) {
+                unsigned int iIndex( 0 );
                 ParseLV4MeshLong(iIndex);
-
-                if (iIndex < 2)
-                {
-                    LogWarning("Mapping channel has an invalid index. Skipping UV channel");
-                    // skip it ...
-                    SkipSection();
-                }
-                if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS)
-                {
-                    LogWarning("Too many UV channels specified. Skipping channel ..");
+                if ( 0 == iIndex ) {
+                    LogWarning( "Mapping channel has an invalid index. Skipping UV channel" );
                     // skip it ...
                     SkipSection();
+                } else {
+                    if ( iIndex < 2 ) {
+                        LogWarning( "Mapping channel has an invalid index. Skipping UV channel" );
+                        // skip it ...
+                        SkipSection();
+                    }
+                    if ( iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS ) {
+                        LogWarning( "Too many UV channels specified. Skipping channel .." );
+                        // skip it ...
+                        SkipSection();
+                    } else {
+                        // parse the mapping channel
+                        ParseLV3MappingChannel( iIndex - 1, mesh );
+                    }
+                    continue;
                 }
-                else
-                {
-                    // parse the mapping channel
-                    ParseLV3MappingChannel(iIndex-1,mesh);
-                }
-                continue;
             }
             // mesh animation keyframe. Not supported
             if (TokenMatch(filePtr,"MESH_ANIMATION" ,14))

+ 35 - 37
code/BlenderDNA.h

@@ -61,15 +61,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // #define ASSIMP_BUILD_BLENDER_NO_STATS
 
 namespace Assimp    {
-    template <bool,bool> class StreamReader;
-    typedef StreamReader<true,true> StreamReaderAny;
 
-    namespace Blender {
-        class  FileDatabase;
-        struct FileBlockHead;
+template <bool,bool> class StreamReader;
+typedef StreamReader<true,true> StreamReaderAny;
 
-        template <template <typename> class TOUT>
-        class ObjectCache;
+namespace Blender {
+
+class  FileDatabase;
+struct FileBlockHead;
+
+template <template <typename> class TOUT>
+class ObjectCache;
 
 // -------------------------------------------------------------------------------
 /** Exception class used by the blender loader to selectively catch exceptions
@@ -78,20 +80,21 @@ namespace Assimp    {
  *  the loader itself, it will still be caught by Assimp due to its
  *  ancestry. */
 // -------------------------------------------------------------------------------
-struct Error : DeadlyImportError
-{
+struct Error : DeadlyImportError {
     Error (const std::string& s)
-        : DeadlyImportError(s)
-    {}
+    : DeadlyImportError(s) {
+        // empty
+    }
 };
 
 // -------------------------------------------------------------------------------
 /** The only purpose of this structure is to feed a virtual dtor into its
  *  descendents. It serves as base class for all data structure fields. */
 // -------------------------------------------------------------------------------
-struct ElemBase
-{
-    virtual ~ElemBase() {}
+struct ElemBase {
+    virtual ~ElemBase() {
+        // empty
+    }
 
     /** Type name of the element. The type
      * string points is the `c_str` of the `name` attribute of the
@@ -103,25 +106,28 @@ struct ElemBase
     const char* dna_type;
 };
 
-
 // -------------------------------------------------------------------------------
 /** Represents a generic pointer to a memory location, which can be either 32
  *  or 64 bits. These pointers are loaded from the BLEND file and finally
  *  fixed to point to the real, converted representation of the objects
  *  they used to point to.*/
 // -------------------------------------------------------------------------------
-struct Pointer
-{
-    Pointer() : val() {}
+struct Pointer {
+    Pointer()
+    : val() {
+        // empty
+    }
     uint64_t val;
 };
 
 // -------------------------------------------------------------------------------
 /** Represents a generic offset within a BLEND file */
 // -------------------------------------------------------------------------------
-struct FileOffset
-{
-    FileOffset() : val() {}
+struct FileOffset {
+    FileOffset()
+    : val() {
+        // empty
+    }
     uint64_t val;
 };
 
@@ -132,8 +138,7 @@ struct FileOffset
  *  functions of shared_ptr */
 // -------------------------------------------------------------------------------
 template <typename T>
-class vector : public std::vector<T>
-{
+class vector : public std::vector<T> {
 public:
     using std::vector<T>::resize;
     using std::vector<T>::empty;
@@ -150,8 +155,7 @@ public:
 // -------------------------------------------------------------------------------
 /** Mixed flags for use in #Field */
 // -------------------------------------------------------------------------------
-enum FieldFlags
-{
+enum FieldFlags {
     FieldFlag_Pointer = 0x1,
     FieldFlag_Array   = 0x2
 };
@@ -159,8 +163,7 @@ enum FieldFlags
 // -------------------------------------------------------------------------------
 /** Represents a single member of a data structure in a BLEND file */
 // -------------------------------------------------------------------------------
-struct Field
-{
+struct Field {
     std::string name;
     std::string type;
 
@@ -180,8 +183,7 @@ struct Field
  *  mission critical so we need them, while others can silently be default
  *  initialized and no animations are harmed. */
 // -------------------------------------------------------------------------------
-enum ErrorPolicy
-{
+enum ErrorPolicy {
     /** Substitute default value and ignore */
     ErrorPolicy_Igno,
     /** Substitute default value and write to log */
@@ -202,15 +204,14 @@ enum ErrorPolicy
  *  binary `blob` read from the file to such a structure instance with
  *  meaningful contents. */
 // -------------------------------------------------------------------------------
-class Structure
-{
+class Structure {
     template <template <typename> class> friend class ObjectCache;
 
 public:
-
     Structure()
-        :   cache_idx(static_cast<size_t>(-1) )
-    {}
+    : cache_idx(static_cast<size_t>(-1) ){
+        // empty
+    }
 
 public:
 
@@ -709,8 +710,6 @@ class FileDatabase
     template <template <typename> class TOUT> friend class ObjectCache;
 
 public:
-
-
     FileDatabase()
         : _cacheArrays(*this)
         , _cache(*this)
@@ -718,7 +717,6 @@ public:
     {}
 
 public:
-
     // publicly accessible fields
     bool i64bit;
     bool little;

+ 17 - 1
code/BlenderDNA.inl

@@ -532,7 +532,7 @@ template <typename T> struct signless;
 template <> struct signless<char> {typedef unsigned char type;};
 template <> struct signless<short> {typedef unsigned short type;};
 template <> struct signless<int> {typedef unsigned int type;};
-
+template <> struct signless<unsigned char> { typedef unsigned char type; };
 template <typename T>
 struct static_cast_silent {
     template <typename V>
@@ -614,6 +614,22 @@ template <> inline void Structure :: Convert<char>   (char& dest,const FileDatab
     ConvertDispatcher(dest,*this,db);
 }
 
+// ------------------------------------------------------------------------------------------------
+template <> inline void Structure::Convert<unsigned char>(unsigned char& dest, const FileDatabase& db) const
+{
+	// automatic rescaling from char to float and vice versa (seems useful for RGB colors)
+	if (name == "float") {
+		dest = static_cast<unsigned char>(db.reader->GetF4() * 255.f);
+		return;
+	}
+	else if (name == "double") {
+		dest = static_cast<unsigned char>(db.reader->GetF8() * 255.f);
+		return;
+	}
+	ConvertDispatcher(dest, *this, db);
+}
+
+
 // ------------------------------------------------------------------------------------------------
 template <> inline void Structure :: Convert<float>  (float& dest,const FileDatabase& db) const
 {

+ 4 - 2
code/BlenderIntermediate.h

@@ -123,7 +123,8 @@ namespace Blender {
 
     struct ObjectCompare {
         bool operator() (const Object* left, const Object* right) const {
-            return strcmp(left->id.name, right->id.name) == -1;
+            printf( "left: %s, right: %s\n", left->id.name, right->id.name );
+            return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) == 0;
         }
     };
 
@@ -144,7 +145,8 @@ namespace Blender {
 
         struct ObjectCompare {
             bool operator() (const Object* left, const Object* right) const {
-                return strcmp(left->id.name, right->id.name) == -1;
+                printf( "left: %s, right: %s\n", left->id.name, right->id.name );
+                return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) == 0;
             }
         };
 

+ 5 - 4
code/BlenderLoader.cpp

@@ -1118,12 +1118,13 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
             const aiFace& f = out->mFaces[out->mNumFaces++];
 
             aiColor4D* vo = &out->mColors[0][out->mNumVertices];
+			const ai_real scaleZeroToOne = 1.f/255.f;
             for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
                 const MLoopCol& col = mesh->mloopcol[v.loopstart + j];
-                vo->r = col.r;
-                vo->g = col.g;
-                vo->b = col.b;
-                vo->a = col.a;
+                vo->r = ai_real(col.r) * scaleZeroToOne;
+                vo->g = ai_real(col.g) * scaleZeroToOne;
+                vo->b = ai_real(col.b) * scaleZeroToOne;
+                vo->a = ai_real(col.a) * scaleZeroToOne;
             }
 
         }

+ 1 - 1
code/BlenderScene.h

@@ -175,7 +175,7 @@ struct MLoopUV : ElemBase {
 // -------------------------------------------------------------------------------
 // Note that red and blue are not swapped, as with MCol
 struct MLoopCol : ElemBase {
-    char r, g, b, a;
+	unsigned char r, g, b, a;
 };
 
 // -------------------------------------------------------------------------------

+ 1 - 0
code/CMakeLists.txt

@@ -722,6 +722,7 @@ if (UNZIP_FOUND)
   SET (unzip_compile_SRCS "")
 else (UNZIP_FOUND)
   SET (unzip_compile_SRCS ${unzip_SRCS})
+  INCLUDE_DIRECTORIES( "../contrib/unzip/" )
 endif (UNZIP_FOUND)
 
 MESSAGE(STATUS "Enabled formats:${ASSIMP_IMPORTERS_ENABLED}")

+ 10 - 6
code/DefaultIOStream.cpp

@@ -55,6 +55,7 @@ DefaultIOStream::~DefaultIOStream()
 {
     if (mFile) {
         ::fclose(mFile);
+        mFile = nullptr;
     }
 }
 
@@ -109,9 +110,9 @@ size_t DefaultIOStream::FileSize() const
         return 0;
     }
 
-    if (SIZE_MAX == cachedSize) {
+    if (SIZE_MAX == mCachedSize ) {
 
-        // Although fseek/ftell would allow us to reuse the exising file handle here,
+        // Although fseek/ftell would allow us to reuse the existing file handle here,
         // it is generally unsafe because:
         //  - For binary streams, it is not technically well-defined
         //  - For text files the results are meaningless
@@ -124,16 +125,19 @@ size_t DefaultIOStream::FileSize() const
         int err = _stat64(  mFilename.c_str(), &fileStat );
         if (0 != err)
             return 0;
-        cachedSize = (size_t) (fileStat.st_size);
-#else
+        mCachedSize = (size_t) (fileStat.st_size);
+#elif defined __gnu_linux__ || defined __APPLE__ || defined __MACH__
         struct stat fileStat;
         int err = stat(mFilename.c_str(), &fileStat );
         if (0 != err)
             return 0;
-        cachedSize = (size_t) (fileStat.st_size);
+        const unsigned long long cachedSize = fileStat.st_size;
+        mCachedSize = static_cast< size_t >( cachedSize );
+#else
+#   error "Unknown platform"
 #endif
     }
-    return cachedSize;
+    return mCachedSize;
 }
 
 // ----------------------------------------------------------------------------------

+ 7 - 7
code/DefaultIOStream.h

@@ -59,11 +59,11 @@ class ASSIMP_API DefaultIOStream : public IOStream
 {
     friend class DefaultIOSystem;
 #if __ANDROID__
-#if __ANDROID_API__ > 9
-#if defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
+# if __ANDROID_API__ > 9
+#  if defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
     friend class AndroidJNIIOSystem;
-#endif // defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
-#endif // __ANDROID_API__ > 9
+#  endif // defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
+# endif // __ANDROID_API__ > 9
 #endif // __ANDROID__
 
 protected:
@@ -111,7 +111,7 @@ private:
     std::string mFilename;
 
     // Cached file size
-    mutable size_t cachedSize;
+    mutable size_t mCachedSize;
 };
 
 
@@ -119,7 +119,7 @@ private:
 inline DefaultIOStream::DefaultIOStream () :
     mFile       (NULL),
     mFilename   (""),
-    cachedSize  (SIZE_MAX)
+    mCachedSize(SIZE_MAX)
 {
     // empty
 }
@@ -130,7 +130,7 @@ inline DefaultIOStream::DefaultIOStream (FILE* pFile,
         const std::string &strFilename) :
     mFile(pFile),
     mFilename(strFilename),
-    cachedSize  (SIZE_MAX)
+    mCachedSize(SIZE_MAX)
 {
     // empty
 }

+ 84 - 73
code/FBXConverter.cpp

@@ -1916,57 +1916,92 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextu
         return;
     }
 
-    const Texture* const tex = ( *it ).second->getTexture();
+    int texCount = (*it).second->textureCount();
+    
+    // Set the blend mode for layered textures
+	int blendmode= (*it).second->GetBlendMode();
+	out_mat->AddProperty(&blendmode,1,_AI_MATKEY_TEXOP_BASE,target,0);
 
-    aiString path;
-    path.Set( tex->RelativeFilename() );
+	for(int texIndex = 0; texIndex < texCount; texIndex++){
+    
+        const Texture* const tex = ( *it ).second->getTexture(texIndex);
 
-    out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 );
+        aiString path;
+        path.Set( tex->RelativeFilename() );
 
-    aiUVTransform uvTrafo;
-    // XXX handle all kinds of UV transformations
-    uvTrafo.mScaling = tex->UVScaling();
-    uvTrafo.mTranslation = tex->UVTranslation();
-    out_mat->AddProperty( &uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0 );
+        out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, texIndex );
 
-    const PropertyTable& props = tex->Props();
+        aiUVTransform uvTrafo;
+        // XXX handle all kinds of UV transformations
+        uvTrafo.mScaling = tex->UVScaling();
+        uvTrafo.mTranslation = tex->UVTranslation();
+        out_mat->AddProperty( &uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex );
 
-    int uvIndex = 0;
+        const PropertyTable& props = tex->Props();
 
-    bool ok;
-    const std::string& uvSet = PropertyGet<std::string>( props, "UVSet", ok );
-    if ( ok ) {
-        // "default" is the name which usually appears in the FbxFileTexture template
-        if ( uvSet != "default" && uvSet.length() ) {
-            // this is a bit awkward - we need to find a mesh that uses this
-            // material and scan its UV channels for the given UV name because
-            // assimp references UV channels by index, not by name.
-
-            // XXX: the case that UV channels may appear in different orders
-            // in meshes is unhandled. A possible solution would be to sort
-            // the UV channels alphabetically, but this would have the side
-            // effect that the primary (first) UV channel would sometimes
-            // be moved, causing trouble when users read only the first
-            // UV channel and ignore UV channel assignments altogether.
-
-            const unsigned int matIndex = static_cast<unsigned int>( std::distance( materials.begin(),
-                std::find( materials.begin(), materials.end(), out_mat )
-                ) );
-
-            uvIndex = -1;
-            if ( !mesh )
-            {
-                for( const MeshMap::value_type& v : meshes_converted ) {
-                    const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> ( v.first );
-                    if ( !mesh ) {
-                        continue;
-                    }
+        int uvIndex = 0;
 
-                    const MatIndexArray& mats = mesh->GetMaterialIndices();
-                    if ( std::find( mats.begin(), mats.end(), matIndex ) == mats.end() ) {
-                        continue;
-                    }
+        bool ok;
+        const std::string& uvSet = PropertyGet<std::string>( props, "UVSet", ok );
+        if ( ok ) {
+            // "default" is the name which usually appears in the FbxFileTexture template
+            if ( uvSet != "default" && uvSet.length() ) {
+                // this is a bit awkward - we need to find a mesh that uses this
+                // material and scan its UV channels for the given UV name because
+                // assimp references UV channels by index, not by name.
 
+                // XXX: the case that UV channels may appear in different orders
+                // in meshes is unhandled. A possible solution would be to sort
+                // the UV channels alphabetically, but this would have the side
+                // effect that the primary (first) UV channel would sometimes
+                // be moved, causing trouble when users read only the first
+                // UV channel and ignore UV channel assignments altogether.
+
+                const unsigned int matIndex = static_cast<unsigned int>( std::distance( materials.begin(),
+                    std::find( materials.begin(), materials.end(), out_mat )
+                    ) );
+
+                uvIndex = -1;
+                if ( !mesh )
+                {
+                    for( const MeshMap::value_type& v : meshes_converted ) {
+                        const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> ( v.first );
+                        if ( !mesh ) {
+                            continue;
+                        }
+
+                        const MatIndexArray& mats = mesh->GetMaterialIndices();
+                        if ( std::find( mats.begin(), mats.end(), matIndex ) == mats.end() ) {
+                            continue;
+                        }
+
+                        int index = -1;
+                        for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) {
+                            if ( mesh->GetTextureCoords( i ).empty() ) {
+                                break;
+                            }
+                            const std::string& name = mesh->GetTextureCoordChannelName( i );
+                            if ( name == uvSet ) {
+                                index = static_cast<int>( i );
+                                break;
+                            }
+                        }
+                        if ( index == -1 ) {
+                            FBXImporter::LogWarn( "did not find UV channel named " + uvSet + " in a mesh using this material" );
+                            continue;
+                        }
+
+                        if ( uvIndex == -1 ) {
+                            uvIndex = index;
+                        }
+                        else {
+                            FBXImporter::LogWarn( "the UV channel named " + uvSet +
+                                " appears at different positions in meshes, results will be wrong" );
+                        }
+                    }
+                }
+                else
+                {
                     int index = -1;
                     for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) {
                         if ( mesh->GetTextureCoords( i ).empty() ) {
@@ -1980,48 +2015,22 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextu
                     }
                     if ( index == -1 ) {
                         FBXImporter::LogWarn( "did not find UV channel named " + uvSet + " in a mesh using this material" );
-                        continue;
                     }
 
                     if ( uvIndex == -1 ) {
                         uvIndex = index;
                     }
-                    else {
-                        FBXImporter::LogWarn( "the UV channel named " + uvSet +
-                            " appears at different positions in meshes, results will be wrong" );
-                    }
-                }
-            }
-            else
-            {
-                int index = -1;
-                for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) {
-                    if ( mesh->GetTextureCoords( i ).empty() ) {
-                        break;
-                    }
-                    const std::string& name = mesh->GetTextureCoordChannelName( i );
-                    if ( name == uvSet ) {
-                        index = static_cast<int>( i );
-                        break;
-                    }
-                }
-                if ( index == -1 ) {
-                    FBXImporter::LogWarn( "did not find UV channel named " + uvSet + " in a mesh using this material" );
                 }
 
                 if ( uvIndex == -1 ) {
-                    uvIndex = index;
+                    FBXImporter::LogWarn( "failed to resolve UV channel " + uvSet + ", using first UV channel" );
+                    uvIndex = 0;
                 }
             }
-
-            if ( uvIndex == -1 ) {
-                FBXImporter::LogWarn( "failed to resolve UV channel " + uvSet + ", using first UV channel" );
-                uvIndex = 0;
-            }
         }
-    }
 
-    out_mat->AddProperty( &uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0 );
+        out_mat->AddProperty( &uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex );
+    }
 }
 
 void Converter::SetTextureProperties( aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh )
@@ -2030,6 +2039,7 @@ void Converter::SetTextureProperties( aiMaterial* out_mat, const TextureMap& tex
     TrySetTextureProperties( out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh );
     TrySetTextureProperties( out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh );
     TrySetTextureProperties( out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh );
+    TrySetTextureProperties( out_mat, textures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
     TrySetTextureProperties( out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh );
     TrySetTextureProperties( out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh );
     TrySetTextureProperties( out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh );
@@ -2044,6 +2054,7 @@ void Converter::SetTextureProperties( aiMaterial* out_mat, const LayeredTextureM
     TrySetTextureProperties( out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh );
     TrySetTextureProperties( out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh );
     TrySetTextureProperties( out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh );
+    TrySetTextureProperties( out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
     TrySetTextureProperties( out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh );
     TrySetTextureProperties( out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh );
     TrySetTextureProperties( out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh );

+ 8 - 7
code/FBXDocument.h

@@ -594,23 +594,24 @@ public:
         BlendMode_BlendModeCount
     };
 
-    const Texture* getTexture() const
+    const Texture* getTexture(int index=0) const
     {
-        return texture;
-    }
+		return textures[index];
 
-    BlendMode GetBlendMode()
+    }
+	const int textureCount() const {
+		return textures.size();
+	}
+    const BlendMode GetBlendMode() const
     {
         return blendMode;
     }
-    
     float Alpha()
     {
         return alpha;
     }
-
 private:
-    const Texture* texture;
+	std::vector<const Texture*> textures;
     BlendMode blendMode;
     float alpha;
 };

+ 2 - 3
code/FBXMaterial.cpp

@@ -227,7 +227,6 @@ Texture::~Texture()
 
 LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name)
 : Object(id,element,name)
-,texture(0)
 ,blendMode(BlendMode_Modulate)
 ,alpha(1)
 {
@@ -249,7 +248,7 @@ LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Docume
 
 LayeredTexture::~LayeredTexture()
 {
-
+    
 }
 
 void LayeredTexture::fillTexture(const Document& doc)
@@ -267,7 +266,7 @@ void LayeredTexture::fillTexture(const Document& doc)
 
         const Texture* const tex = dynamic_cast<const Texture*>(ob);
 
-        texture = tex;
+        textures.push_back(tex);
     }
 }
 

+ 1 - 1
code/IFCGeometry.cpp

@@ -282,7 +282,7 @@ void ProcessRevolvedAreaSolid(const IfcRevolvedAreaSolid& solid, TempMesh& resul
             const size_t next = (i+1)%size;
 
             result.vertcnt.push_back(4);
-            const IfcVector3& base_0 = out[base+i*4+3],base_1 = out[base+next*4+3];
+            const IfcVector3 base_0 = out[base+i*4+3],base_1 = out[base+next*4+3];
 
             out.push_back(base_0);
             out.push_back(base_1);

+ 3 - 0
code/MDLMaterialLoader.cpp

@@ -731,6 +731,9 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
     }
     VALIDATE_FILE_SIZE(szCurrent);
     *szCurrentOut = szCurrent;
+    if ( nullptr != pcNew ) {
+        delete pcNew;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------

+ 1 - 1
code/MakeVerboseFormat.cpp

@@ -171,7 +171,7 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh)
     // build output vertex weights
     for (unsigned int i = 0;i < pcMesh->mNumBones;++i)
     {
-        delete pcMesh->mBones[i]->mWeights;
+        delete [] pcMesh->mBones[i]->mWeights;
         if (!newWeights[i].empty()) {
             pcMesh->mBones[i]->mWeights = new aiVertexWeight[newWeights[i].size()];
             aiVertexWeight *weightToCopy = &( newWeights[i][0] );

+ 0 - 2
code/ObjFileImporter.cpp

@@ -39,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
-
 #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
 
 #include "DefaultIOSystem.h"
@@ -52,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/ai_assert.h>
 #include <assimp/DefaultLogger.hpp>
 
-
 static const aiImporterDesc desc = {
     "Wavefront Object Importer",
     "",

+ 7 - 1
code/ObjFileParser.cpp

@@ -696,6 +696,8 @@ void ObjFileParser::getGroupName()
 {
     std::string strGroupName;
 
+    // here we skip 'g ' from line
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName);
     if( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) {
         return;
@@ -832,7 +834,11 @@ bool ObjFileParser::needsNewMesh( const std::string &materialName )
     bool newMat = false;
     int matIdx = getMaterialIndex( materialName );
     int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
-    if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx )
+    if ( curMatIdx != int(ObjFile::Mesh::NoMaterial)
+        && curMatIdx != matIdx
+        // no need create a new mesh if no faces in current
+        // lets say 'usemtl' goes straight after 'g'
+        && m_pModel->m_pCurrentMesh->m_Faces.size() > 0 )
     {
         // New material -> only one material per mesh, so we need to create a new
         // material

+ 5 - 5
code/PlyExporter.cpp

@@ -56,11 +56,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //using namespace Assimp;
 namespace Assimp    {
 
-// make sure typeof returns consistent output across different platforms
+// make sure type_of returns consistent output across different platforms
 // also consider using: typeid(VAR).name()
-template <typename T> const char* typeof(T&) { return "unknown"; }
-template<> const char* typeof(float&) { return "float"; }
-template<> const char* typeof(double&) { return "double"; }
+template <typename T> const char* type_of(T&) { return "unknown"; }
+template<> const char* type_of(float&) { return "float"; }
+template<> const char* type_of(double&) { return "double"; }
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to PLY. Prototyped and registered in Exporter.cpp
@@ -146,7 +146,7 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina
     //       definitely not good to always write float even if we might have double precision
 
     ai_real tmp = 0.0;
-    const char * typeName = typeof(tmp);
+    const char * typeName = type_of(tmp);
 
     mOutput << "element vertex " << vertices << endl;
     mOutput << "property " << typeName << " x" << endl;

+ 43 - 40
code/XGLLoader.cpp

@@ -102,12 +102,16 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 XGLImporter::XGLImporter()
-{}
+: m_reader( nullptr )
+, m_scene( nullptr ) {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-XGLImporter::~XGLImporter()
-{}
+XGLImporter::~XGLImporter() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
@@ -149,7 +153,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
     free_it free_it_really(dest);
 #endif
 
-    scene = pScene;
+    m_scene = pScene;
     std::shared_ptr<IOStream> stream( pIOHandler->Open( pFile, "rb"));
 
     // check whether we can read from the file
@@ -211,14 +215,13 @@ void XGLImporter::InternReadFile( const std::string& pFile,
 
     // construct the irrXML parser
     CIrrXML_IOStreamReader st(stream.get());
-    std::unique_ptr<IrrXMLReader> read( createIrrXMLReader((IFileReadCallBack*) &st) );
-    reader = read.get();
+    m_reader.reset( createIrrXMLReader( ( IFileReadCallBack* ) &st ) );
 
     // parse the XML file
     TempScope scope;
 
     while (ReadElement())   {
-        if (!ASSIMP_stricmp(reader->getNodeName(),"world")) {
+        if (!ASSIMP_stricmp(m_reader->getNodeName(),"world")) {
             ReadWorld(scope);
         }
     }
@@ -231,21 +234,21 @@ void XGLImporter::InternReadFile( const std::string& pFile,
     }
 
     // copy meshes
-    scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
-    scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
-    std::copy(meshes.begin(),meshes.end(),scene->mMeshes);
+    m_scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
+    m_scene->mMeshes = new aiMesh*[m_scene->mNumMeshes]();
+    std::copy(meshes.begin(),meshes.end(),m_scene->mMeshes);
 
     // copy materials
-    scene->mNumMaterials = static_cast<unsigned int>(materials.size());
-    scene->mMaterials = new aiMaterial*[scene->mNumMaterials]();
-    std::copy(materials.begin(),materials.end(),scene->mMaterials);
+    m_scene->mNumMaterials = static_cast<unsigned int>(materials.size());
+    m_scene->mMaterials = new aiMaterial*[m_scene->mNumMaterials]();
+    std::copy(materials.begin(),materials.end(),m_scene->mMaterials);
 
     if (scope.light) {
-        scene->mNumLights = 1;
-        scene->mLights = new aiLight*[1];
-        scene->mLights[0] = scope.light;
+        m_scene->mNumLights = 1;
+        m_scene->mLights = new aiLight*[1];
+        m_scene->mLights[0] = scope.light;
 
-        scope.light->mName = scene->mRootNode->mName;
+        scope.light->mName = m_scene->mRootNode->mName;
     }
 
     scope.dismiss();
@@ -254,8 +257,8 @@ void XGLImporter::InternReadFile( const std::string& pFile,
 // ------------------------------------------------------------------------------------------------
 bool XGLImporter::ReadElement()
 {
-    while(reader->read()) {
-        if (reader->getNodeType() == EXN_ELEMENT) {
+    while(m_reader->read()) {
+        if (m_reader->getNodeType() == EXN_ELEMENT) {
             return true;
         }
     }
@@ -265,11 +268,11 @@ bool XGLImporter::ReadElement()
 // ------------------------------------------------------------------------------------------------
 bool XGLImporter::ReadElementUpToClosing(const char* closetag)
 {
-    while(reader->read()) {
-        if (reader->getNodeType() == EXN_ELEMENT) {
+    while(m_reader->read()) {
+        if (m_reader->getNodeType() == EXN_ELEMENT) {
             return true;
         }
-        else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(),closetag)) {
+        else if (m_reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(m_reader->getNodeName(),closetag)) {
             return false;
         }
     }
@@ -280,11 +283,11 @@ bool XGLImporter::ReadElementUpToClosing(const char* closetag)
 // ------------------------------------------------------------------------------------------------
 bool XGLImporter::SkipToText()
 {
-    while(reader->read()) {
-        if (reader->getNodeType() == EXN_TEXT) {
+    while(m_reader->read()) {
+        if (m_reader->getNodeType() == EXN_TEXT) {
             return true;
         }
-        else if (reader->getNodeType() == EXN_ELEMENT || reader->getNodeType() == EXN_ELEMENT_END) {
+        else if (m_reader->getNodeType() == EXN_ELEMENT || m_reader->getNodeType() == EXN_ELEMENT_END) {
             ThrowException("expected text contents but found another element (or element end)");
         }
     }
@@ -294,7 +297,7 @@ bool XGLImporter::SkipToText()
 // ------------------------------------------------------------------------------------------------
 std::string XGLImporter::GetElementName()
 {
-    const char* s  = reader->getNodeName();
+    const char* s  = m_reader->getNodeName();
     size_t len = strlen(s);
 
     std::string ret;
@@ -328,7 +331,7 @@ void XGLImporter::ReadWorld(TempScope& scope)
         nd->mName.Set("WORLD");
     }
 
-    scene->mRootNode = nd;
+    m_scene->mRootNode = nd;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -586,29 +589,29 @@ bool XGLImporter::ReadMesh(TempScope& scope)
             ReadMaterial(scope);
         }
         else if (s == "p") {
-            if (!reader->getAttributeValue("ID")) {
+            if (!m_reader->getAttributeValue("ID")) {
                 LogWarn("no ID attribute on <p>, ignoring");
             }
             else {
-                int id = reader->getAttributeValueAsInt("ID");
+                int id = m_reader->getAttributeValueAsInt("ID");
                 t.points[id] = ReadVec3();
             }
         }
         else if (s == "n") {
-            if (!reader->getAttributeValue("ID")) {
+            if (!m_reader->getAttributeValue("ID")) {
                 LogWarn("no ID attribute on <n>, ignoring");
             }
             else {
-                int id = reader->getAttributeValueAsInt("ID");
+                int id = m_reader->getAttributeValueAsInt("ID");
                 t.normals[id] = ReadVec3();
             }
         }
         else if (s == "tc") {
-            if (!reader->getAttributeValue("ID")) {
+            if (!m_reader->getAttributeValue("ID")) {
                 LogWarn("no ID attribute on <tc>, ignoring");
             }
             else {
-                int id = reader->getAttributeValueAsInt("ID");
+                int id = m_reader->getAttributeValueAsInt("ID");
                 t.uvs[id] = ReadVec2();
             }
         }
@@ -828,10 +831,10 @@ void XGLImporter::ReadFaceVertex(const TempMesh& t, TempFace& out)
 // ------------------------------------------------------------------------------------------------
 unsigned int XGLImporter::ReadIDAttr()
 {
-    for(int i = 0, e = reader->getAttributeCount(); i < e; ++i) {
+    for(int i = 0, e = m_reader->getAttributeCount(); i < e; ++i) {
 
-        if(!ASSIMP_stricmp(reader->getAttributeName(i),"id")) {
-            return reader->getAttributeValueAsInt(i);
+        if(!ASSIMP_stricmp(m_reader->getAttributeName(i),"id")) {
+            return m_reader->getAttributeValueAsInt(i);
         }
     }
     return ~0u;
@@ -844,7 +847,7 @@ float XGLImporter::ReadFloat()
         LogError("unexpected EOF reading float element contents");
         return 0.f;
     }
-    const char* s = reader->getNodeData(), *se;
+    const char* s = m_reader->getNodeData(), *se;
 
     if(!SkipSpaces(&s)) {
         LogError("unexpected EOL, failed to parse float");
@@ -869,7 +872,7 @@ unsigned int XGLImporter::ReadIndexFromText()
         LogError("unexpected EOF reading index element contents");
         return ~0u;
     }
-    const char* s = reader->getNodeData(), *se;
+    const char* s = m_reader->getNodeData(), *se;
     if(!SkipSpaces(&s)) {
         LogError("unexpected EOL, failed to parse index element");
         return ~0u;
@@ -894,7 +897,7 @@ aiVector2D XGLImporter::ReadVec2()
         LogError("unexpected EOF reading vec2 contents");
         return vec;
     }
-    const char* s = reader->getNodeData();
+    const char* s = m_reader->getNodeData();
 
     for(int i = 0; i < 2; ++i) {
         if(!SkipSpaces(&s)) {
@@ -923,7 +926,7 @@ aiVector3D XGLImporter::ReadVec3()
         LogError("unexpected EOF reading vec3 contents");
         return vec;
     }
-    const char* s = reader->getNodeData();
+    const char* s = m_reader->getNodeData();
 
     for(int i = 0; i < 3; ++i) {
         if(!SkipSpaces(&s)) {

+ 3 - 6
code/XGLLoader.h

@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Importer.hpp>
 #include <assimp/mesh.h>
 #include <assimp/light.h>
+#include <memory>
 
 struct aiNode;
 
@@ -203,12 +204,8 @@ private:
     unsigned int ResolveMaterialRef(TempScope& scope);
 
 private:
-
-
-private:
-
-    irr::io::IrrXMLReader* reader;
-    aiScene* scene;
+    std::shared_ptr<irr::io::IrrXMLReader> m_reader;
+    aiScene* m_scene;
 };
 
 } // end of namespace Assimp

+ 2 - 0
code/glTFAsset.inl

@@ -40,6 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "StringUtils.h"
 
+using namespace Assimp;
+
 namespace glTF {
 
 namespace {

+ 3 - 3
code/glTFAssetWriter.inl

@@ -105,7 +105,7 @@ namespace glTF {
                 type = "arraybuffer";
         }
 
-        obj.AddMember("byteLength", b.byteLength, w.mAl);
+        obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
         obj.AddMember("type", StringRef(type), w.mAl);
         obj.AddMember("uri", Value(dataURI, w.mAl).Move(), w.mAl);
     }
@@ -113,8 +113,8 @@ namespace glTF {
     inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
     {
         obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl);
-        obj.AddMember("byteOffset", bv.byteOffset, w.mAl);
-        obj.AddMember("byteLength", bv.byteLength, w.mAl);
+        obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl);
+        obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl);
         obj.AddMember("target", int(bv.target), w.mAl);
     }
 

+ 3 - 3
code/glTFExporter.cpp

@@ -93,11 +93,11 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc
     , mScene(pScene)
     , mProperties(pProperties)
 {
-    std::unique_ptr<Asset> asset(new glTF::Asset(pIOSystem));
-    mAsset = asset.get();
+    std::unique_ptr<Asset> asset();
+    mAsset.reset( new glTF::Asset( pIOSystem ) );
 
     if (isBinary) {
-        asset->SetAsBinary();
+        mAsset->SetAsBinary();
     }
 
     ExportMetadata();

+ 2 - 3
code/glTFExporter.h

@@ -46,13 +46,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <assimp/types.h>
 #include <assimp/material.h>
+
 #include <sstream>
 #include <vector>
 #include <map>
-
 #include <memory>
 
-
 struct aiScene;
 struct aiNode;
 struct aiMaterial;
@@ -89,7 +88,7 @@ namespace Assimp
 
         std::map<std::string, unsigned int> mTexturesByPath;
 
-        glTF::Asset* mAsset;
+        std::shared_ptr<glTF::Asset> mAsset;
 
         std::vector<unsigned char> mBodyData;
 

+ 1 - 1
code/glTFImporter.cpp

@@ -303,7 +303,7 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
                 attr.normal[0]->ExtractData(aim->mNormals);
             }
 
-            for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
+            for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
                 attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
                 aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
 

+ 1 - 1
contrib/openddlparser/code/OpenDDLExport.cpp

@@ -280,7 +280,7 @@ bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std:
         statement += "[";
         char buffer[ 256 ];
         ::memset( buffer, '\0', 256 * sizeof( char ) );
-        sprintf( buffer, "%d", numItems );
+        sprintf( buffer, "%d", int(numItems) );
         statement += buffer;
         statement += "]";
     }

+ 3 - 3
contrib/rapidjson/include/rapidjson/allocators.h

@@ -181,7 +181,7 @@ public:
         if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
             AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
 
-        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
+        void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
         chunkHead_->size += size;
         return buffer;
     }
@@ -199,7 +199,7 @@ public:
             return originalPtr;
 
         // Simply expand it if it is the last allocation and there is sufficient space
-        if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+        if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
             size_t increment = static_cast<size_t>(newSize - originalSize);
             increment = RAPIDJSON_ALIGN(increment);
             if (chunkHead_->size + increment <= chunkHead_->capacity) {
@@ -231,7 +231,7 @@ private:
     void AddChunk(size_t capacity) {
         if (!baseAllocator_)
             ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
-        ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
+        ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
         chunk->capacity = capacity;
         chunk->size = 0;
         chunk->next = chunkHead_;

+ 6 - 128
contrib/rapidjson/include/rapidjson/document.h

@@ -69,9 +69,6 @@ RAPIDJSON_NAMESPACE_BEGIN
 template <typename Encoding, typename Allocator>
 class GenericValue;
 
-template <typename Encoding, typename Allocator, typename StackAllocator>
-class GenericDocument;
-
 //! Name-value pair in a JSON object value.
 /*!
     This class was internal to GenericValue. It used to be a inner struct.
@@ -449,16 +446,6 @@ private:
     //! Copy constructor is not permitted.
     GenericValue(const GenericValue& rhs);
 
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
-    //! Moving from a GenericDocument is not permitted.
-    template <typename StackAllocator>
-    GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
-
-    //! Move assignment from a GenericDocument is not permitted.
-    template <typename StackAllocator>
-    GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
-#endif
-
 public:
 
     //! Constructor with JSON value type.
@@ -545,28 +532,6 @@ public:
             flags_ |= kIntFlag;
     }
 
-#if defined(__APPLE__)
-    //! Constructor for unsigned long value.
-    explicit GenericValue(unsigned long u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
-        data_.n.u64 = u64;
-        if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
-            flags_ |= kInt64Flag;
-        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
-            flags_ |= kUintFlag;
-        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
-            flags_ |= kIntFlag;
-    }
-
-#if !defined(__x86_64__) && !defined(__arm64__)
-    //! Constructor for size_t value.
-    explicit GenericValue( size_t u ) RAPIDJSON_NOEXCEPT : data_(), flags_( kNumberUintFlag ) {
-        data_.n.u64 = u;
-        if ( !( u&0x80000000 ) )
-            flags_ |= kIntFlag|kInt64Flag;
-    }
-#endif
-#endif
-
     //! Constructor for double value.
     explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
 
@@ -695,20 +660,6 @@ public:
         return *this;
     }
 
-    //! free-standing swap function helper
-    /*!
-        Helper function to enable support for common swap implementation pattern based on \c std::swap:
-        \code
-        void swap(MyClass& a, MyClass& b) {
-            using std::swap;
-            swap(a.value, b.value);
-            // ...
-        }
-        \endcode
-        \see Swap()
-     */
-    friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
-
     //! Prepare Value for move semantics
     /*! \return *this */
     GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
@@ -1262,31 +1213,6 @@ public:
         return pos;
     }
 
-    //! Erase a member in object by its name.
-    /*! \param name Name of member to be removed.
-        \return Whether the member existed.
-        \note Linear time complexity.
-    */
-    bool EraseMember(const Ch* name) {
-        GenericValue n(StringRef(name));
-        return EraseMember(n);
-    }
-
-#if RAPIDJSON_HAS_STDSTRING
-    bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
-#endif
-
-    template <typename SourceAllocator>
-    bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
-        MemberIterator m = FindMember(name);
-        if (m != MemberEnd()) {
-            EraseMember(m);
-            return true;
-        }
-        else
-            return false;
-    }
-
     //@}
 
     //!@name Array
@@ -1798,22 +1724,7 @@ public:
     typedef Allocator AllocatorType;                        //!< Allocator type from template parameter.
 
     //! Constructor
-    /*! Creates an empty document of specified type.
-        \param type             Mandatory type of object to create.
-        \param allocator        Optional allocator for allocating memory.
-        \param stackCapacity    Optional initial capacity of stack in bytes.
-        \param stackAllocator   Optional allocator for allocating memory for stack.
-    */
-    explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
-        GenericValue<Encoding, Allocator>(type),  allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
-    {
-        if (!allocator_)
-            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
-    }
-
-    //! Constructor
-    /*! Creates an empty document which type is Null. 
-        \param allocator        Optional allocator for allocating memory.
+    /*! \param allocator        Optional allocator for allocating memory.
         \param stackCapacity    Optional initial capacity of stack in bytes.
         \param stackAllocator   Optional allocator for allocating memory for stack.
     */
@@ -1827,7 +1738,7 @@ public:
 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
     //! Move constructor in C++11
     GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
-        : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
+        : ValueType(std::move(rhs)),
           allocator_(rhs.allocator_),
           ownAllocator_(rhs.ownAllocator_),
           stack_(std::move(rhs.stack_)),
@@ -1867,35 +1778,6 @@ public:
     }
 #endif
 
-    //! Exchange the contents of this document with those of another.
-    /*!
-        \param other Another document.
-        \note Constant complexity.
-        \see GenericValue::Swap
-    */
-    GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
-        ValueType::Swap(rhs);
-        stack_.Swap(rhs.stack_);
-        internal::Swap(allocator_, rhs.allocator_);
-        internal::Swap(ownAllocator_, rhs.ownAllocator_);
-        internal::Swap(parseResult_, rhs.parseResult_);
-        return *this;
-    }
-
-    //! free-standing swap function helper
-    /*!
-        Helper function to enable support for common swap implementation pattern based on \c std::swap:
-        \code
-        void swap(MyClass& a, MyClass& b) {
-            using std::swap;
-            swap(a.doc, b.doc);
-            // ...
-        }
-        \endcode
-        \see Swap()
-     */
-    friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
-
     //!@name Parse from stream
     //!@{
 
@@ -1908,13 +1790,13 @@ public:
     */
     template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
     GenericDocument& ParseStream(InputStream& is) {
-        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
-            stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
+        ValueType::SetNull(); // Remove existing root if exist
+        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.GetAllocator());
         ClearStackOnExit scope(*this);
         parseResult_ = reader.template Parse<parseFlags>(is, *this);
         if (parseResult_) {
             RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
-            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+            this->RawAssign(*stack_.template Pop<ValueType>(1));    // Add this-> to prevent issue 13.
         }
         return *this;
     }
@@ -2011,10 +1893,7 @@ public:
     //!@}
 
     //! Get the allocator of this document.
-    Allocator& GetAllocator() {
-        RAPIDJSON_ASSERT(allocator_);
-        return *allocator_;
-    }
+    Allocator& GetAllocator() { return *allocator_; }
 
     //! Get the capacity of stack in bytes.
     size_t GetStackCapacity() const { return stack_.GetCapacity(); }
@@ -2123,7 +2002,6 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc
     default: // kNumberType, kTrueType, kFalseType, kNullType
         flags_ = rhs.flags_;
         data_  = *reinterpret_cast<const Data*>(&rhs.data_);
-        break;
     }
 }
 

+ 5 - 5
contrib/rapidjson/include/rapidjson/encodedstream.h

@@ -77,8 +77,8 @@ public:
     void Flush() { os_.Flush(); }
 
     // Not implemented
-    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
-    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Peek() const { RAPIDJSON_ASSERT(false); }
+    Ch Take() { RAPIDJSON_ASSERT(false);  }
     size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }
     Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
     size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
@@ -146,7 +146,7 @@ private:
         if (!c)
             return;
 
-        unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
+        unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
         hasBOM_ = false;
         if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
         else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
@@ -227,8 +227,8 @@ public:
     void Flush() { os_->Flush(); } 
 
     // Not implemented
-    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
-    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Peek() const { RAPIDJSON_ASSERT(false); }
+    Ch Take() { RAPIDJSON_ASSERT(false); }
     size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
     Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
     size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }

+ 1 - 5
contrib/rapidjson/include/rapidjson/filewritestream.h

@@ -57,11 +57,7 @@ public:
 
     void Flush() {
         if (current_ != buffer_) {
-            size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
-            if (result < static_cast<size_t>(current_ - buffer_)) {
-                // failure deliberately ignored at this time
-                // added to avoid warn_unused_result build errors
-            }
+            fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
             current_ = buffer_;
         }
     }

+ 2 - 12
contrib/rapidjson/include/rapidjson/internal/biginteger.h

@@ -19,7 +19,6 @@
 
 #if defined(_MSC_VER) && defined(_M_AMD64)
 #include <intrin.h> // for _umul128
-#pragma intrinsic(_umul128)
 #endif
 
 RAPIDJSON_NAMESPACE_BEGIN
@@ -51,16 +50,7 @@ public:
         if (length > 0)
             AppendDecimal64(decimals + i, decimals + i + length);
     }
-    
-    BigInteger& operator=(const BigInteger &rhs)
-    {
-        if (this != &rhs) {
-            count_ = rhs.count_;
-            std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
-        }
-        return *this;
-    }
-    
+
     BigInteger& operator=(uint64_t u) {
         digits_[0] = u;            
         count_ = 1;
@@ -240,7 +230,7 @@ private:
         uint64_t r = 0;
         for (const char* p = begin; p != end; ++p) {
             RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
-            r = r * 10u + (unsigned)(*p - '0');
+            r = r * 10 + (*p - '0');
         }
         return r;
     }

+ 2 - 3
contrib/rapidjson/include/rapidjson/internal/diyfp.h

@@ -24,7 +24,6 @@
 #if defined(_MSC_VER) && defined(_M_AMD64)
 #include <intrin.h>
 #pragma intrinsic(_BitScanReverse64)
-#pragma intrinsic(_umul128)
 #endif
 
 RAPIDJSON_NAMESPACE_BEGIN
@@ -233,8 +232,8 @@ inline DiyFp GetCachedPower(int e, int* K) {
 }
 
 inline DiyFp GetCachedPower10(int exp, int *outExp) {
-     unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
-     *outExp = -348 + static_cast<int>(index) * 8;
+     unsigned index = (exp + 348) / 8;
+     *outExp = -348 + index * 8;
      return GetCachedPowerByIndex(index);
  }
 

+ 5 - 5
contrib/rapidjson/include/rapidjson/internal/dtoa.h

@@ -62,7 +62,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
     const DiyFp wp_w = Mp - W;
     uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
     uint64_t p2 = Mp.f & (one.f - 1);
-    unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+    int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
     *len = 0;
 
     while (kappa > 0) {
@@ -101,7 +101,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
         kappa--;
         if (p2 < delta) {
             *K += kappa;
-            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]);
+            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
             return;
         }
     }
@@ -158,14 +158,14 @@ inline char* Prettify(char* buffer, int length, int k) {
     }
     else if (0 < kk && kk <= 21) {
         // 1234e-2 -> 12.34
-        std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
+        std::memmove(&buffer[kk + 1], &buffer[kk], length - kk);
         buffer[kk] = '.';
         return &buffer[length + 1];
     }
     else if (-6 < kk && kk <= 0) {
         // 1234e-6 -> 0.001234
         const int offset = 2 - kk;
-        std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
+        std::memmove(&buffer[offset], &buffer[0], length);
         buffer[0] = '0';
         buffer[1] = '.';
         for (int i = 2; i < offset; i++)
@@ -179,7 +179,7 @@ inline char* Prettify(char* buffer, int length, int k) {
     }
     else {
         // 1234e30 -> 1.234e33
-        std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
+        std::memmove(&buffer[2], &buffer[1], length - 1);
         buffer[1] = '.';
         buffer[length + 1] = 'e';
         return WriteExponent(kk - 1, &buffer[0 + length + 2]);

+ 1 - 1
contrib/rapidjson/include/rapidjson/internal/ieee754.h

@@ -53,7 +53,7 @@ public:
         else if (order <= -1074)
             return 0;
         else
-            return (unsigned)order + 1074;
+            return order + 1074;
     }
 
 private:

+ 1 - 18
contrib/rapidjson/include/rapidjson/internal/stack.h

@@ -16,7 +16,6 @@
 #define RAPIDJSON_INTERNAL_STACK_H_
 
 #include "../rapidjson.h"
-#include "swap.h"
 
 RAPIDJSON_NAMESPACE_BEGIN
 namespace internal {
@@ -82,15 +81,6 @@ public:
     }
 #endif
 
-    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
-        internal::Swap(allocator_, rhs.allocator_);
-        internal::Swap(ownAllocator_, rhs.ownAllocator_);
-        internal::Swap(stack_, rhs.stack_);
-        internal::Swap(stackTop_, rhs.stackTop_);
-        internal::Swap(stackEnd_, rhs.stackEnd_);
-        internal::Swap(initialCapacity_, rhs.initialCapacity_);
-    }
-
     void Clear() { stackTop_ = stack_; }
 
     void ShrinkToFit() { 
@@ -134,14 +124,7 @@ public:
     template<typename T>
     T* Bottom() { return (T*)stack_; }
 
-    bool HasAllocator() const {
-        return allocator_ != 0;
-    }
-
-    Allocator& GetAllocator() {
-        RAPIDJSON_ASSERT(allocator_);
-        return *allocator_;
-    }
+    Allocator& GetAllocator() { return *allocator_; }
     bool Empty() const { return stackTop_ == stack_; }
     size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
     size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }

+ 11 - 11
contrib/rapidjson/include/rapidjson/internal/strtod.h

@@ -95,13 +95,13 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
     hS_Exp2 -= common_Exp2;
 
     BigInteger dS = d;
-    dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
+    dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2;
 
     BigInteger bS(bInt);
-    bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
+    bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2;
 
     BigInteger hS(1);
-    hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
+    hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;
 
     BigInteger delta(0);
     dS.Difference(bS, &delta);
@@ -134,7 +134,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
         if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
             (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
             break;
-        significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
+        significand = significand * 10 + (decimals[i] - '0');
     }
     
     if (i < length && decimals[i] >= '5') // Rounding
@@ -163,10 +163,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
             DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44),  // 10^6
             DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40)   // 10^7
         };
-        int  adjustment = dExp - actualExp - 1;
+        int adjustment = dExp - actualExp - 1;
         RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
         v = v * kPow10[adjustment];
-        if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
+        if (length + adjustment > 19) // has more digits than decimal digits in 64-bit
             error += kUlp / 2;
     }
 
@@ -184,14 +184,14 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
         unsigned scaleExp = (precisionSize + kUlpShift) - 63;
         v.f >>= scaleExp;
         v.e += scaleExp; 
-        error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
+        error = (error >> scaleExp) + 1 + kUlp;
         precisionSize -= scaleExp;
     }
 
-    DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
+    DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
     const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
     const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
-    if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
+    if (precisionBits >= halfWay + error) {
         rounded.f++;
         if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
             rounded.f >>= 1;
@@ -201,7 +201,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
 
     *result = rounded.ToDouble();
 
-    return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
+    return halfWay - error >= precisionBits || precisionBits >= halfWay + error;
 }
 
 inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
@@ -249,7 +249,7 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
     if ((int)length > kMaxDecimalDigit) {
         int delta = (int(length) - kMaxDecimalDigit);
         exp += delta;
-        decimalPosition -= static_cast<unsigned>(delta);
+        decimalPosition -= delta;
         length = kMaxDecimalDigit;
     }
 

+ 4 - 4
contrib/rapidjson/include/rapidjson/rapidjson.h

@@ -223,7 +223,7 @@
 
 //! Whether using 64-bit architecture
 #ifndef RAPIDJSON_64BIT
-#if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__)
+#if defined(__LP64__) || defined(_WIN64)
 #define RAPIDJSON_64BIT 1
 #else
 #define RAPIDJSON_64BIT 0
@@ -238,13 +238,13 @@
     \param x pointer to align
 
     Some machines require strict data alignment. Currently the default uses 4 bytes
-    alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
+    alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.,
 */
 #ifndef RAPIDJSON_ALIGN
 #if RAPIDJSON_64BIT == 1
-#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
+#define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u)
 #else
-#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
+#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
 #endif
 #endif
 

+ 25 - 83
contrib/rapidjson/include/rapidjson/reader.h

@@ -140,7 +140,6 @@ enum ParseFlag {
     kParseIterativeFlag = 4,        //!< Iterative(constant complexity in terms of function call stack size) parsing.
     kParseStopWhenDoneFlag = 8,     //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
     kParseFullPrecisionFlag = 16,   //!< Parse number in full precision (but slower).
-    kParseCommentsFlag = 32,        //!< Allow one-line (//) and multi-line (/**/) comments.
     kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS  //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
 };
 
@@ -272,7 +271,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
 
     // The rest of string using SIMD
     static const char whitespace[16] = " \n\r\t";
-    const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
+    const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]);
 
     for (;; p += 16) {
         const __m128i s = _mm_load_si128((const __m128i *)p);
@@ -399,8 +398,7 @@ public:
 
         ClearStackOnExit scope(*this);
 
-        SkipWhitespaceAndComments<parseFlags>(is);
-        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+        SkipWhitespace(is);
 
         if (is.Peek() == '\0') {
             RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
@@ -411,8 +409,7 @@ public:
             RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
 
             if (!(parseFlags & kParseStopWhenDoneFlag)) {
-                SkipWhitespaceAndComments<parseFlags>(is);
-                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+                SkipWhitespace(is);
 
                 if (is.Peek() != '\0') {
                     RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
@@ -465,40 +462,6 @@ private:
         ClearStackOnExit& operator=(const ClearStackOnExit&);
     };
 
-    template<unsigned parseFlags, typename InputStream>
-    void SkipWhitespaceAndComments(InputStream& is) {
-        SkipWhitespace(is);
-
-        if (parseFlags & kParseCommentsFlag) {
-            while (is.Peek() == '/') {
-                is.Take();
-
-                if (is.Peek() == '*') {
-                    is.Take();
-                    while (true) {
-                        if (is.Peek() == '\0')
-                            RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
-
-                        if (is.Take() == '*') {
-                            if (is.Peek() == '\0')
-                                RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
-
-                            if (is.Take() == '/')
-                                break;
-                        }
-                    }
-                } else if (is.Peek() == '/') {
-                    is.Take();
-                    while (is.Peek() != '\0' && is.Take() != '\n') { }
-                } else {
-                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
-                }
-
-                SkipWhitespace(is);
-            }
-        }
-    }
-
     // Parse object: { string : value, ... }
     template<unsigned parseFlags, typename InputStream, typename Handler>
     void ParseObject(InputStream& is, Handler& handler) {
@@ -508,8 +471,7 @@ private:
         if (!handler.StartObject())
             RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
 
-        SkipWhitespaceAndComments<parseFlags>(is);
-        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+        SkipWhitespace(is);
 
         if (is.Peek() == '}') {
             is.Take();
@@ -525,35 +487,27 @@ private:
             ParseString<parseFlags>(is, handler, true);
             RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
 
-            SkipWhitespaceAndComments<parseFlags>(is);
-            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+            SkipWhitespace(is);
 
             if (is.Take() != ':')
                 RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
 
-            SkipWhitespaceAndComments<parseFlags>(is);
-            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+            SkipWhitespace(is);
 
             ParseValue<parseFlags>(is, handler);
             RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
 
-            SkipWhitespaceAndComments<parseFlags>(is);
-            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+            SkipWhitespace(is);
 
             ++memberCount;
 
             switch (is.Take()) {
-                case ',':
-                    SkipWhitespaceAndComments<parseFlags>(is);
-                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-                    break;
+                case ',': SkipWhitespace(is); break;
                 case '}': 
                     if (!handler.EndObject(memberCount))
                         RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
                     return;
-                default:  
-                    RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
-                    break;
+                default:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
             }
         }
     }
@@ -567,8 +521,7 @@ private:
         if (!handler.StartArray())
             RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
         
-        SkipWhitespaceAndComments<parseFlags>(is);
-        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+        SkipWhitespace(is);
 
         if (is.Peek() == ']') {
             is.Take();
@@ -582,21 +535,15 @@ private:
             RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
 
             ++elementCount;
-            SkipWhitespaceAndComments<parseFlags>(is);
-            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+            SkipWhitespace(is);
 
             switch (is.Take()) {
-                case ',':
-                    SkipWhitespaceAndComments<parseFlags>(is);
-                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-                    break;
+                case ',': SkipWhitespace(is); break;
                 case ']': 
                     if (!handler.EndArray(elementCount))
                         RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
                     return;
-                default:  
-                    RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
-                    break;
+                default:  RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
             }
         }
     }
@@ -1020,13 +967,13 @@ private:
         else {
             if (use64bit) {
                 if (minus)
-                    cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
+                    cont = handler.Int64(-(int64_t)i64);
                 else
                     cont = handler.Uint64(i64);
             }
             else {
                 if (minus)
-                    cont = handler.Int(static_cast<int32_t>(~i + 1));
+                    cont = handler.Int(-(int)i);
                 else
                     cont = handler.Uint(i);
             }
@@ -1045,10 +992,7 @@ private:
             case '"': ParseString<parseFlags>(is, handler); break;
             case '{': ParseObject<parseFlags>(is, handler); break;
             case '[': ParseArray <parseFlags>(is, handler); break;
-            default : 
-                      ParseNumber<parseFlags>(is, handler);
-                      break;
-                      
+            default : ParseNumber<parseFlags>(is, handler);
         }
     }
 
@@ -1443,14 +1387,14 @@ private:
         }
         
         switch (src) {
-        case IterativeParsingStartState:            RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
-        case IterativeParsingFinishState:           RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
+        case IterativeParsingStartState:            RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
+        case IterativeParsingFinishState:           RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
         case IterativeParsingObjectInitialState:
-        case IterativeParsingMemberDelimiterState:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
-        case IterativeParsingMemberKeyState:        RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
-        case IterativeParsingMemberValueState:      RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
-        case IterativeParsingElementState:          RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
-        default:                                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
+        case IterativeParsingMemberDelimiterState:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+        case IterativeParsingMemberKeyState:        RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+        case IterativeParsingMemberValueState:      RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
+        case IterativeParsingElementState:          RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
+        default:                                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
         }       
     }
 
@@ -1460,8 +1404,7 @@ private:
         ClearStackOnExit scope(*this);
         IterativeParsingState state = IterativeParsingStartState;
 
-        SkipWhitespaceAndComments<parseFlags>(is);
-        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+        SkipWhitespace(is);
         while (is.Peek() != '\0') {
             Token t = Tokenize(is.Peek());
             IterativeParsingState n = Predict(state, t);
@@ -1478,8 +1421,7 @@ private:
             if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
                 break;
 
-            SkipWhitespaceAndComments<parseFlags>(is);
-            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+            SkipWhitespace(is);
         }
 
         // Handle the end of file.

+ 5 - 5
contrib/rapidjson/include/rapidjson/writer.h

@@ -350,7 +350,7 @@ template<>
 inline bool Writer<StringBuffer>::WriteInt(int i) {
     char *buffer = os_->Push(11);
     const char* end = internal::i32toa(i, buffer);
-    os_->Pop(static_cast<size_t>(11 - (end - buffer)));
+    os_->Pop(11 - (end - buffer));
     return true;
 }
 
@@ -358,7 +358,7 @@ template<>
 inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
     char *buffer = os_->Push(10);
     const char* end = internal::u32toa(u, buffer);
-    os_->Pop(static_cast<size_t>(10 - (end - buffer)));
+    os_->Pop(10 - (end - buffer));
     return true;
 }
 
@@ -366,7 +366,7 @@ template<>
 inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
     char *buffer = os_->Push(21);
     const char* end = internal::i64toa(i64, buffer);
-    os_->Pop(static_cast<size_t>(21 - (end - buffer)));
+    os_->Pop(21 - (end - buffer));
     return true;
 }
 
@@ -374,7 +374,7 @@ template<>
 inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
     char *buffer = os_->Push(20);
     const char* end = internal::u64toa(u, buffer);
-    os_->Pop(static_cast<size_t>(20 - (end - buffer)));
+    os_->Pop(20 - (end - buffer));
     return true;
 }
 
@@ -382,7 +382,7 @@ template<>
 inline bool Writer<StringBuffer>::WriteDouble(double d) {
     char *buffer = os_->Push(25);
     char* end = internal::dtoa(d, buffer);
-    os_->Pop(static_cast<size_t>(25 - (end - buffer)));
+    os_->Pop(25 - (end - buffer));
     return true;
 }
 

+ 1 - 1
contrib/rapidjson/license.txt

@@ -3,7 +3,7 @@ Tencent is pleased to support the open source community by making RapidJSON avai
 Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.  All rights reserved.
 
 If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
-If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms.  Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
+If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms.  Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON.
 A copy of the MIT License is included in this file.
 
 Other dependencies and licenses:

+ 7 - 7
contrib/rapidjson/readme.md

@@ -10,8 +10,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
 
 * [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
 * RapidJSON Documentation
-  * [English](http://rapidjson.org/)
-  * [简体中文](http://rapidjson.org/zh-cn/)
+  * [English](http://miloyip.github.io/rapidjson/)
+  * [简体中文](http://miloyip.github.io/rapidjson/zh-cn/)
   * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference.
 
 ## Build status
@@ -31,15 +31,15 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
 
 RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/).
 
-* RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code.
+* RapidJSON is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code.
 
-* RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration.
+* RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration.
 
-* RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL.
+* RapidJSON is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL.
 
-* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
+* RapidJSON is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
 
-* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
+* RapidJSON is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
 
 More features can be read [here](doc/features.md).
 

+ 37 - 10
doc/dox_cmd.h

@@ -211,14 +211,14 @@ the dump is written to <tt>&lt;model&gt;-dump.txt</tt>
 <p>
 <tt>-b<br>
 </tt><br>
-Optional. If this switch is specified, the dumb is written in binary format.
+Optional. If this switch is specified, the dump is written in binary format.
 The long form of this parameter is <tt>--binary</tt>.
 </p>
 
 <p>
 <tt>-s&lt;n&gt;<br>
 </tt><br>
-Optional. If this switch is specified, the dumb is shortened to include only
+Optional. If this switch is specified, the dump is shortened to include only
 min/max values for all vertex components and animation channels. The resulting
 file is much smaller, but the original model can't be reconstructed from it. This is 
 used by Assimp's regression test suite, comparing those minidumps provides
@@ -368,7 +368,6 @@ of all supported steps along with short descriptions of what they're doing. <br>
 more information can be found in the <tt>aiPostProcess.h</tt> header.
 
 <table border="1">
- 
   <tr>
     <th>Parameter</th>
     <th>Long parameter</th>
@@ -432,13 +431,13 @@ more information can be found in the <tt>aiPostProcess.h</tt> header.
 	<td>Improve the cache locality of the vertex buffer by reordering the index buffer 
 	to achieve a lower ACMR (average post-transform vertex cache miss ratio)</td>
   </tr>
-   <tr>
+  <tr>
     <td><tt>-sbpt</tt></td>
     <td><tt>--sort-by-ptype</tt></td>
 	<td>Splits meshes which consist of more than one kind of primitives (e.g. lines and triangles mixed up)
 	in 'clean' submeshes. </td>
   </tr>
-   <tr>
+  <tr>
     <td><tt>-lh</tt></td>
     <td><tt>--convert-to-lh</tt></td>
 	<td>Converts the imported data to left-handed coordinate space</td>
@@ -479,19 +478,47 @@ more information can be found in the <tt>aiPostProcess.h</tt> header.
 	<td>Search the data structure for instanced meshes and replace them by references. This can
 	reduce vertex/face counts but the postprocessing-step takes some time.</td>
   </tr>
-
-    <tr>
+  <tr>
     <td><tt>-og</tt></td>
     <td><tt>--optimize-graph</tt></td>
 	<td>Simplify and optimize the scenegraph. Use it with care, all hierarchy information could be lost.
 	Animations remain untouched. </td>
   </tr>
-
-    <tr>
+  <tr>
     <td><tt>-om</tt></td>
-    <td><tt>--optimize-mesh</tt></td>
+    <td><tt>--optimize-meshes</tt></td>
 	<td>Optimize mesh usage. Meshes are merged, if possible. Very effective in combination with <tt>--optimize-graph</tt></td>
   </tr>
+  <tr>
+    <td><tt>-tuv</tt></td>
+    <td><tt>--transform-uv-coords</tt></td>
+    <td>Will transform uv-coordinates if possible.</td>
+  </tr>
+  <tr>
+    <td><tt>-guv</tt></td>
+    <td><tt>--gen-uvcoords</tt></td>
+    <td>Will generate uv-coordinates for textures if possible.</td>
+  </tr>
+  <tr>
+    <td><tt>-fid</tt></td>
+    <td><tt>--find-invalid-data</tt></td>
+    <td>Will look for invalid data in the imported model structure.</td>
+  </tr>
+  <tr>
+    <td><tt>-fixn</tt></td>
+    <td><tt>--fix normals</tt></td>
+    <td>Imported normal vector will be fixed.</td>
+  </tr>
+  <tr>
+    <td><tt>-db</tt></td>
+    <td><tt>--debone</tt></td>
+    <td>Removes nearly losslessly or according to a configured threshold bones from the model.</td>
+  </tr>
+  <tr>
+    <td><tt>-sbc</tt></td>
+    <td><tt>--split-by-bone-count</tt></td>
+    <td>Split meshes with too many bones. Necessary for our (limited) hardware skinning shader.</td>
+  </tr>
 </table>
 
 For convenience some default postprocessing configurations are provided.

+ 31 - 25
include/assimp/material.h

@@ -714,30 +714,33 @@ public:
     // -------------------------------------------------------------------
     /** Helper function to get all parameters pertaining to a
      *  particular texture slot from a material.
-    *
-    *  This function is provided just for convenience, you could also
-    *  read the single material properties manually.
-    *  @param type Specifies the type of the texture to be retrieved (
-    *    e.g. diffuse, specular, height map ...)
-    *  @param index Index of the texture to be retrieved. The function fails
-    *    if there is no texture of that type with this index.
-    *    #GetTextureCount() can be used to determine the number of textures
-    *    per texture type.
-    *  @param path Receives the path to the texture.
-    *    NULL is a valid value.
-   *  @param mapping The texture mapping.
-   *        NULL is allowed as value.
-    *  @param uvindex Receives the UV index of the texture.
-    *    NULL is a valid value.
-    *  @param blend Receives the blend factor for the texture
-    *    NULL is a valid value.
-    *  @param op Receives the texture operation to be performed between
-    *    this texture and the previous texture. NULL is allowed as value.
-    *  @param mapmode Receives the mapping modes to be used for the texture.
-    *    The parameter may be NULL but if it is a valid pointer it MUST
-    *    point to an array of 3 aiTextureMapMode's (one for each
-    *    axis: UVW order (=XYZ)).
-    */
+     *
+     *  This function is provided just for convenience, you could also
+     *  read the single material properties manually.
+     *  @param type Specifies the type of the texture to be retrieved (
+     *    e.g. diffuse, specular, height map ...)
+     *  @param index Index of the texture to be retrieved. The function fails
+     *    if there is no texture of that type with this index.
+     *    #GetTextureCount() can be used to determine the number of textures
+     *    per texture type.
+     *  @param path Receives the path to the texture.
+     *    If the texture is embedded, receives a '*' followed by the id of
+     *    the texture (for the textures stored in the corresponding scene) which
+     *    can be converted to an int using a function like atoi.
+     *    NULL is a valid value.
+     *  @param mapping The texture mapping.
+     *    NULL is allowed as value.
+     *  @param uvindex Receives the UV index of the texture.
+     *    NULL is a valid value.
+     *  @param blend Receives the blend factor for the texture
+     *    NULL is a valid value.
+     *  @param op Receives the texture operation to be performed between
+     *    this texture and the previous texture. NULL is allowed as value.
+     *  @param mapmode Receives the mapping modes to be used for the texture.
+     *    The parameter may be NULL but if it is a valid pointer it MUST
+     *    point to an array of 3 aiTextureMapMode's (one for each
+     *    axis: UVW order (=XYZ)).
+     */
     // -------------------------------------------------------------------
     aiReturn GetTexture(aiTextureType type,
         unsigned int  index,
@@ -1506,7 +1509,10 @@ ASSIMP_API unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMa
  *     #aiGetMaterialTextureCount() can be used to determine the number of
  *     textures in a particular texture stack.
  *  @param[out] path Receives the output path
- *      This parameter must be non-null.
+ *     If the texture is embedded, receives a '*' followed by the id of
+ *     the texture (for the textures stored in the corresponding scene) which
+ *     can be converted to an int using a function like atoi.
+ *     This parameter must be non-null.
  *  @param mapping The texture mapping mode to be used.
  *      Pass NULL if you're not interested in this information.
  *  @param[out] uvindex For UV-mapped textures: receives the index of the UV

+ 1 - 1
include/assimp/types.h

@@ -216,7 +216,7 @@ struct aiColor3D
 
     /** Check whether a color is black */
     bool IsBlack() const {
-        static const ai_real epsilon = 10e-3;
+        static const ai_real epsilon = ai_real(10e-3);
         return std::fabs( r ) < epsilon && std::fabs( g ) < epsilon && std::fabs( b ) < epsilon;
     }
 

+ 1 - 0
test/CMakeLists.txt

@@ -54,6 +54,7 @@ SOURCE_GROUP( unit FILES
 
 SET( TEST_SRCS
   unit/AssimpAPITest.cpp
+  unit/utBlenderIntermediate.cpp
   unit/utBlendImportAreaLight.cpp
   unit/utBlendImportMaterials.cpp
   unit/utColladaExportCamera.cpp

+ 1 - 1
test/regression/ai_regression_ui.py

@@ -63,7 +63,7 @@ def log( sev, msg ):
         logEntry = logEntry + "[WARN]: "
     elif sev == 2:
         logEntry = logEntry + "[ERR] : "
-    logEntry = logEntry + msg
+    logEntry = logEntry + str( msg )
     print( logEntry )
 
 # -------------------------------------------------------------------------------

BIN
test/regression/db.zip


+ 67 - 0
test/unit/utBlenderIntermediate.cpp

@@ -0,0 +1,67 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2016, 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 "UnitTestPCH.h"
+#include "BlenderIntermediate.h"
+
+using namespace ::Assimp;
+using namespace ::Assimp::Blender;
+
+class BlenderIntermediateTest : public ::testing::Test {
+    // empty
+};
+
+TEST_F( BlenderIntermediateTest,ConversionData_ObjectCompareTest ) {
+    Object obj1, obj2;
+    strncpy( obj1.id.name, "name1", 5 );
+    strncpy( obj2.id.name, "name2", 5 );
+    Blender::ObjectCompare cmp_false;
+    bool res( cmp_false( &obj1, &obj2 ) );
+    EXPECT_FALSE( res );
+
+    Blender::ObjectCompare cmp_true;
+    res = cmp_true( &obj1, &obj1 );
+    EXPECT_TRUE( res );
+}
+
+
+
+
+

+ 15 - 3
test/unit/utDefaultIOStream.cpp

@@ -48,7 +48,12 @@ class utDefaultIOStream : public ::testing::Test {
 class TestDefaultIOStream : public DefaultIOStream {
 public:
     TestDefaultIOStream()
-        : DefaultIOStream() {
+    : DefaultIOStream() {
+        // empty
+    }
+
+    TestDefaultIOStream( FILE* pFile, const std::string &strFilename )
+    : DefaultIOStream( pFile, strFilename ) {
         // empty
     }
 
@@ -58,7 +63,14 @@ public:
 };
 
 TEST_F( utDefaultIOStream, FileSizeTest ) {
-    TestDefaultIOStream myStream;
+    char buffer[ L_tmpnam ];
+    tmpnam( buffer );
+    std::FILE *fs( std::fopen( buffer, "w+" ) );
+    size_t written( std::fwrite( buffer, 1, sizeof( char ) * L_tmpnam, fs ) );
+    std::fflush( fs );
+
+    TestDefaultIOStream myStream( fs, buffer );
     size_t size = myStream.FileSize();
-    EXPECT_EQ( size, 0 );
+    EXPECT_EQ( size, sizeof( char ) * L_tmpnam );
+    remove( buffer );
 }

+ 0 - 1
tools/assimp_cmd/Main.cpp

@@ -378,7 +378,6 @@ int ProcessStandardArguments(
 	// -fixn   --fix normals
 	// -tri    --triangulate
 	// -fi     --find-instances
-	// -fi     --find-instances
 	// -og     --optimize-graph
 	// -om     --optimize-meshes
 	// -db     --debone

+ 44 - 0
tools/assimp_qt_viewer/CMakeLists.txt

@@ -0,0 +1,44 @@
+project(assimp_qt_viewer)
+set(PROJECT_VERSION "")
+
+cmake_minimum_required(VERSION 2.6)
+
+find_package(Qt4 REQUIRED)
+find_package(DevIL REQUIRED)
+find_package(OpenGL REQUIRED)
+
+include_directories(
+	${QT_INCLUDES}
+	${Assimp_SOURCE_DIR}/include
+	${Assimp_SOURCE_DIR}/code
+	${CMAKE_CURRENT_BINARY_DIR}
+	${CMAKE_SOURCE_DIR}
+	${OPENGL_INCLUDE_DIR}
+	${IL_INCLUDE_DIR}
+)
+
+link_directories(${Assimp_BINARY_DIR})
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pedantic -Wall")
+
+set(assimp_qt_viewer_SRCS main.cpp loggerview.cpp glview.cpp mainwindow.cpp)
+qt4_wrap_ui(UISrcs mainwindow.ui)
+qt4_wrap_cpp(MOCrcs mainwindow.hpp glview.hpp)
+
+add_executable(${PROJECT_NAME} ${assimp_qt_viewer_SRCS} ${UISrcs} ${MOCrcs})
+target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${IL_LIBRARIES} ${OPENGL_LIBRARIES} assimp)
+
+if(WIN32) # Check if we are on Windows
+	if(MSVC) # Check if we are using the Visual Studio compiler
+		set_target_properties(TestProject PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
+	elseif(CMAKE_COMPILER_IS_GNUCXX)
+		# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") # Not tested
+	else()
+		message(SEND_ERROR "You are using an unsupported Windows compiler! (Not MSVC or GCC)")
+	endif()
+elseif(UNIX)
+	# Nothing special required
+else()
+	message(SEND_ERROR "You are on an unsupported platform! (Not Win32 or Unix)")
+endif()
+
+set_property(TARGET ${PROJECT_NAME} PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

BIN
tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt


BIN
tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt


+ 1043 - 0
tools/assimp_qt_viewer/glview.cpp

@@ -0,0 +1,1043 @@
+/// \file   glview.cpp
+/// \brief  OpenGL visualisation. Implementation file.
+/// \author [email protected]
+/// \date   2016
+
+#include "glview.hpp"
+
+// Header files, OpenGL.
+#include <GL/glu.h>
+
+// Header files, DevIL.
+#include <IL/il.h>
+
+// Header files, Assimp.
+#include <assimp/DefaultLogger.hpp>
+
+#ifndef __unused
+	#define __unused	__attribute__((unused))
+#endif // __unused
+
+/**********************************/
+/********** SHelper_Mesh **********/
+/**********************************/
+
+CGLView::SHelper_Mesh::SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox)
+	: Quantity_Point(pQuantity_Point), Quantity_Line(pQuantity_Line), Quantity_Triangle(pQuantity_Triangle), BBox(pBBox)
+{
+	Index_Point = pQuantity_Point ? new GLuint[pQuantity_Point * 1] : nullptr;
+	Index_Line = pQuantity_Line ? new GLuint[pQuantity_Line * 2] : nullptr;
+	Index_Triangle = pQuantity_Triangle ? new GLuint[pQuantity_Triangle * 3] : nullptr;
+}
+
+CGLView::SHelper_Mesh::~SHelper_Mesh()
+{
+	if(Index_Point != nullptr) delete [] Index_Point;
+	if(Index_Line != nullptr) delete [] Index_Line;
+	if(Index_Triangle != nullptr) delete [] Index_Triangle;
+}
+
+/**********************************/
+/********** SHelper_Mesh **********/
+/**********************************/
+
+void CGLView::SHelper_Camera::SetDefault()
+{
+	Position.Set(0, 0, 0);
+	Target.Set(0, 0, -1);
+	Rotation_AroundCamera = aiMatrix4x4();
+	Rotation_Scene = aiMatrix4x4();
+	Translation_ToScene.Set(0, 0, 2);
+}
+
+/**********************************/
+/************ CGLView *************/
+/**********************************/
+
+void CGLView::Material_Apply(const aiMaterial* pMaterial)
+{
+GLfloat tcol[4];
+aiColor4D taicol;
+unsigned int max;
+int ret1, ret2;
+int texture_index = 0;
+aiString texture_path;
+
+auto set_float4 = [](float f[4], float a, float b, float c, float d) { f[0] = a, f[1] = b, f[2] = c, f[3] = d; };
+auto color4_to_float4 = [](const aiColor4D *c, float f[4]) { f[0] = c->r, f[1] = c->g, f[2] = c->b, f[3] = c->a; };
+
+	///TODO: cache materials
+	// Disable color material because glMaterial is used.
+	glDisable(GL_COLOR_MATERIAL);///TODO: cache
+	// Set texture. If assigned.
+	if(AI_SUCCESS == pMaterial->GetTexture(aiTextureType_DIFFUSE, texture_index, &texture_path))
+	{
+		//bind texture
+		unsigned int texture_ID = mTexture_IDMap.value(texture_path.data, 0);
+
+		glBindTexture(GL_TEXTURE_2D, texture_ID);
+	}
+	//
+	// Set material parameters from scene or default values.
+	//
+	// Diffuse
+	set_float4(tcol, 0.8f, 0.8f, 0.8f, 1.0f);
+	if(AI_SUCCESS == aiGetMaterialColor(pMaterial, AI_MATKEY_COLOR_DIFFUSE, &taicol)) color4_to_float4(&taicol, tcol);
+
+	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, tcol);
+	// Specular
+	set_float4(tcol, 0.0f, 0.0f, 0.0f, 1.0f);
+	if(AI_SUCCESS == aiGetMaterialColor(pMaterial, AI_MATKEY_COLOR_SPECULAR, &taicol)) color4_to_float4(&taicol, tcol);
+
+	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, tcol);
+	// Ambient
+	set_float4(tcol, 0.2f, 0.2f, 0.2f, 1.0f);
+	if(AI_SUCCESS == aiGetMaterialColor(pMaterial, AI_MATKEY_COLOR_AMBIENT, &taicol)) color4_to_float4(&taicol, tcol);
+
+	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, tcol);
+	// Emission
+	set_float4(tcol, 0.0f, 0.0f, 0.0f, 1.0f);
+	if(AI_SUCCESS == aiGetMaterialColor(pMaterial, AI_MATKEY_COLOR_EMISSIVE, &taicol)) color4_to_float4(&taicol, tcol);
+
+	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, tcol);
+	// Shininess
+	float shininess, strength;
+
+	max = 1;
+	ret1 = aiGetMaterialFloatArray(pMaterial, AI_MATKEY_SHININESS, &shininess, &max);
+	// Shininess strength
+	max = 1;
+	ret2 = aiGetMaterialFloatArray(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
+	if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS))
+	{
+		glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);///TODO: cache
+	}
+	else
+	{
+		glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);///TODO: cache
+		set_float4(tcol, 0.0f, 0.0f, 0.0f, 0.0f);
+		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, tcol);
+	}
+
+	// Fill mode
+	GLenum fill_mode;
+	int wireframe;
+
+	max = 1;
+	if(AI_SUCCESS == aiGetMaterialIntegerArray(pMaterial, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
+		fill_mode = wireframe ? GL_LINE : GL_FILL;
+	else
+		fill_mode = GL_FILL;
+
+	glPolygonMode(GL_FRONT_AND_BACK, fill_mode);///TODO: cache
+	// Fill side
+	int two_sided;
+
+	max = 1;
+	if((AI_SUCCESS == aiGetMaterialIntegerArray(pMaterial, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)///TODO: cache
+		glDisable(GL_CULL_FACE);
+	else
+		glEnable(GL_CULL_FACE);
+}
+
+void CGLView::Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix)
+{
+const aiNode* node_cur;
+std::list<aiMatrix4x4> mat_list;
+
+	pOutMatrix = aiMatrix4x4();
+	// starting walk from current element to root
+	node_cur = pNode;
+	if(node_cur != nullptr)
+	{
+		do
+		{
+			// if cur_node is group then store group transformation matrix in list.
+			mat_list.push_back(node_cur->mTransformation);
+			node_cur = node_cur->mParent;
+		} while(node_cur != nullptr);
+	}
+
+	// multiplicate all matrices in reverse order
+	for(std::list<aiMatrix4x4>::reverse_iterator rit = mat_list.rbegin(); rit != mat_list.rend(); rit++) pOutMatrix = pOutMatrix * (*rit);
+}
+
+void CGLView::ImportTextures(const QString& pScenePath)
+{
+ILboolean success;
+
+	if(mScene == nullptr)
+	{
+		LogError("Trying to load textures for empty scene.");
+
+		return;
+	}
+
+	// Before calling ilInit() version should be checked.
+	if(ilGetInteger(IL_VERSION_NUM) < IL_VERSION)
+	{
+		LogError("Wrong DevIL version.");
+
+		return;
+	}
+
+	ilInit();// Initialization of DevIL.
+	//
+	// Load embedded textures
+	//
+	if(mScene->HasTextures()) LogError("Support for meshes with embedded textures is not implemented.");
+
+	//
+	// Load textures from external files.
+	//
+	// Get textures file names and number of textures.
+	for(size_t idx_material = 0; idx_material < mScene->mNumMaterials; idx_material++)
+	{
+		int idx_texture = 0;
+		aiString path;
+
+		do
+		{
+			if(mScene->mMaterials[idx_material]->GetTexture(aiTextureType_DIFFUSE, idx_texture, &path) != AI_SUCCESS) break;
+
+			mTexture_IDMap[path.data] = 0;// Fill map with invalid ID's.
+			idx_texture++;
+		} while(true);
+	}// for(size_t idx_mat = 0; idx_mat < scene->mNumMaterials; idx_mat++)
+
+	// Textures list is empty, exit.
+	if(mTexture_IDMap.size() == 0)
+	{
+		LogInfo("No textures for import.");
+
+		return;
+	}
+
+	size_t num_textures = mTexture_IDMap.size();
+
+
+	ILuint* id_images = nullptr;// Array with DevIL image ID's.
+	GLuint* id_textures = nullptr;// Array with OpenGL textures ID's.
+
+	// Generate DevIL image IDs.
+	id_images = new ILuint[num_textures];
+	ilGenImages(num_textures, id_images);// Generation of 'num_textures' image names.
+	// Create and fill array with OpenGL texture ID's.
+	id_textures = new GLuint[num_textures];
+	///TODO: if can not load textures then will stay orphande texture ID's in OpenGL. Generate OpenGL ID's after successfull loading of image.
+	glGenTextures(num_textures, id_textures);// Texture ID's generation.
+
+	QMap<QString, GLuint>::iterator map_it = mTexture_IDMap.begin();// Get iterator
+	QString basepath = pScenePath.left(pScenePath.lastIndexOf('/') + 1);// path with '/' at the end.
+
+	for(size_t idx_texture = 0; idx_texture < num_textures; idx_texture++)
+	{
+		//save IL image ID
+		QString filename = map_it.key();// get filename
+
+		mTexture_IDMap[filename] = id_textures[idx_texture];// save texture ID for filename in map
+		map_it++;// next texture
+		ilBindImage(id_images[idx_texture]);// Binding of DevIL image name.
+
+		QString fileloc = basepath + filename;	/* Loading of image */
+
+		fileloc.replace('\\', "/");
+		success = ilLoadImage(fileloc.toLocal8Bit());
+		if(!success)
+		{
+			LogError(QString("Couldn't load Image: %1").arg(fileloc));
+			goto it_for_err;
+		}
+
+		// Convert every colour component into unsigned byte. If your image contains alpha channel you can replace IL_RGB with IL_RGBA.
+		success = ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
+		if(!success)
+		{
+			LogError("Couldn't convert image.");
+			goto it_for_err;
+		}
+
+		glBindTexture(GL_TEXTURE_2D, id_textures[idx_texture]);// Binding of texture ID.
+		// Redefine standard texture values
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// We will use linear interpolation for magnification filter.
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// We will use linear interpolation for minifying filter.
+		glTexImage2D(GL_TEXTURE_2D, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), 0,
+						ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());// Texture specification.
+		continue;
+
+it_for_err:
+
+		LogError(QString("DevIL error: %1, [%2]").arg(ilGetError()).arg(ilGetString(ilGetError())));
+		mTexture_IDMap.remove(filename);
+	}// for(size_t idx_texture = 0; idx_texture < num_textures; i++)
+
+	// Because we have already copied image data into texture data we can release memory used by image.
+	ilDeleteImages(num_textures, id_images);
+
+	//Cleanup
+	delete [] id_images;
+	delete [] id_textures;
+}
+
+void CGLView::BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign)
+{
+aiMatrix4x4 mat_trans = pParent_TransformationMatrix * pNode.mTransformation;
+
+	// Check if node has meshes
+	for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++)
+	{
+		size_t idx_mesh;
+		SBBox bbox_local;
+		aiVector3D bbox_vertices[8];
+
+		idx_mesh = pNode.mMeshes[idx_idx_mesh];
+		// Get vertices of mesh BBox
+		BBox_GetVertices(mHelper_Mesh[idx_mesh]->BBox, bbox_vertices);
+		// Transform vertices
+		for(size_t idx_vert = 0; idx_vert < 8; idx_vert++) bbox_vertices[idx_vert] *= mat_trans;
+
+		// And create BBox for transformed mesh
+		BBox_GetFromVertices(bbox_vertices, 8, bbox_local);
+
+		if(!pFirstAssign)
+		{
+			BBox_Extend(bbox_local, pNodeBBox);
+		}
+		else
+		{
+			pFirstAssign = false;
+			pNodeBBox = bbox_local;
+		}
+	}// for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++)
+
+	for(size_t idx_node = 0; idx_node < pNode.mNumChildren; idx_node++)
+	{
+		BBox_GetForNode(*pNode.mChildren[idx_node], mat_trans, pNodeBBox, pFirstAssign);
+	}
+}
+
+void CGLView::BBox_Extend(const SBBox& pChild, SBBox& pParent)
+{
+	// search minimal...
+	AssignIfLesser(&pParent.Minimum.x, pChild.Minimum.x);
+	AssignIfLesser(&pParent.Minimum.y, pChild.Minimum.y);
+	AssignIfLesser(&pParent.Minimum.z, pChild.Minimum.z);
+	// and maximal values
+	AssignIfGreater(&pParent.Maximum.x, pChild.Maximum.x);
+	AssignIfGreater(&pParent.Maximum.y, pChild.Maximum.y);
+	AssignIfGreater(&pParent.Maximum.z, pChild.Maximum.z);
+}
+
+void CGLView::BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertex[8])
+{
+	pVertex[0] = pBBox.Minimum;
+	pVertex[1].Set(pBBox.Minimum.x, pBBox.Minimum.y, pBBox.Maximum.z);
+	pVertex[2].Set(pBBox.Minimum.x, pBBox.Maximum.y, pBBox.Maximum.z);
+	pVertex[3].Set(pBBox.Minimum.x, pBBox.Maximum.y, pBBox.Minimum.z);
+
+	pVertex[4].Set(pBBox.Maximum.x, pBBox.Minimum.y, pBBox.Minimum.z);
+	pVertex[5].Set(pBBox.Maximum.x, pBBox.Minimum.y, pBBox.Maximum.z);
+	pVertex[6] = pBBox.Maximum;
+	pVertex[7].Set(pBBox.Maximum.x, pBBox.Maximum.y, pBBox.Minimum.z);
+
+}
+
+void CGLView::BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox)
+{
+	if(pVerticesQuantity == 0)
+	{
+		pBBox.Maximum.Set(0, 0, 0);
+		pBBox.Minimum.Set(0, 0, 0);
+
+		return;
+	}
+
+	// Assign first values.
+	pBBox.Minimum = pVertices[0];
+	pBBox.Maximum = pVertices[0];
+
+	for(size_t idx_vert = 1; idx_vert < pVerticesQuantity; idx_vert++)
+	{
+		const GLfloat x = pVertices[idx_vert].x;
+		const GLfloat y = pVertices[idx_vert].y;
+		const GLfloat z = pVertices[idx_vert].z;
+
+		// search minimal...
+		AssignIfLesser(&pBBox.Minimum.x, x);
+		AssignIfLesser(&pBBox.Minimum.y, y);
+		AssignIfLesser(&pBBox.Minimum.z, z);
+		// and maximal values
+		AssignIfGreater(&pBBox.Maximum.x, x);
+		AssignIfGreater(&pBBox.Maximum.y, y);
+		AssignIfGreater(&pBBox.Maximum.z, z);
+	}
+}
+
+/********************************************************************/
+/************************ Logging functions *************************/
+/********************************************************************/
+
+void CGLView::LogInfo(const QString& pMessage)
+{
+	Assimp::DefaultLogger::get()->info(pMessage.toStdString());
+}
+
+void CGLView::LogError(const QString& pMessage)
+{
+	Assimp::DefaultLogger::get()->error(pMessage.toStdString());
+}
+
+/********************************************************************/
+/************************** Draw functions **************************/
+/********************************************************************/
+
+void CGLView::Draw_Node(const aiNode* pNode)
+{
+aiMatrix4x4 mat_node = pNode->mTransformation;
+
+	// Apply node transformation matrix.
+	mat_node.Transpose();
+	glPushMatrix();
+	glMultMatrixf((GLfloat*)&mat_node);
+	// Draw all meshes assigned to this node
+	for(size_t idx_mesh_arr = 0; idx_mesh_arr < pNode->mNumMeshes; idx_mesh_arr++) Draw_Mesh(pNode->mMeshes[idx_mesh_arr]);
+
+	// Draw all children nodes
+	for(size_t idx_node = 0; idx_node < pNode->mNumChildren; idx_node++) Draw_Node(pNode->mChildren[idx_node]);
+
+	// Restore transformation matrix.
+	glPopMatrix();
+}
+
+void CGLView::Draw_Mesh(const size_t pMesh_Index)
+{
+	// Check argument
+	if(pMesh_Index >= mHelper_Mesh_Quantity) return;
+
+	aiMesh& mesh_cur = *mScene->mMeshes[pMesh_Index];
+
+	if(!mesh_cur.HasPositions()) return;// Nothing to draw.
+
+	// If mesh use material then apply it
+	if(mScene->HasMaterials()) Material_Apply(mScene->mMaterials[mesh_cur.mMaterialIndex]);
+
+	//
+	// Vertices array
+	//
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glVertexPointer(3, GL_FLOAT, 0, mesh_cur.mVertices);
+
+	if(mesh_cur.HasVertexColors(0))
+	{
+		glEnable(GL_COLOR_MATERIAL);///TODO: cache
+		glEnableClientState(GL_COLOR_ARRAY);
+		glColorPointer(4, GL_FLOAT, 0, mesh_cur.mColors[0]);
+	}
+
+	//
+	// Texture coordinates array
+	//
+	if(mesh_cur.HasTextureCoords(0))
+	{
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexCoordPointer(2, GL_FLOAT, sizeof(aiVector3D), mesh_cur.mTextureCoords[0]);
+	}
+
+	//
+	// Normals array
+	//
+	if(mesh_cur.HasNormals())
+	{
+		glEnableClientState(GL_NORMAL_ARRAY);
+		glNormalPointer(GL_FLOAT, 0, mesh_cur.mNormals);
+	}
+
+	//
+	// Draw arrays
+	//
+	SHelper_Mesh& helper_cur = *mHelper_Mesh[pMesh_Index];
+
+	if(helper_cur.Quantity_Triangle > 0) glDrawElements(GL_TRIANGLES, helper_cur.Quantity_Triangle * 3, GL_UNSIGNED_INT, helper_cur.Index_Triangle);
+	if(helper_cur.Quantity_Line > 0) glDrawElements(GL_LINES,helper_cur.Quantity_Line * 2, GL_UNSIGNED_INT, helper_cur.Index_Line);
+	if(helper_cur.Quantity_Point > 0) glDrawElements(GL_POINTS, helper_cur.Quantity_Point, GL_UNSIGNED_INT, helper_cur.Index_Point);
+
+	//
+	// Clean up
+	//
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_COLOR_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+}
+
+void CGLView::Draw_BBox(const SBBox& pBBox)
+{
+aiVector3D vertex[8];
+
+	BBox_GetVertices(pBBox, vertex);
+	// Draw
+	if(mLightingEnabled) glDisable(GL_LIGHTING);///TODO: display list
+
+	glEnable(GL_COLOR_MATERIAL);
+	glBindTexture(GL_TEXTURE_1D, 0);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glBindTexture(GL_TEXTURE_3D, 0);
+	qglColor(QColor(Qt::white));
+	glBegin(GL_LINE_STRIP);
+		glVertex3fv(&vertex[0][0]), glVertex3fv(&vertex[1][0]), glVertex3fv(&vertex[2][0]), glVertex3fv(&vertex[3][0]), glVertex3fv(&vertex[0][0]);// "Minimum" side.
+		glVertex3fv(&vertex[4][0]), glVertex3fv(&vertex[5][0]), glVertex3fv(&vertex[6][0]), glVertex3fv(&vertex[7][0]), glVertex3fv(&vertex[4][0]);// Edge and "maximum" side.
+	glEnd();
+	glBegin(GL_LINES);
+		glVertex3fv(&vertex[1][0]), glVertex3fv(&vertex[5][0]);
+		glVertex3fv(&vertex[2][0]), glVertex3fv(&vertex[6][0]);
+		glVertex3fv(&vertex[3][0]), glVertex3fv(&vertex[7][0]);
+	glEnd();
+	glDisable(GL_COLOR_MATERIAL);
+	if(mLightingEnabled) glEnable(GL_LIGHTING);
+}
+
+void CGLView::Enable_Textures(const bool pEnable)
+{
+	if(pEnable)
+	{
+		glEnable(GL_TEXTURE_1D);
+		glEnable(GL_TEXTURE_2D);
+		glEnable(GL_TEXTURE_3D);
+	}
+	else
+	{
+		glDisable(GL_TEXTURE_1D);
+		glDisable(GL_TEXTURE_2D);
+		glDisable(GL_TEXTURE_3D);
+	}
+}
+
+/********************************************************************/
+/*********************** Overrided functions ************************/
+/********************************************************************/
+
+void CGLView::initializeGL()
+{
+	qglClearColor(Qt::gray);
+	glShadeModel(GL_SMOOTH);
+
+	glEnable(GL_DEPTH_TEST);
+	glEnable(GL_NORMALIZE);
+	glEnable(GL_TEXTURE_2D);
+
+	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
+	glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+	glDisable(GL_COLOR_MATERIAL);
+
+	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+
+	glFrontFace(GL_CCW);
+}
+
+void CGLView::resizeGL(int pWidth, int pHeight)
+{
+	mCamera_Viewport_AspectRatio = (GLdouble)pWidth / pHeight;
+	glViewport(0, 0, pWidth, pHeight);
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	gluPerspective(mCamera_FOVY, mCamera_Viewport_AspectRatio, 1.0, 100000.0);///TODO: znear/zfar depend on scene size.
+}
+
+void CGLView::paintGL()
+{
+QTime time_paintbegin;
+
+	time_paintbegin = QTime::currentTime();
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+	// Apply current camera transformations.
+	glMultMatrixf((GLfloat*)&mHelper_Camera.Rotation_AroundCamera);
+	glTranslatef(-mHelper_Camera.Translation_ToScene.x, -mHelper_Camera.Translation_ToScene.y, -mHelper_Camera.Translation_ToScene.z);
+	glMultMatrixf((GLfloat*)&mHelper_Camera.Rotation_Scene);
+	// Coordinate system
+	if(mLightingEnabled) glDisable(GL_LIGHTING);///TODO: display list
+
+	glBindTexture(GL_TEXTURE_1D, 0);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glBindTexture(GL_TEXTURE_3D, 0);
+	glEnable(GL_COLOR_MATERIAL);
+	glBegin(GL_LINES);
+		// X, -X
+		qglColor(QColor(Qt::red)),     glVertex3f(0.0, 0.0, 0.0), glVertex3f(100000.0, 0.0, 0.0);
+		qglColor(QColor(Qt::cyan)),    glVertex3f(0.0, 0.0, 0.0), glVertex3f(-100000.0, 0.0, 0.0);
+		// Y, -Y
+		qglColor(QColor(Qt::green)),   glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 100000.0, 0.0);
+		qglColor(QColor(Qt::magenta)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, -100000.0, 0.0);
+		// Z, -Z
+		qglColor(QColor(Qt::blue)),    glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0);
+		qglColor(QColor(Qt::yellow)),  glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0);
+	glEnd();
+	glDisable(GL_COLOR_MATERIAL);
+	if(mLightingEnabled) glEnable(GL_LIGHTING);
+
+	// Scene
+	if(mScene != nullptr)
+	{
+		Draw_Node(mScene->mRootNode);
+		// Scene BBox
+		if(mScene_DrawBBox) Draw_BBox(mScene_BBox);
+	}
+
+	emit Paint_Finished((size_t)time_paintbegin.msecsTo(QTime::currentTime()), mHelper_Camera.Translation_ToScene.Length());
+}
+
+/********************************************************************/
+/********************** Constructor/Destructor **********************/
+/********************************************************************/
+
+CGLView::CGLView(QWidget *pParent)
+	: QGLWidget(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer), pParent)
+{
+	static_assert(sizeof(GLfloat) == sizeof(ai_real), "ai_real in Assimp must be equal to GLfloat/float.");///TODO: may be templates can be used.
+
+	// set initial view
+	mHelper_CameraDefault.SetDefault();
+	Camera_Set(0);
+}
+
+CGLView::~CGLView()
+{
+	FreeScene();
+}
+
+/********************************************************************/
+/********************* Scene control functions **********************/
+/********************************************************************/
+
+void CGLView::FreeScene()
+{
+	// Set scene to null and after that \ref paintGL will not try to render it.
+	mScene = nullptr;
+	// Clean helper objects.
+	if(mHelper_Mesh != nullptr)
+	{
+		for(size_t idx_mesh = 0; idx_mesh < mHelper_Mesh_Quantity; idx_mesh++) delete mHelper_Mesh[idx_mesh];
+
+		delete [] mHelper_Mesh;
+		mHelper_Mesh = nullptr;
+	}
+
+	mHelper_Mesh_Quantity = 0;
+	// Delete textures
+	const int id_tex_size = mTexture_IDMap.size();
+
+	if(id_tex_size)
+	{
+		GLuint* id_tex = new GLuint[id_tex_size];
+		QMap<QString, GLuint>::iterator it = mTexture_IDMap.begin();
+
+		for(int idx = 0; idx < id_tex_size; idx++, it++)
+		{
+			id_tex[idx] = it.value();
+		}
+
+		glDeleteTextures(id_tex_size, id_tex);
+		mTexture_IDMap.clear();
+		delete [] id_tex;
+	}
+}
+
+void CGLView::SetScene(const aiScene *pScene, const QString& pScenePath)
+{
+	FreeScene();// Clear old data
+	// Why checking here, not at begin of function. Because old scene may not exist at know. So, need cleanup.
+	if(pScene == nullptr) return;
+
+	mScene = pScene;// Copy pointer of new scene.
+
+	//
+	// Meshes
+	//
+	// Create helper objects for meshes. This allow to render meshes as OpenGL arrays.
+	if(mScene->HasMeshes())
+	{
+		// Create mesh helpers array.
+		mHelper_Mesh_Quantity = mScene->mNumMeshes;
+		mHelper_Mesh = new SHelper_Mesh*[mScene->mNumMeshes];
+
+		// Walk thru the meshes and extract needed data and, also calculate BBox.
+		for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++)
+		{
+			aiMesh& mesh_cur = *mScene->mMeshes[idx_mesh];
+
+			//
+			// Calculate BBox
+			//
+			SBBox mesh_bbox;
+
+			BBox_GetFromVertices(mesh_cur.mVertices, mesh_cur.mNumVertices, mesh_bbox);
+			//
+			// Create vertices indices arrays splited by primitive type.
+			//
+			size_t indcnt_p = 0;// points quantity
+			size_t indcnt_l = 0;// lines quantity
+			size_t indcnt_t = 0;// triangles quantity
+
+			if(mesh_cur.HasFaces())
+			{
+				// Usual way: all faces are triangles
+				if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE)
+				{
+					indcnt_t = mesh_cur.mNumFaces;
+				}
+				else
+				{
+					// Calculate count of primitives by types.
+					for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++)
+					{
+						if(mesh_cur.mFaces[idx_face].mNumIndices == 3)
+							indcnt_t++;
+						else if(mesh_cur.mFaces[idx_face].mNumIndices == 2)
+							indcnt_l++;
+						else if(mesh_cur.mFaces[idx_face].mNumIndices == 1)
+							indcnt_p++;
+					}
+				}// if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) else
+
+				// Create helper
+				mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, indcnt_l, indcnt_t, mesh_bbox);
+				// Fill indices arrays
+				indcnt_p = 0, indcnt_l = 0, indcnt_t = 0;// Reuse variables as indices
+				for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++)
+				{
+					if(mesh_cur.mFaces[idx_face].mNumIndices == 3)
+					{
+						mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[0];
+						mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[1];
+						mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[2];
+					}
+					else if(mesh_cur.mFaces[idx_face].mNumIndices == 2)
+					{
+						mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[0];
+						mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[1];
+					}
+					else if(mesh_cur.mFaces[idx_face].mNumIndices == 1)
+					{
+						mHelper_Mesh[idx_mesh]->Index_Point[indcnt_p++] = mesh_cur.mFaces[idx_face].mIndices[0];
+					}
+				}// for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++)
+			}// if(mesh_cur.HasFaces())
+			else
+			{
+				// If mesh has no faces then vertices can be just points set.
+				indcnt_p = mesh_cur.mNumVertices;
+				// Create helper
+				mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, 0, 0, mesh_bbox);
+				// Fill indices arrays
+				for(size_t idx = 0; idx < indcnt_p; idx++) mHelper_Mesh[idx_mesh]->Index_Point[idx] = idx;
+
+			}// if(mesh_cur.HasFaces()) else
+		}// for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++)
+	}// if(mScene->HasMeshes())
+
+	//
+	// Scene BBox
+	//
+	// For calculating right BBox we must walk thru all nodes and apply transformation to meshes BBoxes
+	if(mHelper_Mesh_Quantity > 0)
+	{
+		bool first_assign = true;
+		aiMatrix4x4 mat_root;
+
+		BBox_GetForNode(*mScene->mRootNode, mat_root, mScene_BBox, first_assign);
+		mScene_Center = mScene_BBox.Maximum + mScene_BBox.Minimum;
+		mScene_Center /= 2;
+	}
+	else
+	{
+		mScene_BBox = {{0, 0, 0}, {0, 0, 0}};
+		mScene_Center = {0, 0, 0};
+	}// if(mHelper_Mesh_Count > 0) else
+
+	//
+	// Textures
+	//
+	ImportTextures(pScenePath);
+
+	//
+	// Light sources
+	//
+	Lighting_Enable();
+	// If scene has no lights then enable default
+	if(!mScene->HasLights())
+	{
+		const GLfloat col_amb[4] = { 0.2, 0.2, 0.2, 1.0 };
+		SLightParameters lp;
+
+		lp.Type = aiLightSource_POINT;
+		lp.Ambient.r = col_amb[0], lp.Ambient.g = col_amb[1], lp.Ambient.b = col_amb[2], lp.Ambient.a = col_amb[3];
+		lp.Diffuse = { 1.0, 1.0, 1.0, 1.0 };
+		lp.Specular = lp.Diffuse;
+		lp.For.Point.Position = mScene_Center;
+		lp.For.Point.Attenuation_Constant = 1;
+		lp.For.Point.Attenuation_Linear = 0;
+		lp.For.Point.Attenuation_Quadratic = 0;
+		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col_amb);
+		Lighting_EditSource(0, lp);
+		emit SceneObject_LightSource("_default");// Light source will be enabled in signal handler.
+	}
+	else
+	{
+		for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++)
+		{
+			SLightParameters lp;
+			QString name;
+			const aiLight& light_cur = *mScene->mLights[idx_light];
+
+			auto col3_to_col4 = [](const aiColor3D& pCol3) -> aiColor4D { return aiColor4D(pCol3.r, pCol3.g, pCol3.b, 1.0); };
+
+			///TODO: find light source node and apply all transformations
+			// General properties
+			name = light_cur.mName.C_Str();
+			lp.Ambient = col3_to_col4(light_cur.mColorAmbient);
+			lp.Diffuse = col3_to_col4(light_cur.mColorDiffuse);
+			lp.Specular = col3_to_col4(light_cur.mColorSpecular);
+			lp.Type = light_cur.mType;
+			// Depend on type properties
+			switch(light_cur.mType)
+			{
+				case aiLightSource_DIRECTIONAL:
+					lp.For.Directional.Direction = light_cur.mDirection;
+					break;
+				case aiLightSource_POINT:
+					lp.For.Point.Position = light_cur.mPosition;
+					lp.For.Point.Attenuation_Constant = light_cur.mAttenuationConstant;
+					lp.For.Point.Attenuation_Linear = light_cur.mAttenuationLinear;
+					lp.For.Point.Attenuation_Quadratic = light_cur.mAttenuationQuadratic;
+					break;
+				case aiLightSource_SPOT:
+					lp.For.Spot.Position = light_cur.mPosition;
+					lp.For.Spot.Direction = light_cur.mDirection;
+					lp.For.Spot.Attenuation_Constant = light_cur.mAttenuationConstant;
+					lp.For.Spot.Attenuation_Linear = light_cur.mAttenuationLinear;
+					lp.For.Spot.Attenuation_Quadratic = light_cur.mAttenuationQuadratic;
+					lp.For.Spot.CutOff = light_cur.mAngleOuterCone;
+					break;
+				case aiLightSource_AMBIENT:
+					lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0;
+					name.append("_unsup_ambient");
+					break;
+				case aiLightSource_AREA:
+					lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0;
+					name.append("_unsup_area");
+					break;
+				case aiLightSource_UNDEFINED:
+					lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0;
+					name.append("_unsup_undefined");
+					break;
+				default:
+					lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0;
+					name.append("_unsupported_invalid");
+					break;
+			}// switch(light_cur.mType)
+
+			// Add light source
+			if(name.isEmpty()) name += QString("%1").arg(idx_light);// Use index if name is empty.
+
+			Lighting_EditSource(idx_light, lp);
+			emit SceneObject_LightSource(name);// Light source will be enabled in signal handler.
+		}// for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++)
+	}// if(!mScene->HasLights()) else
+
+	//
+	// Cameras
+	//
+	if(!mScene->HasCameras())
+	{
+		mCamera_DefaultAdded = true;
+		mHelper_CameraDefault.SetDefault();
+		// Calculate distance from camera to scene. Distance must be enoguh for that viewport contain whole scene.
+		const GLfloat tg_angle = tan(mCamera_FOVY / 2);
+
+		GLfloat val_x = ((mScene_BBox.Maximum.x - mScene_BBox.Minimum.x) / 2) / (mCamera_Viewport_AspectRatio * tg_angle);
+		GLfloat val_y = ((mScene_BBox.Maximum.y - mScene_BBox.Minimum.y) / 2) / tg_angle;
+		GLfloat val_step = val_x;
+
+		AssignIfGreater(val_step, val_y);
+		mHelper_CameraDefault.Translation_ToScene.Set(mScene_Center.x, mScene_Center.y, val_step + mScene_BBox.Maximum.z);
+		emit SceneObject_Camera("_default");
+	}
+	else
+	{
+		mCamera_DefaultAdded = false;
+		for(size_t idx_cam = 0; idx_cam < mScene->mNumCameras; idx_cam++)
+		{
+			emit SceneObject_Camera(mScene->mCameras[idx_cam]->mName.C_Str());
+		}
+	}// if(!mScene->HasCameras()) else
+}
+
+/********************************************************************/
+/******************** Lighting control functions ********************/
+/********************************************************************/
+
+void CGLView::Lighting_Enable()
+{
+	mLightingEnabled = true;
+	glEnable(GL_LIGHTING);
+}
+
+void CGLView::Lighting_Disable()
+{
+	glDisable(GL_LIGHTING);
+	mLightingEnabled = false;
+}
+
+void CGLView::Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters)
+{
+const size_t light_num = GL_LIGHT0 + pLightNumber;
+
+GLfloat farr[4];
+
+	if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value;
+
+	glLightfv(light_num, GL_AMBIENT, &pLightParameters.Ambient.r);// Ambient color
+	glLightfv(light_num, GL_DIFFUSE, &pLightParameters.Diffuse.r);// Diffuse color
+	glLightfv(light_num, GL_SPECULAR, &pLightParameters.Specular.r);// Specular color
+	// Other parameters
+	switch(pLightParameters.Type)
+	{
+		case aiLightSource_DIRECTIONAL:
+			// Direction
+			farr[0] = pLightParameters.For.Directional.Direction.x, farr[2] = pLightParameters.For.Directional.Direction.y;
+			farr[2] = pLightParameters.For.Directional.Direction.z; farr[3] = 0;
+			glLightfv(light_num, GL_POSITION, farr);
+			break;
+		case aiLightSource_POINT:
+			// Position
+			farr[0] = pLightParameters.For.Point.Position.x, farr[2] = pLightParameters.For.Point.Position.y;
+			farr[2] = pLightParameters.For.Point.Position.z; farr[3] = 1;
+			glLightfv(light_num, GL_POSITION, farr);
+			// Attenuation
+			glLightf(light_num, GL_CONSTANT_ATTENUATION, pLightParameters.For.Point.Attenuation_Constant);
+			glLightf(light_num, GL_LINEAR_ATTENUATION, pLightParameters.For.Point.Attenuation_Linear);
+			glLightf(light_num, GL_QUADRATIC_ATTENUATION, pLightParameters.For.Point.Attenuation_Quadratic);
+			glLightf(light_num, GL_SPOT_CUTOFF, 180.0);
+			break;
+		case aiLightSource_SPOT:
+			// Position
+			farr[0] = pLightParameters.For.Spot.Position.x, farr[2] = pLightParameters.For.Spot.Position.y, farr[2] = pLightParameters.For.Spot.Position.z; farr[3] = 1;
+			glLightfv(light_num, GL_POSITION, farr);
+			// Attenuation
+			glLightf(light_num, GL_CONSTANT_ATTENUATION, pLightParameters.For.Spot.Attenuation_Constant);
+			glLightf(light_num, GL_LINEAR_ATTENUATION, pLightParameters.For.Spot.Attenuation_Linear);
+			glLightf(light_num, GL_QUADRATIC_ATTENUATION, pLightParameters.For.Spot.Attenuation_Quadratic);
+			// Spot specific
+			farr[0] = pLightParameters.For.Spot.Direction.x, farr[2] = pLightParameters.For.Spot.Direction.y, farr[2] = pLightParameters.For.Spot.Direction.z; farr[3] = 0;
+			glLightfv(light_num, GL_SPOT_DIRECTION, farr);
+			glLightf(light_num, GL_SPOT_CUTOFF, pLightParameters.For.Spot.CutOff);
+			break;
+		default:// For unknown light source types use point source.
+			// Position
+			farr[0] = pLightParameters.For.Point.Position.x, farr[2] = pLightParameters.For.Point.Position.y;
+			farr[2] = pLightParameters.For.Point.Position.z; farr[3] = 1;
+			glLightfv(light_num, GL_POSITION, farr);
+			// Attenuation
+			glLightf(light_num, GL_CONSTANT_ATTENUATION, 1);
+			glLightf(light_num, GL_LINEAR_ATTENUATION, 0);
+			glLightf(light_num, GL_QUADRATIC_ATTENUATION, 0);
+			glLightf(light_num, GL_SPOT_CUTOFF, 180.0);
+			break;
+	}// switch(pLightParameters.Type)
+}
+
+void CGLView::Lighting_EnableSource(const size_t pLightNumber)
+{
+	if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value;
+
+	glEnable(GL_LIGHT0 + pLightNumber);
+}
+
+void CGLView::Lighting_DisableSource(const size_t pLightNumber)
+{
+	if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value;
+
+	glDisable(GL_LIGHT0 + pLightNumber);
+}
+
+/********************************************************************/
+/******************** Cameras control functions *********************/
+/********************************************************************/
+
+void CGLView::Camera_Set(const size_t pCameraNumber)
+{
+SHelper_Camera& hcam = mHelper_Camera;// reference with short name for conveniance.
+aiVector3D up;
+
+	if(mCamera_DefaultAdded || (pCameraNumber >= mScene->mNumCameras))// If default camera used then 'pCameraNumber' doesn't matter.
+	{
+		// Transformation parameters
+		hcam = mHelper_CameraDefault;
+		up.Set(0, 1, 0);
+	}
+	else
+	{
+		const aiCamera& camera_cur = *mScene->mCameras[pCameraNumber];
+		const aiNode* camera_node;
+
+		aiMatrix4x4 camera_mat;
+		aiQuaternion camera_quat_rot;
+		aiVector3D camera_tr;
+
+		up = camera_cur.mUp;
+		//
+		// Try to get real coordinates of the camera.
+		//
+		// Find node
+		camera_node = mScene->mRootNode->FindNode(camera_cur.mName);
+		if(camera_node != nullptr) Matrix_NodeToRoot(camera_node, camera_mat);
+
+		hcam.Position = camera_cur.mLookAt;
+		hcam.Target = camera_cur.mPosition;
+		hcam.Rotation_AroundCamera = aiMatrix4x4(camera_quat_rot.GetMatrix());
+		hcam.Rotation_AroundCamera.Transpose();
+		// get components of transformation matrix.
+		camera_mat.DecomposeNoScaling(camera_quat_rot, camera_tr);
+		hcam.Rotation_Scene = aiMatrix4x4();
+		hcam.Translation_ToScene = camera_tr;
+	}
+
+	// Load identity matrix - travel to world begin.
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+	// Set camera and update picture
+	gluLookAt(hcam.Position.x, hcam.Position.y, hcam.Position.z, hcam.Target.x, hcam.Target.y, hcam.Target.z, up.x, up.y, up.z);
+}
+
+void CGLView::Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z)
+{
+auto deg2rad = [](const GLfloat pDegree) -> GLfloat { return pDegree * M_PI / 180.0; };
+
+	aiMatrix4x4 mat_rot;
+
+	mat_rot.FromEulerAnglesXYZ(deg2rad(pAngle_X), deg2rad(pAngle_Y), deg2rad(pAngle_Z));
+	mHelper_Camera.Rotation_Scene *= mat_rot;
+}
+
+void CGLView::Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z)
+{
+auto deg2rad = [](const GLfloat pDegree) -> GLfloat { return pDegree * M_PI / 180.0; };
+
+	aiMatrix4x4 mat_rot;
+
+	mat_rot.FromEulerAnglesXYZ(deg2rad(pAngle_X), deg2rad(pAngle_Y), deg2rad(pAngle_Z));
+	mHelper_Camera.Rotation_AroundCamera *= mat_rot;
+}
+
+void CGLView::Camera_Translate(const GLfloat pTranslate_X, const GLfloat pTranslate_Y, const GLfloat pTranslate_Z)
+{
+aiVector3D vect_tr(pTranslate_X, pTranslate_Y, pTranslate_Z);
+
+	vect_tr *= mHelper_Camera.Rotation_AroundCamera;
+	mHelper_Camera.Translation_ToScene += vect_tr;
+}

+ 382 - 0
tools/assimp_qt_viewer/glview.hpp

@@ -0,0 +1,382 @@
+/// \file   glview.hpp
+/// \brief  OpenGL visualisation.
+/// \author [email protected]
+/// \date   2016
+
+#pragma once
+
+// Header files, Qt.
+#include <QtOpenGL>
+
+// Header files Assimp
+#include <assimp/scene.h>
+
+/// \class CGLView
+/// Class which hold and render scene.
+class CGLView : public QGLWidget
+{
+	Q_OBJECT
+
+	/**********************************/
+	/************* Types **************/
+	/**********************************/
+
+private:
+
+	/// \struct SBBox
+	/// Bounding box for object.
+	struct SBBox
+	{
+		aiVector3D Minimum;///< Minimum values of coordinates.
+		aiVector3D Maximum;///< Maximum values of coordinates.
+	};
+
+	/// \struct SHelper_Mesh
+	/// Helper object for fast rendering of mesh (\ref aiMesh).
+	struct SHelper_Mesh
+	{
+		const size_t Quantity_Point;///< Quantity of points.
+		const size_t Quantity_Line;///< Quantity of lines.
+		const size_t Quantity_Triangle;///< Quantity of triangles.
+		GLuint* Index_Point;///< Array of indices for drawing points.
+		GLuint* Index_Line;///< Array of indices for drawing lines.
+		GLuint* Index_Triangle;///< Array of indices for drawing triangles.
+
+		const SBBox BBox;///< BBox of mesh.
+
+		/// \fn explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}})
+		/// Constructor.
+		/// \param [in] pQuantity_Point - quantity of points.
+		/// \param [in] pQuantity_Line - quantity of lines.
+		/// \param [in] pQuantity_Triangle - quantity of triangles.
+		/// \param [in] pBBox - BBox of mesh.
+		explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}});
+
+		/// \fn ~SHelper_Mesh()
+		/// Destructor.
+		~SHelper_Mesh();
+	};
+
+	/// \struct SHelper_Camera
+	/// Information about position of the camera in space.
+	struct SHelper_Camera
+	{
+		aiVector3D Position;///< Coordinates of the camera.
+		aiVector3D Target;///< Target point of the camera.
+		// Transformation path:
+		// set Camera -> Rotation_AroundCamera -> Translation_ToScene -> Rotation_Scene -> draw Scene
+		aiMatrix4x4 Rotation_AroundCamera;///< Rotation matrix which set rotation angles of the scene around camera.
+		aiMatrix4x4 Rotation_Scene;///< Rotation matrix which set rotation angles of the scene around own center.
+		aiVector3D Translation_ToScene;///< Translation vector from camera to the scene.
+
+		/// \fn void SetDefault()
+		/// Set default parameters of camera.
+		void SetDefault();
+	};
+
+public:
+
+	/// \enum ELightType
+	/// Type of light source.
+	enum class ELightType { Directional, Point, Spot };
+
+	/// \struct SLightParameters
+	/// Parameters of light source.
+	struct SLightParameters
+	{
+		aiLightSourceType Type;///< Type of light source.
+
+		aiColor4D Ambient;///< Ambient RGBA intensity of the light.
+		aiColor4D Diffuse;///< Diffuse RGBA intensity of the light.
+		aiColor4D Specular;///< Specular RGBA intensity of the light.
+
+		union UFor
+		{
+			/// \struct SDirectional
+			/// Parameters of directional light source.
+			struct SDirectional
+			{
+				aiVector3D Direction;
+
+				SDirectional() {}
+			} Directional;
+
+			/// \struct SPoint
+			/// Parameters of point light source.
+			struct SPoint
+			{
+				aiVector3D Position;
+				GLfloat Attenuation_Constant;
+				GLfloat Attenuation_Linear;
+				GLfloat Attenuation_Quadratic;
+
+				SPoint() {}
+			} Point;
+
+			/// \struct SSpot
+			/// Parameters of spot light source.
+			struct SSpot
+			{
+				aiVector3D Position;
+				GLfloat Attenuation_Constant;
+				GLfloat Attenuation_Linear;
+				GLfloat Attenuation_Quadratic;
+				aiVector3D Direction;
+				GLfloat CutOff;
+
+				SSpot() {}
+			} Spot;
+
+			UFor() {}
+		} For;
+
+		SLightParameters() {}
+	};
+
+	/**********************************/
+	/************ Variables ***********/
+	/**********************************/
+
+private:
+
+	// Scene
+	const aiScene* mScene = nullptr;///< Copy of pointer to scene (\ref aiScene).
+	SBBox mScene_BBox;///< Bounding box of scene.
+	aiVector3D mScene_Center;///< Coordinates of center of the scene.
+	bool mScene_DrawBBox = false;///< Flag which control drawing scene BBox.
+	// Meshes
+	size_t mHelper_Mesh_Quantity = 0;///< Quantity of meshes in scene.
+	SHelper_Mesh** mHelper_Mesh = nullptr;///< Array of pointers to helper objects for drawing mesh. Sequence of meshes are equivalent to \ref aiScene::mMeshes.
+	// Cameras
+	SHelper_Camera mHelper_Camera;///< Information about current camera placing in space.
+	SHelper_Camera mHelper_CameraDefault;///< Information about default camera initial placing in space.
+	bool mCamera_DefaultAdded = true;///< If true then scene has no defined cameras and default was added, if false - scene has defined cameras.
+	GLdouble mCamera_FOVY = 45.0;///< Specifies the field of view angle, in degrees, in the y direction.
+	GLdouble mCamera_Viewport_AspectRatio;///< Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+	// Lighting
+	bool mLightingEnabled = false;///< If true then OpenGL lighting is enabled (glEnable(GL_LIGHTING)), if false - disabled.
+	// Textures
+	QMap<QString, GLuint> mTexture_IDMap;///< Map image filenames to textures ID's.
+
+	/**********************************/
+	/************ Functions ***********/
+	/**********************************/
+
+private:
+
+	// Why in some cases pointers are used? Because: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566
+	template<typename TArg> void AssignIfLesser(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue < *pBaseValue) *pBaseValue = pTestValue; }
+	template<typename TArg> void AssignIfGreater(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue > *pBaseValue) *pBaseValue = pTestValue; }
+
+	template<typename TArg> void AssignIfLesser(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue < pBaseValue) pBaseValue = pTestValue; }
+	template<typename TArg> void AssignIfGreater(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue > pBaseValue) pBaseValue = pTestValue; }
+
+	/// \fn void Material_Apply(const aiMaterial* pMaterial)
+	/// Enable pointed material.
+	/// \param [in] pMaterial - pointer to material which must be used.
+	void Material_Apply(const aiMaterial* pMaterial);
+
+	/// \fn void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix)
+	/// Calculate matrix for transforming coordinates from pointed node to root node (read as "global coordinate system").
+	/// \param [in] pNode - pointer initial node from which relative coordintaes will be taken,
+	/// \param [out] pOutMatrix - matrix for transform relative coordinates in \ref pNode to coordinates in root node (\ref aiScene::mRootNode).
+	void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix);
+
+	/// \fn void ImportTextures()
+	/// Import textures.
+	/// \param [in] pScenePath - path to the file of the scene.
+	void ImportTextures(const QString& pScenePath);
+
+	/// \fn void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParentNode_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign)
+	/// Calculate BBox for pointed node. Function walk thru child nodes and apply all transformations.
+	/// \param [in] pNode - reference to node for which needed BBox.
+	/// \param [in] pParent_TransformationMatrix - reference to parent (parent for pNode) transformation matrix.
+	/// \param [in,out] pNodeBBox - reference to where pNode BBox will be placed. It will expanded by child nodes BBoxes.
+	/// \param [in] pFirstAssign - means that pNodeBBox not contain valid BBox at now and assign ('=') will used for setting new value, If
+	/// false then \ref BBox_Extend will be used for setting new BBox.
+	void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign);
+
+	/// \fn void BBox_Extend(const SBBox& pChild, SBBox& pParent)
+	/// Check and if need - extend current node BBox with BBox of child node.
+	/// \param [in] pChild - reference to BBox which used for extend parent BBox.
+	/// \param [in.out] pParent - BBox which will be extended using child BBox.
+	void BBox_Extend(const SBBox& pChild, SBBox& pParent);
+
+	/// \fn void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8])
+	/// Get vertices of a parallelepiped which is described by BBox.
+	/// \param [in] pBBox - input BBox.
+	/// \param [out] pVertices - array of vertices.
+	void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8]);
+
+	/// \fn void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox)
+	/// Calculate BBox for vertices array.
+	/// \param [in] pVertices - vertices array.
+	/// \param [in] pVerticesQuantity - quantity of vertices in array. If 0 then pBBox will be assigned with {{0, 0, 0}, {0, 0, 0}}.
+	/// \param [out] pBBox - calculated BBox.
+	void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox);
+
+	/********************************************************************/
+	/************************ Logging functions *************************/
+	/********************************************************************/
+
+	/// \fn void LogInfo(const QString& pMessage)
+	/// Add message with severity "Warning" to log.
+	void LogInfo(const QString& pMessage);
+
+	/// \fn void LogError(const QString& pMessage)
+	/// Add message with severity "Error" to log.
+	void LogError(const QString& pMessage);
+
+	/********************************************************************/
+	/************************** Draw functions **************************/
+	/********************************************************************/
+
+	/// \fn void Draw_Node(const aiNode* pNode)
+	/// Apply node transformation and draw meshes assigned to this node.
+	/// \param [in] pNode - pointer to node for drawing (\ref aiNode).
+	void Draw_Node(const aiNode* pNode);
+
+	/// \fn void Draw_Mesh(const size_t pMesh_Index)
+	/// Draw mesh.
+	/// \param [in] pMesh_Index - index of mesh which must be drawn. Index point to mesh in \ref mHelper_Mesh.
+	void Draw_Mesh(const size_t pMesh_Index);
+
+	/// \fn void Draw_BBox(const SBBox& pBBox)
+	/// Draw bounding box using lines.
+	/// \param [in] pBBox - bounding box for drawing.
+	void Draw_BBox(const SBBox& pBBox);
+
+	/********************************************************************/
+	/*********************** Overrided functions ************************/
+	/********************************************************************/
+
+protected:
+
+	/// \fn void initializeGL() override
+	/// Overrided function for initialise OpenGL.
+	void initializeGL() override;
+
+	/// \fn void resizeGL(int pWidth, int pHeight) override
+	/// \param [in] pWidth - new width of viewport.
+	/// \param [in] pHeight - new height of viewport.
+	void resizeGL(int pWidth, int pHeight) override;
+
+	/// \fn void paintGL() override
+	/// Overrided function for rendering.
+	void paintGL() override;
+
+public:
+
+	/********************************************************************/
+	/********************** Constructor/Destructor **********************/
+	/********************************************************************/
+
+	/// \fn explicit CGLView(QWidget* pParent)
+	/// Constructor.
+	/// \param [in] pParent - parent widget.
+	explicit CGLView(QWidget* pParent);
+
+	/// \fn virtual ~CGLView()
+	/// Destructor.
+	virtual ~CGLView();
+
+	/********************************************************************/
+	/********************* Scene control functions **********************/
+	/********************************************************************/
+
+	/// \fn void FreeScene()
+	/// Free all helper objects data.
+	void FreeScene();
+
+	/// \fn void SetScene(const aiScene* pScene)
+	/// Set scene for rendering.
+	/// \param [in] pScene - pointer to scene.
+	/// \param [in] pScenePath - path to the file of the scene.
+	void SetScene(const aiScene* pScene, const QString& pScenePath);
+
+	/// \fn void Enable_SceneBBox(const bool pEnable)
+	/// Enable drawing scene bounding box.
+	/// \param [in] pEnable - if true then bbox will be drawing, if false - will not be drawing.
+	void Enable_SceneBBox(const bool pEnable) { mScene_DrawBBox = pEnable; }
+
+	/// \fn void Enable_Textures(const bool pEnable)
+	/// Control textures drawing.
+	/// \param [in] pEnable - if true then enable textures, false - disable textures.
+	void Enable_Textures(const bool pEnable);
+
+	/********************************************************************/
+	/******************** Lighting control functions ********************/
+	/********************************************************************/
+
+	/// \fn void Lighting_Enable()
+	/// Enable OpenGL lighting.
+	void Lighting_Enable();
+
+	/// \fn void Lighting_Disable()
+	/// Disable OpenGL lighting.
+	void Lighting_Disable();
+
+	/// \fn void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters)
+	/// Edit light source properties.
+	/// \param [in] pLightNumber - light source number. \ref aiScene::mLights.
+	/// \param [in] pLightParameters - light source parameters.
+	void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters);///TODO: function set
+
+	/// \fn void Lighting_EnableSource(const size_t pLightNumber)
+	/// Enable light source.
+	/// \param [in] pLightNumber - light source number. \ref aiScene::mLights.
+	void Lighting_EnableSource(const size_t pLightNumber);
+
+	///void Lighting_DisableSource(const size_t pLightNumber)
+	/// Disable light source,
+	/// \param [in] pLightNumber - light source number. \ref aiScene::mLights.
+	void Lighting_DisableSource(const size_t pLightNumber);
+
+	/********************************************************************/
+	/******************** Cameras control functions *********************/
+	/********************************************************************/
+
+	/// \fn void Camera_Set(const size_t pCameraNumber)
+	/// Set view from pointed camera.
+	/// \param [in] pCamera_Index - index of the camera (\ref aiScene::mCameras).
+	void Camera_Set(const size_t pCameraNumber);
+
+	/// \fn void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z)
+	/// Rotate scene around axisees.
+	/// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees.
+	/// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees.
+	/// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees.
+	void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z);
+
+	/// \fn void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z)
+	/// Rotate camera around axisees.
+	/// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees.
+	/// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees.
+	/// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees.
+	void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z);
+
+	/// \fn void Camera_Translate(const size_t pTranslate_X, const size_t pTranslate_Y, const size_t pTranslate_Z)
+	/// Translate camera along axises. In local coordinates.
+	/// \param [in] pTranslate_X - specifies the X coordinate of translation vector.
+	/// \param [in] pTranslate_Y - specifies the Y coordinate of translation vector.
+	/// \param [in] pTranslate_Z - specifies the Z coordinate of translation vector.
+	void Camera_Translate(const GLfloat pTranslate_X, const GLfloat pTranslate_Y, const GLfloat pTranslate_Z);
+
+signals:
+
+	/// \fn void Paint_Finished(const size_t pPaintTime, const GLfloat pDistance)
+	///< Signal. Emits when execution of \ref paintGL is end.
+	/// \param [out] pPaintTime_ms - time spent for rendering, in milliseconds.
+	/// \param [out] pDistance - distance between current camera and center of the scene. \sa SHelper_Camera::Translation_ToScene.
+	void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance);
+
+	/// \fn void SceneObject_Camera(const QString& pName)
+	/// Signal. Emit for every camera found in scene. Also for default camera.
+	/// \param [out] pName - name of the camera.
+	void SceneObject_Camera(const QString& pName);
+
+	/// \fn void SceneObject_LightSource(const QString& pName)
+	/// Signal. Emit for every light source found in scene. Also for default light source.
+	/// \param [out] pName - name of the light source.
+	void SceneObject_LightSource(const QString& pName);
+};// class CGLView

+ 19 - 0
tools/assimp_qt_viewer/loggerview.cpp

@@ -0,0 +1,19 @@
+/// \file   loggerview.cpp
+/// \brief  Stream for Assimp logging subsystem.
+/// \author [email protected]
+/// \date   2016
+
+#include "loggerview.hpp"
+
+// Header files, Qt.
+#include <QTime>
+
+CLoggerView::CLoggerView(QTextBrowser* pOutputWidget)
+	: mOutputWidget(pOutputWidget)
+{
+}
+
+void CLoggerView::write(const char *pMessage)
+{
+	mOutputWidget->insertPlainText(QString("[%1] %2").arg(QTime::currentTime().toString()).arg(pMessage));
+}

+ 33 - 0
tools/assimp_qt_viewer/loggerview.hpp

@@ -0,0 +1,33 @@
+/// \file   loggerview.hpp
+/// \brief  Stream for Assimp logging subsystem.
+/// \author [email protected]
+/// \date   2016
+
+#pragma once
+
+// Header files, Qt.
+#include <QTextBrowser>
+
+// Header files, Assimp.
+#include <assimp/DefaultLogger.hpp>
+
+/// \class CLoggerView
+/// GUI-stream for Assimp logging subsytem. Get data for logging and write it to output widget.
+class CLoggerView final : public Assimp::LogStream
+{
+private:
+
+	QTextBrowser* mOutputWidget;///< Widget for displaying messages.
+
+public:
+
+	/// \fn explicit CLoggerView(QTextBrowser* pOutputWidget)
+	/// Constructor.
+	/// \param [in] pOutputWidget - pointer to output widget.
+	explicit CLoggerView(QTextBrowser* pOutputWidget);
+
+	/// \fn virtual void write(const char *pMessage)
+	/// Write message to output widget. Used by Assimp.
+	/// \param [in] pMessage - message for displaying.
+	virtual void write(const char *pMessage);
+};

+ 21 - 0
tools/assimp_qt_viewer/main.cpp

@@ -0,0 +1,21 @@
+/// \file   main.cpp
+/// \brief  Start-up file which contain function "main".
+/// \author [email protected]
+/// \date   2016
+// Thanks to acorn89 for support.
+
+// Header files, project.
+#include "mainwindow.hpp"
+
+// Header files, Qt.
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+QApplication a(argc, argv);
+MainWindow w;
+
+	w.show();
+
+	return a.exec();
+}

+ 344 - 0
tools/assimp_qt_viewer/mainwindow.cpp

@@ -0,0 +1,344 @@
+/// \file   mainwindow.hpp
+/// \brief  Main window and algorhytms.
+/// \author [email protected]
+/// \date   2016
+
+#include "mainwindow.hpp"
+#include "ui_mainwindow.h"
+
+// Header files, Assimp.
+#include <assimp/Exporter.hpp>
+#include <assimp/postprocess.h>
+
+#ifndef __unused
+	#define __unused	__attribute__((unused))
+#endif // __unused
+
+/**********************************/
+/************ Functions ***********/
+/**********************************/
+
+/********************************************************************/
+/********************* Import/Export functions **********************/
+/********************************************************************/
+
+void MainWindow::ImportFile(const QString &pFileName)
+{
+using namespace Assimp;
+
+QTime time_begin = QTime::currentTime();
+
+	if(mScene != nullptr)
+	{
+		mImporter.FreeScene();
+		mGLView->FreeScene();
+	}
+
+	// Try to import scene.
+	mScene = mImporter.ReadFile(pFileName.toStdString(), aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_ValidateDataStructure | \
+															aiProcess_GenUVCoords | aiProcess_TransformUVCoords | aiProcess_FlipUVs);
+	if(mScene != nullptr)
+	{
+		ui->lblLoadTime->setText(QString("%1").arg(time_begin.secsTo(QTime::currentTime())));
+		LogInfo("Import done: " + pFileName);
+		// Prepare widgets for new scene.
+		ui->leFileName->setText(pFileName.right(pFileName.length() - pFileName.lastIndexOf('/') - 1));
+		ui->lstLight->clear();
+		ui->lstCamera->clear();
+		ui->cbxLighting->setChecked(true), mGLView->Lighting_Enable();
+		ui->cbxBBox->setChecked(false); mGLView->Enable_SceneBBox(false);
+		ui->cbxTextures->setChecked(true), mGLView->Enable_Textures(true);
+		//
+		// Fill info labels
+		//
+		// Cameras
+		ui->lblCameraCount->setText(QString("%1").arg(mScene->mNumCameras));
+		// Lights
+		ui->lblLightCount->setText(QString("%1").arg(mScene->mNumLights));
+		// Meshes, faces, vertices.
+		size_t qty_face = 0;
+		size_t qty_vert = 0;
+
+		for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++)
+		{
+			qty_face += mScene->mMeshes[idx_mesh]->mNumFaces;
+			qty_vert += mScene->mMeshes[idx_mesh]->mNumVertices;
+		}
+
+		ui->lblMeshCount->setText(QString("%1").arg(mScene->mNumMeshes));
+		ui->lblFaceCount->setText(QString("%1").arg(qty_face));
+		ui->lblVertexCount->setText(QString("%1").arg(qty_vert));
+		// Animation
+		if(mScene->mNumAnimations)
+			ui->lblHasAnimation->setText("yes");
+		else
+			ui->lblHasAnimation->setText("no");
+
+		//
+		// Set scene for GL viewer.
+		//
+		mGLView->SetScene(mScene, pFileName);
+		// Select first camera
+		ui->lstCamera->setCurrentRow(0);
+		mGLView->Camera_Set(0);
+		// Scene is loaded, do first rendering.
+		LogInfo("Scene is ready for rendering.");
+		mGLView->updateGL();
+	}
+	else
+	{
+		ui->lblLoadTime->clear();
+		LogError(QString("Error parsing \'%1\' : \'%2\'").arg(pFileName).arg(mImporter.GetErrorString()));
+	}// if(mScene != nullptr)
+}
+
+/********************************************************************/
+/************************ Logging functions *************************/
+/********************************************************************/
+
+void MainWindow::LogInfo(const QString& pMessage)
+{
+	Assimp::DefaultLogger::get()->info(pMessage.toStdString());
+}
+
+void MainWindow::LogError(const QString& pMessage)
+{
+	Assimp::DefaultLogger::get()->error(pMessage.toStdString());
+}
+
+/********************************************************************/
+/*********************** Overrided functions ************************/
+/********************************************************************/
+
+void MainWindow::mousePressEvent(QMouseEvent* pEvent)
+{
+	if(pEvent->button() & Qt::LeftButton)
+		mPosition_Pressed_LMB = pEvent->pos();
+	else if(pEvent->button() & Qt::RightButton)
+		mPosition_Pressed_RMB = pEvent->pos();
+}
+
+void MainWindow::mouseMoveEvent(QMouseEvent* pEvent)
+{
+	if(pEvent->buttons() & Qt::LeftButton)
+	{
+		GLfloat dx = 180 * GLfloat(pEvent->x() - mPosition_Pressed_LMB.x()) / mGLView->width();
+		GLfloat dy = 180 * GLfloat(pEvent->y() - mPosition_Pressed_LMB.y()) / mGLView->height();
+
+		if(pEvent->modifiers() & Qt::ShiftModifier)
+			mGLView->Camera_RotateScene(dy, 0, dx);// Rotate around oX and oZ axises.
+		else
+			mGLView->Camera_RotateScene(dy, dx, 0);// Rotate around oX and oY axises.
+
+		mGLView->updateGL();
+		mPosition_Pressed_LMB = pEvent->pos();
+	}
+
+	if(pEvent->buttons() & Qt::RightButton)
+	{
+		GLfloat dx = 180 * GLfloat(pEvent->x() - mPosition_Pressed_RMB.x()) / mGLView->width();
+		GLfloat dy = 180 * GLfloat(pEvent->y() - mPosition_Pressed_RMB.y()) / mGLView->height();
+
+		if(pEvent->modifiers() & Qt::ShiftModifier)
+			mGLView->Camera_Rotate(dy, 0, dx);// Rotate around oX and oZ axises.
+		else
+			mGLView->Camera_Rotate(dy, dx, 0);// Rotate around oX and oY axises.
+
+		mGLView->updateGL();
+		mPosition_Pressed_RMB = pEvent->pos();
+	}
+}
+
+void MainWindow::keyPressEvent(QKeyEvent* pEvent)
+{
+GLfloat step;
+
+	if(pEvent->modifiers() & Qt::ControlModifier)
+		step = 10;
+	else if(pEvent->modifiers() & Qt::AltModifier)
+		step = 100;
+	else
+		step = 1;
+
+	if(pEvent->key() == Qt::Key_A)
+		mGLView->Camera_Translate(-step, 0, 0);
+	else if(pEvent->key() == Qt::Key_D)
+		mGLView->Camera_Translate(step, 0, 0);
+	else if(pEvent->key() == Qt::Key_W)
+		mGLView->Camera_Translate(0, step, 0);
+	else if(pEvent->key() == Qt::Key_S)
+		mGLView->Camera_Translate(0, -step, 0);
+	else if(pEvent->key() == Qt::Key_Up)
+		mGLView->Camera_Translate(0, 0, -step);
+	else if(pEvent->key() == Qt::Key_Down)
+		mGLView->Camera_Translate(0, 0, step);
+
+	mGLView->updateGL();
+}
+
+/********************************************************************/
+/********************** Constructor/Destructor **********************/
+/********************************************************************/
+
+MainWindow::MainWindow(QWidget *parent)
+	: QMainWindow(parent), ui(new Ui::MainWindow),
+		mScene(nullptr)
+{
+using namespace Assimp;
+
+	ui->setupUi(this);
+	// Create OpenGL widget
+	mGLView = new CGLView(this);
+	mGLView->setMinimumSize(800, 600);
+	mGLView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
+	mGLView->setFocusPolicy(Qt::StrongFocus);
+	// Connect to GLView signals.
+	connect(mGLView, SIGNAL(Paint_Finished(size_t, GLfloat)), SLOT(Paint_Finished(size_t, GLfloat)));
+	connect(mGLView, SIGNAL(SceneObject_Camera(QString)), SLOT(SceneObject_Camera(QString)));
+	connect(mGLView, SIGNAL(SceneObject_LightSource(QString)), SLOT(SceneObject_LightSource(QString)));
+	// and add it to layout
+	ui->hlMainView->insertWidget(0, mGLView, 4);
+	// Create logger
+	mLoggerView = new CLoggerView(ui->tbLog);
+	DefaultLogger::create("", Logger::VERBOSE);
+	DefaultLogger::get()->attachStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn);
+}
+
+MainWindow::~MainWindow()
+{
+using namespace Assimp;
+
+	DefaultLogger::get()->detatchStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn);
+	DefaultLogger::kill();
+
+	if(mScene != nullptr) mImporter.FreeScene();
+	if(mLoggerView != nullptr) delete mLoggerView;
+	if(mGLView != nullptr) delete mGLView;
+	delete ui;
+}
+
+/********************************************************************/
+/****************************** Slots *******************************/
+/********************************************************************/
+
+void MainWindow::Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance)
+{
+	ui->lblRenderTime->setText(QString("%1").arg(pPaintTime_ms));
+	ui->lblDistance->setText(QString("%1").arg(pDistance));
+}
+
+void MainWindow::SceneObject_Camera(const QString& pName)
+{
+	ui->lstCamera->addItem(pName);
+}
+
+void MainWindow::SceneObject_LightSource(const QString& pName)
+{
+	ui->lstLight->addItem(pName);
+	// After item added "currentRow" is still contain old value (even '-1' if first item added). Because "currentRow"/"currentItem" is changed by user interaction,
+	// not by "addItem". So, "currentRow" must be set manually.
+	ui->lstLight->setCurrentRow(ui->lstLight->count() - 1);
+	// And after "selectAll" handler of "signal itemSelectionChanged" will get right "currentItem" and "currentRow" values.
+	ui->lstLight->selectAll();
+}
+
+void MainWindow::on_butOpenFile_clicked()
+{
+aiString filter_temp;
+QString filename, filter;
+
+	mImporter.GetExtensionList(filter_temp);
+	filter = filter_temp.C_Str();
+	filter.replace(';', ' ');
+	filter.append(" ;; All (*.*)");
+	filename = QFileDialog::getOpenFileName(this, "Choose the file", "", filter);
+
+	if(!filename.isEmpty()) ImportFile(filename);
+}
+
+
+void MainWindow::on_butExport_clicked()
+{
+using namespace Assimp;
+
+QString filename, filter, format_id;
+Exporter exporter;
+QTime time_begin;
+aiReturn rv;
+
+	if(mScene == nullptr)
+	{
+		QMessageBox::critical(this, "Export error", "Scene is empty");
+
+		return;
+	}
+
+	// build filter
+	{
+		aiString filter_temp;
+
+		mImporter.GetExtensionList(filter_temp);
+		filter = filter_temp.C_Str();
+		filter.replace(';', ' ');
+	}
+
+	// get file path
+	filename = QFileDialog::getSaveFileName(this, "Set file name", "", filter);
+	// extract format ID
+	format_id = filename.right(filename.length() - filename.lastIndexOf('.') - 1);
+	if(format_id.isEmpty())
+	{
+		QMessageBox::critical(this, "Export error", "File name must has extension.");
+
+		return;
+	}
+
+	// begin export
+	time_begin = QTime::currentTime();
+	rv = exporter.Export(mScene, format_id.toLocal8Bit(), filename.toLocal8Bit());
+	ui->lblExportTime->setText(QString("%1").arg(time_begin.secsTo(QTime::currentTime())));
+	if(rv == aiReturn_SUCCESS)
+		LogInfo("Export done: " + filename);
+	else
+		LogError("Export failed: " + filename);
+}
+
+void MainWindow::on_cbxLighting_clicked(bool pChecked)
+{
+	if(pChecked)
+		mGLView->Lighting_Enable();
+	else
+		mGLView->Lighting_Disable();
+
+	mGLView->updateGL();
+}
+
+void MainWindow::on_lstLight_itemSelectionChanged()
+{
+bool selected = ui->lstLight->isItemSelected(ui->lstLight->currentItem());
+
+	if(selected)
+		mGLView->Lighting_EnableSource(ui->lstLight->currentRow());
+	else
+		mGLView->Lighting_DisableSource(ui->lstLight->currentRow());
+
+	mGLView->updateGL();
+}
+
+void MainWindow::on_lstCamera_clicked(__unused const QModelIndex &index)
+{
+	mGLView->Camera_Set(ui->lstLight->currentRow());
+	mGLView->updateGL();
+}
+
+void MainWindow::on_cbxBBox_clicked(bool checked)
+{
+	mGLView->Enable_SceneBBox(checked);
+	mGLView->updateGL();
+}
+
+void MainWindow::on_cbxTextures_clicked(bool checked)
+{
+	mGLView->Enable_Textures(checked);
+	mGLView->updateGL();
+}

+ 131 - 0
tools/assimp_qt_viewer/mainwindow.hpp

@@ -0,0 +1,131 @@
+/// \file   mainwindow.hpp
+/// \brief  Main window and algorhytms.
+/// \author [email protected]
+/// \date   2016
+
+#pragma once
+
+// Header files, Qt.
+#include <QMainWindow>
+
+// Header files, project.
+#include "glview.hpp"
+#include "loggerview.hpp"
+
+// Header files, Assimp.
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+
+namespace Ui { class MainWindow; }
+
+/// \class MainWindow
+/// Main window and algorhytms.
+class MainWindow : public QMainWindow
+{
+	Q_OBJECT
+
+	/**********************************/
+	/************ Variables ***********/
+	/**********************************/
+
+private:
+
+	Ui::MainWindow *ui;
+
+	CGLView* mGLView;///< Pointer to OpenGL render.
+	CLoggerView* mLoggerView;///< Pointer to logging object.
+	Assimp::Importer mImporter;///< Assimp importer.
+	const aiScene* mScene;///< Pointer to loaded scene (\ref aiScene).
+	QPoint mPosition_Pressed_LMB;///< Position where was pressed left mouse button.
+	QPoint mPosition_Pressed_RMB;///< Position where was pressed right mouse button.
+
+	/**********************************/
+	/************ Functions ***********/
+	/**********************************/
+
+	/********************************************************************/
+	/********************* Import/Export functions **********************/
+	/********************************************************************/
+
+	/// \fn void ImportFile(const QString& pFileName)
+	/// Import scene from file.
+	/// \param [in] pFileName - path and name of the file.
+	void ImportFile(const QString& pFileName);
+
+	/********************************************************************/
+	/************************ Logging functions *************************/
+	/********************************************************************/
+
+	/// \fn void LogInfo(const QString& pMessage)
+	/// Add message with severity "Warning" to log.
+	void LogInfo(const QString& pMessage);
+
+	/// \fn void LogError(const QString& pMessage)
+	/// Add message with severity "Error" to log.
+	void LogError(const QString& pMessage);
+
+	/********************************************************************/
+	/*********************** Overrided functions ************************/
+	/********************************************************************/
+
+protected:
+
+	/// \fn void mousePressEvent(QMouseEvent* pEvent) override
+	/// Overrided function which handle mouse event "button pressed".
+	/// \param [in] pEvent - pointer to event data.
+	void mousePressEvent(QMouseEvent* pEvent) override;
+
+	/// \fn void mouseMoveEvent(QMouseEvent* pEvent) override
+	/// Overrided function which handle mouse event "move".
+	/// \param [in] pEvent - pointer to event data.
+	void mouseMoveEvent(QMouseEvent* pEvent) override;
+
+	/// \fn void keyPressEvent(QKeyEvent* pEvent) override
+	/// Overrided function which handle key event "key pressed".
+	/// \param [in] pEvent - pointer to event data.
+	void keyPressEvent(QKeyEvent* pEvent) override;
+
+
+public:
+
+	/********************************************************************/
+	/********************** Constructor/Destructor **********************/
+	/********************************************************************/
+
+	/// \fn explicit MainWindow(QWidget* pParent = 0)
+	/// \param [in] pParent - pointer to parent widget.
+	explicit MainWindow(QWidget* pParent = 0);
+
+	/// \fn ~MainWindow()
+	/// Destructor.
+	~MainWindow();
+
+	/********************************************************************/
+	/****************************** Slots *******************************/
+	/********************************************************************/
+
+private slots:
+
+	/// \fn void Paint_Finished(const int pPaintTime)
+	/// Show paint/render time and distance between camera and center of the scene.
+	/// \param [in] pPaintTime_ms - paint time in milliseconds.
+	void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance);
+
+	/// \fn void SceneObject_Camera(const QString& pName)
+	/// Add camera name to list.
+	/// \param [in] pName - name of the camera.
+	void SceneObject_Camera(const QString& pName);
+
+	/// \fn void SceneObject_LightSource(const QString& pName)
+	/// Add lighting source name to list.
+	/// \param [in] pName - name of the light source,
+	void SceneObject_LightSource(const QString& pName);
+
+	void on_butOpenFile_clicked();
+	void on_butExport_clicked();
+	void on_cbxLighting_clicked(bool pChecked);
+	void on_lstLight_itemSelectionChanged();
+	void on_lstCamera_clicked(const QModelIndex &index);
+	void on_cbxBBox_clicked(bool checked);
+	void on_cbxTextures_clicked(bool checked);
+};

+ 516 - 0
tools/assimp_qt_viewer/mainwindow.ui

@@ -0,0 +1,516 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>641</width>
+    <height>734</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QVBoxLayout" name="verticalLayout_2">
+    <item>
+     <layout class="QVBoxLayout" name="verticalLayout" stretch="5,1">
+      <item>
+       <layout class="QHBoxLayout" name="hlMainView" stretch="0">
+        <property name="sizeConstraint">
+         <enum>QLayout::SetDefaultConstraint</enum>
+        </property>
+        <item>
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <item>
+           <widget class="QGroupBox" name="grpFile">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="focusPolicy">
+             <enum>Qt::NoFocus</enum>
+            </property>
+            <property name="title">
+             <string>File</string>
+            </property>
+            <layout class="QFormLayout" name="formLayout_2">
+             <item row="0" column="0" colspan="2">
+              <widget class="QPushButton" name="butOpenFile">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Open file</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="0">
+              <widget class="QLabel" name="lblFileName_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>File name</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="1">
+              <widget class="QLineEdit" name="leFileName">
+               <property name="maximumSize">
+                <size>
+                 <width>160</width>
+                 <height>16777215</height>
+                </size>
+               </property>
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="frame">
+                <bool>false</bool>
+               </property>
+               <property name="readOnly">
+                <bool>true</bool>
+               </property>
+              </widget>
+             </item>
+             <item row="2" column="0">
+              <widget class="QLabel" name="lblLoadTime_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Load time, s</string>
+               </property>
+              </widget>
+             </item>
+             <item row="2" column="1">
+              <widget class="QLabel" name="lblLoadTime">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignCenter</set>
+               </property>
+              </widget>
+             </item>
+             <item row="4" column="0" colspan="2">
+              <widget class="Line" name="line">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+              </widget>
+             </item>
+             <item row="5" column="0" colspan="2">
+              <widget class="QPushButton" name="butExport">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Export</string>
+               </property>
+              </widget>
+             </item>
+             <item row="6" column="0">
+              <widget class="QLabel" name="lblExportTime_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Export time, s</string>
+               </property>
+              </widget>
+             </item>
+             <item row="6" column="1">
+              <widget class="QLabel" name="lblExportTime">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QGroupBox" name="grpInfo">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="focusPolicy">
+             <enum>Qt::NoFocus</enum>
+            </property>
+            <property name="title">
+             <string>Info</string>
+            </property>
+            <layout class="QFormLayout" name="formLayout_4">
+             <item row="0" column="0">
+              <widget class="QLabel" name="lblRenderTime_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Render time, ms</string>
+               </property>
+              </widget>
+             </item>
+             <item row="0" column="1">
+              <widget class="QLabel" name="lblRenderTime">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignCenter</set>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="0">
+              <widget class="QLabel" name="lblMeshCount_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Meshes</string>
+               </property>
+              </widget>
+             </item>
+             <item row="2" column="0">
+              <widget class="QLabel" name="lblFaceCount_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Faces</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="1">
+              <widget class="QLabel" name="lblMeshCount">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignCenter</set>
+               </property>
+              </widget>
+             </item>
+             <item row="2" column="1">
+              <widget class="QLabel" name="lblFaceCount">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignCenter</set>
+               </property>
+              </widget>
+             </item>
+             <item row="3" column="0">
+              <widget class="QLabel" name="lblVertexCount_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Vertices</string>
+               </property>
+              </widget>
+             </item>
+             <item row="3" column="1">
+              <widget class="QLabel" name="lblVertexCount">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignCenter</set>
+               </property>
+              </widget>
+             </item>
+             <item row="4" column="0">
+              <widget class="QLabel" name="lblLightCount_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Lights</string>
+               </property>
+              </widget>
+             </item>
+             <item row="5" column="0">
+              <widget class="QLabel" name="lblCameraCount_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Cameras</string>
+               </property>
+              </widget>
+             </item>
+             <item row="7" column="0">
+              <widget class="QLabel" name="lblHasAnimation_Label">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Animation</string>
+               </property>
+              </widget>
+             </item>
+             <item row="6" column="0">
+              <widget class="QLabel" name="lblShaderCount_Label">
+               <property name="enabled">
+                <bool>false</bool>
+               </property>
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Shaders</string>
+               </property>
+              </widget>
+             </item>
+             <item row="4" column="1">
+              <widget class="QLabel" name="lblLightCount">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+              </widget>
+             </item>
+             <item row="5" column="1">
+              <widget class="QLabel" name="lblCameraCount">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+              </widget>
+             </item>
+             <item row="6" column="1">
+              <widget class="QLabel" name="lblShaderCount">
+               <property name="enabled">
+                <bool>false</bool>
+               </property>
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+              </widget>
+             </item>
+             <item row="7" column="1">
+              <widget class="QLabel" name="lblHasAnimation">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string/>
+               </property>
+              </widget>
+             </item>
+             <item row="8" column="0">
+              <widget class="QLabel" name="lblDistance_Label">
+               <property name="text">
+                <string>Distance</string>
+               </property>
+              </widget>
+             </item>
+             <item row="8" column="1">
+              <widget class="QLabel" name="lblDistance">
+               <property name="text">
+                <string/>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QGroupBox" name="grpDynamics">
+            <property name="enabled">
+             <bool>false</bool>
+            </property>
+            <property name="focusPolicy">
+             <enum>Qt::NoFocus</enum>
+            </property>
+            <property name="title">
+             <string>Dynamics</string>
+            </property>
+            <layout class="QGridLayout" name="gridLayout">
+             <item row="0" column="0">
+              <widget class="QPushButton" name="butAnimationStart">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Animation start</string>
+               </property>
+              </widget>
+             </item>
+             <item row="1" column="0">
+              <widget class="QPushButton" name="butAnimationStop">
+               <property name="focusPolicy">
+                <enum>Qt::NoFocus</enum>
+               </property>
+               <property name="text">
+                <string>Animation stop</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QTabWidget" name="tabInfoAndControl">
+        <property name="focusPolicy">
+         <enum>Qt::NoFocus</enum>
+        </property>
+        <property name="currentIndex">
+         <number>2</number>
+        </property>
+        <widget class="QWidget" name="tab">
+         <attribute name="title">
+          <string>Log</string>
+         </attribute>
+         <layout class="QGridLayout" name="gridLayout_2">
+          <item row="0" column="0">
+           <widget class="QTextBrowser" name="tbLog">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="focusPolicy">
+             <enum>Qt::NoFocus</enum>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="tab_2">
+         <attribute name="title">
+          <string>Lights and cameras</string>
+         </attribute>
+         <layout class="QHBoxLayout" name="horizontalLayout">
+          <item>
+           <widget class="QListWidget" name="lstLight">
+            <property name="focusPolicy">
+             <enum>Qt::NoFocus</enum>
+            </property>
+            <property name="toolTip">
+             <string>Light sources of the scene</string>
+            </property>
+            <property name="editTriggers">
+             <set>QAbstractItemView::SelectedClicked</set>
+            </property>
+            <property name="showDropIndicator" stdset="0">
+             <bool>false</bool>
+            </property>
+            <property name="selectionMode">
+             <enum>QAbstractItemView::MultiSelection</enum>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QListWidget" name="lstCamera">
+            <property name="focusPolicy">
+             <enum>Qt::NoFocus</enum>
+            </property>
+            <property name="toolTip">
+             <string>Cameras of the scene</string>
+            </property>
+            <property name="editTriggers">
+             <set>QAbstractItemView::NoEditTriggers</set>
+            </property>
+            <property name="showDropIndicator" stdset="0">
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="tab_3">
+         <attribute name="title">
+          <string>Control</string>
+         </attribute>
+         <layout class="QGridLayout" name="gridLayout_3">
+          <item row="0" column="0">
+           <widget class="QCheckBox" name="cbxLighting">
+            <property name="toolTip">
+             <string>Enable/Disable OpenGL lighting</string>
+            </property>
+            <property name="text">
+             <string>Lighting</string>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QCheckBox" name="cbxBBox">
+            <property name="text">
+             <string>Scene BBox</string>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="0">
+           <widget class="QCheckBox" name="cbxTextures">
+            <property name="text">
+             <string>Textures</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>

+ 1 - 0
tools/assimp_view/CMakeLists.txt

@@ -62,6 +62,7 @@ ADD_EXECUTABLE(  assimp_viewer WIN32
   Normals.cpp
   SceneAnimator.cpp
   Shaders.cpp
+  assimp_view.h
   assimp_view.cpp
   stdafx.cpp
   assimp_view.rc

+ 1 - 2
tools/assimp_view/assimp_view.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2015, assimp team
+Copyright (c) 2006-2016, assimp team
 
 All rights reserved.
 
@@ -160,7 +160,6 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
 
     // Call ASSIMPs C-API to load the file
     g_pcAsset->pcScene = (aiScene*)aiImportFileExWithProperties(g_szFileName,
-
         ppsteps | /* configurable pp steps */
         aiProcess_GenSmoothNormals		   | // generate smooth normal vectors if not existing
         aiProcess_SplitLargeMeshes         | // split large, unrenderable meshes into submeshes

+ 1 - 9
tools/assimp_view/assimp_view.h

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2012, assimp team
+Copyright (c) 2006-2016, assimp team
 
 All rights reserved.
 
@@ -71,14 +71,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../../code/MaterialSystem.h"   // aiMaterial class
 #include "../../code/StringComparison.h" // ASSIMP_stricmp and ASSIMP_strincmp
 
-// in order for std::min and std::max to behave properly
-#ifndef max
-#define max(a,b)            (((a) > (b)) ? (a) : (b))
-#endif // max
-#ifndef min
-#define min(a,b)            (((a) < (b)) ? (a) : (b))
-#endif // min
-
 #include <time.h>
 
 // default movement speed