Pārlūkot izejas kodu

Merge remote-tracking branch 'github/master' into contrib

Leo Terziman 8 gadi atpakaļ
vecāks
revīzija
4974c99288
50 mainītis faili ar 4245 papildinājumiem un 2084 dzēšanām
  1. 2 1
      .travis.sh
  2. 18 23
      .travis.yml
  3. 11 0
      CMakeLists.txt
  4. 12 19
      code/Assimp.cpp
  5. 12 4
      code/ColladaLoader.cpp
  6. 90 5
      code/IOStreamBuffer.h
  7. 34 23
      code/ObjFileParser.cpp
  8. 2 2
      code/ObjFileParser.h
  9. 5 3
      code/ObjTools.h
  10. 855 911
      code/PlyLoader.cpp
  11. 14 47
      code/PlyLoader.h
  12. 930 754
      code/PlyParser.cpp
  13. 39 56
      code/PlyParser.h
  14. 3 3
      code/STLLoader.cpp
  15. 2 3
      code/SpatialSort.cpp
  16. 10 3
      code/fast_atof.h
  17. 23 31
      contrib/poly2tri/poly2tri/common/shapes.cc
  18. 29 31
      contrib/poly2tri/poly2tri/common/shapes.h
  19. 32 8
      contrib/poly2tri/poly2tri/common/utils.h
  20. 2 3
      contrib/poly2tri/poly2tri/poly2tri.h
  21. 3 4
      contrib/poly2tri/poly2tri/sweep/advancing_front.cc
  22. 3 3
      contrib/poly2tri/poly2tri/sweep/advancing_front.h
  23. 4 5
      contrib/poly2tri/poly2tri/sweep/cdt.cc
  24. 17 17
      contrib/poly2tri/poly2tri/sweep/cdt.h
  25. 91 42
      contrib/poly2tri/poly2tri/sweep/sweep.cc
  26. 28 21
      contrib/poly2tri/poly2tri/sweep/sweep.h
  27. 31 22
      contrib/poly2tri/poly2tri/sweep/sweep_context.cc
  28. 17 17
      contrib/poly2tri/poly2tri/sweep/sweep_context.h
  29. 0 2
      include/assimp/color4.inl
  30. 4 3
      include/assimp/matrix4x4.h
  31. 1 4
      port/PyAssimp/pyassimp/helper.py
  32. 1 3
      port/PyAssimp/setup.py
  33. 28 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln
  34. 102 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h
  35. 205 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
  36. 44 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h
  37. 9 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl
  38. 146 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj
  39. 50 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters
  40. 691 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp
  41. 55 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h
  42. 23 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl
  43. 518 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp
  44. 28 4
      test/unit/utObjTools.cpp
  45. 3 2
      test/unit/utPMXImporter.cpp
  46. 2 0
      tools/assimp_view/Display.cpp
  47. 2 0
      tools/assimp_view/LogWindow.cpp
  48. 2 0
      tools/assimp_view/MessageProc.cpp
  49. 11 5
      tools/assimp_view/SceneAnimator.h
  50. 1 0
      tools/assimp_view/assimp_view.cpp

+ 2 - 1
.travis.sh

@@ -5,7 +5,8 @@ function generate()
 
 if [ $ANDROID ]; then
     ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
-else
+fi
+if [ "$TRAVIS_OS_NAME" = "linux" ]; then
     generate \
     && make -j4 \
     && sudo make install \

+ 18 - 23
.travis.yml

@@ -1,22 +1,18 @@
+language: cpp
+
 before_install:
-  - sudo apt-get update -qq
-  - sudo apt-get install cmake
-  - sudo apt-get install cmake python3
-  - if [ $LINUX ]; then sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; fi
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; fi
+  - if [ "$TRAVIS_OS_NAME" =   "osx" ]; then brew install cmake python3 homebrew/x11/freeglut; fi
   - echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
   # install latest LCOV (1.9 was failing)
-  - cd ${TRAVIS_BUILD_DIR}
-  - wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz
-  - tar xf lcov_1.11.orig.tar.gz
-  - sudo make -C lcov-1.11/ install
-  - gem install coveralls-lcov
-  - lcov --version
-  - g++ --version
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz && tar xf lcov_1.11.orig.tar.gz && sudo make -C lcov-1.11/ install && gem install coveralls-lcov && lcov --version && g++ --version ; fi
 
 branches:
   only:
     - master
 
+osx_image: xcode8.3
+
 env:
   global:
     - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
@@ -26,10 +22,11 @@ env:
     - LINUX=1 TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
     - LINUX=1 SHARED_BUILD=ON      ENABLE_COVERALLS=OFF
     - LINUX=1 SHARED_BUILD=OFF     ENABLE_COVERALLS=OFF
-    - ANDROID=1
-
-language: cpp
-  
+    #exclude:
+    #    - os: linux
+    #      compiler: clang
+    #    - os: osx
+    #      compiler: gcc  
 compiler:
   - gcc
   - clang
@@ -38,21 +35,19 @@ install:
   - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
 
 before_script:
-  - cd ${TRAVIS_BUILD_DIR}
   # init coverage to 0 (optional)
-  - lcov --directory . --zerocounters
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --zerocounters ; fi
 
 script:
   - export COVERALLS_SERVICE_NAME=travis-ci
   - export COVERALLS_REPO_TOKEN=abc12345
   - . ./.travis.sh
-
+os:
+  - linux
+  - osx
+ 
 after_success:
-  - cd ${TRAVIS_BUILD_DIR}
-  - lcov --directory . --capture --output-file coverage.info
-  - lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info
-  - lcov --list coverage.info
-  - coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi
 
 addons:
   coverity_scan:

+ 11 - 0
CMakeLists.txt

@@ -89,6 +89,10 @@ OPTION ( BUILD_DOCS
    OFF
 )
 
+if (WIN32)
+    add_definitions( -DWIN32_LEAN_AND_MEAN )
+endif()
+
 IF(MSVC)
   set (CMAKE_PREFIX_PATH "D:\\libs\\devil")
   OPTION( ASSIMP_INSTALL_PDB
@@ -141,6 +145,13 @@ IF(ASSIMP_DOUBLE_PRECISION)
   ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
 ENDIF(ASSIMP_DOUBLE_PRECISION)
 
+# Check for OpenMP support
+find_package(OpenMP)
+if (OPENMP_FOUND)
+    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+endif()
+
 configure_file(
   ${CMAKE_CURRENT_LIST_DIR}/revision.h.in
   ${CMAKE_CURRENT_BINARY_DIR}/revision.h

+ 12 - 19
code/Assimp.cpp

@@ -66,8 +66,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // ------------------------------------------------------------------------------------------------
 using namespace Assimp;
 
-namespace Assimp
-{
+namespace Assimp {
     // underlying structure for aiPropertyStore
     typedef BatchLoader::PropertyMap PropertyMap;
 
@@ -110,12 +109,11 @@ static std::mutex gLogStreamMutex;
 
 // ------------------------------------------------------------------------------------------------
 // Custom LogStream implementation for the C-API
-class LogToCallbackRedirector : public LogStream
-{
+class LogToCallbackRedirector : public LogStream {
 public:
     explicit LogToCallbackRedirector(const aiLogStream& s)
-        : stream (s)    {
-            ai_assert(NULL != s.callback);
+    : stream (s)    {
+        ai_assert(NULL != s.callback);
     }
 
     ~LogToCallbackRedirector()  {
@@ -146,8 +144,7 @@ private:
 };
 
 // ------------------------------------------------------------------------------------------------
-void ReportSceneNotFoundError()
-{
+void ReportSceneNotFoundError() {
     DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
         "The C-API does not accept scenes produced by the C++ API and vice versa");
 
@@ -156,22 +153,18 @@ void ReportSceneNotFoundError()
 
 // ------------------------------------------------------------------------------------------------
 // Reads the given file and returns its content.
-const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
-{
+const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) {
     return aiImportFileEx(pFile,pFlags,NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,  aiFileIO* pFS)
-{
+const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,  aiFileIO* pFS) {
     return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
-    aiFileIO* pFS,
-    const aiPropertyStore* props)
-{
+const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, 
+        aiFileIO* pFS, const aiPropertyStore* props) {
     ai_assert(NULL != pFile);
 
     const aiScene* scene = NULL;
@@ -190,7 +183,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
         pimpl->mMatrixProperties = pp->matrices;
     }
     // setup a custom IO system if necessary
-    if (pFS)    {
+    if (pFS) {
         imp->SetIOHandler( new CIOSystemWrapper (pFS) );
     }
 
@@ -201,8 +194,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
     if( scene)  {
         ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
         priv->mOrigImporter = imp;
-    }
-    else    {
+    } else {
         // if failed, extract error code and destroy the import
         gLastErrorString = imp->GetErrorString();
         delete imp;
@@ -210,6 +202,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
 
     // return imported data. If the import failed the pointer is NULL anyways
     ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    
     return scene;
 }
 

+ 12 - 4
code/ColladaLoader.cpp

@@ -1726,6 +1726,8 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/)
 aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser,
     const Collada::Effect& pEffect, const std::string& pName)
 {
+    aiString result;
+
     // recurse through the param references until we end up at an image
     std::string name = pName;
     while( 1)
@@ -1744,11 +1746,17 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
     ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name);
     if( imIt == pParser.mImageLibrary.end())
     {
-        throw DeadlyImportError( format() <<
-            "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." );
-    }
+        //missing texture should not stop the conversion
+        //throw DeadlyImportError( format() <<
+        //    "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." );
 
-    aiString result;
+        DefaultLogger::get()->warn("Collada: Unable to resolve effect texture entry \"" + pName + "\", ended up at ID \"" + name + "\".");
+
+        //set default texture file name
+        result.Set(name + ".jpg");
+        ConvertPath(result);
+        return result;
+    }
 
     // if this is an embedded texture image setup an aiTexture for it
     if (imIt->second.mFileName.empty())

+ 90 - 5
code/IOStreamBuffer.h

@@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOStream.hpp>
 #include "ParsingUtils.h"
 
+#include <vector>
+
 namespace Assimp {
 
 // ---------------------------------------------------------------------------
@@ -69,8 +71,8 @@ public:
     /// @return true if successful.
     bool close();
 
-    /// @brief  Returns the filesize.
-    /// @return The filesize.
+    /// @brief  Returns the file-size.
+    /// @return The file-size.
     size_t size() const;
     
     /// @brief  Returns the cache size.
@@ -96,7 +98,17 @@ public:
     /// @brief  Will read the next line.
     /// @param  buffer      The buffer for the next line.
     /// @return true if successful.
-    bool getNextLine( std::vector<T> &buffer );
+    bool getNextDataLine( std::vector<T> &buffer, T continuationToken );
+
+    /// @brief  Will read the next line ascii or binary end line char.
+    /// @param  buffer      The buffer for the next line.
+    /// @return true if successful.
+    bool getNextLine(std::vector<T> &buffer);
+
+    /// @brief  Will read the next block.
+    /// @param  buffer      The buffer for the next block.
+    /// @return true if successful.
+    bool getNextBlock( std::vector<T> &buffer );
 
 private:
     IOStream *m_stream;
@@ -227,15 +239,35 @@ size_t IOStreamBuffer<T>::getFilePos() const {
 
 template<class T>
 inline
-bool IOStreamBuffer<T>::getNextLine( std::vector<T> &buffer ) {
+bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationToken ) {
     buffer.resize( m_cacheSize );
     if ( m_cachePos == m_cacheSize || 0 == m_filePos ) {
         if ( !readNextBlock() ) {
             return false;
         }
     }
+
+    bool continuationFound( false ), endOfDataLine( false );
     size_t i = 0;
-    while ( !IsLineEnd( m_cache[ m_cachePos ] ) ) {
+    while ( !endOfDataLine ) {
+        if ( continuationToken == m_cache[ m_cachePos ] ) {
+            continuationFound = true;
+            ++m_cachePos;
+        }
+        if ( IsLineEnd( m_cache[ m_cachePos ] ) ) {
+            if ( !continuationFound ) {
+                // the end of the data line
+                break;
+            } else {
+                // skip line end
+                while ( m_cache[m_cachePos] != '\n') {
+                    ++m_cachePos;
+                }
+                ++m_cachePos;
+                continuationFound = false;
+            }
+        }
+
         buffer[ i ] = m_cache[ m_cachePos ];
         m_cachePos++;
         i++;
@@ -245,10 +277,63 @@ bool IOStreamBuffer<T>::getNextLine( std::vector<T> &buffer ) {
             }
         }
     }
+    
     buffer[ i ] = '\n';
     m_cachePos++;
 
     return true;
 }
 
+template<class T>
+inline
+bool IOStreamBuffer<T>::getNextLine(std::vector<T> &buffer) {
+    buffer.resize(m_cacheSize);
+    if (m_cachePos == m_cacheSize || 0 == m_filePos) {
+       if (!readNextBlock()) {
+          return false;
+       }
+      }
+
+    if (IsLineEnd(m_cache[m_cachePos])) {
+        // skip line end
+        while (m_cache[m_cachePos] != '\n') {
+            ++m_cachePos;
+        }
+        ++m_cachePos;
+    }
+
+    size_t i = 0;
+    while (!IsLineEnd(m_cache[m_cachePos])) {
+        buffer[i] = m_cache[m_cachePos];
+        m_cachePos++;
+        i++;
+        if (m_cachePos >= m_cacheSize) {
+            if (!readNextBlock()) {
+                return false;
+            }
+        }
+    }
+    buffer[i] = '\n';
+    m_cachePos++;
+
+    return true;
+}
+
+template<class T>
+inline
+bool IOStreamBuffer<T>::getNextBlock( std::vector<T> &buffer) {
+  //just return the last blockvalue if getNextLine was used before
+  if ( m_cachePos !=  0) {      
+      buffer = std::vector<T>(m_cache.begin() + m_cachePos, m_cache.end());
+      m_cachePos = 0;
+  }
+  else {
+      if ( !readNextBlock() )
+          return false;
+
+      buffer = std::vector<T>(m_cache.begin(), m_cache.end());
+  }
+  return true;
+}
+
 } // !ns Assimp

+ 34 - 23
code/ObjFileParser.cpp

@@ -109,7 +109,7 @@ ObjFile::Model *ObjFileParser::GetModel() const {
     return m_pModel;
 }
 
-void ignoreNewLines(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer)
+/*void ignoreNewLines(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer)
 {
     auto curPosition = buffer.begin();
     do
@@ -123,13 +123,13 @@ void ignoreNewLines(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffe
             std::vector<char> tempBuf;
             do
             {
-                streamBuffer.getNextLine(tempBuf);
+                streamBuffer.getNextDataLine(tempBuf, '\\' );
             } while (tempBuf[0]=='\n');
             *curPosition = ' ';
             std::copy(tempBuf.cbegin(), tempBuf.cend(), ++curPosition);
         }
     } while (*curPosition!='\n');
-}
+}*/
 
 void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
     // only update every 100KB or it'll be too slow
@@ -142,7 +142,7 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
     size_t lastFilePos( 0 );
 
     std::vector<char> buffer;
-    while ( streamBuffer.getNextLine( buffer ) ) {
+    while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) {
         m_DataIt = buffer.begin();
         m_DataItEnd = buffer.end();
 
@@ -154,14 +154,14 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
             progressCounter++;
             m_progress->UpdateFileRead( progressOffset + processed * 2, progressTotal );
         }
-		//ignoreNewLines(streamBuffer, buffer);
+
         // parse line
         switch (*m_DataIt) {
         case 'v': // Parse a vertex texture coordinate
             {
                 ++m_DataIt;
                 if (*m_DataIt == ' ' || *m_DataIt == '\t') {
-                    size_t numComponents = getNumComponentsInLine();
+                    size_t numComponents = getNumComponentsInDataDefinition();
                     if (numComponents == 3) {
                         // read in vertex definition
                         getVector3(m_pModel->m_Vertices);
@@ -245,7 +245,6 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
         default:
             {
 pf_skip_line:
-
                 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
             }
             break;
@@ -274,21 +273,44 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
     pBuffer[index] = '\0';
 }
 
-size_t ObjFileParser::getNumComponentsInLine() {
+static bool isDataDefinitionEnd( const char *tmp ) {
+    if ( *tmp == '\\' ) {
+        tmp++;
+        if ( IsLineEnd( *tmp ) ) {
+            tmp++;
+            return true;
+        }
+    }
+    return false;
+}
+
+size_t ObjFileParser::getNumComponentsInDataDefinition() {
     size_t numComponents( 0 );
     const char* tmp( &m_DataIt[0] );
-    while( !IsLineEnd( *tmp ) ) {        
+    bool end_of_definition = false;
+    while ( !end_of_definition ) {
+        if ( isDataDefinitionEnd( tmp ) ) {
+            tmp += 2;
+        } else if ( IsLineEnd( *tmp ) ) {
+            end_of_definition = true;
+        }
         if ( !SkipSpaces( &tmp ) ) {
             break;
         }
+        const bool isNum( IsNumeric( *tmp ) );
         SkipToken( tmp );
-        ++numComponents;
+        if ( isNum ) {
+            ++numComponents;
+        }
+        if ( !SkipSpaces( &tmp ) ) {
+            break;
+        }
     }
     return numComponents;
 }
 
 void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
-    size_t numComponents = getNumComponentsInLine();
+    size_t numComponents = getNumComponentsInDataDefinition();
     ai_real x, y, z;
     if( 2 == numComponents ) {
         copyNextWord( m_buffer, Buffersize );
@@ -397,10 +419,6 @@ static const std::string DefaultObjName = "defaultobject";
 // -------------------------------------------------------------------
 //  Get values for a new face instance
 void ObjFileParser::getFace( aiPrimitiveType type ) {
-    //copyNextLine(m_buffer, Buffersize);
-    //char *pPtr = m_DataIt;
-    //char *pPtr = m_buffer;
-    //char *pEnd = &pPtr[Buffersize];
     m_DataIt = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
     if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) {
         return;
@@ -571,14 +589,7 @@ void ObjFileParser::getMaterialDesc() {
 // -------------------------------------------------------------------
 //  Get a comment, values will be skipped
 void ObjFileParser::getComment() {
-    while (m_DataIt != m_DataItEnd) {
-        if ( '\n' == (*m_DataIt)) {
-            ++m_DataIt;
-            break;
-        } else {
-            ++m_DataIt;
-        }
-    }
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------

+ 2 - 2
code/ObjFileParser.h

@@ -91,6 +91,8 @@ protected:
     void copyNextWord(char *pBuffer, size_t length);
     /// Method to copy the new line.
 //    void copyNextLine(char *pBuffer, size_t length);
+    /// Get the number of components in a line.
+    size_t getNumComponentsInDataDefinition();
     /// Stores the vector
     void getVector( std::vector<aiVector3D> &point3d_array );
     /// Stores the following 3d vector.
@@ -129,8 +131,6 @@ protected:
     bool needsNewMesh( const std::string &rMaterialName );
     /// Error report in token
     void reportErrorTokenInFace();
-    /// Get the number of components in a line.
-    size_t getNumComponentsInLine();
 
 private:
     // Copy and assignment constructor should be private

+ 5 - 3
code/ObjTools.h

@@ -116,14 +116,16 @@ inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) {
     while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) {
         ++it;
     }
-    if ( it != end )
-    {
+    
+    if ( it != end ) {
         ++it;
         ++uiLine;
     }
     // fix .. from time to time there are spaces at the beginning of a material line
-    while ( it != end && (*it == '\t' || *it == ' ') )
+    while ( it != end && ( *it == '\t' || *it == ' ' ) ) {
         ++it;
+    }
+
     return it;
 }
 

+ 855 - 911
code/PlyLoader.cpp

@@ -5,7 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2017, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -13,18 +12,18 @@ 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.
+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.
+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.
+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
@@ -48,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "PlyLoader.h"
+#include "IOStreamBuffer.h"
 #include "Macros.h"
 #include <memory>
 #include <assimp/IOSystem.hpp>
@@ -57,16 +57,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-    "Stanford Polygon Library (PLY) Importer",
-    "",
-    "",
-    "",
-    aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour,
-    0,
-    0,
-    0,
-    0,
-    "ply"
+  "Stanford Polygon Library (PLY) Importer",
+  "",
+  "",
+  "",
+  aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour,
+  0,
+  0,
+  0,
+  0,
+  "ply"
 };
 
 
@@ -74,1040 +74,984 @@ static const aiImporterDesc desc = {
 // Internal stuff
 namespace
 {
-    // ------------------------------------------------------------------------------------------------
-    // Checks that property index is within range
-    template <class T>
-    const T &GetProperty(const std::vector<T> &props, int idx)
-    {
-        if( static_cast< size_t >( idx ) >= props.size() ) {
-            throw DeadlyImportError( "Invalid .ply file: Property index is out of range." );
-        }
-
-        return props[idx];
+  // ------------------------------------------------------------------------------------------------
+  // Checks that property index is within range
+  template <class T>
+  const T &GetProperty(const std::vector<T> &props, int idx)
+  {
+    if (static_cast<size_t>(idx) >= props.size()) {
+      throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
     }
+
+    return props[idx];
+  }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 PLYImporter::PLYImporter()
-: mBuffer()
-, pcDOM(){
-    // empty
+  : mBuffer()
+  , pcDOM()
+  , mGeneratedMesh(NULL){
+  // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 PLYImporter::~PLYImporter() {
-    // empty
+  // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool PLYImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "ply")
-        return true;
-    else if (!extension.length() || checkSig)
-    {
-        if (!pIOHandler)return true;
-        const char* tokens[] = {"ply"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+  const std::string extension = GetExtension(pFile);
+
+  if (extension == "ply")
+    return true;
+  else if (!extension.length() || checkSig)
+  {
+    if (!pIOHandler)return true;
+    const char* tokens[] = { "ply" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+  }
+  return false;
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiImporterDesc* PLYImporter::GetInfo () const
+const aiImporterDesc* PLYImporter::GetInfo() const
 {
-    return &desc;
+  return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
-static bool isBigEndian( const char* szMe ) {
-    ai_assert( NULL != szMe );
+static bool isBigEndian(const char* szMe) {
+  ai_assert(NULL != szMe);
 
-    // binary_little_endian
-    // binary_big_endian
-    bool isBigEndian( false );
+  // binary_little_endian
+  // binary_big_endian
+  bool isBigEndian(false);
 #if (defined AI_BUILD_BIG_ENDIAN)
-    if ( 'l' == *szMe || 'L' == *szMe ) {
-        isBigEndian = true;
-}
+  if ( 'l' == *szMe || 'L' == *szMe ) {
+    isBigEndian = true;
+  }
 #else
-    if ( 'b' == *szMe || 'B' == *szMe ) {
-        isBigEndian = true;
-    }
+  if ('b' == *szMe || 'B' == *szMe) {
+    isBigEndian = true;
+  }
 #endif // ! AI_BUILD_BIG_ENDIAN
 
-    return isBigEndian;
+  return isBigEndian;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void PLYImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
+void PLYImporter::InternReadFile(const std::string& pFile,
+  aiScene* pScene, IOSystem* pIOHandler)
 {
-    std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
-
-    // Check whether we can read from the file
-    if( file.get() == NULL) {
-        throw DeadlyImportError( "Failed to open PLY file " + pFile + ".");
+  static const std::string mode = "rb";
+  std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
+  if (!fileStream.get()) {
+    throw DeadlyImportError("Failed to open file " + pFile + ".");
+  }
+
+  // Get the file-size
+  size_t fileSize = fileStream->FileSize();
+
+  IOStreamBuffer<char> streamedBuffer(1024 * 1024);
+  streamedBuffer.open(fileStream.get());
+
+  // the beginning of the file must be PLY - magic, magic
+  std::vector<char> headerCheck;
+  streamedBuffer.getNextLine(headerCheck);
+
+  if ((headerCheck.size() >= 3) && (headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
+    (headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
+    (headerCheck[2] != 'Y' && headerCheck[2] != 'y'))
+  {
+    streamedBuffer.close();
+    throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
+  }
+
+  std::vector<char> mBuffer2;
+  streamedBuffer.getNextLine(mBuffer2);
+  mBuffer = (unsigned char*)&mBuffer2[0];
+
+  char* szMe = (char*)&this->mBuffer[0];
+  SkipSpacesAndLineEnd(szMe, (const char**)&szMe);
+
+  // determine the format of the file data and construct the aimesh
+  PLY::DOM sPlyDom;
+  this->pcDOM = &sPlyDom;
+
+  if (TokenMatch(szMe, "format", 6)) {
+    if (TokenMatch(szMe, "ascii", 5)) {
+      SkipLine(szMe, (const char**)&szMe);
+      if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this))
+      {
+        if (mGeneratedMesh != NULL)
+          delete(mGeneratedMesh);
+
+        streamedBuffer.close();
+        throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)");
+      }
+    }
+    else if (!::strncmp(szMe, "binary_", 7))
+    {
+      szMe += 7;
+      const bool bIsBE(isBigEndian(szMe));
+
+      // skip the line, parse the rest of the header and build the DOM
+      if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE))
+      {
+        if (mGeneratedMesh != NULL)
+          delete(mGeneratedMesh);
+
+        streamedBuffer.close();
+        throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
+      }
     }
+    else
+    {
+      if (mGeneratedMesh != NULL)
+        delete(mGeneratedMesh);
 
-    // allocate storage and copy the contents of the file to a memory buffer
-    std::vector<char> mBuffer2;
-    TextFileToBuffer(file.get(),mBuffer2);
-    mBuffer = (unsigned char*)&mBuffer2[0];
+      streamedBuffer.close();
+      throw DeadlyImportError("Invalid .ply file: Unknown file format");
+    }
+  }
+  else
+  {
+    AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
+    if (mGeneratedMesh != NULL)
+      delete(mGeneratedMesh);
+
+    streamedBuffer.close();
+    throw DeadlyImportError("Invalid .ply file: Missing format specification");
+  }
+
+  //free the file buffer
+  streamedBuffer.close();
+
+  if (mGeneratedMesh == NULL)
+  {
+    throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
+  }
+
+  // if no face list is existing we assume that the vertex
+  // list is containing a list of points
+  bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
+  if (pointsOnly)
+  {
+    if (mGeneratedMesh->mNumVertices < 3)
+    {
+      if (mGeneratedMesh != NULL)
+        delete(mGeneratedMesh);
 
-    // the beginning of the file must be PLY - magic, magic
-    if ((mBuffer[0] != 'P' && mBuffer[0] != 'p') ||
-        (mBuffer[1] != 'L' && mBuffer[1] != 'l') ||
-        (mBuffer[2] != 'Y' && mBuffer[2] != 'y'))   {
-        throw DeadlyImportError( "Invalid .ply file: Magic number \'ply\' is no there");
+      streamedBuffer.close();
+      throw DeadlyImportError("Invalid .ply file: Not enough "
+        "vertices to build a proper face list. ");
     }
 
-    char* szMe = (char*)&this->mBuffer[3];
-    SkipSpacesAndLineEnd(szMe,(const char**)&szMe);
-
-    // determine the format of the file data
-    PLY::DOM sPlyDom;
-    if (TokenMatch(szMe,"format",6)) {
-        if (TokenMatch(szMe,"ascii",5)) {
-            SkipLine(szMe,(const char**)&szMe);
-            if(!PLY::DOM::ParseInstance(szMe,&sPlyDom))
-                throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#1)");
-        } else if (!::strncmp(szMe,"binary_",7))
-        {
-            szMe += 7;
-            const bool bIsBE( isBigEndian( szMe ) );
+    const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3;
+    mGeneratedMesh->mNumFaces = iNum;
+    mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
 
-            // skip the line, parse the rest of the header and build the DOM
-            SkipLine(szMe,(const char**)&szMe);
-            if ( !PLY::DOM::ParseInstanceBinary( szMe, &sPlyDom, bIsBE ) ) {
-                throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#2)" );
-            }
-        } else {
-            throw DeadlyImportError( "Invalid .ply file: Unknown file format" );
-        }
-    }
-    else
+    for (unsigned int i = 0; i < iNum; ++i)
     {
-        AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
-        throw DeadlyImportError( "Invalid .ply file: Missing format specification");
+      mGeneratedMesh->mFaces[i].mNumIndices = 3;
+      mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3];
+      mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3);
+      mGeneratedMesh->mFaces[i].mIndices[1] = (i * 3) + 1;
+      mGeneratedMesh->mFaces[i].mIndices[2] = (i * 3) + 2;
     }
-    this->pcDOM = &sPlyDom;
+  }
+
+  // now load a list of all materials
+  std::vector<aiMaterial*> avMaterials;
+  std::string defaultTexture;
+  LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
+
+  // now generate the output scene object. Fill the material list
+  pScene->mNumMaterials = (unsigned int)avMaterials.size();
+  pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
+  for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
+    pScene->mMaterials[i] = avMaterials[i];
+  }
+
+  // fill the mesh list
+  pScene->mNumMeshes = 1;
+  pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+  pScene->mMeshes[0] = mGeneratedMesh;
+
+  // generate a simple node structure
+  pScene->mRootNode = new aiNode();
+  pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
+  pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+
+  for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i) {
+    pScene->mRootNode->mMeshes[i] = i;
+  }
+}
 
-    // now load a list of vertices. This must be successfully in order to procedure
-    std::vector<aiVector3D> avPositions;
-    this->LoadVertices(&avPositions,false);
+void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos)
+{
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != instElement);
 
-    if ( avPositions.empty() ) {
-        throw DeadlyImportError( "Invalid .ply file: No vertices found. "
-            "Unable to parse the data format of the PLY file." );
-    }
+  ai_uint aiPositions[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
+
+  ai_uint aiNormal[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiNormalTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
+
+  unsigned int aiColors[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiColorsTypes[4] = { EDT_Char, EDT_Char, EDT_Char, EDT_Char };
+
+  unsigned int aiTexcoord[2] = { 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char };
 
-    // now load a list of normals.
-    std::vector<aiVector3D> avNormals;
-    LoadVertices(&avNormals,true);
+  unsigned int cnt = 0;
 
-    // load the face list
-    std::vector<PLY::Face> avFaces;
-    LoadFaces(&avFaces);
+  // now check whether which normal components are available
+  unsigned int _a = 0;
+  for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+    a != pcElement->alProperties.end(); ++a, ++_a)
+  {
+    if ((*a).bIsList)continue;
 
-    // if no face list is existing we assume that the vertex
-    // list is containing a list of triangles
-    if (avFaces.empty())
+    // Positions
+    if (PLY::EST_XCoord == (*a).Semantic)
     {
-        if (avPositions.size() < 3)
-        {
-            throw DeadlyImportError( "Invalid .ply file: Not enough "
-                "vertices to build a proper face list. ");
-        }
+      cnt++;
+      aiPositions[0] = _a;
+      aiTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_YCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiPositions[1] = _a;
+      aiTypes[1] = (*a).eType;
+    }
+    else if (PLY::EST_ZCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiPositions[2] = _a;
+      aiTypes[2] = (*a).eType;
+    }
 
-        const unsigned int iNum = (unsigned int)avPositions.size() / 3;
-        for (unsigned int i = 0; i< iNum;++i)
-        {
-            PLY::Face sFace;
-            sFace.mIndices.push_back((iNum*3));
-            sFace.mIndices.push_back((iNum*3)+1);
-            sFace.mIndices.push_back((iNum*3)+2);
-            avFaces.push_back(sFace);
-        }
+    // Normals
+    else if (PLY::EST_XNormal == (*a).Semantic)
+    {
+      cnt++;
+      aiNormal[0] = _a;
+      aiNormalTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_YNormal == (*a).Semantic)
+    {
+      cnt++;
+      aiNormal[1] = _a;
+      aiNormalTypes[1] = (*a).eType;
+    }
+    else if (PLY::EST_ZNormal == (*a).Semantic)
+    {
+      cnt++;
+      aiNormal[2] = _a;
+      aiNormalTypes[2] = (*a).eType;
+    }
+    // Colors
+    else if (PLY::EST_Red == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[0] = _a;
+      aiColorsTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_Green == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[1] = _a;
+      aiColorsTypes[1] = (*a).eType;
+    }
+    else if (PLY::EST_Blue == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[2] = _a;
+      aiColorsTypes[2] = (*a).eType;
+    }
+    else if (PLY::EST_Alpha == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[3] = _a;
+      aiColorsTypes[3] = (*a).eType;
+    }
+    // Texture coordinates
+    else if (PLY::EST_UTextureCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiTexcoord[0] = _a;
+      aiTexcoordTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_VTextureCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiTexcoord[1] = _a;
+      aiTexcoordTypes[1] = (*a).eType;
+    }
+  }
+
+  // check whether we have a valid source for the vertex data
+  if (0 != cnt)
+  {
+    // Position
+    aiVector3D vOut;
+    if (0xFFFFFFFF != aiPositions[0])
+    {
+      vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]);
     }
 
-    // now load a list of all materials
-    std::vector<aiMaterial*> avMaterials;
-    LoadMaterial(&avMaterials);
+    if (0xFFFFFFFF != aiPositions[1])
+    {
+      vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]);
+    }
 
-    // now load a list of all vertex color channels
-    std::vector<aiColor4D> avColors;
-    avColors.reserve(avPositions.size());
-    LoadVertexColor(&avColors);
+    if (0xFFFFFFFF != aiPositions[2])
+    {
+      vOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]);
+    }
 
-    // now try to load texture coordinates
-    std::vector<aiVector2D> avTexCoords;
-    avTexCoords.reserve(avPositions.size());
-    LoadTextureCoordinates(&avTexCoords);
+    // Normals
+    aiVector3D nOut;
+    bool haveNormal = false;
+    if (0xFFFFFFFF != aiNormal[0])
+    {
+      nOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]);
+      haveNormal = true;
+    }
 
-    // now replace the default material in all faces and validate all material indices
-    ReplaceDefaultMaterial(&avFaces,&avMaterials);
+    if (0xFFFFFFFF != aiNormal[1])
+    {
+      nOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]);
+      haveNormal = true;
+    }
 
-    // now convert this to a list of aiMesh instances
-    std::vector<aiMesh*> avMeshes;
-    avMeshes.reserve(avMaterials.size()+1);
-    ConvertMeshes(&avFaces,&avPositions,&avNormals,
-        &avColors,&avTexCoords,&avMaterials,&avMeshes);
+    if (0xFFFFFFFF != aiNormal[2])
+    {
+      nOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]);
+      haveNormal = true;
+    }
 
-    if ( avMeshes.empty() ) {
-        throw DeadlyImportError( "Invalid .ply file: Unable to extract mesh data " );
+    //Colors
+    aiColor4D cOut;
+    bool haveColor = false;
+    if (0xFFFFFFFF != aiColors[0])
+    {
+      cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[0]).avList.front(), aiColorsTypes[0]);
+      haveColor = true;
     }
 
-    // now generate the output scene object. Fill the material list
-    pScene->mNumMaterials = (unsigned int)avMaterials.size();
-    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
-    for ( unsigned int i = 0; i < pScene->mNumMaterials; ++i ) {
-        pScene->mMaterials[ i ] = avMaterials[ i ];
+    if (0xFFFFFFFF != aiColors[1])
+    {
+      cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[1]).avList.front(), aiColorsTypes[1]);
+      haveColor = true;
     }
 
-    // fill the mesh list
-    pScene->mNumMeshes = (unsigned int)avMeshes.size();
-    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-    for ( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) {
-        pScene->mMeshes[ i ] = avMeshes[ i ];
+    if (0xFFFFFFFF != aiColors[2])
+    {
+      cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[2]).avList.front(), aiColorsTypes[2]);
+      haveColor = true;
     }
 
-    // generate a simple node structure
-    pScene->mRootNode = new aiNode();
-    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
-    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+    // assume 1.0 for the alpha channel ifit is not set
+    if (0xFFFFFFFF == aiColors[3])
+    {
+      cOut.a = 1.0;
+    }
+    else
+    {
+      cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[3]).avList.front(), aiColorsTypes[3]);
 
-    for ( unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i ) {
-        pScene->mRootNode->mMeshes[ i ] = i;
+      haveColor = true;
     }
-}
 
-// ------------------------------------------------------------------------------------------------
-// Split meshes by material IDs
-void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
-    const std::vector<aiVector3D>*          avPositions,
-    const std::vector<aiVector3D>*          avNormals,
-    const std::vector<aiColor4D>*           avColors,
-    const std::vector<aiVector2D>*          avTexCoords,
-    const std::vector<aiMaterial*>*     avMaterials,
-    std::vector<aiMesh*>* avOut)
-{
-    ai_assert(NULL != avFaces);
-    ai_assert(NULL != avPositions);
-    ai_assert(NULL != avMaterials);
+    //Texture coordinates
+    aiVector3D tOut;
+    tOut.z = 0;
+    bool haveTextureCoords = false;
+    if (0xFFFFFFFF != aiTexcoord[0])
+    {
+      tOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]);
+      haveTextureCoords = true;
+    }
 
-    // split by materials
-    std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[avMaterials->size()];
+    if (0xFFFFFFFF != aiTexcoord[1])
+    {
+      tOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]);
+      haveTextureCoords = true;
+    }
 
-    unsigned int iNum = 0;
-    for (std::vector<PLY::Face>::const_iterator i = avFaces->begin();i != avFaces->end();++i,++iNum)
-        aiSplit[(*i).iMaterialIndex].push_back(iNum);
+    //create aiMesh if needed
+    if (mGeneratedMesh == NULL)
+    {
+      mGeneratedMesh = new aiMesh();
+      mGeneratedMesh->mMaterialIndex = 0;
+    }
 
-    // now generate sub-meshes
-    for (unsigned int p = 0; p < avMaterials->size();++p)
+    if (mGeneratedMesh->mVertices == NULL)
     {
-        if (aiSplit[p].size() != 0)
-        {
-            // allocate the mesh object
-            aiMesh* p_pcOut = new aiMesh();
-            p_pcOut->mMaterialIndex = p;
+      mGeneratedMesh->mNumVertices = pcElement->NumOccur;
+      mGeneratedMesh->mVertices = new aiVector3D[mGeneratedMesh->mNumVertices];
+    }
 
-            p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
-            p_pcOut->mFaces = new aiFace[aiSplit[p].size()];
+    mGeneratedMesh->mVertices[pos] = vOut;
 
-            // at first we need to determine the size of the output vector array
-            unsigned int iNum = 0;
-            for (unsigned int i = 0; i < aiSplit[p].size();++i)
-            {
-                iNum += (unsigned int)(*avFaces)[aiSplit[p][i]].mIndices.size();
-            }
-            p_pcOut->mNumVertices = iNum;
-            if( 0 == iNum ) {     // nothing to do
-                delete[] aiSplit; // cleanup
-                delete p_pcOut;
-                return;
-            }
-            p_pcOut->mVertices = new aiVector3D[iNum];
+    if (haveNormal)
+    {
+      if (mGeneratedMesh->mNormals == NULL)
+        mGeneratedMesh->mNormals = new aiVector3D[mGeneratedMesh->mNumVertices];
+      mGeneratedMesh->mNormals[pos] = nOut;
+    }
 
-            if (!avColors->empty())
-                p_pcOut->mColors[0] = new aiColor4D[iNum];
-            if (!avTexCoords->empty())
-            {
-                p_pcOut->mNumUVComponents[0] = 2;
-                p_pcOut->mTextureCoords[0] = new aiVector3D[iNum];
-            }
-            if (!avNormals->empty())
-                p_pcOut->mNormals = new aiVector3D[iNum];
-
-            // add all faces
-            iNum = 0;
-            unsigned int iVertex = 0;
-            for (std::vector<unsigned int>::const_iterator i =  aiSplit[p].begin();
-                i != aiSplit[p].end();++i,++iNum)
-            {
-                p_pcOut->mFaces[iNum].mNumIndices = (unsigned int)(*avFaces)[*i].mIndices.size();
-                p_pcOut->mFaces[iNum].mIndices = new unsigned int[p_pcOut->mFaces[iNum].mNumIndices];
-
-                // build an unique set of vertices/colors for this face
-                for (unsigned int q = 0; q <  p_pcOut->mFaces[iNum].mNumIndices;++q)
-                {
-                    p_pcOut->mFaces[iNum].mIndices[q] = iVertex;
-                    const size_t idx = ( *avFaces )[ *i ].mIndices[ q ];
-                    if( idx >= ( *avPositions ).size() ) {
-                        // out of border
-                        continue;
-                    }
-                    p_pcOut->mVertices[ iVertex ] = ( *avPositions )[ idx ];
-
-                    if (!avColors->empty())
-                        p_pcOut->mColors[ 0 ][ iVertex ] = ( *avColors )[ idx ];
-
-                    if (!avTexCoords->empty())
-                    {
-                        const aiVector2D& vec = ( *avTexCoords )[ idx ];
-                        p_pcOut->mTextureCoords[0][iVertex].x = vec.x;
-                        p_pcOut->mTextureCoords[0][iVertex].y = vec.y;
-                    }
-
-                    if (!avNormals->empty())
-                        p_pcOut->mNormals[ iVertex ] = ( *avNormals )[ idx ];
-                    iVertex++;
-                }
+    if (haveColor)
+    {
+      if (mGeneratedMesh->mColors[0] == NULL)
+        mGeneratedMesh->mColors[0] = new aiColor4D[mGeneratedMesh->mNumVertices];
+      mGeneratedMesh->mColors[0][pos] = cOut;
+    }
 
-            }
-            // add the mesh to the output list
-            avOut->push_back(p_pcOut);
-        }
+    if (haveTextureCoords)
+    {
+      if (mGeneratedMesh->mTextureCoords[0] == NULL)
+      {
+        mGeneratedMesh->mNumUVComponents[0] = 2;
+        mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
+      }
+      mGeneratedMesh->mTextureCoords[0][pos] = tOut;
     }
-    delete[] aiSplit; // cleanup
+  }
 }
 
+
 // ------------------------------------------------------------------------------------------------
-// Generate a default material if none was specified and apply it to all vanilla faces
-void PLYImporter::ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
-    std::vector<aiMaterial*>* avMaterials)
+// Convert a color component to [0...1]
+ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val,
+  PLY::EDataType eType)
 {
-    bool bNeedDefaultMat = false;
+  switch (eType)
+  {
+  case EDT_Float:
+    return val.fFloat;
+  case EDT_Double:
+    return (ai_real)val.fDouble;
+
+  case EDT_UChar:
+    return (ai_real)val.iUInt / (ai_real)0xFF;
+  case EDT_Char:
+    return (ai_real)(val.iInt + (0xFF / 2)) / (ai_real)0xFF;
+  case EDT_UShort:
+    return (ai_real)val.iUInt / (ai_real)0xFFFF;
+  case EDT_Short:
+    return (ai_real)(val.iInt + (0xFFFF / 2)) / (ai_real)0xFFFF;
+  case EDT_UInt:
+    return (ai_real)val.iUInt / (ai_real)0xFFFF;
+  case EDT_Int:
+    return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f;
+  default:;
+  };
+  return 0.0f;
+}
 
-    for (std::vector<PLY::Face>::iterator i =  avFaces->begin();i != avFaces->end();++i)    {
-        if (0xFFFFFFFF == (*i).iMaterialIndex)  {
-            bNeedDefaultMat = true;
-            (*i).iMaterialIndex = (unsigned int)avMaterials->size();
-        }
-        else if ((*i).iMaterialIndex >= avMaterials->size() )   {
-            // clamp the index
-            (*i).iMaterialIndex = (unsigned int)avMaterials->size()-1;
-        }
-    }
+// ------------------------------------------------------------------------------------------------
+// Try to extract proper faces from the PLY DOM
+void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos)
+{
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != instElement);
 
-    if (bNeedDefaultMat)    {
-        // generate a default material
-        aiMaterial* pcHelper = new aiMaterial();
+  if (mGeneratedMesh == NULL)
+    throw DeadlyImportError("Invalid .ply file: Vertices shoud be declared before faces");
 
-        // fill in a default material
-        int iMode = (int)aiShadingMode_Gouraud;
-        pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+  bool bOne = false;
 
-        aiColor3D clr;
-        clr.b = clr.g = clr.r = 0.6f;
-        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
-        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
+  // index of the vertex index list
+  unsigned int iProperty = 0xFFFFFFFF;
+  PLY::EDataType eType = EDT_Char;
+  bool bIsTriStrip = false;
 
-        clr.b = clr.g = clr.r = 0.05f;
-        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
+  // index of the material index property
+  //unsigned int iMaterialIndex = 0xFFFFFFFF;
+  //PLY::EDataType eType2 = EDT_Char;
 
-        // The face order is absolutely undefined for PLY, so we have to
-        // use two-sided rendering to be sure it's ok.
-        const int two_sided = 1;
-        pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
+  // texture coordinates
+  unsigned int iTextureCoord = 0xFFFFFFFF;
+  PLY::EDataType eType3 = EDT_Char;
 
-        avMaterials->push_back(pcHelper);
+  // face = unique number of vertex indices
+  if (PLY::EEST_Face == pcElement->eSemantic)
+  {
+    unsigned int _a = 0;
+    for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+      a != pcElement->alProperties.end(); ++a, ++_a)
+    {
+      if (PLY::EST_VertexIndex == (*a).Semantic)
+      {
+        // must be a dynamic list!
+        if (!(*a).bIsList)
+          continue;
+
+        iProperty = _a;
+        bOne = true;
+        eType = (*a).eType;
+      }
+      /*else if (PLY::EST_MaterialIndex == (*a).Semantic)
+      {
+      if ((*a).bIsList)
+      continue;
+      iMaterialIndex = _a;
+      bOne = true;
+      eType2 = (*a).eType;
+      }*/
+      else if (PLY::EST_TextureCoordinates == (*a).Semantic)
+      {
+        // must be a dynamic list!
+        if (!(*a).bIsList)
+          continue;
+        iTextureCoord = _a;
+        bOne = true;
+        eType3 = (*a).eType;
+      }
     }
-}
-
-// ------------------------------------------------------------------------------------------------
-void PLYImporter::LoadTextureCoordinates(std::vector<aiVector2D>* pvOut)
-{
-    ai_assert(NULL != pvOut);
-
-    unsigned int aiPositions[2] = {0xFFFFFFFF,0xFFFFFFFF};
-    PLY::EDataType aiTypes[2] = {EDT_Char,EDT_Char};
-    PLY::ElementInstanceList* pcList = NULL;
-    unsigned int cnt = 0;
-
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
+  }
+  // triangle strip
+  // TODO: triangle strip and material index support???
+  else if (PLY::EEST_TriStrip == pcElement->eSemantic)
+  {
+    unsigned int _a = 0;
+    for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+      a != pcElement->alProperties.end(); ++a, ++_a)
     {
-        if (PLY::EEST_Vertex == (*i).eSemantic)
-        {
-            pcList = &this->pcDOM->alElementData[_i];
+      // must be a dynamic list!
+      if (!(*a).bIsList)
+        continue;
+      iProperty = _a;
+      bOne = true;
+      bIsTriStrip = true;
+      eType = (*a).eType;
+      break;
+    }
+  }
 
-            // now check whether which normal components are available
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if ((*a).bIsList)continue;
-                if (PLY::EST_UTextureCoord == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[0] = _a;
-                    aiTypes[0] = (*a).eType;
-                }
-                else if (PLY::EST_VTextureCoord == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[1] = _a;
-                    aiTypes[1] = (*a).eType;
-                }
-            }
-        }
+  // check whether we have at least one per-face information set
+  if (bOne)
+  {
+    if (mGeneratedMesh->mFaces == NULL)
+    {
+      mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+      mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
     }
-    // check whether we have a valid source for the texture coordinates data
-    if (NULL != pcList && 0 != cnt)
+
+    if (!bIsTriStrip)
     {
-        pvOut->reserve(pcList->alInstances.size());
-        for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
-            i != pcList->alInstances.end();++i)
-        {
-            // convert the vertices to sp floats
-            aiVector2D vOut;
+      // parse the list of vertex indices
+      if (0xFFFFFFFF != iProperty)
+      {
+        const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iProperty).avList.size();
+        mGeneratedMesh->mFaces[pos].mNumIndices = iNum;
+        mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum];
 
-            if (0xFFFFFFFF != aiPositions[0])
-            {
-                vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
-            }
+        std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+          GetProperty(instElement->alProperties, iProperty).avList.begin();
 
-            if (0xFFFFFFFF != aiPositions[1])
-            {
-                vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
-            }
-            // and add them to our nice list
-            pvOut->push_back(vOut);
+        for (unsigned int a = 0; a < iNum; ++a, ++p)
+        {
+          mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p, eType);
         }
-    }
-}
+      }
 
-// ------------------------------------------------------------------------------------------------
-// Try to extract vertices from the PLY DOM
-void PLYImporter::LoadVertices(std::vector<aiVector3D>* pvOut, bool p_bNormals)
-{
-    ai_assert(NULL != pvOut);
+      // parse the material index
+      // cannot be handled without processing the whole file first
+      /*if (0xFFFFFFFF != iMaterialIndex)
+      {
+      mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo<unsigned int>(
+      GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2);
+      }*/
 
-    ai_uint aiPositions[3] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
-    PLY::EDataType aiTypes[3] = {EDT_Char,EDT_Char,EDT_Char};
-    PLY::ElementInstanceList* pcList = NULL;
-    unsigned int cnt = 0;
+      if (0xFFFFFFFF != iTextureCoord)
+      {
+        const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size();
 
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i =  pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
-    {
-        if (PLY::EEST_Vertex == (*i).eSemantic)
-        {
-            pcList = &pcDOM->alElementData[_i];
+        //should be 6 coords
+        std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+          GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
 
-            // load normal vectors?
-            if (p_bNormals)
-            {
-                // now check whether which normal components are available
-                unsigned int _a = 0;
-                for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
-                    a != (*i).alProperties.end();++a,++_a)
-                {
-                    if ((*a).bIsList)continue;
-                    if (PLY::EST_XNormal == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[0] = _a;
-                        aiTypes[0] = (*a).eType;
-                    }
-                    else if (PLY::EST_YNormal == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[1] = _a;
-                        aiTypes[1] = (*a).eType;
-                    }
-                    else if (PLY::EST_ZNormal == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[2] = _a;
-                        aiTypes[2] = (*a).eType;
-                    }
-                }
-            }
-            // load vertex coordinates
-            else
+        if ((iNum / 3) == 2) // X Y coord
+        {
+          for (unsigned int a = 0; a < iNum; ++a, ++p)
+          {
+            unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
+            if (vindex < mGeneratedMesh->mNumVertices)
             {
-                // now check whether which coordinate sets are available
-                unsigned int _a = 0;
-                for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
-                    a != (*i).alProperties.end();++a,++_a)
-                {
-                    if ((*a).bIsList)continue;
-                    if (PLY::EST_XCoord == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[0] = _a;
-                        aiTypes[0] = (*a).eType;
-                    }
-                    else if (PLY::EST_YCoord == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[1] = _a;
-                        aiTypes[1] = (*a).eType;
-                    }
-                    else if (PLY::EST_ZCoord == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[2] = _a;
-                        aiTypes[2] = (*a).eType;
-                    }
-                    if (3 == cnt)break;
-                }
+              if (mGeneratedMesh->mTextureCoords[0] == NULL)
+              {
+                mGeneratedMesh->mNumUVComponents[0] = 2;
+                mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
+              }
+
+              if (a % 2 == 0)
+                mGeneratedMesh->mTextureCoords[0][vindex].x = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
+              else
+                mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
+
+              mGeneratedMesh->mTextureCoords[0][vindex].z = 0;
             }
-            break;
+          }
         }
+      }
     }
-    // check whether we have a valid source for the vertex data
-    if (NULL != pcList && 0 != cnt)
+    else // triangle strips
     {
-        pvOut->reserve(pcList->alInstances.size());
-        for (std::vector<ElementInstance>::const_iterator
-            i =  pcList->alInstances.begin();
-            i != pcList->alInstances.end();++i)
-        {
-            // convert the vertices to sp floats
-            aiVector3D vOut;
-
-            if (0xFFFFFFFF != aiPositions[0])
-            {
-                vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
-            }
+      // normally we have only one triangle strip instance where
+      // a value of -1 indicates a restart of the strip
+      bool flip = false;
+      const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty(instElement->alProperties, iProperty).avList;
+      //pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption
+
+      int aiTable[2] = { -1, -1 };
+      for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin(); a != quak.end(); ++a)  {
+        const int p = PLY::PropertyInstance::ConvertTo<int>(*a, eType);
+
+        if (-1 == p)    {
+          // restart the strip ...
+          aiTable[0] = aiTable[1] = -1;
+          flip = false;
+          continue;
+        }
+        if (-1 == aiTable[0]) {
+          aiTable[0] = p;
+          continue;
+        }
+        if (-1 == aiTable[1]) {
+          aiTable[1] = p;
+          continue;
+        }
 
-            if (0xFFFFFFFF != aiPositions[1])
-            {
-                vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
-            }
+        if (mGeneratedMesh->mFaces == NULL)
+        {
+          mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+          mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
+        }
 
-            if (0xFFFFFFFF != aiPositions[2])
-            {
-                vOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[2]).avList.front(),aiTypes[2]);
-            }
+        mGeneratedMesh->mFaces[pos].mNumIndices = 3;
+        mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[3];
+        mGeneratedMesh->mFaces[pos].mIndices[0] = aiTable[0];
+        mGeneratedMesh->mFaces[pos].mIndices[1] = aiTable[1];
+        mGeneratedMesh->mFaces[pos].mIndices[2] = aiTable[2];
 
-            // and add them to our nice list
-            pvOut->push_back(vOut);
+        if ((flip = !flip)) {
+          std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
         }
+
+        aiTable[0] = aiTable[1];
+        aiTable[1] = p;
+      }
     }
+  }
 }
 
 // ------------------------------------------------------------------------------------------------
-// Convert a color component to [0...1]
-ai_real PLYImporter::NormalizeColorValue (PLY::PropertyInstance::ValueUnion val,
-    PLY::EDataType eType)
+// Get a RGBA color in [0...1] range
+void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
+  unsigned int aiPositions[4],
+  PLY::EDataType aiTypes[4],
+  aiColor4D* clrOut)
 {
-    switch (eType)
-    {
-    case EDT_Float:
-        return val.fFloat;
-    case EDT_Double:
-        return (ai_real)val.fDouble;
-
-    case EDT_UChar:
-        return (ai_real)val.iUInt / (ai_real)0xFF;
-    case EDT_Char:
-        return (ai_real)(val.iInt+(0xFF/2)) / (ai_real)0xFF;
-    case EDT_UShort:
-        return (ai_real)val.iUInt / (ai_real)0xFFFF;
-    case EDT_Short:
-        return (ai_real)(val.iInt+(0xFFFF/2)) / (ai_real)0xFFFF;
-    case EDT_UInt:
-        return (ai_real)val.iUInt / (ai_real)0xFFFF;
-    case EDT_Int:
-        return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f;
-    default: ;
-    };
-    return 0.0f;
+  ai_assert(NULL != clrOut);
+
+  if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
+  else
+  {
+    clrOut->r = NormalizeColorValue(GetProperty(avList,
+      aiPositions[0]).avList.front(), aiTypes[0]);
+  }
+
+  if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
+  else
+  {
+    clrOut->g = NormalizeColorValue(GetProperty(avList,
+      aiPositions[1]).avList.front(), aiTypes[1]);
+  }
+
+  if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
+  else
+  {
+    clrOut->b = NormalizeColorValue(GetProperty(avList,
+      aiPositions[2]).avList.front(), aiTypes[2]);
+  }
+
+  // assume 1.0 for the alpha channel ifit is not set
+  if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
+  else
+  {
+    clrOut->a = NormalizeColorValue(GetProperty(avList,
+      aiPositions[3]).avList.front(), aiTypes[3]);
+  }
 }
 
 // ------------------------------------------------------------------------------------------------
-// Try to extract proper vertex colors from the PLY DOM
-void PLYImporter::LoadVertexColor(std::vector<aiColor4D>* pvOut)
+// Extract a material from the PLY DOM
+void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly)
 {
-    ai_assert(NULL != pvOut);
-
-    unsigned int aiPositions[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
-    PLY::EDataType aiTypes[4] = {EDT_Char, EDT_Char, EDT_Char, EDT_Char}; // silencing gcc
-    unsigned int cnt = 0;
-    PLY::ElementInstanceList* pcList = NULL;
-
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
+  ai_assert(NULL != pvOut);
+
+  // diffuse[4], specular[4], ambient[4]
+  // rgba order
+  unsigned int aaiPositions[3][4] = {
+
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
+  };
+
+  PLY::EDataType aaiTypes[3][4] = {
+    { EDT_Char, EDT_Char, EDT_Char, EDT_Char },
+    { EDT_Char, EDT_Char, EDT_Char, EDT_Char },
+    { EDT_Char, EDT_Char, EDT_Char, EDT_Char }
+  };
+  PLY::ElementInstanceList* pcList = NULL;
+
+  unsigned int iPhong = 0xFFFFFFFF;
+  PLY::EDataType ePhong = EDT_Char;
+
+  unsigned int iOpacity = 0xFFFFFFFF;
+  PLY::EDataType eOpacity = EDT_Char;
+
+  // search in the DOM for a vertex entry
+  unsigned int _i = 0;
+  for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
+    i != this->pcDOM->alElements.end(); ++i, ++_i)
+  {
+    if (PLY::EEST_Material == (*i).eSemantic)
     {
-        if (PLY::EEST_Vertex == (*i).eSemantic)
+      pcList = &this->pcDOM->alElementData[_i];
+
+      // now check whether which coordinate sets are available
+      unsigned int _a = 0;
+      for (std::vector<PLY::Property>::const_iterator
+        a = (*i).alProperties.begin();
+        a != (*i).alProperties.end(); ++a, ++_a)
+      {
+        if ((*a).bIsList)continue;
+
+        // pohng specularity      -----------------------------------
+        if (PLY::EST_PhongPower == (*a).Semantic)
         {
-            pcList = &this->pcDOM->alElementData[_i];
-
-            // now check whether which coordinate sets are available
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator
-                a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if ((*a).bIsList)continue;
-                if (PLY::EST_Red == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[0] = _a;
-                    aiTypes[0] = (*a).eType;
-                }
-                else if (PLY::EST_Green == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[1] = _a;
-                    aiTypes[1] = (*a).eType;
-                }
-                else if (PLY::EST_Blue == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[2] = _a;
-                    aiTypes[2] = (*a).eType;
-                }
-                else if (PLY::EST_Alpha == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[3] = _a;
-                    aiTypes[3] = (*a).eType;
-                }
-                if (4 == cnt)break;
-            }
-            break;
+          iPhong = _a;
+          ePhong = (*a).eType;
         }
-    }
-    // check whether we have a valid source for the vertex data
-    if (NULL != pcList && 0 != cnt)
-    {
-        pvOut->reserve(pcList->alInstances.size());
-        for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
-            i != pcList->alInstances.end();++i)
-        {
-            // convert the vertices to sp floats
-            aiColor4D vOut;
-
-            if (0xFFFFFFFF != aiPositions[0])
-            {
-                vOut.r = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[0]).avList.front(),aiTypes[0]);
-            }
-
-            if (0xFFFFFFFF != aiPositions[1])
-            {
-                vOut.g = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[1]).avList.front(),aiTypes[1]);
-            }
-
-            if (0xFFFFFFFF != aiPositions[2])
-            {
-                vOut.b = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[2]).avList.front(),aiTypes[2]);
-            }
-
-            // assume 1.0 for the alpha channel ifit is not set
-            if (0xFFFFFFFF == aiPositions[3])vOut.a = 1.0;
-            else
-            {
-                vOut.a = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[3]).avList.front(),aiTypes[3]);
-            }
 
-            // and add them to our nice list
-            pvOut->push_back(vOut);
+        // general opacity        -----------------------------------
+        if (PLY::EST_Opacity == (*a).Semantic)
+        {
+          iOpacity = _a;
+          eOpacity = (*a).eType;
         }
-    }
-}
-
-// ------------------------------------------------------------------------------------------------
-// Try to extract proper faces from the PLY DOM
-void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
-{
-    ai_assert(NULL != pvOut);
 
-    PLY::ElementInstanceList* pcList = NULL;
-    bool bOne = false;
-
-    // index of the vertex index list
-    unsigned int iProperty = 0xFFFFFFFF;
-    PLY::EDataType eType = EDT_Char;
-    bool bIsTriStrip = false;
-
-    // index of the material index property
-    unsigned int iMaterialIndex = 0xFFFFFFFF;
-    PLY::EDataType eType2 = EDT_Char;
-
-    // search in the DOM for a face entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i =  pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
-    {
-        // face = unique number of vertex indices
-        if (PLY::EEST_Face == (*i).eSemantic)
+        // diffuse color channels -----------------------------------
+        if (PLY::EST_DiffuseRed == (*a).Semantic)
         {
-            pcList = &pcDOM->alElementData[_i];
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if (PLY::EST_VertexIndex == (*a).Semantic)
-                {
-                    // must be a dynamic list!
-                    if (!(*a).bIsList)continue;
-                    iProperty   = _a;
-                    bOne        = true;
-                    eType       = (*a).eType;
-                }
-                else if (PLY::EST_MaterialIndex == (*a).Semantic)
-                {
-                    if ((*a).bIsList)continue;
-                    iMaterialIndex  = _a;
-                    bOne            = true;
-                    eType2      = (*a).eType;
-                }
-            }
-            break;
+          aaiPositions[0][0] = _a;
+          aaiTypes[0][0] = (*a).eType;
         }
-        // triangle strip
-        // TODO: triangle strip and material index support???
-        else if (PLY::EEST_TriStrip == (*i).eSemantic)
+        else if (PLY::EST_DiffuseGreen == (*a).Semantic)
         {
-            // find a list property in this ...
-            pcList = &this->pcDOM->alElementData[_i];
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                // must be a dynamic list!
-                if (!(*a).bIsList)continue;
-                iProperty   = _a;
-                bOne        = true;
-                bIsTriStrip = true;
-                eType       = (*a).eType;
-                break;
-            }
-            break;
+          aaiPositions[0][1] = _a;
+          aaiTypes[0][1] = (*a).eType;
         }
-    }
-    // check whether we have at least one per-face information set
-    if (pcList && bOne)
-    {
-        if (!bIsTriStrip)
+        else if (PLY::EST_DiffuseBlue == (*a).Semantic)
         {
-            pvOut->reserve(pcList->alInstances.size());
-            for (std::vector<ElementInstance>::const_iterator i =  pcList->alInstances.begin();
-                i != pcList->alInstances.end();++i)
-            {
-                PLY::Face sFace;
-
-                // parse the list of vertex indices
-                if (0xFFFFFFFF != iProperty)
-                {
-                    const unsigned int iNum = (unsigned int)GetProperty((*i).alProperties, iProperty).avList.size();
-                    sFace.mIndices.resize(iNum);
-
-                    std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
-                        GetProperty((*i).alProperties, iProperty).avList.begin();
-
-                    for (unsigned int a = 0; a < iNum;++a,++p)
-                    {
-                        sFace.mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p,eType);
-                    }
-                }
-
-                // parse the material index
-                if (0xFFFFFFFF != iMaterialIndex)
-                {
-                    sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo<unsigned int>(
-                        GetProperty((*i).alProperties, iMaterialIndex).avList.front(),eType2);
-                }
-                pvOut->push_back(sFace);
-            }
+          aaiPositions[0][2] = _a;
+          aaiTypes[0][2] = (*a).eType;
         }
-        else // triangle strips
+        else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
         {
-            // normally we have only one triangle strip instance where
-            // a value of -1 indicates a restart of the strip
-            bool flip = false;
-            for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) {
-                const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty((*i).alProperties, iProperty).avList;
-                pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u));
-
-                int aiTable[2] = {-1,-1};
-                for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a =  quak.begin();a != quak.end();++a)  {
-                    const int p = PLY::PropertyInstance::ConvertTo<int>(*a,eType);
-
-                    if (-1 == p)    {
-                        // restart the strip ...
-                        aiTable[0] = aiTable[1] = -1;
-                        flip = false;
-                        continue;
-                    }
-                    if (-1 == aiTable[0]) {
-                        aiTable[0] = p;
-                        continue;
-                    }
-                    if (-1 == aiTable[1]) {
-                        aiTable[1] = p;
-                        continue;
-                    }
-
-                    pvOut->push_back(PLY::Face());
-                    PLY::Face& sFace = pvOut->back();
-                    sFace.mIndices[0] = aiTable[0];
-                    sFace.mIndices[1] = aiTable[1];
-                    sFace.mIndices[2] = p;
-                    if ((flip = !flip)) {
-                        std::swap(sFace.mIndices[0],sFace.mIndices[1]);
-                    }
-
-                    aiTable[0] = aiTable[1];
-                    aiTable[1] = p;
-                }
-            }
+          aaiPositions[0][3] = _a;
+          aaiTypes[0][3] = (*a).eType;
+        }
+        // specular color channels -----------------------------------
+        else if (PLY::EST_SpecularRed == (*a).Semantic)
+        {
+          aaiPositions[1][0] = _a;
+          aaiTypes[1][0] = (*a).eType;
         }
+        else if (PLY::EST_SpecularGreen == (*a).Semantic)
+        {
+          aaiPositions[1][1] = _a;
+          aaiTypes[1][1] = (*a).eType;
+        }
+        else if (PLY::EST_SpecularBlue == (*a).Semantic)
+        {
+          aaiPositions[1][2] = _a;
+          aaiTypes[1][2] = (*a).eType;
+        }
+        else if (PLY::EST_SpecularAlpha == (*a).Semantic)
+        {
+          aaiPositions[1][3] = _a;
+          aaiTypes[1][3] = (*a).eType;
+        }
+        // ambient color channels -----------------------------------
+        else if (PLY::EST_AmbientRed == (*a).Semantic)
+        {
+          aaiPositions[2][0] = _a;
+          aaiTypes[2][0] = (*a).eType;
+        }
+        else if (PLY::EST_AmbientGreen == (*a).Semantic)
+        {
+          aaiPositions[2][1] = _a;
+          aaiTypes[2][1] = (*a).eType;
+        }
+        else if (PLY::EST_AmbientBlue == (*a).Semantic)
+        {
+          aaiPositions[2][2] = _a;
+          aaiTypes[2][2] = (*a).eType;
+        }
+        else if (PLY::EST_AmbientAlpha == (*a).Semantic)
+        {
+          aaiPositions[2][3] = _a;
+          aaiTypes[2][3] = (*a).eType;
+        }
+      }
+      break;
     }
-}
-
-// ------------------------------------------------------------------------------------------------
-// Get a RGBA color in [0...1] range
-void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
-    unsigned int aiPositions[4],
-    PLY::EDataType aiTypes[4],
-     aiColor4D* clrOut)
-{
-    ai_assert(NULL != clrOut);
-
-    if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
-    else
+    else if (PLY::EEST_TextureFile == (*i).eSemantic)
     {
-        clrOut->r = NormalizeColorValue(GetProperty(avList,
-            aiPositions[0]).avList.front(),aiTypes[0]);
+      defaultTexture = (*i).szName;
     }
-
-    if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
-    else
-    {
-        clrOut->g = NormalizeColorValue(GetProperty(avList,
-            aiPositions[1]).avList.front(),aiTypes[1]);
+  }
+  // check whether we have a valid source for the material data
+  if (NULL != pcList) {
+    for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i)  {
+      aiColor4D clrOut;
+      aiMaterial* pcHelper = new aiMaterial();
+
+      // build the diffuse material color
+      GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut);
+      pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE);
+
+      // build the specular material color
+      GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut);
+      pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR);
+
+      // build the ambient material color
+      GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut);
+      pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_AMBIENT);
+
+      // handle phong power and shading mode
+      int iMode = (int)aiShadingMode_Gouraud;
+      if (0xFFFFFFFF != iPhong)   {
+        ai_real fSpec = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), ePhong);
+
+        // if shininess is 0 (and the pow() calculation would therefore always
+        // become 1, not depending on the angle), use gouraud lighting
+        if (fSpec)  {
+          // scale this with 15 ... hopefully this is correct
+          fSpec *= 15;
+          pcHelper->AddProperty<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
+
+          iMode = (int)aiShadingMode_Phong;
+        }
+      }
+      pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+
+      // handle opacity
+      if (0xFFFFFFFF != iOpacity) {
+        ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity);
+        pcHelper->AddProperty<ai_real>(&fOpacity, 1, AI_MATKEY_OPACITY);
+      }
+
+      // The face order is absolutely undefined for PLY, so we have to
+      // use two-sided rendering to be sure it's ok.
+      const int two_sided = 1;
+      pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
+
+      //default texture
+      if (!defaultTexture.empty())
+      {
+        const aiString name(defaultTexture.c_str());
+        pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
+      }
+
+      if (!pointsOnly)
+      {
+        const int two_sided = 1;
+        pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
+      }
+
+      //set to wireframe, so when using this material info we can switch to points rendering
+      if (pointsOnly)
+      {
+        const int wireframe = 1;
+        pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
+      }
+
+      // add the newly created material instance to the list
+      pvOut->push_back(pcHelper);
     }
-
-    if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
-    else
+  }
+  else
+  {
+    // generate a default material
+    aiMaterial* pcHelper = new aiMaterial();
+
+    // fill in a default material
+    int iMode = (int)aiShadingMode_Gouraud;
+    pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+
+    //generate white material most 3D engine just multiply ambient / diffuse color with actual ambient / light color
+    aiColor3D clr;
+    clr.b = clr.g = clr.r = 1.0f;
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
+
+    clr.b = clr.g = clr.r = 1.0f;
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
+
+    // The face order is absolutely undefined for PLY, so we have to
+    // use two-sided rendering to be sure it's ok.
+    if (!pointsOnly)
     {
-        clrOut->b = NormalizeColorValue(GetProperty(avList,
-            aiPositions[2]).avList.front(),aiTypes[2]);
+      const int two_sided = 1;
+      pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
     }
 
-    // assume 1.0 for the alpha channel ifit is not set
-    if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
-    else
+    //default texture
+    if (!defaultTexture.empty())
     {
-        clrOut->a = NormalizeColorValue(GetProperty(avList,
-            aiPositions[3]).avList.front(),aiTypes[3]);
+      const aiString name(defaultTexture.c_str());
+      pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
     }
-}
 
-// ------------------------------------------------------------------------------------------------
-// Extract a material from the PLY DOM
-void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut)
-{
-    ai_assert(NULL != pvOut);
-
-    // diffuse[4], specular[4], ambient[4]
-    // rgba order
-    unsigned int aaiPositions[3][4] = {
-
-        {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
-        {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
-        {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
-    };
-
-    PLY::EDataType aaiTypes[3][4] = {
-        {EDT_Char,EDT_Char,EDT_Char,EDT_Char},
-        {EDT_Char,EDT_Char,EDT_Char,EDT_Char},
-        {EDT_Char,EDT_Char,EDT_Char,EDT_Char}
-    };
-    PLY::ElementInstanceList* pcList = NULL;
-
-    unsigned int iPhong = 0xFFFFFFFF;
-    PLY::EDataType ePhong = EDT_Char;
-
-    unsigned int iOpacity = 0xFFFFFFFF;
-    PLY::EDataType eOpacity = EDT_Char;
-
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i =  this->pcDOM->alElements.begin();
-        i != this->pcDOM->alElements.end();++i,++_i)
+    //set to wireframe, so when using this material info we can switch to points rendering
+    if (pointsOnly)
     {
-        if (PLY::EEST_Material == (*i).eSemantic)
-        {
-            pcList = &this->pcDOM->alElementData[_i];
-
-            // now check whether which coordinate sets are available
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator
-                a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if ((*a).bIsList)continue;
-
-                // pohng specularity      -----------------------------------
-                if (PLY::EST_PhongPower == (*a).Semantic)
-                {
-                    iPhong      = _a;
-                    ePhong      = (*a).eType;
-                }
-
-                // general opacity        -----------------------------------
-                if (PLY::EST_Opacity == (*a).Semantic)
-                {
-                    iOpacity        = _a;
-                    eOpacity        = (*a).eType;
-                }
-
-                // diffuse color channels -----------------------------------
-                if (PLY::EST_DiffuseRed == (*a).Semantic)
-                {
-                    aaiPositions[0][0]  = _a;
-                    aaiTypes[0][0]      = (*a).eType;
-                }
-                else if (PLY::EST_DiffuseGreen == (*a).Semantic)
-                {
-                    aaiPositions[0][1]  = _a;
-                    aaiTypes[0][1]      = (*a).eType;
-                }
-                else if (PLY::EST_DiffuseBlue == (*a).Semantic)
-                {
-                    aaiPositions[0][2]  = _a;
-                    aaiTypes[0][2]      = (*a).eType;
-                }
-                else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
-                {
-                    aaiPositions[0][3]  = _a;
-                    aaiTypes[0][3]      = (*a).eType;
-                }
-                // specular color channels -----------------------------------
-                else if (PLY::EST_SpecularRed == (*a).Semantic)
-                {
-                    aaiPositions[1][0]  = _a;
-                    aaiTypes[1][0]      = (*a).eType;
-                }
-                else if (PLY::EST_SpecularGreen == (*a).Semantic)
-                {
-                    aaiPositions[1][1]  = _a;
-                    aaiTypes[1][1]      = (*a).eType;
-                }
-                else if (PLY::EST_SpecularBlue == (*a).Semantic)
-                {
-                    aaiPositions[1][2]  = _a;
-                    aaiTypes[1][2]      = (*a).eType;
-                }
-                else if (PLY::EST_SpecularAlpha == (*a).Semantic)
-                {
-                    aaiPositions[1][3]  = _a;
-                    aaiTypes[1][3]      = (*a).eType;
-                }
-                // ambient color channels -----------------------------------
-                else if (PLY::EST_AmbientRed == (*a).Semantic)
-                {
-                    aaiPositions[2][0]  = _a;
-                    aaiTypes[2][0]      = (*a).eType;
-                }
-                else if (PLY::EST_AmbientGreen == (*a).Semantic)
-                {
-                    aaiPositions[2][1]  = _a;
-                    aaiTypes[2][1]      = (*a).eType;
-                }
-                else if (PLY::EST_AmbientBlue == (*a).Semantic)
-                {
-                    aaiPositions[2][2]  = _a;
-                    aaiTypes[2][2]      = (*a).eType;
-                }
-                else if (PLY::EST_AmbientAlpha == (*a).Semantic)
-                {
-                    aaiPositions[2][3]  = _a;
-                    aaiTypes[2][3]      = (*a).eType;
-                }
-            }
-            break;
-        }
+      const int wireframe = 1;
+      pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
     }
-    // check whether we have a valid source for the material data
-    if (NULL != pcList) {
-        for (std::vector<ElementInstance>::const_iterator i =  pcList->alInstances.begin();i != pcList->alInstances.end();++i)  {
-            aiColor4D clrOut;
-            aiMaterial* pcHelper = new aiMaterial();
-
-            // build the diffuse material color
-            GetMaterialColor((*i).alProperties,aaiPositions[0],aaiTypes[0],&clrOut);
-            pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_DIFFUSE);
-
-            // build the specular material color
-            GetMaterialColor((*i).alProperties,aaiPositions[1],aaiTypes[1],&clrOut);
-            pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_SPECULAR);
-
-            // build the ambient material color
-            GetMaterialColor((*i).alProperties,aaiPositions[2],aaiTypes[2],&clrOut);
-            pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_AMBIENT);
-
-            // handle phong power and shading mode
-            int iMode = (int)aiShadingMode_Gouraud;
-            if (0xFFFFFFFF != iPhong)   {
-                ai_real fSpec = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(),ePhong);
-
-                // if shininess is 0 (and the pow() calculation would therefore always
-                // become 1, not depending on the angle), use gouraud lighting
-                if (fSpec)  {
-                    // scale this with 15 ... hopefully this is correct
-                    fSpec *= 15;
-                    pcHelper->AddProperty<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
-
-                    iMode = (int)aiShadingMode_Phong;
-                }
-            }
-            pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
-
-            // handle opacity
-            if (0xFFFFFFFF != iOpacity) {
-                ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(),eOpacity);
-                pcHelper->AddProperty<ai_real>(&fOpacity, 1, AI_MATKEY_OPACITY);
-            }
 
-            // The face order is absolutely undefined for PLY, so we have to
-            // use two-sided rendering to be sure it's ok.
-            const int two_sided = 1;
-            pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
-
-            // add the newly created material instance to the list
-            pvOut->push_back(pcHelper);
-        }
-    }
+    pvOut->push_back(pcHelper);
+  }
 }
 
 #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER

+ 14 - 47
code/PlyLoader.h

@@ -68,7 +68,6 @@ public:
     PLYImporter();
     ~PLYImporter();
 
-
 public:
 
     // -------------------------------------------------------------------
@@ -78,6 +77,16 @@ public:
     bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
         bool checkSig) const;
 
+    // -------------------------------------------------------------------
+    /** Extract a vertex from the DOM
+    */
+    void LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos);
+
+    // -------------------------------------------------------------------
+    /** Extract a face from the DOM
+    */
+    void LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos);
+
 protected:
 
     // -------------------------------------------------------------------
@@ -94,53 +103,10 @@ protected:
         IOSystem* pIOHandler);
 
 protected:
-
-
-    // -------------------------------------------------------------------
-    /** Extract vertices from the DOM
-    */
-    void LoadVertices(std::vector<aiVector3D>* pvOut,
-        bool p_bNormals = false);
-
-    // -------------------------------------------------------------------
-    /** Extract vertex color channels from the DOM
-    */
-    void LoadVertexColor(std::vector<aiColor4D>* pvOut);
-
-    // -------------------------------------------------------------------
-    /** Extract texture coordinate channels from the DOM
-    */
-    void LoadTextureCoordinates(std::vector<aiVector2D>* pvOut);
-
-    // -------------------------------------------------------------------
-    /** Extract a face list from the DOM
-    */
-    void LoadFaces(std::vector<PLY::Face>* pvOut);
-
     // -------------------------------------------------------------------
     /** Extract a material list from the DOM
     */
-    void LoadMaterial(std::vector<aiMaterial*>* pvOut);
-
-
-    // -------------------------------------------------------------------
-    /** Validate material indices, replace default material identifiers
-    */
-    void ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
-        std::vector<aiMaterial*>* avMaterials);
-
-
-    // -------------------------------------------------------------------
-    /** Convert all meshes into our ourer representation
-    */
-    void ConvertMeshes(std::vector<PLY::Face>* avFaces,
-        const std::vector<aiVector3D>* avPositions,
-        const std::vector<aiVector3D>* avNormals,
-        const std::vector<aiColor4D>* avColors,
-        const std::vector<aiVector2D>* avTexCoords,
-        const std::vector<aiMaterial*>* avMaterials,
-        std::vector<aiMesh*>* avOut);
-
+    void LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly);
 
     // -------------------------------------------------------------------
     /** Static helper to parse a color from four single channels in
@@ -151,7 +117,6 @@ protected:
         PLY::EDataType aiTypes[4],
         aiColor4D* clrOut);
 
-
     // -------------------------------------------------------------------
     /** Static helper to parse a color channel value. The input value
     *  is normalized to 0-1.
@@ -160,12 +125,14 @@ protected:
         PLY::PropertyInstance::ValueUnion val,
         PLY::EDataType eType);
 
-
     /** Buffer to hold the loaded file */
     unsigned char* mBuffer;
 
     /** Document object model representation extracted from the file */
     PLY::DOM* pcDOM;
+
+    /** Mesh generated by loader */
+    aiMesh* mGeneratedMesh;
 };
 
 } // end of namespace Assimp

+ 930 - 754
code/PlyParser.cpp

@@ -5,7 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2017, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -13,18 +12,18 @@ 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.
+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.
+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.
+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
@@ -45,916 +44,1093 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER
 
-#include "PlyLoader.h"
 #include "fast_atof.h"
 #include <assimp/DefaultLogger.hpp>
 #include "ByteSwapper.h"
-
+#include "PlyLoader.h"
 
 using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
-PLY::EDataType PLY::Property::ParseDataType(const char* pCur,const char** pCurOut) {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-
-    PLY::EDataType eOut = PLY::EDT_INVALID;
-
-    if (TokenMatch(pCur,"char",4) ||
-        TokenMatch(pCur,"int8",4))
-    {
-        eOut = PLY::EDT_Char;
-    }
-    else if (TokenMatch(pCur,"uchar",5) ||
-             TokenMatch(pCur,"uint8",5))
-    {
-        eOut = PLY::EDT_UChar;
-    }
-    else if (TokenMatch(pCur,"short",5) ||
-             TokenMatch(pCur,"int16",5))
-    {
-        eOut = PLY::EDT_Short;
-    }
-    else if (TokenMatch(pCur,"ushort",6) ||
-             TokenMatch(pCur,"uint16",6))
-    {
-        eOut = PLY::EDT_UShort;
-    }
-    else if (TokenMatch(pCur,"int32",5) || TokenMatch(pCur,"int",3))
-    {
-        eOut = PLY::EDT_Int;
-    }
-    else if (TokenMatch(pCur,"uint32",6) || TokenMatch(pCur,"uint",4))
-    {
-        eOut = PLY::EDT_UInt;
-    }
-    else if (TokenMatch(pCur,"float",5) || TokenMatch(pCur,"float32",7))
-    {
-        eOut = PLY::EDT_Float;
-    }
-    else if (TokenMatch(pCur,"double64",8) || TokenMatch(pCur,"double",6) ||
-             TokenMatch(pCur,"float64",7))
-    {
-        eOut = PLY::EDT_Double;
-    }
-    if (PLY::EDT_INVALID == eOut)
-    {
-        DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK");
-    }
-    *pCurOut = pCur;
-
-    return eOut;
+PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
+  ai_assert(!buffer.empty());
+
+  PLY::EDataType eOut = PLY::EDT_INVALID;
+
+  if (PLY::DOM::TokenMatch(buffer, "char", 4) ||
+    PLY::DOM::TokenMatch(buffer, "int8", 4))
+  {
+    eOut = PLY::EDT_Char;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "uchar", 5) ||
+    PLY::DOM::TokenMatch(buffer, "uint8", 5))
+  {
+    eOut = PLY::EDT_UChar;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "short", 5) ||
+    PLY::DOM::TokenMatch(buffer, "int16", 5))
+  {
+    eOut = PLY::EDT_Short;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ushort", 6) ||
+    PLY::DOM::TokenMatch(buffer, "uint16", 6))
+  {
+    eOut = PLY::EDT_UShort;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "int32", 5) || PLY::DOM::TokenMatch(buffer, "int", 3))
+  {
+    eOut = PLY::EDT_Int;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "uint32", 6) || PLY::DOM::TokenMatch(buffer, "uint", 4))
+  {
+    eOut = PLY::EDT_UInt;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "float", 5) || PLY::DOM::TokenMatch(buffer, "float32", 7))
+  {
+    eOut = PLY::EDT_Float;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "double64", 8) || PLY::DOM::TokenMatch(buffer, "double", 6) ||
+    PLY::DOM::TokenMatch(buffer, "float64", 7))
+  {
+    eOut = PLY::EDT_Double;
+  }
+  if (PLY::EDT_INVALID == eOut)
+  {
+    DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK");
+  }
+
+  return eOut;
 }
 
 // ------------------------------------------------------------------------------------------------
-PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOut) {
-    ai_assert (NULL != pCur );
-    ai_assert( NULL != pCurOut );
-
-    PLY::ESemantic eOut = PLY::EST_INVALID;
-    if (TokenMatch(pCur,"red",3)) {
-        eOut = PLY::EST_Red;
-    } else if (TokenMatch(pCur,"green",5)) {
-        eOut = PLY::EST_Green;
-    } else if (TokenMatch(pCur,"blue",4)) {
-        eOut = PLY::EST_Blue;
-    } else if (TokenMatch(pCur,"alpha",5)) {
-        eOut = PLY::EST_Alpha;
-    } else if (TokenMatch(pCur,"vertex_index",12) || TokenMatch(pCur,"vertex_indices",14)) {
-        eOut = PLY::EST_VertexIndex;
-    }
-    else if (TokenMatch(pCur,"material_index",14))
-    {
-        eOut = PLY::EST_MaterialIndex;
-    }
-    else if (TokenMatch(pCur,"ambient_red",11))
-    {
-        eOut = PLY::EST_AmbientRed;
-    }
-    else if (TokenMatch(pCur,"ambient_green",13))
-    {
-        eOut = PLY::EST_AmbientGreen;
-    }
-    else if (TokenMatch(pCur,"ambient_blue",12))
-    {
-        eOut = PLY::EST_AmbientBlue;
-    }
-    else if (TokenMatch(pCur,"ambient_alpha",13))
-    {
-        eOut = PLY::EST_AmbientAlpha;
-    }
-    else if (TokenMatch(pCur,"diffuse_red",11))
-    {
-        eOut = PLY::EST_DiffuseRed;
-    }
-    else if (TokenMatch(pCur,"diffuse_green",13))
-    {
-        eOut = PLY::EST_DiffuseGreen;
-    }
-    else if (TokenMatch(pCur,"diffuse_blue",12))
-    {
-        eOut = PLY::EST_DiffuseBlue;
-    }
-    else if (TokenMatch(pCur,"diffuse_alpha",13))
-    {
-        eOut = PLY::EST_DiffuseAlpha;
-    }
-    else if (TokenMatch(pCur,"specular_red",12))
-    {
-        eOut = PLY::EST_SpecularRed;
-    }
-    else if (TokenMatch(pCur,"specular_green",14))
-    {
-        eOut = PLY::EST_SpecularGreen;
-    }
-    else if (TokenMatch(pCur,"specular_blue",13))
-    {
-        eOut = PLY::EST_SpecularBlue;
-    }
-    else if (TokenMatch(pCur,"specular_alpha",14))
-    {
-        eOut = PLY::EST_SpecularAlpha;
-    }
-    else if (TokenMatch(pCur,"opacity",7))
-    {
-        eOut = PLY::EST_Opacity;
-    }
-    else if (TokenMatch(pCur,"specular_power",14))
-    {
-        eOut = PLY::EST_PhongPower;
-    }
-    else if (TokenMatch(pCur,"r",1))
-    {
-        eOut = PLY::EST_Red;
-    }
-    else if (TokenMatch(pCur,"g",1))
-    {
-        eOut = PLY::EST_Green;
-    }
-    else if (TokenMatch(pCur,"b",1))
-    {
-        eOut = PLY::EST_Blue;
-    }
-    // NOTE: Blender3D exports texture coordinates as s,t tuples
-    else if (TokenMatch(pCur,"u",1) ||  TokenMatch(pCur,"s",1) || TokenMatch(pCur,"tx",2) || TokenMatch(pCur,"texture_u",9))
-    {
-        eOut = PLY::EST_UTextureCoord;
-    }
-    else if (TokenMatch(pCur,"v",1) ||  TokenMatch(pCur,"t",1) || TokenMatch(pCur,"ty",2) || TokenMatch(pCur,"texture_v",9))
-    {
-        eOut = PLY::EST_VTextureCoord;
-    }
-    else if (TokenMatch(pCur,"x",1))
-    {
-        eOut = PLY::EST_XCoord;
-    } else if (TokenMatch(pCur,"y",1)) {
-        eOut = PLY::EST_YCoord;
-    } else if (TokenMatch(pCur,"z",1)) {
-        eOut = PLY::EST_ZCoord;
-    } else if (TokenMatch(pCur,"nx",2)) {
-        eOut = PLY::EST_XNormal;
-    } else if (TokenMatch(pCur,"ny",2)) {
-        eOut = PLY::EST_YNormal;
-    } else if (TokenMatch(pCur,"nz",2)) {
-        eOut = PLY::EST_ZNormal;
-    } else {
-        DefaultLogger::get()->info("Found unknown property semantic in file. This is ok");
-        SkipLine(&pCur);
-    }
-    *pCurOut = pCur;
-    return eOut;
+PLY::ESemantic PLY::Property::ParseSemantic(std::vector<char> &buffer) {
+  ai_assert(!buffer.empty());
+
+  PLY::ESemantic eOut = PLY::EST_INVALID;
+  if (PLY::DOM::TokenMatch(buffer, "red", 3)) {
+    eOut = PLY::EST_Red;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "green", 5)) {
+    eOut = PLY::EST_Green;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "blue", 4)) {
+    eOut = PLY::EST_Blue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "alpha", 5)) {
+    eOut = PLY::EST_Alpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "vertex_index", 12) || PLY::DOM::TokenMatch(buffer, "vertex_indices", 14)) {
+    eOut = PLY::EST_VertexIndex;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "texcoord", 8)) // Manage uv coords on faces
+  {
+    eOut = PLY::EST_TextureCoordinates;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "material_index", 14))
+  {
+    eOut = PLY::EST_MaterialIndex;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_red", 11))
+  {
+    eOut = PLY::EST_AmbientRed;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_green", 13))
+  {
+    eOut = PLY::EST_AmbientGreen;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_blue", 12))
+  {
+    eOut = PLY::EST_AmbientBlue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_alpha", 13))
+  {
+    eOut = PLY::EST_AmbientAlpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_red", 11))
+  {
+    eOut = PLY::EST_DiffuseRed;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_green", 13))
+  {
+    eOut = PLY::EST_DiffuseGreen;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_blue", 12))
+  {
+    eOut = PLY::EST_DiffuseBlue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_alpha", 13))
+  {
+    eOut = PLY::EST_DiffuseAlpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_red", 12))
+  {
+    eOut = PLY::EST_SpecularRed;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_green", 14))
+  {
+    eOut = PLY::EST_SpecularGreen;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_blue", 13))
+  {
+    eOut = PLY::EST_SpecularBlue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_alpha", 14))
+  {
+    eOut = PLY::EST_SpecularAlpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "opacity", 7))
+  {
+    eOut = PLY::EST_Opacity;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_power", 14))
+  {
+    eOut = PLY::EST_PhongPower;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "r", 1))
+  {
+    eOut = PLY::EST_Red;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "g", 1))
+  {
+    eOut = PLY::EST_Green;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "b", 1))
+  {
+    eOut = PLY::EST_Blue;
+  }
+
+  // NOTE: Blender3D exports texture coordinates as s,t tuples
+  else if (PLY::DOM::TokenMatch(buffer, "u", 1) || PLY::DOM::TokenMatch(buffer, "s", 1) || PLY::DOM::TokenMatch(buffer, "tx", 2) || PLY::DOM::TokenMatch(buffer, "texture_u", 9))
+  {
+    eOut = PLY::EST_UTextureCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2) || PLY::DOM::TokenMatch(buffer, "texture_v", 9))
+  {
+    eOut = PLY::EST_VTextureCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "x", 1))
+  {
+    eOut = PLY::EST_XCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "y", 1)) {
+    eOut = PLY::EST_YCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "z", 1)) {
+    eOut = PLY::EST_ZCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "nx", 2)) {
+    eOut = PLY::EST_XNormal;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ny", 2)) {
+    eOut = PLY::EST_YNormal;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "nz", 2)) {
+    eOut = PLY::EST_ZNormal;
+  }
+  else {
+    DefaultLogger::get()->info("Found unknown property semantic in file. This is ok");
+    PLY::DOM::SkipLine(buffer);
+  }
+  return eOut;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::Property::ParseProperty (const char* pCur,
-    const char** pCurOut,
-    PLY::Property* pOut)
+bool PLY::Property::ParseProperty(std::vector<char> &buffer, PLY::Property* pOut)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
+  ai_assert(!buffer.empty());
 
-    // Forms supported:
-    // "property float x"
-    // "property list uchar int vertex_index"
-    *pCurOut = pCur;
+  // Forms supported:
+  // "property float x"
+  // "property list uchar int vertex_index"
 
-    // skip leading spaces
-    if (!SkipSpaces(pCur,&pCur)) {
-        return false;
-    }
+  // skip leading spaces
+  if (!PLY::DOM::SkipSpaces(buffer)) {
+    return false;
+  }
 
-    // skip the "property" string at the beginning
-    if (!TokenMatch(pCur,"property",8))
+  // skip the "property" string at the beginning
+  if (!PLY::DOM::TokenMatch(buffer, "property", 8))
+  {
+    // seems not to be a valid property entry
+    return false;
+  }
+  // get next word
+  if (!PLY::DOM::SkipSpaces(buffer)) {
+    return false;
+  }
+  if (PLY::DOM::TokenMatch(buffer, "list", 4))
+  {
+    pOut->bIsList = true;
+
+    // seems to be a list.
+    if (EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(buffer)))
     {
-        // seems not to be a valid property entry
-        return false;
+      // unable to parse list size data type
+      PLY::DOM::SkipLine(buffer);
+      return false;
     }
-    // get next word
-    if (!SkipSpaces(pCur,&pCur)) {
-        return false;
-    }
-    if (TokenMatch(pCur,"list",4))
+    if (!PLY::DOM::SkipSpaces(buffer))return false;
+    if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer)))
     {
-        pOut->bIsList = true;
-
-        // seems to be a list.
-        if(EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(pCur, &pCur)))
-        {
-            // unable to parse list size data type
-            SkipLine(pCur,&pCur);
-            *pCurOut = pCur;
-            return false;
-        }
-        if (!SkipSpaces(pCur,&pCur))return false;
-        if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur)))
-        {
-            // unable to parse list data type
-            SkipLine(pCur,&pCur);
-            *pCurOut = pCur;
-            return false;
-        }
-    }
-    else
+      // unable to parse list data type
+      PLY::DOM::SkipLine(buffer);
+      return false;
+    }
+  }
+  else
+  {
+    if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer)))
     {
-        if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur)))
-        {
-            // unable to parse data type. Skip the property
-            SkipLine(pCur,&pCur);
-            *pCurOut = pCur;
-            return false;
-        }
+      // unable to parse data type. Skip the property
+      PLY::DOM::SkipLine(buffer);
+      return false;
     }
+  }
 
-    if (!SkipSpaces(pCur,&pCur))return false;
-    const char* szCur = pCur;
-    pOut->Semantic = PLY::Property::ParseSemantic(pCur, &pCur);
-
-    if (PLY::EST_INVALID == pOut->Semantic)
-    {
-        // store the name of the semantic
-        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+  if (!PLY::DOM::SkipSpaces(buffer))
+    return false;
 
-        DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK");
-        pOut->szName = std::string(szCur,iDiff);
-    }
+  pOut->Semantic = PLY::Property::ParseSemantic(buffer);
 
-    SkipSpacesAndLineEnd(pCur,&pCur);
-    *pCurOut = pCur;
+  if (PLY::EST_INVALID == pOut->Semantic)
+  {
+    DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK");
+    std::string(&buffer[0], &buffer[0] + strlen(&buffer[0]));
+  }
 
-    return true;
+  PLY::DOM::SkipSpacesAndLineEnd(buffer);
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-PLY::EElementSemantic PLY::Element::ParseSemantic(const char* pCur,
-    const char** pCurOut)
+PLY::EElementSemantic PLY::Element::ParseSemantic(std::vector<char> &buffer)
 {
-    ai_assert(NULL != pCur && NULL != pCurOut);
-    PLY::EElementSemantic eOut = PLY::EEST_INVALID;
-    if (TokenMatch(pCur,"vertex",6))
-    {
-        eOut = PLY::EEST_Vertex;
-    }
-    else if (TokenMatch(pCur,"face",4))
-    {
-        eOut = PLY::EEST_Face;
-    }
+  ai_assert(!buffer.empty());
+
+  PLY::EElementSemantic eOut = PLY::EEST_INVALID;
+  if (PLY::DOM::TokenMatch(buffer, "vertex", 6))
+  {
+    eOut = PLY::EEST_Vertex;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "face", 4))
+  {
+    eOut = PLY::EEST_Face;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "tristrips", 9))
+  {
+    eOut = PLY::EEST_TriStrip;
+  }
 #if 0
-    // TODO: maybe implement this?
-    else if (TokenMatch(pCur,"range_grid",10))
-    {
-        eOut = PLY::EEST_Face;
-    }
+  // TODO: maybe implement this?
+  else if (PLY::DOM::TokenMatch(buffer,"range_grid",10))
+  {
+    eOut = PLY::EEST_Face;
+  }
 #endif
-    else if (TokenMatch(pCur,"tristrips",9))
-    {
-        eOut = PLY::EEST_TriStrip;
-    }
-    else if (TokenMatch(pCur,"edge",4))
-    {
-        eOut = PLY::EEST_Edge;
-    }
-    else if (TokenMatch(pCur,"material",8))
-    {
-        eOut = PLY::EEST_Material;
-    }
-    *pCurOut = pCur;
-
-    return eOut;
+  else if (PLY::DOM::TokenMatch(buffer, "edge", 4))
+  {
+    eOut = PLY::EEST_Edge;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "material", 8))
+  {
+    eOut = PLY::EEST_Material;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "TextureFile", 11))
+  {
+    eOut = PLY::EEST_TextureFile;
+  }
+
+  return eOut;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::Element::ParseElement (const char* pCur,
-    const char** pCurOut,
-    PLY::Element* pOut)
+bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLY::Element* pOut)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pOut );
+  ai_assert(NULL != pOut);
+  // Example format: "element vertex 8"
 
-    // Example format: "element vertex 8"
-    *pCurOut = pCur;
+  // skip leading spaces
+  if (!PLY::DOM::SkipSpaces(buffer))
+  {
+    return false;
+  }
 
-    // skip leading spaces
-    if (!SkipSpaces(&pCur)) {
-        return false;
-    }
+  // skip the "element" string at the beginning
+  if (!PLY::DOM::TokenMatch(buffer, "element", 7) && !PLY::DOM::TokenMatch(buffer, "comment", 7))
+  {
+    // seems not to be a valid property entry
+    return false;
+  }
+  // get next word
+  if (!PLY::DOM::SkipSpaces(buffer))
+    return false;
 
-    // skip the "element" string at the beginning
-    if (!TokenMatch(pCur,"element",7))
-    {
-        // seems not to be a valid property entry
-        return false;
-    }
-    // get next word
-    if (!SkipSpaces(&pCur))return false;
+  // parse the semantic of the element
+  pOut->eSemantic = PLY::Element::ParseSemantic(buffer);
+  if (PLY::EEST_INVALID == pOut->eSemantic)
+  {
+    // if the exact semantic can't be determined, just store
+    // the original string identifier
+    pOut->szName = std::string(&buffer[0], &buffer[0] + strlen(&buffer[0]));
+  }
 
-    // parse the semantic of the element
-    const char* szCur = pCur;
-    pOut->eSemantic = PLY::Element::ParseSemantic(pCur,&pCur);
-    if (PLY::EEST_INVALID == pOut->eSemantic)
-    {
-        // if the exact semantic can't be determined, just store
-        // the original string identifier
-        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
-        pOut->szName = std::string(szCur,iDiff);
-    }
+  if (!PLY::DOM::SkipSpaces(buffer))
+    return false;
 
-    if (!SkipSpaces(&pCur))return false;
+  if (PLY::EEST_TextureFile == pOut->eSemantic)
+  {
+    char* endPos = &buffer[0] + (strlen(&buffer[0]) - 1);
+    pOut->szName = std::string(&buffer[0], endPos);
+  }
 
-    //parse the number of occurrences of this element
-    pOut->NumOccur = strtoul10(pCur,&pCur);
+  //parse the number of occurrences of this element
+  const char* pCur = (char*)&buffer[0];
+  pOut->NumOccur = strtoul10(pCur, &pCur);
 
-    // go to the next line
-    SkipSpacesAndLineEnd(pCur,&pCur);
+  // go to the next line
+  PLY::DOM::SkipSpacesAndLineEnd(buffer);
 
-    // now parse all properties of the element
-    while(true)
-    {
-        // skip all comments
-        PLY::DOM::SkipComments(pCur,&pCur);
+  // now parse all properties of the element
+  while (true)
+  {
+    streamBuffer.getNextLine(buffer);
+    pCur = (char*)&buffer[0];
 
-        PLY::Property prop;
-        if(!PLY::Property::ParseProperty(pCur,&pCur,&prop))break;
-        pOut->alProperties.push_back(prop);
-    }
-    *pCurOut = pCur;
+    // skip all comments
+    PLY::DOM::SkipComments(buffer);
 
-    return true;
-}
+    PLY::Property prop;
+    if (!PLY::Property::ParseProperty(buffer, &prop))
+      break;
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::SkipComments (const char* pCur,
-    const char** pCurOut)
-{
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    *pCurOut = pCur;
+    pOut->alProperties.push_back(prop);
+  }
 
-    // skip spaces
-    if (!SkipSpaces(pCur,&pCur)) {
-        return false;
-    }
-
-    if (TokenMatch(pCur,"comment",7))
-    {
-        if ( !IsLineEnd(pCur[-1]) )
-        {
-            SkipLine(pCur,&pCur);
-        }
-        SkipComments(pCur,&pCur);
-        *pCurOut = pCur;
-        return true;
-    }
-    *pCurOut = pCur;
-
-    return false;
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut,bool isBinary) {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
+bool PLY::DOM::SkipSpaces(std::vector<char> &buffer)
+{
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::SkipSpaces(pCur, &pCur);
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    // after ply and format line
-    *pCurOut = pCur;
+  return ret;
+}
 
-    // parse all elements
-    while ((*pCur) != '\0')
-    {
-        // skip all comments
-        PLY::DOM::SkipComments(pCur,&pCur);
+bool PLY::DOM::SkipLine(std::vector<char> &buffer)
+{
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::SkipLine(pCur, &pCur);
 
-        PLY::Element out;
-        if(PLY::Element::ParseElement(pCur,&pCur,&out))
-        {
-            // add the element to the list of elements
-            alElements.push_back(out);
-        }
-        else if (TokenMatch(pCur,"end_header",10))
-        {
-            // we have reached the end of the header
-            break;
-        }
-        else
-        {
-            // ignore unknown header elements
-            SkipLine(&pCur);
-        }
-    }
-    if(!isBinary)
-    { // it would occur an error, if binary data start with values as space or line end.
-        SkipSpacesAndLineEnd(pCur,&pCur);
-    }
-    *pCurOut = pCur;
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded");
-    return true;
+  return ret;
 }
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseElementInstanceLists (
-    const char* pCur,
-    const char** pCurOut)
+bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char* token, unsigned int len)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::TokenMatch(pCur, token, len);
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin");
-    *pCurOut = pCur;
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    alElementData.resize(alElements.size());
+  return ret;
+}
 
-    std::vector<PLY::Element>::const_iterator i = alElements.begin();
-    std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer)
+{
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur);
 
-    // parse all element instances
-    for (;i != alElements.end();++i,++a)
-    {
-        (*a).alInstances.resize((*i).NumOccur);
-        PLY::ElementInstanceList::ParseInstanceList(pCur,&pCur,&(*i),&(*a));
-    }
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded");
-    *pCurOut = pCur;
-    return true;
+  return ret;
 }
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseElementInstanceListsBinary (
-    const char* pCur,
-    const char** pCurOut,
-    bool p_bBE)
+bool PLY::DOM::SkipComments(std::vector<char> &buffer)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut);
+  ai_assert(!buffer.empty());
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin");
-    *pCurOut = pCur;
-
-    alElementData.resize(alElements.size());
+  std::vector<char> nbuffer = buffer;
+  // skip spaces
+  if (!SkipSpaces(nbuffer)) {
+    return false;
+  }
 
-    std::vector<PLY::Element>::const_iterator i = alElements.begin();
-    std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+  if (TokenMatch(nbuffer, "comment", 7))
+  {
+    if (!SkipSpaces(nbuffer))
+      SkipLine(nbuffer);
 
-    // parse all element instances
-    for (;i != alElements.end();++i,++a)
+    if (!TokenMatch(nbuffer, "TextureFile", 11))
     {
-        (*a).alInstances.resize((*i).NumOccur);
-        PLY::ElementInstanceList::ParseInstanceListBinary(pCur,&pCur,&(*i),&(*a),p_bBE);
+      SkipLine(nbuffer);
+      buffer = nbuffer;
+      return true;
     }
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded");
-    *pCurOut = pCur;
     return true;
+  }
+
+  return false;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE)
-{
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != p_pcOut );
+bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, bool isBinary) {
+  DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
+  // parse all elements
+  while (!buffer.empty())
+  {
+    // skip all comments
+    PLY::DOM::SkipComments(buffer);
 
-    if(!p_pcOut->ParseHeader(pCur,&pCur,true))
+    PLY::Element out;
+    if (PLY::Element::ParseElement(streamBuffer, buffer, &out))
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
-        return false;
+      // add the element to the list of elements
+      alElements.push_back(out);
     }
-    if(!p_pcOut->ParseElementInstanceListsBinary(pCur,&pCur,p_bBE))
+    else if (TokenMatch(buffer, "end_header", 10))
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
-        return false;
+      // we have reached the end of the header
+      break;
     }
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded");
-    return true;
+    else
+    {
+      // ignore unknown header elements
+      streamBuffer.getNextLine(buffer);
+    }
+  }
+
+  if (!isBinary) // it would occur an error, if binary data start with values as space or line end.
+    SkipSpacesAndLineEnd(buffer);
+
+  DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseInstance (const char* pCur,DOM* p_pcOut)
+bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLYImporter* loader)
 {
-    ai_assert(NULL != pCur);
-    ai_assert(NULL != p_pcOut);
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin");
+  alElementData.resize(alElements.size());
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
+  std::vector<PLY::Element>::const_iterator i = alElements.begin();
+  std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
 
-
-    if(!p_pcOut->ParseHeader(pCur,&pCur,false))
+  // parse all element instances
+  //construct vertices and faces
+  for (; i != alElements.end(); ++i, ++a)
+  {
+    if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip)
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
-        return false;
+      PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), NULL, loader);
     }
-    if(!p_pcOut->ParseElementInstanceLists(pCur,&pCur))
+    else
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
-        return false;
+      (*a).alInstances.resize((*i).NumOccur);
+      PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), &(*a), NULL);
     }
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded");
-    return true;
+  }
+
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstanceList::ParseInstanceList (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstanceList* p_pcOut)
+bool PLY::DOM::ParseElementInstanceListsBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+    const char* &pCur,
+    unsigned int &bufferSize,
+    PLYImporter* loader,
+    bool p_bBE)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin");
+  alElementData.resize(alElements.size());
 
-    if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty())
+  std::vector<PLY::Element>::const_iterator i = alElements.begin();
+  std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+
+  // parse all element instances
+  for (; i != alElements.end(); ++i, ++a)
+  {
+    if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip)
     {
-        // if the element has an unknown semantic we can skip all lines
-        // However, there could be comments
-        for (unsigned int i = 0; i < pcElement->NumOccur;++i)
-        {
-            PLY::DOM::SkipComments(pCur,&pCur);
-            SkipLine(pCur,&pCur);
-        }
+      PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), NULL, loader, p_bBE);
     }
     else
     {
-        // be sure to have enough storage
-        for (unsigned int i = 0; i < pcElement->NumOccur;++i)
-        {
-            PLY::DOM::SkipComments(pCur,&pCur);
-            PLY::ElementInstance::ParseInstance(pCur, &pCur,pcElement,
-                &p_pcOut->alInstances[i]);
-        }
+      (*a).alInstances.resize((*i).NumOccur);
+      PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), &(*a), NULL, p_bBE);
     }
-    *pCurOut = pCur;
-    return true;
-}
+  }
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstanceList::ParseInstanceListBinary (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstanceList* p_pcOut,
-    bool p_bBE /* = false */)
-{
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
-
-    // we can add special handling code for unknown element semantics since
-    // we can't skip it as a whole block (we don't know its exact size
-    // due to the fact that lists could be contained in the property list
-    // of the unknown element)
-    for (unsigned int i = 0; i < pcElement->NumOccur;++i)
-    {
-        PLY::ElementInstance::ParseInstanceBinary(pCur, &pCur,pcElement,
-            &p_pcOut->alInstances[i], p_bBE);
-    }
-    *pCurOut = pCur;
-    return true;
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstance::ParseInstance (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstance* p_pcOut)
+bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
+  ai_assert(NULL != p_pcOut);
+  ai_assert(NULL != loader);
 
-    if (!SkipSpaces(pCur, &pCur)) {
-        return false;
-    }
-
-    // allocate enough storage
-    p_pcOut->alProperties.resize(pcElement->alProperties.size());
-
-    std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
-    std::vector<PLY::Property>::const_iterator  a = pcElement->alProperties.begin();
-    for (;i != p_pcOut->alProperties.end();++i,++a)
-    {
-        if(!(PLY::PropertyInstance::ParseInstance(pCur, &pCur,&(*a),&(*i))))
-        {
-            DefaultLogger::get()->warn("Unable to parse property instance. "
-                "Skipping this element instance");
+  std::vector<char> buffer;
+  streamBuffer.getNextLine(buffer);
 
-            // skip the rest of the instance
-            SkipLine(pCur, &pCur);
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
 
-            PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType);
-            (*i).avList.push_back(v);
-        }
-    }
-    *pCurOut = pCur;
-    return true;
+  if (!p_pcOut->ParseHeader(streamBuffer, buffer, true))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
+    return false;
+  }
+
+  streamBuffer.getNextBlock(buffer);
+  unsigned int bufferSize = buffer.size();
+  const char* pCur = (char*)&buffer[0];
+  if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
+    return false;
+  }
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstance::ParseInstanceBinary (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstance* p_pcOut,
-    bool p_bBE /* = false */)
+bool PLY::DOM::ParseInstance(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
+  ai_assert(NULL != p_pcOut);
+  ai_assert(NULL != loader);
 
-    // allocate enough storage
-    p_pcOut->alProperties.resize(pcElement->alProperties.size());
+  std::vector<char> buffer;
+  streamBuffer.getNextLine(buffer);
 
-    std::vector<PLY::PropertyInstance>::iterator i =  p_pcOut->alProperties.begin();
-    std::vector<PLY::Property>::const_iterator   a =  pcElement->alProperties.begin();
-    for (;i != p_pcOut->alProperties.end();++i,++a)
-    {
-        if(!(PLY::PropertyInstance::ParseInstanceBinary(pCur, &pCur,&(*a),&(*i),p_bBE)))
-        {
-            DefaultLogger::get()->warn("Unable to parse binary property instance. "
-                "Skipping this element instance");
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
 
-            (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType));
-        }
-    }
-    *pCurOut = pCur;
-    return true;
+  if (!p_pcOut->ParseHeader(streamBuffer, buffer, false))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
+    return false;
+  }
+
+  //get next line after header
+  streamBuffer.getNextLine(buffer);
+  if (!p_pcOut->ParseElementInstanceLists(streamBuffer, buffer, loader))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
+    return false;
+  }
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseInstance (const char* pCur,const char** pCurOut,
-    const PLY::Property* prop, PLY::PropertyInstance* p_pcOut)
+bool PLY::ElementInstanceList::ParseInstanceList(
+  IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const PLY::Element* pcElement,
+  PLY::ElementInstanceList* p_pcOut,
+  PLYImporter* loader)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != prop );
-    ai_assert( NULL != p_pcOut );
-
-    *pCurOut = pCur;
-
-    // skip spaces at the beginning
-    if (!SkipSpaces(pCur, &pCur)) {
-        return false;
-    }
-
-    if (prop->bIsList)
+  ai_assert(NULL != pcElement);
+  const char* pCur = (const char*)&buffer[0];
+
+  // parse all elements
+  if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty())
+  {
+    // if the element has an unknown semantic we can skip all lines
+    // However, there could be comments
+    for (unsigned int i = 0; i < pcElement->NumOccur; ++i)
     {
-        // parse the number of elements in the list
-        PLY::PropertyInstance::ValueUnion v;
-        PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eFirstType,&v);
-
-        // convert to unsigned int
-        unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v,prop->eFirstType);
-
-        // parse all list elements
-        p_pcOut->avList.resize(iNum);
-        for (unsigned int i = 0; i < iNum;++i)
+      PLY::DOM::SkipComments(buffer);
+      PLY::DOM::SkipLine(buffer);
+      streamBuffer.getNextLine(buffer);
+      pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0];
+    }
+  }
+  else
+  {
+    // be sure to have enough storage
+    for (unsigned int i = 0; i < pcElement->NumOccur; ++i)
+    {
+      if (p_pcOut)
+        PLY::ElementInstance::ParseInstance(pCur, pcElement, &p_pcOut->alInstances[i]);
+      else
+      {
+        ElementInstance elt;
+        PLY::ElementInstance::ParseInstance(pCur, pcElement, &elt);
+
+        // Create vertex or face
+        if (pcElement->eSemantic == EEST_Vertex)
         {
-            if (!SkipSpaces(pCur, &pCur))return false;
-            PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&p_pcOut->avList[i]);
+          //call loader instance from here
+          loader->LoadVertex(pcElement, &elt, i);
         }
-    }
-    else
-    {
-        // parse the property
-        PLY::PropertyInstance::ValueUnion v;
+        else if (pcElement->eSemantic == EEST_Face)
+        {
+          //call loader instance from here
+          loader->LoadFace(pcElement, &elt, i);
+        }
+        else if (pcElement->eSemantic == EEST_TriStrip)
+        {
+          //call loader instance from here
+          loader->LoadFace(pcElement, &elt, i);
+        }
+      }
 
-        PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&v);
-        p_pcOut->avList.push_back(v);
+      streamBuffer.getNextLine(buffer);
+      pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0];
     }
-    SkipSpacesAndLineEnd(pCur, &pCur);
-    *pCurOut = pCur;
-    return true;
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseInstanceBinary (
-    const char*  pCur,
-    const char** pCurOut,
-    const PLY::Property* prop,
-    PLY::PropertyInstance* p_pcOut,
-    bool p_bBE)
+bool PLY::ElementInstanceList::ParseInstanceListBinary(
+  IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  const PLY::Element* pcElement,
+  PLY::ElementInstanceList* p_pcOut,
+  PLYImporter* loader,
+  bool p_bBE /* = false */)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != prop );
-    ai_assert( NULL != p_pcOut );
-
-    if (prop->bIsList)
-    {
-        // parse the number of elements in the list
-        PLY::PropertyInstance::ValueUnion v;
-        PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eFirstType,&v,p_bBE);
-
-        // convert to unsigned int
-        unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v,prop->eFirstType);
-
-        // parse all list elements
-        p_pcOut->avList.resize(iNum);
-        for (unsigned int i = 0; i < iNum;++i){
-            PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&p_pcOut->avList[i],p_bBE);
-        }
-    }
+  ai_assert(NULL != pcElement);
+
+  // we can add special handling code for unknown element semantics since
+  // we can't skip it as a whole block (we don't know its exact size
+  // due to the fact that lists could be contained in the property list
+  // of the unknown element)
+  for (unsigned int i = 0; i < pcElement->NumOccur; ++i)
+  {
+    if (p_pcOut)
+      PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &p_pcOut->alInstances[i], p_bBE);
     else
     {
-        // parse the property
-        PLY::PropertyInstance::ValueUnion v;
-        PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&v,p_bBE);
-        p_pcOut->avList.push_back(v);
-    }
-    *pCurOut = pCur;
-    return true;
+      ElementInstance elt;
+      PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &elt, p_bBE);
+
+      // Create vertex or face
+      if (pcElement->eSemantic == EEST_Vertex)
+      {
+        //call loader instance from here
+        loader->LoadVertex(pcElement, &elt, i);
+      }
+      else if (pcElement->eSemantic == EEST_Face)
+      {
+        //call loader instance from here
+        loader->LoadFace(pcElement, &elt, i);
+      }
+      else if (pcElement->eSemantic == EEST_TriStrip)
+      {
+        //call loader instance from here
+        loader->LoadFace(pcElement, &elt, i);
+      }
+    }
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue( PLY::EDataType eType )
+bool PLY::ElementInstance::ParseInstance(const char* &pCur,
+  const PLY::Element* pcElement,
+  PLY::ElementInstance* p_pcOut)
 {
-    PLY::PropertyInstance::ValueUnion out;
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != p_pcOut);
 
-    switch (eType)
-    {
-    case EDT_Float:
-        out.fFloat = 0.f;
-        return out;
+  // allocate enough storage
+  p_pcOut->alProperties.resize(pcElement->alProperties.size());
 
-    case EDT_Double:
-        out.fDouble = 0.;
-        return out;
+  std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
+  std::vector<PLY::Property>::const_iterator  a = pcElement->alProperties.begin();
+  for (; i != p_pcOut->alProperties.end(); ++i, ++a)
+  {
+    if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i))))
+    {
+      DefaultLogger::get()->warn("Unable to parse property instance. "
+        "Skipping this element instance");
 
-    default: ;
-    };
-    out.iUInt = 0;
-    return out;
+      PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType);
+      (*i).avList.push_back(v);
+    }
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseValue(
-    const char* pCur,
-    const char** pCurOut,
-    PLY::EDataType eType,
-    PLY::PropertyInstance::ValueUnion* out)
+bool PLY::ElementInstance::ParseInstanceBinary(
+  IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  const PLY::Element* pcElement,
+  PLY::ElementInstance* p_pcOut,
+  bool p_bBE /* = false */)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != out );
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != p_pcOut);
+
+  // allocate enough storage
+  p_pcOut->alProperties.resize(pcElement->alProperties.size());
 
-    bool ret = true;
-    *pCurOut = pCur;
-    switch (eType)
+  std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
+  std::vector<PLY::Property>::const_iterator   a = pcElement->alProperties.begin();
+  for (; i != p_pcOut->alProperties.end(); ++i, ++a)
+  {
+    if (!(PLY::PropertyInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, &(*a), &(*i), p_bBE)))
     {
-    case EDT_UInt:
-    case EDT_UShort:
-    case EDT_UChar:
-
-        out->iUInt = (uint32_t)strtoul10(pCur, &pCur);
-        break;
-
-    case EDT_Int:
-    case EDT_Short:
-    case EDT_Char:
-
-        out->iInt = (int32_t)strtol10(pCur, &pCur);
-        break;
-
-    case EDT_Float:
-        // technically this should cast to float, but people tend to use float descriptors for double data
-        // this is the best way to not risk losing precision on import and it doesn't hurt to do this
-        ai_real f;
-        pCur = fast_atoreal_move<ai_real>(pCur,f);
-        out->fFloat = (ai_real)f;
-        break;
-
-    case EDT_Double:
-        double d;
-        pCur = fast_atoreal_move<double>(pCur,d);
-        out->fDouble = (double)d;
-        break;
-
-    default:
-        ret = false;
-        break;
-    }
-    *pCurOut = pCur;
+      DefaultLogger::get()->warn("Unable to parse binary property instance. "
+        "Skipping this element instance");
 
-    return ret;
+      (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType));
+    }
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseValueBinary(
-    const char* pCur,
-    const char** pCurOut,
-    PLY::EDataType eType,
-    PLY::PropertyInstance::ValueUnion* out,
-    bool p_bBE)
+bool PLY::PropertyInstance::ParseInstance(const char* &pCur,
+  const PLY::Property* prop, PLY::PropertyInstance* p_pcOut)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != out );
+  ai_assert(NULL != prop);
+  ai_assert(NULL != p_pcOut);
 
-    bool ret = true;
-    switch (eType)
-    {
-    case EDT_UInt:
-        out->iUInt = (uint32_t)*((uint32_t*)pCur);
-        pCur += 4;
+  // skip spaces at the beginning
+  if (!SkipSpaces(&pCur))
+  {
+    return false;
+  }
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt);
-        break;
+  if (prop->bIsList)
+  {
+    // parse the number of elements in the list
+    PLY::PropertyInstance::ValueUnion v;
+    PLY::PropertyInstance::ParseValue(pCur, prop->eFirstType, &v);
 
-    case EDT_UShort:
-        {
-        uint16_t i = *((uint16_t*)pCur);
+    // convert to unsigned int
+    unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v, prop->eFirstType);
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap(&i);
-        out->iUInt = (uint32_t)i;
-        pCur += 2;
-        break;
-        }
+    // parse all list elements
+    p_pcOut->avList.resize(iNum);
+    for (unsigned int i = 0; i < iNum; ++i)
+    {
+      if (!SkipSpaces(&pCur))
+        return false;
 
-    case EDT_UChar:
-        {
-        out->iUInt = (uint32_t)(*((uint8_t*)pCur));
-        pCur ++;
-        break;
-        }
+      PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]);
+    }
+  }
+  else
+  {
+    // parse the property
+    PLY::PropertyInstance::ValueUnion v;
 
-    case EDT_Int:
-        out->iInt = *((int32_t*)pCur);
-        pCur += 4;
+    PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v);
+    p_pcOut->avList.push_back(v);
+  }
+  SkipSpacesAndLineEnd(&pCur);
+  return true;
+}
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap(&out->iInt);
-        break;
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  const PLY::Property* prop,
+  PLY::PropertyInstance* p_pcOut,
+  bool p_bBE)
+{
+  ai_assert(NULL != prop);
+  ai_assert(NULL != p_pcOut);
+
+  // parse all elements
+  if (prop->bIsList)
+  {
+    // parse the number of elements in the list
+    PLY::PropertyInstance::ValueUnion v;
+    PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eFirstType, &v, p_bBE);
+
+    // convert to unsigned int
+    unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v, prop->eFirstType);
+
+    // parse all list elements
+    p_pcOut->avList.resize(iNum);
+    for (unsigned int i = 0; i < iNum; ++i)
+    {
+      PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &p_pcOut->avList[i], p_bBE);
+    }
+  }
+  else
+  {
+    // parse the property
+    PLY::PropertyInstance::ValueUnion v;
+    PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &v, p_bBE);
+    p_pcOut->avList.push_back(v);
+  }
+  return true;
+}
 
-    case EDT_Short:
-        {
-        int16_t i = *((int16_t*)pCur);
+// ------------------------------------------------------------------------------------------------
+PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue(PLY::EDataType eType)
+{
+  PLY::PropertyInstance::ValueUnion out;
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap(&i);
-        out->iInt = (int32_t)i;
-        pCur += 2;
-        break;
-        }
+  switch (eType)
+  {
+  case EDT_Float:
+    out.fFloat = 0.f;
+    return out;
 
-    case EDT_Char:
-        out->iInt = (int32_t)*((int8_t*)pCur);
-        pCur ++;
-        break;
+  case EDT_Double:
+    out.fDouble = 0.;
+    return out;
 
-    case EDT_Float:
-        {
-        out->fFloat = *((float*)pCur);
+  default:;
+  };
+  out.iUInt = 0;
+  return out;
+}
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat);
-        pCur += 4;
-        break;
-        }
-    case EDT_Double:
-        {
-        out->fDouble = *((double*)pCur);
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseValue(const char* &pCur,
+  PLY::EDataType eType,
+  PLY::PropertyInstance::ValueUnion* out)
+{
+  ai_assert(NULL != pCur);
+  ai_assert(NULL != out);
+  
+  //calc element size
+  unsigned int lsize = 0;
+  switch (eType)
+  {
+  case EDT_Char:
+  case EDT_UChar:
+    lsize = 1;
+    break;
+
+  case EDT_UShort:
+  case EDT_Short:
+    lsize = 2;
+    break;
+
+  case EDT_UInt:
+  case EDT_Int:
+  case EDT_Float:
+    lsize = 4;
+    break;
+
+  case EDT_Double:
+    lsize = 8;
+    break;
+  }
+
+  bool ret = true;
+  switch (eType)
+  {
+  case EDT_UInt:
+  case EDT_UShort:
+  case EDT_UChar:
+
+    out->iUInt = (uint32_t)strtoul10(pCur, &pCur);
+    break;
+
+  case EDT_Int:
+  case EDT_Short:
+  case EDT_Char:
+
+    out->iInt = (int32_t)strtol10(pCur, &pCur);
+    break;
+
+  case EDT_Float:
+    // technically this should cast to float, but people tend to use float descriptors for double data
+    // this is the best way to not risk losing precision on import and it doesn't hurt to do this
+    ai_real f;
+    pCur = fast_atoreal_move<ai_real>(pCur, f);
+    out->fFloat = (ai_real)f;
+    break;
+
+  case EDT_Double:
+    double d;
+    pCur = fast_atoreal_move<double>(pCur, d);
+    out->fDouble = (double)d;
+    break;
+
+  default:
+    ret = false;
+    break;
+  }
+
+  return ret;
+}
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble);
-        pCur += 8;
-        break;
-        }
-    default:
-        ret = false;
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  PLY::EDataType eType,
+  PLY::PropertyInstance::ValueUnion* out,
+  bool p_bBE)
+{
+  ai_assert(NULL != out);
+
+  //calc element size
+  unsigned int lsize = 0;
+  switch (eType)
+  {
+  case EDT_Char:
+  case EDT_UChar:
+    lsize = 1;
+    break;
+
+  case EDT_UShort:
+  case EDT_Short:
+    lsize = 2;
+    break;
+
+  case EDT_UInt:
+  case EDT_Int:
+  case EDT_Float:
+    lsize = 4;
+    break;
+
+  case EDT_Double:
+    lsize = 8;
+    break;
+  }
+
+  //read the next file block if needed
+  if (bufferSize < lsize)
+  {
+    std::vector<char> nbuffer;
+    if (streamBuffer.getNextBlock(nbuffer))
+    {
+      //concat buffer contents
+      buffer = std::vector<char>(buffer.end() - bufferSize, buffer.end());
+      buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end());
+      nbuffer.clear();
+      bufferSize = buffer.size();
+      pCur = (char*)&buffer[0];
     }
-    *pCurOut = pCur;
-
-    return ret;
+    else
+    {
+      throw DeadlyImportError("Invalid .ply file: File corrupted");
+    }
+  }
+
+  bool ret = true;
+  switch (eType)
+  {
+  case EDT_UInt:
+    out->iUInt = (uint32_t)*((uint32_t*)pCur);
+    pCur += 4;
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt);
+    break;
+
+  case EDT_UShort:
+  {
+    uint16_t i = *((uint16_t*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap(&i);
+    out->iUInt = (uint32_t)i;
+    pCur += 2;
+    break;
+  }
+
+  case EDT_UChar:
+  {
+    out->iUInt = (uint32_t)(*((uint8_t*)pCur));
+    pCur++;
+    break;
+  }
+
+  case EDT_Int:
+    out->iInt = *((int32_t*)pCur);
+    pCur += 4;
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap(&out->iInt);
+    break;
+
+  case EDT_Short:
+  {
+    int16_t i = *((int16_t*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap(&i);
+    out->iInt = (int32_t)i;
+    pCur += 2;
+    break;
+  }
+
+  case EDT_Char:
+    out->iInt = (int32_t)*((int8_t*)pCur);
+    pCur++;
+    break;
+
+  case EDT_Float:
+  {
+    out->fFloat = *((float*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat);
+    pCur += 4;
+    break;
+  }
+  case EDT_Double:
+  {
+    out->fDouble = *((double*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble);
+    pCur += 8;
+    break;
+  }
+  default:
+    ret = false;
+  }
+
+  bufferSize -= lsize;
+
+  return ret;
 }
 
 #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER

+ 39 - 56
code/PlyParser.h

@@ -3,7 +3,6 @@ Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
 Copyright (c) 2006-2017, assimp team
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -46,19 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "ParsingUtils.h"
+#include "IOStreamBuffer.h"
 #include <vector>
 
-
 namespace Assimp
 {
 
+//pre-declaration
+class PLYImporter;
+
 // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/
 // http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf
 // http://www.okino.com/conv/exp_ply.htm
 namespace PLY
 {
 
-
 // ---------------------------------------------------------------------------------
 /*
 name        type        number of bytes
@@ -197,6 +198,9 @@ enum EElementSemantic
     //! The element is a material description
     EEST_Material,
 
+    //! texture path
+    EEST_TextureFile,
+
     //! Marks invalid entries
     EEST_INVALID
 };
@@ -238,16 +242,15 @@ public:
     //! string is either '\n', '\r' or '\0'. Return value is false
     //! if the input string is NOT a valid property (E.g. does
     //! not start with the "property" keyword)
-    static bool ParseProperty (const char* pCur, const char** pCurOut,
-        Property* pOut);
+    static bool ParseProperty(std::vector<char> &buffer, Property* pOut);
 
     // -------------------------------------------------------------------
     //! Parse a data type from a string
-    static EDataType ParseDataType(const char* pCur,const char** pCurOut);
+    static EDataType ParseDataType(std::vector<char> &buffer);
 
     // -------------------------------------------------------------------
     //! Parse a semantic from a string
-    static ESemantic ParseSemantic(const char* pCur,const char** pCurOut);
+    static ESemantic ParseSemantic(std::vector<char> &buffer);
 };
 
 // ---------------------------------------------------------------------------------
@@ -285,13 +288,11 @@ public:
     //! Parse an element from a string.
     //! The function will parse all properties contained in the
     //! element, too.
-    static bool ParseElement (const char* pCur, const char** pCurOut,
-        Element* pOut);
+    static bool ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, Element* pOut);
 
     // -------------------------------------------------------------------
     //! Parse a semantic from a string
-    static EElementSemantic ParseSemantic(const char* pCur,
-        const char** pCurOut);
+    static EElementSemantic ParseSemantic(std::vector<char> &buffer);
 };
 
 // ---------------------------------------------------------------------------------
@@ -331,13 +332,13 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse a property instance
-    static bool ParseInstance (const char* pCur,const char** pCurOut,
+    static bool ParseInstance(const char* &pCur,
         const Property* prop, PropertyInstance* p_pcOut);
 
     // -------------------------------------------------------------------
     //! Parse a property instance in binary format
-    static bool ParseInstanceBinary (const char* pCur,const char** pCurOut,
-        const Property* prop, PropertyInstance* p_pcOut,bool p_bBE);
+    static bool ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, const Property* prop, PropertyInstance* p_pcOut, bool p_bBE);
 
     // -------------------------------------------------------------------
     //! Get the default value for a given data type
@@ -345,13 +346,12 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse a value
-    static bool ParseValue(const char* pCur,const char** pCurOut,
-        EDataType eType,ValueUnion* out);
+    static bool ParseValue(const char* &pCur, EDataType eType, ValueUnion* out);
 
     // -------------------------------------------------------------------
     //! Parse a binary value
-    static bool ParseValueBinary(const char* pCur,const char** pCurOut,
-        EDataType eType,ValueUnion* out,bool p_bBE);
+    static bool ParseValueBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, EDataType eType, ValueUnion* out, bool p_bBE);
 
     // -------------------------------------------------------------------
     //! Convert a property value to a given type TYPE
@@ -375,13 +375,13 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse an element instance
-    static bool ParseInstance (const char* pCur,const char** pCurOut,
+    static bool ParseInstance(const char* &pCur,
         const Element* pcElement, ElementInstance* p_pcOut);
 
     // -------------------------------------------------------------------
     //! Parse a binary element instance
-    static bool ParseInstanceBinary (const char* pCur,const char** pCurOut,
-        const Element* pcElement, ElementInstance* p_pcOut,bool p_bBE);
+    static bool ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstance* p_pcOut, bool p_bBE);
 };
 
 // ---------------------------------------------------------------------------------
@@ -400,13 +400,13 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse an element instance list
-    static bool ParseInstanceList (const char* pCur,const char** pCurOut,
-        const Element* pcElement, ElementInstanceList* p_pcOut);
+    static bool ParseInstanceList(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader);
 
     // -------------------------------------------------------------------
     //! Parse a binary element instance list
-    static bool ParseInstanceListBinary (const char* pCur,const char** pCurOut,
-        const Element* pcElement, ElementInstanceList* p_pcOut,bool p_bBE);
+    static bool ParseInstanceListBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader, bool p_bBE);
 };
 // ---------------------------------------------------------------------------------
 /** \brief Class to represent the document object model of an ASCII or binary
@@ -428,50 +428,33 @@ public:
 
     //! Parse the DOM for a PLY file. The input string is assumed
     //! to be terminated with zero
-    static bool ParseInstance (const char* pCur,DOM* p_pcOut);
-    static bool ParseInstanceBinary (const char* pCur,
-        DOM* p_pcOut,bool p_bBE);
+    static bool ParseInstance(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader);
+    static bool ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE);
 
     //! Skip all comment lines after this
-    static bool SkipComments (const char* pCur,const char** pCurOut);
+    static bool SkipComments(std::vector<char> &buffer);
+
+    static bool SkipSpaces(std::vector<char> &buffer);
+
+    static bool SkipLine(std::vector<char> &buffer);
+
+    static bool TokenMatch(std::vector<char> &buffer, const char* token, unsigned int len);
+
+    static bool SkipSpacesAndLineEnd(std::vector<char> &buffer);
 
 private:
 
     // -------------------------------------------------------------------
     //! Handle the file header and read all element descriptions
-    bool ParseHeader (const char* pCur,const char** pCurOut, bool p_bBE);
+    bool ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, bool p_bBE);
 
     // -------------------------------------------------------------------
     //! Read in all element instance lists
-    bool ParseElementInstanceLists (const char* pCur,const char** pCurOut);
+    bool ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLYImporter* loader);
 
     // -------------------------------------------------------------------
     //! Read in all element instance lists for a binary file format
-    bool ParseElementInstanceListsBinary (const char* pCur,
-        const char** pCurOut,bool p_bBE);
-};
-
-// ---------------------------------------------------------------------------------
-/** \brief Helper class to represent a loaded PLY face
- */
-class Face
-{
-public:
-
-    Face()
-        : iMaterialIndex(0xFFFFFFFF)
-    {
-        // set all indices to zero by default
-        mIndices.resize(3,0);
-    }
-
-public:
-
-    //! List of vertex indices
-    std::vector<unsigned int> mIndices;
-
-    //! Material index
-    unsigned int iMaterialIndex;
+    bool ParseElementInstanceListsBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, const char* &pCur, unsigned int &bufferSize, PLYImporter* loader, bool p_bBE);
 };
 
 // ---------------------------------------------------------------------------------

+ 3 - 3
code/STLLoader.cpp

@@ -211,20 +211,20 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
     for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
         pScene->mRootNode->mMeshes[i] = i;
 
-    // create a single default material, using a light gray diffuse color for consistency with
+    // create a single default material, using a white diffuse color for consistency with
     // other geometric types (e.g., PLY).
     aiMaterial* pcMat = new aiMaterial();
     aiString s;
     s.Set(AI_DEFAULT_MATERIAL_NAME);
     pcMat->AddProperty(&s, AI_MATKEY_NAME);
 
-    aiColor4D clrDiffuse(ai_real(0.6),ai_real(0.6),ai_real(0.6),ai_real(1.0));
+    aiColor4D clrDiffuse(ai_real(1.0),ai_real(1.0),ai_real(1.0),ai_real(1.0));
     if (bMatClr) {
         clrDiffuse = clrColorDefault;
     }
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
-    clrDiffuse = aiColor4D( ai_real( 0.05), ai_real( 0.05), ai_real( 0.05), ai_real( 1.0));
+    clrDiffuse = aiColor4D( ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0));
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
 
     pScene->mNumMaterials = 1;

+ 2 - 3
code/SpatialSort.cpp

@@ -126,9 +126,8 @@ void SpatialSort::FindPositions( const aiVector3D& pPosition,
     const ai_real dist = pPosition * mPlaneNormal;
     const ai_real minDist = dist - pRadius, maxDist = dist + pRadius;
 
-    // clear the array in this strange fashion because a simple clear() would also deallocate
-    // the array which we want to avoid
-    poResults.erase( poResults.begin(), poResults.end());
+    // clear the array
+    poResults.clear();
 
     // quick check for positions outside the range
     if( mPositions.size() == 0)

+ 10 - 3
code/fast_atof.h

@@ -1,3 +1,5 @@
+#pragma once
+
 // Copyright (C) 2002-2007 Nikolaus Gebhardt
 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
@@ -22,6 +24,7 @@
 #include <assimp/defs.h>
 
 #include "StringComparison.h"
+#include <assimp/DefaultLogger.hpp>
 
 
 #ifdef _MSC_VER
@@ -192,7 +195,7 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
     uint64_t value = 0;
 
     if ( *in < '0' || *in > '9' )
-            throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value.");
+        throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value.");
 
     bool running = true;
     while ( running )
@@ -202,8 +205,12 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 
         const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
 
-        if (new_value < value) /* numeric overflow, we rely on you */
-            throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow.");
+        // numeric overflow, we rely on you
+        if ( new_value < value ) {
+            DefaultLogger::get()->warn( std::string( "Converting the string \"" ) + in + "\" into a value resulted in overflow." );
+            return 0;
+        }
+            //throw std::overflow_error();
 
         value = new_value;
 

+ 23 - 31
contrib/poly2tri/poly2tri/common/shapes.cc

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -88,7 +88,7 @@ void Triangle::Clear()
     points_[0]=points_[1]=points_[2] = NULL;
 }
 
-void Triangle::ClearNeighbor(Triangle *triangle )
+void Triangle::ClearNeighbor(const Triangle *triangle )
 {
     if( neighbors_[0] == triangle )
     {
@@ -96,14 +96,14 @@ void Triangle::ClearNeighbor(Triangle *triangle )
     }
     else if( neighbors_[1] == triangle )
     {
-        neighbors_[1] = NULL;            
+        neighbors_[1] = NULL;
     }
     else
     {
         neighbors_[2] = NULL;
     }
 }
-    
+
 void Triangle::ClearNeighbors()
 {
   neighbors_[0] = NULL;
@@ -116,13 +116,9 @@ void Triangle::ClearDelunayEdges()
   delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false;
 }
 
-Point* Triangle::OppositePoint(Triangle& t, Point& p)
+Point* Triangle::OppositePoint(Triangle& t, const Point& p)
 {
   Point *cw = t.PointCW(p);
-  //double x = cw->x;
-  //double y = cw->y;
-  //x = p.x;
-  //y = p.y;
   return PointCW(*cw);
 }
 
@@ -164,8 +160,7 @@ int Triangle::Index(const Point* p)
     return 2;
   }
   assert(0);
-
-  return 0;
+  return -1;
 }
 
 int Triangle::EdgeIndex(const Point* p1, const Point* p2)
@@ -192,7 +187,7 @@ int Triangle::EdgeIndex(const Point* p1, const Point* p2)
   return -1;
 }
 
-void Triangle::MarkConstrainedEdge(const int index)
+void Triangle::MarkConstrainedEdge(int index)
 {
   constrained_edge[index] = true;
 }
@@ -215,7 +210,7 @@ void Triangle::MarkConstrainedEdge(Point* p, Point* q)
 }
 
 // The point counter-clockwise to given point
-Point* Triangle::PointCW(Point& point)
+Point* Triangle::PointCW(const Point& point)
 {
   if (&point == points_[0]) {
     return points_[2];
@@ -225,12 +220,11 @@ Point* Triangle::PointCW(Point& point)
     return points_[1];
   }
   assert(0);
-
-  return 0;
+  return NULL;
 }
 
 // The point counter-clockwise to given point
-Point* Triangle::PointCCW(Point& point)
+Point* Triangle::PointCCW(const Point& point)
 {
   if (&point == points_[0]) {
     return points_[1];
@@ -240,12 +234,11 @@ Point* Triangle::PointCCW(Point& point)
     return points_[0];
   }
   assert(0);
-
-  return 0;
+  return NULL;
 }
 
 // The neighbor clockwise to given point
-Triangle* Triangle::NeighborCW(Point& point)
+Triangle* Triangle::NeighborCW(const Point& point)
 {
   if (&point == points_[0]) {
     return neighbors_[1];
@@ -256,7 +249,7 @@ Triangle* Triangle::NeighborCW(Point& point)
 }
 
 // The neighbor counter-clockwise to given point
-Triangle* Triangle::NeighborCCW(Point& point)
+Triangle* Triangle::NeighborCCW(const Point& point)
 {
   if (&point == points_[0]) {
     return neighbors_[2];
@@ -266,7 +259,7 @@ Triangle* Triangle::NeighborCCW(Point& point)
   return neighbors_[1];
 }
 
-bool Triangle::GetConstrainedEdgeCCW(Point& p)
+bool Triangle::GetConstrainedEdgeCCW(const Point& p)
 {
   if (&p == points_[0]) {
     return constrained_edge[2];
@@ -276,7 +269,7 @@ bool Triangle::GetConstrainedEdgeCCW(Point& p)
   return constrained_edge[1];
 }
 
-bool Triangle::GetConstrainedEdgeCW(Point& p)
+bool Triangle::GetConstrainedEdgeCW(const Point& p)
 {
   if (&p == points_[0]) {
     return constrained_edge[1];
@@ -286,7 +279,7 @@ bool Triangle::GetConstrainedEdgeCW(Point& p)
   return constrained_edge[0];
 }
 
-void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce)
+void Triangle::SetConstrainedEdgeCCW(const Point& p, bool ce)
 {
   if (&p == points_[0]) {
     constrained_edge[2] = ce;
@@ -297,7 +290,7 @@ void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce)
   }
 }
 
-void Triangle::SetConstrainedEdgeCW(Point& p, bool ce)
+void Triangle::SetConstrainedEdgeCW(const Point& p, bool ce)
 {
   if (&p == points_[0]) {
     constrained_edge[1] = ce;
@@ -308,7 +301,7 @@ void Triangle::SetConstrainedEdgeCW(Point& p, bool ce)
   }
 }
 
-bool Triangle::GetDelunayEdgeCCW(Point& p)
+bool Triangle::GetDelunayEdgeCCW(const Point& p)
 {
   if (&p == points_[0]) {
     return delaunay_edge[2];
@@ -318,7 +311,7 @@ bool Triangle::GetDelunayEdgeCCW(Point& p)
   return delaunay_edge[1];
 }
 
-bool Triangle::GetDelunayEdgeCW(Point& p)
+bool Triangle::GetDelunayEdgeCW(const Point& p)
 {
   if (&p == points_[0]) {
     return delaunay_edge[1];
@@ -328,7 +321,7 @@ bool Triangle::GetDelunayEdgeCW(Point& p)
   return delaunay_edge[0];
 }
 
-void Triangle::SetDelunayEdgeCCW(Point& p, bool e)
+void Triangle::SetDelunayEdgeCCW(const Point& p, bool e)
 {
   if (&p == points_[0]) {
     delaunay_edge[2] = e;
@@ -339,7 +332,7 @@ void Triangle::SetDelunayEdgeCCW(Point& p, bool e)
   }
 }
 
-void Triangle::SetDelunayEdgeCW(Point& p, bool e)
+void Triangle::SetDelunayEdgeCW(const Point& p, bool e)
 {
   if (&p == points_[0]) {
     delaunay_edge[1] = e;
@@ -351,7 +344,7 @@ void Triangle::SetDelunayEdgeCW(Point& p, bool e)
 }
 
 // The neighbor across to given point
-Triangle& Triangle::NeighborAcross(Point& opoint)
+Triangle& Triangle::NeighborAcross(const Point& opoint)
 {
   if (&opoint == points_[0]) {
     return *neighbors_[0];
@@ -369,5 +362,4 @@ void Triangle::DebugPrint()
   cout << points_[2]->x << "," << points_[2]->y << endl;
 }
 
-}
-
+}

+ 29 - 31
contrib/poly2tri/poly2tri/common/shapes.h

@@ -113,7 +113,7 @@ struct Point {
   /// Convert this point into a unit point. Returns the Length.
   double Normalize()
   {
-    double len = Length();
+    const double len = Length();
     x /= len;
     y /= len;
     return len;
@@ -162,50 +162,50 @@ bool constrained_edge[3];
 /// Flags to determine if an edge is a Delauney edge
 bool delaunay_edge[3];
 
-Point* GetPoint(const int& index);
-Point* PointCW(Point& point);
-Point* PointCCW(Point& point);
-Point* OppositePoint(Triangle& t, Point& p);
+Point* GetPoint(int index);
+Point* PointCW(const Point& point);
+Point* PointCCW(const Point& point);
+Point* OppositePoint(Triangle& t, const Point& p);
 
-Triangle* GetNeighbor(const int& index);
+Triangle* GetNeighbor(int index);
 void MarkNeighbor(Point* p1, Point* p2, Triangle* t);
 void MarkNeighbor(Triangle& t);
 
-void MarkConstrainedEdge(const int index);
+void MarkConstrainedEdge(int index);
 void MarkConstrainedEdge(Edge& edge);
 void MarkConstrainedEdge(Point* p, Point* q);
 
 int Index(const Point* p);
 int EdgeIndex(const Point* p1, const Point* p2);
 
-Triangle* NeighborCW(Point& point);
-Triangle* NeighborCCW(Point& point);
-bool GetConstrainedEdgeCCW(Point& p);
-bool GetConstrainedEdgeCW(Point& p);
-void SetConstrainedEdgeCCW(Point& p, bool ce);
-void SetConstrainedEdgeCW(Point& p, bool ce);
-bool GetDelunayEdgeCCW(Point& p);
-bool GetDelunayEdgeCW(Point& p);
-void SetDelunayEdgeCCW(Point& p, bool e);
-void SetDelunayEdgeCW(Point& p, bool e);
-
-bool Contains(Point* p);
+Triangle* NeighborCW(const Point& point);
+Triangle* NeighborCCW(const Point& point);
+bool GetConstrainedEdgeCCW(const Point& p);
+bool GetConstrainedEdgeCW(const Point& p);
+void SetConstrainedEdgeCCW(const Point& p, bool ce);
+void SetConstrainedEdgeCW(const Point& p, bool ce);
+bool GetDelunayEdgeCCW(const Point& p);
+bool GetDelunayEdgeCW(const Point& p);
+void SetDelunayEdgeCCW(const Point& p, bool e);
+void SetDelunayEdgeCW(const Point& p, bool e);
+
+bool Contains(const Point* p);
 bool Contains(const Edge& e);
-bool Contains(Point* p, Point* q);
+bool Contains(const Point* p, const Point* q);
 void Legalize(Point& point);
 void Legalize(Point& opoint, Point& npoint);
 /**
  * Clears all references to all other triangles and points
  */
 void Clear();
-void ClearNeighbor(Triangle *triangle );
+void ClearNeighbor(const Triangle *triangle);
 void ClearNeighbors();
 void ClearDelunayEdges();
 
 inline bool IsInterior();
 inline void IsInterior(bool b);
 
-Triangle& NeighborAcross(Point& opoint);
+Triangle& NeighborAcross(const Point& opoint);
 
 void DebugPrint();
 
@@ -258,7 +258,7 @@ inline bool operator ==(const Point& a, const Point& b)
 
 inline bool operator !=(const Point& a, const Point& b)
 {
-  return a.x != b.x || a.y != b.y;
+  return !(a.x == b.x) && !(a.y == b.y);
 }
 
 /// Peform the dot product on two vectors.
@@ -282,22 +282,22 @@ inline Point Cross(const Point& a, double s)
 
 /// Perform the cross product on a scalar and a point. In 2D this produces
 /// a point.
-inline Point Cross(const double s, const Point& a)
+inline Point Cross(double s, const Point& a)
 {
   return Point(-s * a.y, s * a.x);
 }
 
-inline Point* Triangle::GetPoint(const int& index)
+inline Point* Triangle::GetPoint(int index)
 {
   return points_[index];
 }
 
-inline Triangle* Triangle::GetNeighbor(const int& index)
+inline Triangle* Triangle::GetNeighbor(int index)
 {
   return neighbors_[index];
 }
 
-inline bool Triangle::Contains(Point* p)
+inline bool Triangle::Contains(const Point* p)
 {
   return p == points_[0] || p == points_[1] || p == points_[2];
 }
@@ -307,7 +307,7 @@ inline bool Triangle::Contains(const Edge& e)
   return Contains(e.p) && Contains(e.q);
 }
 
-inline bool Triangle::Contains(Point* p, Point* q)
+inline bool Triangle::Contains(const Point* p, const Point* q)
 {
   return Contains(p) && Contains(q);
 }
@@ -324,6 +324,4 @@ inline void Triangle::IsInterior(bool b)
 
 }
 
-#endif
-
-
+#endif

+ 32 - 8
contrib/poly2tri/poly2tri/common/utils.h

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -28,18 +28,26 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 #ifndef UTILS_H
 #define UTILS_H
 
+// Otherwise #defines like M_PI are undeclared under Visual Studio
+#define _USE_MATH_DEFINES
+
 #include <exception>
+#include <math.h>
+
+// C99 removes M_PI from math.h
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338327
+#endif
 
 namespace p2t {
 
-const double PI = 3.1415926535897932384626433832795029;
-const double PI_2 = 2 * PI;
-const double PI_3div4 = 3 * PI / 4;
-const double EPSILON = 1e-15;
+const double PI_3div4 = 3 * M_PI / 4;
+const double PI_div2 = 1.57079632679489661923;
+const double EPSILON = 1e-12;
 
 enum Orientation { CW, CCW, COLLINEAR };
 
@@ -53,7 +61,7 @@ enum Orientation { CW, CCW, COLLINEAR };
  *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
  * </pre>
  */
-Orientation Orient2d(Point& pa, Point& pb, Point& pc)
+Orientation Orient2d(const Point& pa, const Point& pb, const Point& pc)
 {
   double detleft = (pa.x - pc.x) * (pb.y - pc.y);
   double detright = (pa.y - pc.y) * (pb.x - pc.x);
@@ -66,6 +74,7 @@ Orientation Orient2d(Point& pa, Point& pb, Point& pc)
   return CW;
 }
 
+/*
 bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd)
 {
   double pdx = pd.x;
@@ -97,7 +106,22 @@ bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd)
   return true;
 }
 
+*/
+
+bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point& pd)
+{
+  double oadb = (pa.x - pb.x)*(pd.y - pb.y) - (pd.x - pb.x)*(pa.y - pb.y);
+  if (oadb >= -EPSILON) {
+    return false;
+  }
+
+  double oadc = (pa.x - pc.x)*(pd.y - pc.y) - (pd.x - pc.x)*(pa.y - pc.y);
+  if (oadc <= EPSILON) {
+    return false;
+  }
+  return true;
 }
 
-#endif
+}
 
+#endif

+ 2 - 3
contrib/poly2tri/poly2tri/poly2tri.h

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -35,5 +35,4 @@
 #include "common/shapes.h"
 #include "sweep/cdt.h"
 
-#endif
-
+#endif

+ 3 - 4
contrib/poly2tri/poly2tri/sweep/advancing_front.cc

@@ -39,7 +39,7 @@ AdvancingFront::AdvancingFront(Node& head, Node& tail)
   search_node_ = &head;
 }
 
-Node* AdvancingFront::LocateNode(const double& x)
+Node* AdvancingFront::LocateNode(double x)
 {
   Node* node = search_node_;
 
@@ -61,7 +61,7 @@ Node* AdvancingFront::LocateNode(const double& x)
   return NULL;
 }
 
-Node* AdvancingFront::FindSearchNode(const double& x)
+Node* AdvancingFront::FindSearchNode(double x)
 {
   (void)x; // suppress compiler warnings "unused parameter 'x'"
   // TODO: implement BST index
@@ -105,5 +105,4 @@ AdvancingFront::~AdvancingFront()
 {
 }
 
-}
-
+}

+ 3 - 3
contrib/poly2tri/poly2tri/sweep/advancing_front.h

@@ -74,7 +74,7 @@ Node* search();
 void set_search(Node* node);
 
 /// Locate insertion point along advancing front
-Node* LocateNode(const double& x);
+Node* LocateNode(double x);
 
 Node* LocatePoint(const Point* point);
 
@@ -82,7 +82,7 @@ private:
 
 Node* head_, *tail_, *search_node_;
 
-Node* FindSearchNode(const double& x);
+Node* FindSearchNode(double x);
 };
 
 inline Node* AdvancingFront::head()
@@ -115,4 +115,4 @@ inline void AdvancingFront::set_search(Node* node)
 
 }
 
-#endif
+#endif

+ 4 - 5
contrib/poly2tri/poly2tri/sweep/cdt.cc

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -32,13 +32,13 @@
 
 namespace p2t {
 
-CDT::CDT(std::vector<Point*> polyline)
+CDT::CDT(const std::vector<Point*>& polyline)
 {
   sweep_context_ = new SweepContext(polyline);
   sweep_ = new Sweep;
 }
 
-void CDT::AddHole(std::vector<Point*> polyline)
+void CDT::AddHole(const std::vector<Point*>& polyline)
 {
   sweep_context_->AddHole(polyline);
 }
@@ -68,5 +68,4 @@ CDT::~CDT()
   delete sweep_;
 }
 
-}
-
+}

+ 17 - 17
contrib/poly2tri/poly2tri/sweep/cdt.h

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -28,7 +28,7 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 #ifndef CDT_H
 #define CDT_H
 
@@ -37,11 +37,11 @@
 #include "sweep.h"
 
 /**
- * 
+ *
  * @author Mason Green <[email protected]>
  *
  */
- 
+
 namespace p2t {
 
 class CDT
@@ -50,40 +50,40 @@ public:
 
   /**
    * Constructor - add polyline with non repeating points
-   * 
+   *
    * @param polyline
    */
-  CDT(std::vector<Point*> polyline);
-  
+  CDT(const std::vector<Point*>& polyline);
+
    /**
    * Destructor - clean up memory
    */
   ~CDT();
-  
+
   /**
    * Add a hole
-   * 
+   *
    * @param polyline
    */
-  void AddHole(std::vector<Point*> polyline);
-  
+  void AddHole(const std::vector<Point*>& polyline);
+
   /**
    * Add a steiner point
-   * 
+   *
    * @param point
    */
   void AddPoint(Point* point);
-  
+
   /**
    * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points
    */
   void Triangulate();
-  
+
   /**
    * Get CDT triangles
    */
   std::vector<Triangle*> GetTriangles();
-  
+
   /**
    * Get triangle map
    */
@@ -94,7 +94,7 @@ public:
   /**
    * Internals
    */
-   
+
   SweepContext* sweep_context_;
   Sweep* sweep_;
 
@@ -102,4 +102,4 @@ public:
 
 }
 
-#endif
+#endif

+ 91 - 42
contrib/poly2tri/poly2tri/sweep/sweep.cc

@@ -49,7 +49,7 @@ void Sweep::Triangulate(SweepContext& tcx)
 
 void Sweep::SweepPoints(SweepContext& tcx)
 {
-  for (int i = 1; i < tcx.point_count(); i++) {
+  for (size_t i = 1; i < tcx.point_count(); i++) {
     Point& point = *tcx.GetPoint(i);
     Node* node = &PointEvent(tcx, point);
     for (unsigned int i = 0; i < point.edge_list.size(); i++) {
@@ -117,7 +117,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
 	  throw std::runtime_error("EdgeEvent - collinear points not supported");
     if( triangle->Contains(&eq, p1)) {
       triangle->MarkConstrainedEdge(&eq, p1 );
-      // We are modifying the constraint maybe it would be better to 
+      // We are modifying the constraint maybe it would be better to
       // not change the given constraint and just keep a variable for the new constraint
       tcx.edge_event.constrained_edge->q = p1;
       triangle = &triangle->NeighborAcross(point);
@@ -137,7 +137,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
 
     if( triangle->Contains(&eq, p2)) {
       triangle->MarkConstrainedEdge(&eq, p2 );
-      // We are modifying the constraint maybe it would be better to 
+      // We are modifying the constraint maybe it would be better to
       // not change the given constraint and just keep a variable for the new constraint
       tcx.edge_event.constrained_edge->q = p2;
       triangle = &triangle->NeighborAcross(point);
@@ -166,7 +166,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
 
 bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq)
 {
-  int index = triangle.EdgeIndex(&ep, &eq);
+  const int index = triangle.EdgeIndex(&ep, &eq);
 
   if (index != -1) {
     triangle.MarkConstrainedEdge(index);
@@ -230,8 +230,8 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
   Node* node = n.next;
 
   while (node->next) {
-    double angle = HoleAngle(*node);
-    if (angle > PI_2 || angle < -PI_2) break;
+    // if HoleAngle exceeds 90 degrees then break.
+    if (LargeHole_DontFill(node)) break;
     Fill(tcx, *node);
     node = node->next;
   }
@@ -240,29 +240,81 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
   node = n.prev;
 
   while (node->prev) {
-    double angle = HoleAngle(*node);
-    if (angle > PI_2 || angle < -PI_2) break;
+    // if HoleAngle exceeds 90 degrees then break.
+    if (LargeHole_DontFill(node)) break;
     Fill(tcx, *node);
     node = node->prev;
   }
 
   // Fill right basins
   if (n.next && n.next->next) {
-    double angle = BasinAngle(n);
+    const double angle = BasinAngle(n);
     if (angle < PI_3div4) {
       FillBasin(tcx, n);
     }
   }
 }
 
-double Sweep::BasinAngle(Node& node)
+// True if HoleAngle exceeds 90 degrees.
+bool Sweep::LargeHole_DontFill(const Node* node) const {
+
+  const Node* nextNode = node->next;
+  const Node* prevNode = node->prev;
+  if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point))
+          return false;
+
+  // Check additional points on front.
+  const Node* next2Node = nextNode->next;
+  // "..Plus.." because only want angles on same side as point being added.
+  if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point))
+          return false;
+
+  const Node* prev2Node = prevNode->prev;
+  // "..Plus.." because only want angles on same side as point being added.
+  if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point))
+          return false;
+
+  return true;
+}
+
+bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const {
+  const double angle = Angle(origin, pa, pb);
+  return ((angle > PI_div2) || (angle < -PI_div2));
+}
+
+bool Sweep::AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const {
+  const double angle = Angle(origin, pa, pb);
+  return (angle > PI_div2) || (angle < 0);
+}
+
+double Sweep::Angle(const Point* origin, const Point* pa, const Point* pb) const {
+  /* Complex plane
+   * ab = cosA +i*sinA
+   * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx)
+   * atan2(y,x) computes the principal value of the argument function
+   * applied to the complex number x+iy
+   * Where x = ax*bx + ay*by
+   *       y = ax*by - ay*bx
+   */
+  const double px = origin->x;
+  const double py = origin->y;
+  const double ax = pa->x- px;
+  const double ay = pa->y - py;
+  const double bx = pb->x - px;
+  const double by = pb->y - py;
+  const double x = ax * by - ay * bx;
+  const double y = ax * bx + ay * by;
+  return atan2(x, y);
+}
+
+double Sweep::BasinAngle(const Node& node) const
 {
-  double ax = node.point->x - node.next->next->point->x;
-  double ay = node.point->y - node.next->next->point->y;
+  const double ax = node.point->x - node.next->next->point->x;
+  const double ay = node.point->y - node.next->next->point->y;
   return atan2(ay, ax);
 }
 
-double Sweep::HoleAngle(Node& node)
+double Sweep::HoleAngle(const Node& node) const
 {
   /* Complex plane
    * ab = cosA +i*sinA
@@ -272,10 +324,10 @@ double Sweep::HoleAngle(Node& node)
    * Where x = ax*bx + ay*by
    *       y = ax*by - ay*bx
    */
-  double ax = node.next->point->x - node.point->x;
-  double ay = node.next->point->y - node.point->y;
-  double bx = node.prev->point->x - node.point->x;
-  double by = node.prev->point->y - node.point->y;
+  const double ax = node.next->point->x - node.point->x;
+  const double ay = node.next->point->y - node.point->y;
+  const double bx = node.prev->point->x - node.point->x;
+  const double by = node.prev->point->y - node.point->y;
   return atan2(ax * by - ay * bx, ax * bx + ay * by);
 }
 
@@ -340,43 +392,43 @@ bool Sweep::Legalize(SweepContext& tcx, Triangle& t)
   return false;
 }
 
-bool Sweep::Incircle(Point& pa, Point& pb, Point& pc, Point& pd)
+bool Sweep::Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const
 {
-  double adx = pa.x - pd.x;
-  double ady = pa.y - pd.y;
-  double bdx = pb.x - pd.x;
-  double bdy = pb.y - pd.y;
+  const double adx = pa.x - pd.x;
+  const double ady = pa.y - pd.y;
+  const double bdx = pb.x - pd.x;
+  const double bdy = pb.y - pd.y;
 
-  double adxbdy = adx * bdy;
-  double bdxady = bdx * ady;
-  double oabd = adxbdy - bdxady;
+  const double adxbdy = adx * bdy;
+  const double bdxady = bdx * ady;
+  const double oabd = adxbdy - bdxady;
 
   if (oabd <= 0)
     return false;
 
-  double cdx = pc.x - pd.x;
-  double cdy = pc.y - pd.y;
+  const double cdx = pc.x - pd.x;
+  const double cdy = pc.y - pd.y;
 
-  double cdxady = cdx * ady;
-  double adxcdy = adx * cdy;
-  double ocad = cdxady - adxcdy;
+  const double cdxady = cdx * ady;
+  const double adxcdy = adx * cdy;
+  const double ocad = cdxady - adxcdy;
 
   if (ocad <= 0)
     return false;
 
-  double bdxcdy = bdx * cdy;
-  double cdxbdy = cdx * bdy;
+  const double bdxcdy = bdx * cdy;
+  const double cdxbdy = cdx * bdy;
 
-  double alift = adx * adx + ady * ady;
-  double blift = bdx * bdx + bdy * bdy;
-  double clift = cdx * cdx + cdy * cdy;
+  const double alift = adx * adx + ady * ady;
+  const double blift = bdx * bdx + bdy * bdy;
+  const double clift = cdx * cdx + cdy * cdy;
 
-  double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
+  const double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
 
   return det > 0;
 }
 
-void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op)
+void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const
 {
   Triangle* n1, *n2, *n3, *n4;
   n1 = t.NeighborCCW(p);
@@ -708,11 +760,8 @@ Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op)
   } else if (o2d == CCW) {
     // Left
     return *ot.PointCW(op);
-  } else{
-    //throw new RuntimeException("[Unsupported] Opposing point on constrained edge");
-	  // ASSIMP_CHANGE (aramis_acg)
-	  throw std::runtime_error("[Unsupported] Opposing point on constrained edge");
   }
+  throw std::runtime_error("[Unsupported] Opposing point on constrained edge");
 }
 
 void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle,
@@ -740,7 +789,7 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle&
 Sweep::~Sweep() {
 
     // Clean up memory
-    for(unsigned int i = 0; i < nodes_.size(); i++) {
+    for(size_t i = 0; i < nodes_.size(); i++) {
         delete nodes_[i];
     }
 

+ 28 - 21
contrib/poly2tri/poly2tri/sweep/sweep.h

@@ -33,7 +33,7 @@
  * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation',
  * International Journal of Geographical Information Science
  *
- * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, [email protected]
+ * "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, [email protected]
  */
 
 #ifndef SWEEP_H
@@ -49,17 +49,17 @@ struct Point;
 struct Edge;
 class Triangle;
 
-class Sweep 
+class Sweep
 {
 public:
 
   /**
    * Triangulate
-   * 
+   *
    * @param tcx
    */
   void Triangulate(SweepContext& tcx);
-  
+
   /**
    * Destructor - clean up memory
    */
@@ -69,7 +69,7 @@ private:
 
   /**
    * Start sweeping the Y-sorted point set from bottom to top
-   * 
+   *
    * @param tcx
    */
   void SweepPoints(SweepContext& tcx);
@@ -86,8 +86,8 @@ private:
   Node& PointEvent(SweepContext& tcx, Point& point);
 
    /**
-     * 
-     * 
+     *
+     *
      * @param tcx
      * @param edge
      * @param node
@@ -98,7 +98,7 @@ private:
 
   /**
    * Creates a new front triangle and legalize it
-   * 
+   *
    * @param tcx
    * @param point
    * @param node
@@ -142,7 +142,7 @@ private:
    * @param d - point opposite a
    * @return true if d is inside circle, false if on circle edge
    */
-  bool Incircle(Point& pa, Point& pb, Point& pc, Point& pd);
+  bool Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const;
 
   /**
    * Rotates a triangle pair one vertex CW
@@ -158,7 +158,7 @@ private:
    *       n4                    n4
    * </pre>
    */
-  void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op);
+  void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const;
 
   /**
    * Fills holes in the Advancing Front
@@ -169,17 +169,24 @@ private:
    */
   void FillAdvancingFront(SweepContext& tcx, Node& n);
 
+  // Decision-making about when to Fill hole.
+  // Contributed by ToolmakerSteve2
+  bool LargeHole_DontFill(const Node* node) const;
+  bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const;
+  bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const;
+  double Angle(const Point* origin, const Point* pa, const Point* pb) const;
+
   /**
    *
    * @param node - middle node
    * @return the angle between 3 front nodes
    */
-  double HoleAngle(Node& node);
+  double HoleAngle(const Node& node) const;
 
   /**
    * The basin angle is decided against the horizontal line [1,0]
    */
-  double BasinAngle(Node& node);
+  double BasinAngle(const Node& node) const;
 
   /**
    * Fills a basin that has formed on the Advancing Front to the right
@@ -228,22 +235,22 @@ private:
   /**
    * After a flip we have two triangles and know that only one will still be
    * intersecting the edge. So decide which to contiune with and legalize the other
-   * 
+   *
    * @param tcx
    * @param o - should be the result of an orient2d( eq, op, ep )
    * @param t - triangle 1
    * @param ot - triangle 2
-   * @param p - a point shared by both triangles 
+   * @param p - a point shared by both triangles
    * @param op - another point shared by both triangles
    * @return returns the triangle still intersecting the edge
    */
   Triangle& NextFlipTriangle(SweepContext& tcx, int o, Triangle&  t, Triangle& ot, Point& p, Point& op);
 
    /**
-     * When we need to traverse from one triangle to the next we need 
+     * When we need to traverse from one triangle to the next we need
      * the point in current triangle that is the opposite point to the next
-     * triangle. 
-     * 
+     * triangle.
+     *
      * @param ep
      * @param eq
      * @param ot
@@ -254,10 +261,10 @@ private:
 
    /**
      * Scan part of the FlipScan algorithm<br>
-     * When a triangle pair isn't flippable we will scan for the next 
-     * point that is inside the flip triangle scan area. When found 
+     * When a triangle pair isn't flippable we will scan for the next
+     * point that is inside the flip triangle scan area. When found
      * we generate a new flipEdgeEvent
-     * 
+     *
      * @param tcx
      * @param ep - last point on the edge we are traversing
      * @param eq - first point on the edge we are traversing
@@ -275,4 +282,4 @@ private:
 
 }
 
-#endif
+#endif

+ 31 - 22
contrib/poly2tri/poly2tri/sweep/sweep_context.cc

@@ -34,17 +34,18 @@
 
 namespace p2t {
 
-SweepContext::SweepContext(std::vector<Point*> polyline)
+SweepContext::SweepContext(const std::vector<Point*>& polyline) : points_(polyline),
+  front_(0),
+  head_(0),
+  tail_(0),
+  af_head_(0),
+  af_middle_(0),
+  af_tail_(0)
 {
-  basin = Basin();
-  edge_event = EdgeEvent();
-
-  points_ = polyline;
-
   InitEdges(points_);
 }
 
-void SweepContext::AddHole(std::vector<Point*> polyline)
+void SweepContext::AddHole(const std::vector<Point*>& polyline)
 {
   InitEdges(polyline);
   for(unsigned int i = 0; i < polyline.size(); i++) {
@@ -56,12 +57,12 @@ void SweepContext::AddPoint(Point* point) {
   points_.push_back(point);
 }
 
-std::vector<Triangle*> SweepContext::GetTriangles()
+std::vector<Triangle*> &SweepContext::GetTriangles()
 {
   return triangles_;
 }
 
-std::list<Triangle*> SweepContext::GetMap()
+std::list<Triangle*> &SweepContext::GetMap()
 {
   return map_;
 }
@@ -94,16 +95,16 @@ void SweepContext::InitTriangulation()
 
 }
 
-void SweepContext::InitEdges(std::vector<Point*> polyline)
+void SweepContext::InitEdges(const std::vector<Point*>& polyline)
 {
-  int num_points = static_cast<int>(polyline.size());
-  for (int i = 0; i < num_points; i++) {
-    int j = i < num_points - 1 ? i + 1 : 0;
+  size_t num_points = polyline.size();
+  for (size_t i = 0; i < num_points; i++) {
+    size_t j = i < num_points - 1 ? i + 1 : 0;
     edge_list.push_back(new Edge(*polyline[i], *polyline[j]));
   }
 }
 
-Point* SweepContext::GetPoint(const int& index)
+Point* SweepContext::GetPoint(size_t index)
 {
   return points_[index];
 }
@@ -113,13 +114,13 @@ void SweepContext::AddToMap(Triangle* triangle)
   map_.push_back(triangle);
 }
 
-Node& SweepContext::LocateNode(Point& point)
+Node& SweepContext::LocateNode(const Point& point)
 {
   // TODO implement search tree
   return *front_->LocateNode(point.x);
 }
 
-void SweepContext::CreateAdvancingFront(std::vector<Node*> nodes)
+void SweepContext::CreateAdvancingFront(const std::vector<Node*>& nodes)
 {
 
   (void) nodes;
@@ -164,12 +165,20 @@ void SweepContext::RemoveFromMap(Triangle* triangle)
 
 void SweepContext::MeshClean(Triangle& triangle)
 {
-  if (!triangle.IsInterior()) {
-    triangle.IsInterior(true);
-    triangles_.push_back(&triangle);
-    for (int i = 0; i < 3; i++) {
-      if (!triangle.constrained_edge[i])
-        MeshClean(*triangle.GetNeighbor(i));
+  std::vector<Triangle *> triangles;
+  triangles.push_back(&triangle);
+
+  while(!triangles.empty()){
+	Triangle *t = triangles.back();
+	triangles.pop_back();
+
+    if (t != NULL && !t->IsInterior()) {
+      t->IsInterior(true);
+      triangles_.push_back(t);
+      for (int i = 0; i < 3; i++) {
+        if (!t->constrained_edge[i])
+          triangles.push_back(t->GetNeighbor(i));
+      }
     }
   }
 }

+ 17 - 17
contrib/poly2tri/poly2tri/sweep/sweep_context.h

@@ -52,47 +52,47 @@ class SweepContext {
 public:
 
 /// Constructor
-SweepContext(std::vector<Point*> polyline);
+SweepContext(const std::vector<Point*>& polyline);
 /// Destructor
 ~SweepContext();
 
 void set_head(Point* p1);
 
-Point* head();
+Point* head() const;
 
 void set_tail(Point* p1);
 
-Point* tail();
+Point* tail() const;
 
-int point_count();
+size_t point_count() const;
 
-Node& LocateNode(Point& point);
+Node& LocateNode(const Point& point);
 
 void RemoveNode(Node* node);
 
-void CreateAdvancingFront(std::vector<Node*> nodes);
+void CreateAdvancingFront(const std::vector<Node*>& nodes);
 
 /// Try to map a node to all sides of this triangle that don't have a neighbor
 void MapTriangleToNodes(Triangle& t);
 
 void AddToMap(Triangle* triangle);
 
-Point* GetPoint(const int& index);
+Point* GetPoint(size_t index);
 
 Point* GetPoints();
 
 void RemoveFromMap(Triangle* triangle);
 
-void AddHole(std::vector<Point*> polyline);
+void AddHole(const std::vector<Point*>& polyline);
 
 void AddPoint(Point* point);
 
-AdvancingFront* front();
+AdvancingFront* front() const;
 
 void MeshClean(Triangle& triangle);
 
-std::vector<Triangle*> GetTriangles();
-std::list<Triangle*> GetMap();
+std::vector<Triangle*> &GetTriangles();
+std::list<Triangle*> &GetMap();
 
 std::vector<Edge*> edge_list;
 
@@ -147,18 +147,18 @@ Point* tail_;
 Node *af_head_, *af_middle_, *af_tail_;
 
 void InitTriangulation();
-void InitEdges(std::vector<Point*> polyline);
+void InitEdges(const std::vector<Point*>& polyline);
 
 };
 
-inline AdvancingFront* SweepContext::front()
+inline AdvancingFront* SweepContext::front() const
 {
   return front_;
 }
 
-inline int SweepContext::point_count()
+inline size_t SweepContext::point_count() const
 {
-  return static_cast<int>(points_.size());
+  return points_.size();
 }
 
 inline void SweepContext::set_head(Point* p1)
@@ -166,7 +166,7 @@ inline void SweepContext::set_head(Point* p1)
   head_ = p1;
 }
 
-inline Point* SweepContext::head()
+inline Point* SweepContext::head() const
 {
   return head_;
 }
@@ -176,7 +176,7 @@ inline void SweepContext::set_tail(Point* p1)
   tail_ = p1;
 }
 
-inline Point* SweepContext::tail()
+inline Point* SweepContext::tail() const
 {
   return tail_;
 }

+ 0 - 2
include/assimp/color4.inl

@@ -77,7 +77,6 @@ AI_FORCE_INLINE const aiColor4t<TReal>& aiColor4t<TReal>::operator /= (TReal f)
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 AI_FORCE_INLINE TReal aiColor4t<TReal>::operator[](unsigned int i) const {
-    //return *(&r + i);
     switch ( i ) {
         case 0:
             return r;
@@ -93,7 +92,6 @@ AI_FORCE_INLINE TReal aiColor4t<TReal>::operator[](unsigned int i) const {
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 AI_FORCE_INLINE TReal& aiColor4t<TReal>::operator[](unsigned int i) {
-//    return *(&r + i);
     switch ( i ) {
         case 0:
             return r;

+ 4 - 3
include/assimp/matrix4x4.h

@@ -224,7 +224,7 @@ public:
      *  @return Reference to the output matrix
      */
     static aiMatrix4x4t& Rotation(TReal a, const aiVector3t<TReal>& axis,
-        aiMatrix4x4t& out);
+            aiMatrix4x4t& out);
 
     // -------------------------------------------------------------------
     /** @brief Returns a translation matrix
@@ -232,7 +232,8 @@ public:
      *  @param out Receives the output matrix
      *  @return Reference to the output matrix
      */
-    static aiMatrix4x4t& Translation( const aiVector3t<TReal>& v, aiMatrix4x4t& out);
+    static aiMatrix4x4t& Translation( const aiVector3t<TReal>& v, 
+            aiMatrix4x4t& out);
 
     // -------------------------------------------------------------------
     /** @brief Returns a scaling matrix
@@ -252,7 +253,7 @@ public:
      *          Journal of Graphics Tools, 4(4):1-4, 1999
      */
     static aiMatrix4x4t& FromToMatrix(const aiVector3t<TReal>& from,
-        const aiVector3t<TReal>& to, aiMatrix4x4t& out);
+            const aiVector3t<TReal>& to, aiMatrix4x4t& out);
 
 public:
     TReal a1, a2, a3, a4;

+ 1 - 4
port/PyAssimp/pyassimp/helper.py

@@ -8,7 +8,6 @@ import os
 import ctypes
 from ctypes import POINTER
 import operator
-import sys
 
 try: import numpy
 except: numpy = None
@@ -40,9 +39,7 @@ elif os.name=='nt':
     for dir_candidate in path_dirs:
         if 'assimp' in dir_candidate.lower():
             additional_dirs.append(dir_candidate)
-
-additional_dirs += sys.path
-
+            
 #print(additional_dirs)
 def vec2tuple(x):
     """ Converts a VECTOR3D to a Tuple """

+ 1 - 3
port/PyAssimp/setup.py

@@ -9,7 +9,5 @@ setup(name='pyassimp',
       url='https://github.com/assimp/assimp',
       packages=['pyassimp'],
       data_files=[('share/pyassimp', ['README.md']),
-                  ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')]),
-                  ('lib/', [f for f in os.listdir('../../lib') if os.path.isfile(f)])],
-      requires=['numpy']
+                  ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')])], requires=['numpy']
       )

+ 28 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln

@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.9
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedDirectx11", "SimpleTexturedDirectx11\SimpleTexturedDirectx11.vcxproj", "{E3B160B5-E71F-4F3F-9310-B8F156F736D8}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.ActiveCfg = Debug|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.Build.0 = Debug|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.ActiveCfg = Debug|Win32
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.Build.0 = Debug|Win32
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.ActiveCfg = Release|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.Build.0 = Release|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.ActiveCfg = Release|Win32
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 102 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h

@@ -0,0 +1,102 @@
+#ifndef MESH_H
+#define MESH_H
+
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <iostream>
+#include <vector>
+using namespace std;
+
+#include <vector>
+#include <d3d11_1.h>
+#include <DirectXMath.h>
+using namespace DirectX;
+
+struct VERTEX {
+	FLOAT X, Y, Z;
+	XMFLOAT2 texcoord;
+};
+
+struct Texture {
+	string type;
+	string path;
+	ID3D11ShaderResourceView *texture;
+};
+
+class Mesh {
+public:
+	vector<VERTEX> vertices;
+	vector<UINT> indices;
+	vector<Texture> textures;
+	ID3D11Device *dev;
+
+	Mesh(ID3D11Device *dev, vector<VERTEX> vertices, vector<UINT> indices, vector<Texture> textures)
+	{
+		this->vertices = vertices;
+		this->indices = indices;
+		this->textures = textures;
+
+		this->dev = dev;
+
+		this->setupMesh(dev);
+	}
+
+	void Draw(ID3D11DeviceContext *devcon)
+	{
+		UINT stride = sizeof(VERTEX);
+		UINT offset = 0;
+
+		devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
+		devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
+
+		devcon->PSSetShaderResources(0, 1, &textures[0].texture);
+
+		devcon->DrawIndexed(indices.size(), 0, 0);
+	}
+
+	void Close()
+	{
+		VertexBuffer->Release();
+		IndexBuffer->Release();
+	}
+private:
+	/*  Render data  */
+	ID3D11Buffer *VertexBuffer, *IndexBuffer;
+
+	/*  Functions    */
+	// Initializes all the buffer objects/arrays
+	bool setupMesh(ID3D11Device *dev)
+	{
+		HRESULT hr;
+
+		D3D11_BUFFER_DESC vbd;
+		vbd.Usage = D3D11_USAGE_IMMUTABLE;
+		vbd.ByteWidth = sizeof(VERTEX) * vertices.size();
+		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+		vbd.CPUAccessFlags = 0;
+		vbd.MiscFlags = 0;
+
+		D3D11_SUBRESOURCE_DATA initData;
+		initData.pSysMem = &vertices[0];
+
+		hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer);
+		if (FAILED(hr))
+			return false;
+
+		D3D11_BUFFER_DESC ibd;
+		ibd.Usage = D3D11_USAGE_IMMUTABLE;
+		ibd.ByteWidth = sizeof(UINT) * indices.size();
+		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
+		ibd.CPUAccessFlags = 0;
+		ibd.MiscFlags = 0;
+
+		initData.pSysMem = &indices[0];
+
+		hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
+		if (FAILED(hr))
+			return false;
+	}
+};
+
+#endif

+ 205 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp

@@ -0,0 +1,205 @@
+#include "ModelLoader.h"
+
+ModelLoader::ModelLoader()
+{
+}
+
+
+ModelLoader::~ModelLoader()
+{
+}
+
+bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename)
+{
+	Assimp::Importer importer;
+
+	const aiScene* pScene = importer.ReadFile(filename,
+		aiProcess_Triangulate |
+		aiProcess_ConvertToLeftHanded);
+
+	if (pScene == NULL)
+		return false;
+
+	this->directory = filename.substr(0, filename.find_last_of('/'));
+
+	this->dev = dev;
+	this->hwnd = hwnd;
+
+	processNode(pScene->mRootNode, pScene);
+
+	return true;
+}
+
+void ModelLoader::Draw(ID3D11DeviceContext * devcon)
+{
+	for (int i = 0; i < meshes.size(); i++)
+	{
+		meshes[i].Draw(devcon);
+	}
+}
+
+string textype;
+
+Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene)
+{
+	// Data to fill
+	vector<VERTEX> vertices;
+	vector<UINT> indices;
+	vector<Texture> textures;
+
+	if (mesh->mMaterialIndex >= 0)
+	{
+		aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
+
+		if (textype.empty()) textype = determineTextureType(scene, mat);
+	}
+
+	// Walk through each of the mesh's vertices
+	for (UINT i = 0; i < mesh->mNumVertices; i++)
+	{
+		VERTEX vertex;
+
+		vertex.X = mesh->mVertices[i].x;
+		vertex.Y = mesh->mVertices[i].y;
+		vertex.Z = mesh->mVertices[i].z;
+
+		if (mesh->mTextureCoords[0])
+		{
+			vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x;
+			vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y;
+		}
+
+		vertices.push_back(vertex);
+	}
+
+	for (UINT i = 0; i < mesh->mNumFaces; i++)
+	{
+		aiFace face = mesh->mFaces[i];
+
+		for (UINT j = 0; j < face.mNumIndices; j++)
+			indices.push_back(face.mIndices[j]);
+	}
+
+	if (mesh->mMaterialIndex >= 0)
+	{
+		aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
+
+		vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
+		textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
+	}
+
+	return Mesh(dev, vertices, indices, textures);
+}
+
+vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene)
+{
+	vector<Texture> textures;
+	for (UINT i = 0; i < mat->GetTextureCount(type); i++)
+	{
+		aiString str;
+		mat->GetTexture(type, i, &str);
+		// Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
+		bool skip = false;
+		for (UINT j = 0; j < textures_loaded.size(); j++)
+		{
+			if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0)
+			{
+				textures.push_back(textures_loaded[j]);
+				skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)
+				break;
+			}
+		}
+		if (!skip)
+		{   // If texture hasn't been loaded already, load it
+			HRESULT hr;
+			Texture texture;
+			if (textype == "embedded compressed texture")
+			{
+				int textureindex = getTextureIndex(&str);
+				texture.texture = getTextureFromModel(scene, textureindex);
+			}
+			else
+			{
+				string filename = string(str.C_Str());
+				filename = directory + '/' + filename;
+				wstring filenamews = wstring(filename.begin(), filename.end());
+				hr = CreateWICTextureFromFile(dev, devcon, filenamews.c_str(), nullptr, &texture.texture);
+				if (FAILED(hr))
+					MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK);
+			}
+			texture.type = typeName;
+			texture.path = str.C_Str();
+			textures.push_back(texture);
+			this->textures_loaded.push_back(texture);  // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
+		}
+	}
+	return textures;
+}
+
+void ModelLoader::Close()
+{
+	for (int i = 0; i < meshes.size(); i++)
+	{
+		meshes[i].Close();
+	}
+
+	dev->Release();
+}
+
+void ModelLoader::processNode(aiNode * node, const aiScene * scene)
+{
+	for (UINT i = 0; i < node->mNumMeshes; i++)
+	{
+		aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
+		meshes.push_back(this->processMesh(mesh, scene));
+	}
+
+	for (UINT i = 0; i < node->mNumChildren; i++)
+	{
+		this->processNode(node->mChildren[i], scene);
+	}
+}
+
+string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat)
+{
+	aiString textypeStr;
+	mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
+	string textypeteststr = textypeStr.C_Str();
+	if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5")
+	{
+		if (scene->mTextures[0]->mHeight == 0)
+		{
+			return "embedded compressed texture";
+		}
+		else
+		{
+			return "embedded non-compressed texture";
+		}
+	}
+	if (textypeteststr.find('.') != string::npos)
+	{
+		return "textures are on disk";
+	}
+}
+
+int ModelLoader::getTextureIndex(aiString * str)
+{
+	string tistr;
+	tistr = str->C_Str();
+	tistr = tistr.substr(1);
+	return stoi(tistr);
+}
+
+ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex)
+{
+	HRESULT hr;
+	ID3D11ShaderResourceView *texture;
+
+	int* size = reinterpret_cast<int*>(&scene->mTextures[textureindex]->mWidth);
+
+	hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast<unsigned char*>(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture);
+	if (FAILED(hr))
+		MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);
+
+	return texture;
+}

+ 44 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h

@@ -0,0 +1,44 @@
+#ifndef MODEL_LOADER_H
+#define MODEL_LOADER_H
+
+#include <vector>
+#include <d3d11_1.h>
+#include <DirectXMath.h>
+
+#include <assimp\Importer.hpp>
+#include <assimp\scene.h>
+#include <assimp\postprocess.h>
+
+#include "Mesh.h"
+#include "TextureLoader.h"
+
+using namespace DirectX;
+
+class ModelLoader
+{
+public:
+	ModelLoader();
+	~ModelLoader();
+
+	bool Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon, std::string filename);
+	void Draw(ID3D11DeviceContext* devcon);
+
+	void Close();
+private:
+	ID3D11Device *dev;
+	ID3D11DeviceContext *devcon;
+	std::vector<Mesh> meshes;
+	string directory;
+	vector<Texture> textures_loaded;
+	HWND hwnd;
+
+	void processNode(aiNode* node, const aiScene* scene);
+	Mesh processMesh(aiMesh* mesh, const aiScene* scene);
+	vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName, const aiScene* scene);
+	string determineTextureType(const aiScene* scene, aiMaterial* mat);
+	int getTextureIndex(aiString* str);
+	ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex);
+};
+
+#endif // !MODEL_LOADER_H
+

+ 9 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl

@@ -0,0 +1,9 @@
+Texture2D diffTexture;
+SamplerState SampleType;
+
+float4 main(float4 pos : SV_POSITION, float2 texcoord : TEXCOORD) : SV_TARGET
+{
+	float4 textureColor = diffTexture.Sample(SampleType, texcoord);
+
+	return textureColor;
+}

+ 146 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj

@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>15.0</VCProjectVersion>
+    <ProjectGuid>{E3B160B5-E71F-4F3F-9310-B8F156F736D8}</ProjectGuid>
+    <RootNamespace>SimpleTexturedDirectx11</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(IncludePath);E:\OpenGL VS Files\include</IncludePath>
+    <LibraryPath>$(LibraryPath);E:\OpenGL VS Files\lib</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>assimp-vc140-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="ModelLoader.cpp" />
+    <ClCompile Include="TextureLoader.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <FxCompile Include="PixelShader.hlsl">
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
+    </FxCompile>
+    <FxCompile Include="VertexShader.hlsl">
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Vertex</ShaderType>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Vertex</ShaderType>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Vertex</ShaderType>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Vertex</ShaderType>
+    </FxCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Mesh.h" />
+    <ClInclude Include="ModelLoader.h" />
+    <ClInclude Include="TextureLoader.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 50 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Shaders">
+      <UniqueIdentifier>{b6a86d3e-70a5-4d1e-ba05-c20902300206}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="ModelLoader.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="TextureLoader.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <FxCompile Include="VertexShader.hlsl">
+      <Filter>Shaders</Filter>
+    </FxCompile>
+    <FxCompile Include="PixelShader.hlsl">
+      <Filter>Shaders</Filter>
+    </FxCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="ModelLoader.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Mesh.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="TextureLoader.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 691 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp

@@ -0,0 +1,691 @@
+//--------------------------------------------------------------------------------------
+// File: WICTextureLoader.cpp
+//
+// Function for loading a WIC image and creating a Direct3D 11 runtime texture for it
+// (auto-generating mipmaps if possible)
+//
+// Note: Assumes application has already called CoInitializeEx
+//
+// Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for
+//          auto-gen mipmap support.
+//
+// Note these functions are useful for images created as simple 2D textures. For
+// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader.
+// For a full-featured DDS file reader, writer, and texture processing pipeline see
+// the 'Texconv' sample and the 'DirectXTex' library.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// http://go.microsoft.com/fwlink/?LinkId=248926
+// http://go.microsoft.com/fwlink/?LinkId=248929
+//--------------------------------------------------------------------------------------
+
+// We could load multi-frame images (TIFF/GIF) into a texture array.
+// For now, we just load the first frame (note: DirectXTex supports multi-frame images)
+
+#include <dxgiformat.h>
+#include <assert.h>
+
+#pragma warning(push)
+#pragma warning(disable : 4005)
+#include <wincodec.h>
+#pragma warning(pop)
+
+#include <memory>
+
+#include "TextureLoader.h"
+
+#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS)
+#define DXGI_1_2_FORMATS
+#endif
+
+//---------------------------------------------------------------------------------
+template<class T> class ScopedObject
+{
+public:
+	explicit ScopedObject(T *p = 0) : _pointer(p) {}
+	~ScopedObject()
+	{
+		if (_pointer)
+		{
+			_pointer->Release();
+			_pointer = nullptr;
+		}
+	}
+
+	bool IsNull() const { return (!_pointer); }
+
+	T& operator*() { return *_pointer; }
+	T* operator->() { return _pointer; }
+	T** operator&() { return &_pointer; }
+
+	void Reset(T *p = 0) { if (_pointer) { _pointer->Release(); } _pointer = p; }
+
+	T* Get() const { return _pointer; }
+
+private:
+	ScopedObject(const ScopedObject&);
+	ScopedObject& operator=(const ScopedObject&);
+
+	T* _pointer;
+};
+
+//-------------------------------------------------------------------------------------
+// WIC Pixel Format Translation Data
+//-------------------------------------------------------------------------------------
+struct WICTranslate
+{
+	GUID                wic;
+	DXGI_FORMAT         format;
+};
+
+static WICTranslate g_WICFormats[] =
+{
+	{ GUID_WICPixelFormat128bppRGBAFloat,       DXGI_FORMAT_R32G32B32A32_FLOAT },
+
+	{ GUID_WICPixelFormat64bppRGBAHalf,         DXGI_FORMAT_R16G16B16A16_FLOAT },
+	{ GUID_WICPixelFormat64bppRGBA,             DXGI_FORMAT_R16G16B16A16_UNORM },
+
+	{ GUID_WICPixelFormat32bppRGBA,             DXGI_FORMAT_R8G8B8A8_UNORM },
+	{ GUID_WICPixelFormat32bppBGRA,             DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1
+	{ GUID_WICPixelFormat32bppBGR,              DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1
+
+	{ GUID_WICPixelFormat32bppRGBA1010102XR,    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1
+	{ GUID_WICPixelFormat32bppRGBA1010102,      DXGI_FORMAT_R10G10B10A2_UNORM },
+	{ GUID_WICPixelFormat32bppRGBE,             DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
+
+#ifdef DXGI_1_2_FORMATS
+
+	{ GUID_WICPixelFormat16bppBGRA5551,         DXGI_FORMAT_B5G5R5A1_UNORM },
+	{ GUID_WICPixelFormat16bppBGR565,           DXGI_FORMAT_B5G6R5_UNORM },
+
+#endif // DXGI_1_2_FORMATS
+
+	{ GUID_WICPixelFormat32bppGrayFloat,        DXGI_FORMAT_R32_FLOAT },
+	{ GUID_WICPixelFormat16bppGrayHalf,         DXGI_FORMAT_R16_FLOAT },
+	{ GUID_WICPixelFormat16bppGray,             DXGI_FORMAT_R16_UNORM },
+	{ GUID_WICPixelFormat8bppGray,              DXGI_FORMAT_R8_UNORM },
+
+	{ GUID_WICPixelFormat8bppAlpha,             DXGI_FORMAT_A8_UNORM },
+
+#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
+	{ GUID_WICPixelFormat96bppRGBFloat,         DXGI_FORMAT_R32G32B32_FLOAT },
+#endif
+};
+
+//-------------------------------------------------------------------------------------
+// WIC Pixel Format nearest conversion table
+//-------------------------------------------------------------------------------------
+
+struct WICConvert
+{
+	GUID        source;
+	GUID        target;
+};
+
+static WICConvert g_WICConvert[] =
+{
+	// Note target GUID in this conversion table must be one of those directly supported formats (above).
+
+	{ GUID_WICPixelFormatBlackWhite,            GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
+
+	{ GUID_WICPixelFormat1bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+	{ GUID_WICPixelFormat2bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+	{ GUID_WICPixelFormat4bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+	{ GUID_WICPixelFormat8bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+
+	{ GUID_WICPixelFormat2bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM 
+	{ GUID_WICPixelFormat4bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM 
+
+	{ GUID_WICPixelFormat16bppGrayFixedPoint,   GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT 
+	{ GUID_WICPixelFormat32bppGrayFixedPoint,   GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT 
+
+#ifdef DXGI_1_2_FORMATS
+
+	{ GUID_WICPixelFormat16bppBGR555,           GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM
+
+#else
+
+	{ GUID_WICPixelFormat16bppBGR555,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
+	{ GUID_WICPixelFormat16bppBGRA5551,         GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
+	{ GUID_WICPixelFormat16bppBGR565,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
+
+#endif // DXGI_1_2_FORMATS
+
+	{ GUID_WICPixelFormat32bppBGR101010,        GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM
+
+	{ GUID_WICPixelFormat24bppBGR,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+	{ GUID_WICPixelFormat24bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+	{ GUID_WICPixelFormat32bppPBGRA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+	{ GUID_WICPixelFormat32bppPRGBA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+
+	{ GUID_WICPixelFormat48bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+	{ GUID_WICPixelFormat48bppBGR,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+	{ GUID_WICPixelFormat64bppBGRA,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+	{ GUID_WICPixelFormat64bppPRGBA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+	{ GUID_WICPixelFormat64bppPBGRA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+
+	{ GUID_WICPixelFormat48bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+	{ GUID_WICPixelFormat48bppBGRFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+	{ GUID_WICPixelFormat64bppRGBAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+	{ GUID_WICPixelFormat64bppBGRAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+	{ GUID_WICPixelFormat64bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+	{ GUID_WICPixelFormat64bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+	{ GUID_WICPixelFormat48bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+
+	{ GUID_WICPixelFormat96bppRGBFixedPoint,    GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 
+	{ GUID_WICPixelFormat128bppPRGBAFloat,      GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 
+	{ GUID_WICPixelFormat128bppRGBFloat,        GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 
+	{ GUID_WICPixelFormat128bppRGBAFixedPoint,  GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 
+	{ GUID_WICPixelFormat128bppRGBFixedPoint,   GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 
+
+	{ GUID_WICPixelFormat32bppCMYK,             GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 
+	{ GUID_WICPixelFormat64bppCMYK,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+	{ GUID_WICPixelFormat40bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+	{ GUID_WICPixelFormat80bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+
+#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
+	{ GUID_WICPixelFormat32bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
+	{ GUID_WICPixelFormat64bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
+	{ GUID_WICPixelFormat64bppPRGBAHalf,        GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 
+#endif
+
+																					// We don't support n-channel formats
+};
+
+//--------------------------------------------------------------------------------------
+static IWICImagingFactory* _GetWIC()
+{
+	static IWICImagingFactory* s_Factory = nullptr;
+
+	if (s_Factory)
+		return s_Factory;
+
+	HRESULT hr = CoCreateInstance(
+		CLSID_WICImagingFactory,
+		nullptr,
+		CLSCTX_INPROC_SERVER,
+		__uuidof(IWICImagingFactory),
+		(LPVOID*)&s_Factory
+	);
+
+	if (FAILED(hr))
+	{
+		s_Factory = nullptr;
+		return nullptr;
+	}
+
+	return s_Factory;
+}
+
+//---------------------------------------------------------------------------------
+static DXGI_FORMAT _WICToDXGI(const GUID& guid)
+{
+	for (size_t i = 0; i < _countof(g_WICFormats); ++i)
+	{
+		if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0)
+			return g_WICFormats[i].format;
+	}
+
+	return DXGI_FORMAT_UNKNOWN;
+}
+
+//---------------------------------------------------------------------------------
+static size_t _WICBitsPerPixel(REFGUID targetGuid)
+{
+	IWICImagingFactory* pWIC = _GetWIC();
+	if (!pWIC)
+		return 0;
+
+	ScopedObject<IWICComponentInfo> cinfo;
+	if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo)))
+		return 0;
+
+	WICComponentType type;
+	if (FAILED(cinfo->GetComponentType(&type)))
+		return 0;
+
+	if (type != WICPixelFormat)
+		return 0;
+
+	ScopedObject<IWICPixelFormatInfo> pfinfo;
+	if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast<void**>(&pfinfo))))
+		return 0;
+
+	UINT bpp;
+	if (FAILED(pfinfo->GetBitsPerPixel(&bpp)))
+		return 0;
+
+	return bpp;
+}
+
+//---------------------------------------------------------------------------------
+static HRESULT CreateTextureFromWIC(_In_ ID3D11Device* d3dDevice,
+	_In_opt_ ID3D11DeviceContext* d3dContext,
+	_In_ IWICBitmapFrameDecode *frame,
+	_Out_opt_ ID3D11Resource** texture,
+	_Out_opt_ ID3D11ShaderResourceView** textureView,
+	_In_ size_t maxsize)
+{
+	UINT width, height;
+	HRESULT hr = frame->GetSize(&width, &height);
+	if (FAILED(hr))
+		return hr;
+
+	assert(width > 0 && height > 0);
+
+	if (!maxsize)
+	{
+		// This is a bit conservative because the hardware could support larger textures than
+		// the Feature Level defined minimums, but doing it this way is much easier and more
+		// performant for WIC than the 'fail and retry' model used by DDSTextureLoader
+
+		switch (d3dDevice->GetFeatureLevel())
+		{
+		case D3D_FEATURE_LEVEL_9_1:
+		case D3D_FEATURE_LEVEL_9_2:
+			maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
+			break;
+
+		case D3D_FEATURE_LEVEL_9_3:
+			maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
+			break;
+
+		case D3D_FEATURE_LEVEL_10_0:
+		case D3D_FEATURE_LEVEL_10_1:
+			maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
+			break;
+
+		default:
+			maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+			break;
+		}
+	}
+
+	assert(maxsize > 0);
+
+	UINT twidth, theight;
+	if (width > maxsize || height > maxsize)
+	{
+		float ar = static_cast<float>(height) / static_cast<float>(width);
+		if (width > height)
+		{
+			twidth = static_cast<UINT>(maxsize);
+			theight = static_cast<UINT>(static_cast<float>(maxsize) * ar);
+		}
+		else
+		{
+			theight = static_cast<UINT>(maxsize);
+			twidth = static_cast<UINT>(static_cast<float>(maxsize) / ar);
+		}
+		assert(twidth <= maxsize && theight <= maxsize);
+	}
+	else
+	{
+		twidth = width;
+		theight = height;
+	}
+
+	// Determine format
+	WICPixelFormatGUID pixelFormat;
+	hr = frame->GetPixelFormat(&pixelFormat);
+	if (FAILED(hr))
+		return hr;
+
+	WICPixelFormatGUID convertGUID;
+	memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID));
+
+	size_t bpp = 0;
+
+	DXGI_FORMAT format = _WICToDXGI(pixelFormat);
+	if (format == DXGI_FORMAT_UNKNOWN)
+	{
+		for (size_t i = 0; i < _countof(g_WICConvert); ++i)
+		{
+			if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0)
+			{
+				memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID));
+
+				format = _WICToDXGI(g_WICConvert[i].target);
+				assert(format != DXGI_FORMAT_UNKNOWN);
+				bpp = _WICBitsPerPixel(convertGUID);
+				break;
+			}
+		}
+
+		if (format == DXGI_FORMAT_UNKNOWN)
+			return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
+	}
+	else
+	{
+		bpp = _WICBitsPerPixel(pixelFormat);
+	}
+
+	if (!bpp)
+		return E_FAIL;
+
+	// Verify our target format is supported by the current device
+	// (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support)
+	UINT support = 0;
+	hr = d3dDevice->CheckFormatSupport(format, &support);
+	if (FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D))
+	{
+		// Fallback to RGBA 32-bit format which is supported by all devices
+		memcpy(&convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID));
+		format = DXGI_FORMAT_R8G8B8A8_UNORM;
+		bpp = 32;
+	}
+
+	// Allocate temporary memory for image
+	size_t rowPitch = (twidth * bpp + 7) / 8;
+	size_t imageSize = rowPitch * theight;
+
+	std::unique_ptr<uint8_t[]> temp(new uint8_t[imageSize]);
+
+	// Load image data
+	if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0
+		&& twidth == width
+		&& theight == height)
+	{
+		// No format conversion or resize needed
+		hr = frame->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
+		if (FAILED(hr))
+			return hr;
+	}
+	else if (twidth != width || theight != height)
+	{
+		// Resize
+		IWICImagingFactory* pWIC = _GetWIC();
+		if (!pWIC)
+			return E_NOINTERFACE;
+
+		ScopedObject<IWICBitmapScaler> scaler;
+		hr = pWIC->CreateBitmapScaler(&scaler);
+		if (FAILED(hr))
+			return hr;
+
+		hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant);
+		if (FAILED(hr))
+			return hr;
+
+		WICPixelFormatGUID pfScaler;
+		hr = scaler->GetPixelFormat(&pfScaler);
+		if (FAILED(hr))
+			return hr;
+
+		if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0)
+		{
+			// No format conversion needed
+			hr = scaler->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
+			if (FAILED(hr))
+				return hr;
+		}
+		else
+		{
+			ScopedObject<IWICFormatConverter> FC;
+			hr = pWIC->CreateFormatConverter(&FC);
+			if (FAILED(hr))
+				return hr;
+
+			hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom);
+			if (FAILED(hr))
+				return hr;
+
+			hr = FC->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
+			if (FAILED(hr))
+				return hr;
+		}
+	}
+	else
+	{
+		// Format conversion but no resize
+		IWICImagingFactory* pWIC = _GetWIC();
+		if (!pWIC)
+			return E_NOINTERFACE;
+
+		ScopedObject<IWICFormatConverter> FC;
+		hr = pWIC->CreateFormatConverter(&FC);
+		if (FAILED(hr))
+			return hr;
+
+		hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom);
+		if (FAILED(hr))
+			return hr;
+
+		hr = FC->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
+		if (FAILED(hr))
+			return hr;
+	}
+
+	// See if format is supported for auto-gen mipmaps (varies by feature level)
+	bool autogen = false;
+	if (d3dContext != 0 && textureView != 0) // Must have context and shader-view to auto generate mipmaps
+	{
+		UINT fmtSupport = 0;
+		hr = d3dDevice->CheckFormatSupport(format, &fmtSupport);
+		if (SUCCEEDED(hr) && (fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN))
+		{
+			autogen = true;
+		}
+	}
+
+	// Create texture
+	D3D11_TEXTURE2D_DESC desc;
+	desc.Width = twidth;
+	desc.Height = theight;
+	desc.MipLevels = (autogen) ? 0 : 1;
+	desc.ArraySize = 1;
+	desc.Format = format;
+	desc.SampleDesc.Count = 1;
+	desc.SampleDesc.Quality = 0;
+	desc.Usage = D3D11_USAGE_DEFAULT;
+	desc.BindFlags = (autogen) ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : (D3D11_BIND_SHADER_RESOURCE);
+	desc.CPUAccessFlags = 0;
+	desc.MiscFlags = (autogen) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
+
+	D3D11_SUBRESOURCE_DATA initData;
+	initData.pSysMem = temp.get();
+	initData.SysMemPitch = static_cast<UINT>(rowPitch);
+	initData.SysMemSlicePitch = static_cast<UINT>(imageSize);
+
+	ID3D11Texture2D* tex = nullptr;
+	hr = d3dDevice->CreateTexture2D(&desc, (autogen) ? nullptr : &initData, &tex);
+	if (SUCCEEDED(hr) && tex != 0)
+	{
+		if (textureView != 0)
+		{
+			D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
+			memset(&SRVDesc, 0, sizeof(SRVDesc));
+			SRVDesc.Format = format;
+			SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+			SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1;
+
+			hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
+			if (FAILED(hr))
+			{
+				tex->Release();
+				return hr;
+			}
+
+			if (autogen)
+			{
+				assert(d3dContext != 0);
+				d3dContext->UpdateSubresource(tex, 0, nullptr, temp.get(), static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize));
+				d3dContext->GenerateMips(*textureView);
+			}
+		}
+
+		if (texture != 0)
+		{
+			*texture = tex;
+		}
+		else
+		{
+#if defined(_DEBUG) || defined(PROFILE)
+			tex->SetPrivateData(WKPDID_D3DDebugObjectName,
+				sizeof("WICTextureLoader") - 1,
+				"WICTextureLoader"
+			);
+#endif
+			tex->Release();
+		}
+	}
+
+	return hr;
+}
+
+//--------------------------------------------------------------------------------------
+HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice,
+	_In_opt_ ID3D11DeviceContext* d3dContext,
+	_In_bytecount_(wicDataSize) const uint8_t* wicData,
+	_In_ size_t wicDataSize,
+	_Out_opt_ ID3D11Resource** texture,
+	_Out_opt_ ID3D11ShaderResourceView** textureView,
+	_In_ size_t maxsize
+)
+{
+	if (!d3dDevice || !wicData || (!texture && !textureView))
+	{
+		return E_INVALIDARG;
+	}
+
+	if (!wicDataSize)
+	{
+		return E_FAIL;
+	}
+
+#ifdef _M_AMD64
+	if (wicDataSize > 0xFFFFFFFF)
+		return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
+#endif
+
+	IWICImagingFactory* pWIC = _GetWIC();
+	if (!pWIC)
+		return E_NOINTERFACE;
+
+	// Create input stream for memory
+	ScopedObject<IWICStream> stream;
+	HRESULT hr = pWIC->CreateStream(&stream);
+	if (FAILED(hr))
+		return hr;
+
+	hr = stream->InitializeFromMemory(const_cast<uint8_t*>(wicData), static_cast<DWORD>(wicDataSize));
+	if (FAILED(hr))
+		return hr;
+
+	// Initialize WIC
+	ScopedObject<IWICBitmapDecoder> decoder;
+	hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder);
+	if (FAILED(hr))
+		return hr;
+
+	ScopedObject<IWICBitmapFrameDecode> frame;
+	hr = decoder->GetFrame(0, &frame);
+	if (FAILED(hr))
+		return hr;
+
+	hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize);
+	if (FAILED(hr))
+		return hr;
+
+#if defined(_DEBUG) || defined(PROFILE)
+	if (texture != 0 && *texture != 0)
+	{
+		(*texture)->SetPrivateData(WKPDID_D3DDebugObjectName,
+			sizeof("WICTextureLoader") - 1,
+			"WICTextureLoader"
+		);
+	}
+
+	if (textureView != 0 && *textureView != 0)
+	{
+		(*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName,
+			sizeof("WICTextureLoader") - 1,
+			"WICTextureLoader"
+		);
+	}
+#endif
+
+	return hr;
+}
+
+//--------------------------------------------------------------------------------------
+HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice,
+	_In_opt_ ID3D11DeviceContext* d3dContext,
+	_In_z_ const wchar_t* fileName,
+	_Out_opt_ ID3D11Resource** texture,
+	_Out_opt_ ID3D11ShaderResourceView** textureView,
+	_In_ size_t maxsize)
+{
+	if (!d3dDevice || !fileName || (!texture && !textureView))
+	{
+		return E_INVALIDARG;
+	}
+
+	IWICImagingFactory* pWIC = _GetWIC();
+	if (!pWIC)
+		return E_NOINTERFACE;
+
+	// Initialize WIC
+	ScopedObject<IWICBitmapDecoder> decoder;
+	HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder);
+	if (FAILED(hr))
+		return hr;
+
+	ScopedObject<IWICBitmapFrameDecode> frame;
+	hr = decoder->GetFrame(0, &frame);
+	if (FAILED(hr))
+		return hr;
+
+	hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize);
+	if (FAILED(hr))
+		return hr;
+
+#if defined(_DEBUG) || defined(PROFILE)
+	if (texture != 0 || textureView != 0)
+	{
+		CHAR strFileA[MAX_PATH];
+		WideCharToMultiByte(CP_ACP,
+			WC_NO_BEST_FIT_CHARS,
+			fileName,
+			-1,
+			strFileA,
+			MAX_PATH,
+			nullptr,
+			FALSE
+		);
+		const CHAR* pstrName = strrchr(strFileA, '\\');
+		if (!pstrName)
+		{
+			pstrName = strFileA;
+		}
+		else
+		{
+			pstrName++;
+		}
+
+		if (texture != 0 && *texture != 0)
+		{
+			(*texture)->SetPrivateData(WKPDID_D3DDebugObjectName,
+				static_cast<UINT>(strnlen_s(pstrName, MAX_PATH)),
+				pstrName
+			);
+		}
+
+		if (textureView != 0 && *textureView != 0)
+		{
+			(*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName,
+				static_cast<UINT>(strnlen_s(pstrName, MAX_PATH)),
+				pstrName
+			);
+		}
+	}
+#endif
+
+	return hr;
+}

+ 55 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h

@@ -0,0 +1,55 @@
+//--------------------------------------------------------------------------------------
+// File: WICTextureLoader.h
+//
+// Function for loading a WIC image and creating a Direct3D 11 runtime texture for it
+// (auto-generating mipmaps if possible)
+//
+// Note: Assumes application has already called CoInitializeEx
+//
+// Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for
+//          auto-gen mipmap support.
+//
+// Note these functions are useful for images created as simple 2D textures. For
+// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader.
+// For a full-featured DDS file reader, writer, and texture processing pipeline see
+// the 'Texconv' sample and the 'DirectXTex' library.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// http://go.microsoft.com/fwlink/?LinkId=248926
+// http://go.microsoft.com/fwlink/?LinkId=248929
+//--------------------------------------------------------------------------------------
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <d3d11.h>
+
+#pragma warning(push)
+#pragma warning(disable : 4005)
+#include <stdint.h>
+#pragma warning(pop)
+
+HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice,
+	_In_opt_ ID3D11DeviceContext* d3dContext,
+	_In_bytecount_(wicDataSize) const uint8_t* wicData,
+	_In_ size_t wicDataSize,
+	_Out_opt_ ID3D11Resource** texture,
+	_Out_opt_ ID3D11ShaderResourceView** textureView,
+	_In_ size_t maxsize = 0
+);
+
+HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice,
+	_In_opt_ ID3D11DeviceContext* d3dContext,
+	_In_z_ const wchar_t* szFileName,
+	_Out_opt_ ID3D11Resource** texture,
+	_Out_opt_ ID3D11ShaderResourceView** textureView,
+	_In_ size_t maxsize = 0
+);
+

+ 23 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl

@@ -0,0 +1,23 @@
+cbuffer ConstantBuffer : register(b0)
+{
+	matrix World;
+	matrix View;
+	matrix Projection;
+}
+
+struct VOut {
+	float4 pos : SV_POSITION;
+	float2 texcoord : TEXCOORD;
+};
+
+VOut main(float4 pos : POSITION, float2 texcoord : TEXCOORD)
+{
+	VOut output;
+
+	output.pos = mul(pos, World);
+	output.pos = mul(output.pos, View);
+	output.pos = mul(output.pos, Projection);
+	output.texcoord = texcoord;
+
+	return output;
+}

+ 518 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp

@@ -0,0 +1,518 @@
+// ---------------------------------------------------------------------------
+// Simple Assimp Directx11 Sample
+// This is a very basic sample and only reads diffuse texture
+// but this can load both embedded textures in fbx and non-embedded textures
+//
+//
+// Replace ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx") this with your
+// model name (line 480)
+// If your model isn't a fbx with embedded textures make sure your model's
+// textures are in same directory as your model
+//
+//
+// Written by IAS. :)
+// ---------------------------------------------------------------------------
+
+#include <Windows.h>
+#include <windowsx.h>
+#include <d3d11_1.h>
+#include <dxgi1_2.h>
+#include <DirectXMath.h>
+#include <d3dcompiler.h>
+#include "ModelLoader.h"
+
+#pragma comment (lib, "d3d11.lib")
+#pragma comment (lib, "Dxgi.lib")
+#pragma comment(lib,"d3dcompiler.lib")
+#pragma comment (lib, "dxguid.lib")
+
+using namespace DirectX;
+
+// ------------------------------------------------------------
+//                        Structs
+// ------------------------------------------------------------
+struct ConstantBuffer {
+	XMMATRIX mWorld;
+	XMMATRIX mView;
+	XMMATRIX mProjection;
+};
+
+// ------------------------------------------------------------
+//                        Window Variables
+// ------------------------------------------------------------
+#define SCREEN_WIDTH  800
+#define SCREEN_HEIGHT 600
+
+const char g_szClassName[] = "directxWindowClass";
+
+
+UINT width, height;
+HWND hwnd;
+
+// ------------------------------------------------------------
+//                        DirectX Variables
+// ------------------------------------------------------------
+D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
+D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
+ID3D11Device *dev;
+ID3D11Device1 *dev1;
+ID3D11DeviceContext *devcon;
+ID3D11DeviceContext1 *devcon1;
+IDXGISwapChain *swapchain;
+IDXGISwapChain1 *swapchain1;
+ID3D11RenderTargetView *backbuffer;
+ID3D11VertexShader *pVS;
+ID3D11PixelShader *pPS;
+ID3D11InputLayout *pLayout;
+ID3D11Buffer *pConstantBuffer;
+ID3D11Texture2D *g_pDepthStencil;
+ID3D11DepthStencilView *g_pDepthStencilView;
+ID3D11SamplerState *TexSamplerState;
+
+XMMATRIX m_World;
+XMMATRIX m_View;
+XMMATRIX m_Projection;
+
+// ------------------------------------------------------------
+//                      Function identifiers
+// ------------------------------------------------------------
+
+void InitD3D(HINSTANCE hinstance, HWND hWnd);
+void CleanD3D(void);
+void RenderFrame(void);
+
+void InitPipeline();
+void InitGraphics();
+
+HRESULT	CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob);
+void Throwanerror(LPCSTR errormessage);
+
+// ------------------------------------------------------------
+//                        Our Model
+// ------------------------------------------------------------
+
+ModelLoader *ourModel;
+
+LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	switch (msg)
+	{
+	case WM_CLOSE:
+		DestroyWindow(hwnd);
+		break;
+	case WM_DESTROY:
+		PostQuitMessage(0);
+		break;
+	default:
+		return DefWindowProc(hwnd, msg, wParam, lParam);
+	}
+	return 0;
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+	LPSTR lpCmdLine, int nCmdShow)
+{
+	WNDCLASSEX wc;
+	MSG msg;
+
+	wc.cbSize = sizeof(WNDCLASSEX);
+	wc.style = 0;
+	wc.lpfnWndProc = WndProc;
+	wc.cbClsExtra = 0;
+	wc.cbWndExtra = 0;
+	wc.hInstance = hInstance;
+	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+	wc.hbrBackground = NULL;
+	wc.lpszMenuName = NULL;
+	wc.lpszClassName = g_szClassName;
+	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+
+	if (!RegisterClassEx(&wc))
+	{
+		MessageBox(NULL, "Window Registration Failed!", "Error!",
+			MB_ICONEXCLAMATION | MB_OK);
+		return 0;
+	}
+
+	RECT wr = { 0,0, SCREEN_WIDTH, SCREEN_HEIGHT };
+	AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
+
+	hwnd = CreateWindowEx(
+		WS_EX_CLIENTEDGE,
+		g_szClassName,
+		" Simple Textured Directx11 Sample ",
+		WS_OVERLAPPEDWINDOW,
+		CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top,
+		NULL, NULL, hInstance, NULL
+	);
+
+	if (hwnd == NULL)
+	{
+		MessageBox(NULL, "Window Creation Failed!", "Error!",
+			MB_ICONEXCLAMATION | MB_OK);
+		return 0;
+	}
+
+	ShowWindow(hwnd, nCmdShow);
+	UpdateWindow(hwnd);
+
+	width = wr.right - wr.left;
+	height = wr.bottom - wr.top;
+
+	InitD3D(hInstance, hwnd);
+
+	while (true)
+	{
+
+		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+		{
+			TranslateMessage(&msg);
+			DispatchMessage(&msg);
+
+			if (msg.message == WM_QUIT)
+				break;
+		}
+
+		RenderFrame();
+	}
+
+	CleanD3D();
+
+	return msg.wParam;
+}
+
+void InitD3D(HINSTANCE hinstance, HWND hWnd)
+{
+	HRESULT hr;
+
+	UINT createDeviceFlags = 0;
+#ifdef _DEBUG
+	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+
+	D3D_DRIVER_TYPE driverTypes[] =
+	{
+		D3D_DRIVER_TYPE_HARDWARE,
+		D3D_DRIVER_TYPE_WARP,
+		D3D_DRIVER_TYPE_REFERENCE,
+	};
+	UINT numDriverTypes = ARRAYSIZE(driverTypes);
+
+	D3D_FEATURE_LEVEL featureLevels[] =
+	{
+		D3D_FEATURE_LEVEL_11_1,
+		D3D_FEATURE_LEVEL_11_0,
+		D3D_FEATURE_LEVEL_10_1,
+		D3D_FEATURE_LEVEL_10_0,
+	};
+	UINT numFeatureLevels = ARRAYSIZE(featureLevels);
+
+	for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
+	{
+		g_driverType = driverTypes[driverTypeIndex];
+		hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
+			D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon);
+
+		if (hr == E_INVALIDARG)
+		{
+			// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
+			hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
+				D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon);
+		}
+
+		if (SUCCEEDED(hr))
+			break;
+	}
+	if (FAILED(hr))
+		Throwanerror("Directx Device Creation Failed!");
+
+	UINT m4xMsaaQuality;
+	dev->CheckMultisampleQualityLevels(
+		DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality);
+
+
+	// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
+	IDXGIFactory1* dxgiFactory = nullptr;
+	{
+		IDXGIDevice* dxgiDevice = nullptr;
+		hr = dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
+		if (SUCCEEDED(hr))
+		{
+			IDXGIAdapter* adapter = nullptr;
+			hr = dxgiDevice->GetAdapter(&adapter);
+			if (SUCCEEDED(hr))
+			{
+				hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory));
+				adapter->Release();
+			}
+			dxgiDevice->Release();
+		}
+	}
+	if (FAILED(hr))
+		Throwanerror("DXGI Factory couldn't be obtained!");
+
+	// Create swap chain
+	IDXGIFactory2* dxgiFactory2 = nullptr;
+	hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2));
+	if (dxgiFactory2)
+	{
+		// DirectX 11.1 or later
+		hr = dev->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast<void**>(&dev1));
+		if (SUCCEEDED(hr))
+		{
+			(void)devcon->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(&devcon1));
+		}
+
+		DXGI_SWAP_CHAIN_DESC1 sd;
+		ZeroMemory(&sd, sizeof(sd));
+		sd.Width = SCREEN_WIDTH;
+		sd.Height = SCREEN_HEIGHT;
+		sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+		sd.SampleDesc.Count = 4;
+		sd.SampleDesc.Quality = m4xMsaaQuality - 1;
+		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+		sd.BufferCount = 1;
+
+		hr = dxgiFactory2->CreateSwapChainForHwnd(dev, hWnd, &sd, nullptr, nullptr, &swapchain1);
+		if (SUCCEEDED(hr))
+		{
+			hr = swapchain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast<void**>(&swapchain));
+		}
+
+		dxgiFactory2->Release();
+	}
+	else
+	{
+		// DirectX 11.0 systems
+		DXGI_SWAP_CHAIN_DESC sd;
+		ZeroMemory(&sd, sizeof(sd));
+		sd.BufferCount = 1;
+		sd.BufferDesc.Width = SCREEN_WIDTH;
+		sd.BufferDesc.Height = SCREEN_HEIGHT;
+		sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+		sd.BufferDesc.RefreshRate.Numerator = 60;
+		sd.BufferDesc.RefreshRate.Denominator = 1;
+		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+		sd.OutputWindow = hWnd;
+		sd.SampleDesc.Count = 1;
+		sd.SampleDesc.Quality = m4xMsaaQuality - 1;
+		sd.Windowed = TRUE;
+
+		hr = dxgiFactory->CreateSwapChain(dev, &sd, &swapchain);
+	}
+
+	// Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut
+	dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
+
+	dxgiFactory->Release();
+
+	if (FAILED(hr))
+		Throwanerror("Swapchain Creation Failed!");
+
+	ID3D11Texture2D *pBackBuffer;
+	swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
+
+	dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
+	pBackBuffer->Release();
+
+	D3D11_TEXTURE2D_DESC descDepth;
+	ZeroMemory(&descDepth, sizeof(descDepth));
+	descDepth.Width = SCREEN_WIDTH;
+	descDepth.Height = SCREEN_HEIGHT;
+	descDepth.MipLevels = 1;
+	descDepth.ArraySize = 1;
+	descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
+	descDepth.SampleDesc.Count = 4;
+	descDepth.SampleDesc.Quality = m4xMsaaQuality - 1;
+	descDepth.Usage = D3D11_USAGE_DEFAULT;
+	descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+	descDepth.CPUAccessFlags = 0;
+	descDepth.MiscFlags = 0;
+	hr = dev->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencil);
+	if (FAILED(hr))
+		Throwanerror("Depth Stencil Texture couldn't be created!");
+
+	// Create the depth stencil view
+	D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
+	ZeroMemory(&descDSV, sizeof(descDSV));
+	descDSV.Format = descDepth.Format;
+	descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+	descDSV.Texture2D.MipSlice = 0;
+	hr = dev->CreateDepthStencilView(g_pDepthStencil, 0, &g_pDepthStencilView);
+	if (FAILED(hr))
+	{
+		Throwanerror("Depth Stencil View couldn't be created!");
+	}
+
+	devcon->OMSetRenderTargets(1, &backbuffer, g_pDepthStencilView);
+
+	D3D11_RASTERIZER_DESC rasterDesc;
+	ID3D11RasterizerState *rasterState;
+	rasterDesc.AntialiasedLineEnable = false;
+	rasterDesc.CullMode = D3D11_CULL_BACK;
+	rasterDesc.DepthBias = 0;
+	rasterDesc.DepthBiasClamp = 0.0f;
+	rasterDesc.DepthClipEnable = true;
+	rasterDesc.FillMode = D3D11_FILL_SOLID;
+	rasterDesc.FrontCounterClockwise = false;
+	rasterDesc.MultisampleEnable = false;
+	rasterDesc.ScissorEnable = false;
+	rasterDesc.SlopeScaledDepthBias = 0.0f;
+
+	dev->CreateRasterizerState(&rasterDesc, &rasterState);
+	devcon->RSSetState(rasterState);
+
+	D3D11_VIEWPORT viewport;
+	ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
+
+	viewport.TopLeftX = 0;
+	viewport.TopLeftY = 0;
+	viewport.MinDepth = 0.0f;
+	viewport.MaxDepth = 1.0f;
+	viewport.Width = SCREEN_WIDTH;
+	viewport.Height = SCREEN_HEIGHT;
+
+	devcon->RSSetViewports(1, &viewport);
+
+	InitPipeline();
+	InitGraphics();
+}
+
+void CleanD3D(void)
+{
+	swapchain->SetFullscreenState(FALSE, NULL);
+
+	ourModel->Close();
+	g_pDepthStencil->Release();
+	g_pDepthStencilView->Release();
+	pLayout->Release();
+	pVS->Release();
+	pPS->Release();
+	pConstantBuffer->Release();
+	swapchain->Release();
+	backbuffer->Release();
+	dev->Release();
+	devcon->Release();
+}
+
+void RenderFrame(void)
+{
+	static float t = 0.0f;
+	static ULONGLONG timeStart = 0;
+	ULONGLONG timeCur = GetTickCount64();
+	if (timeStart == 0)
+		timeStart = timeCur;
+	t = (timeCur - timeStart) / 1000.0f;
+
+	float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
+	devcon->ClearRenderTargetView(backbuffer, clearColor);
+	devcon->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
+
+	devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+	m_World = XMMatrixRotationY(-t);
+
+	ConstantBuffer cb;
+	cb.mWorld = XMMatrixTranspose(m_World);
+	cb.mView = XMMatrixTranspose(m_View);
+	cb.mProjection = XMMatrixTranspose(m_Projection);
+	devcon->UpdateSubresource(pConstantBuffer, 0, nullptr, &cb, 0, 0);
+
+	devcon->VSSetShader(pVS, 0, 0);
+	devcon->VSSetConstantBuffers(0, 1, &pConstantBuffer);
+	devcon->PSSetShader(pPS, 0, 0);
+	devcon->PSSetSamplers(0, 1, &TexSamplerState);
+	ourModel->Draw(devcon);
+
+	swapchain->Present(0, 0);
+}
+
+void InitPipeline()
+{
+	ID3DBlob *VS, *PS;
+	CompileShaderFromFile(L"VertexShader.hlsl", 0, "main", "vs_4_0", &VS);
+	CompileShaderFromFile(L"PixelShader.hlsl", 0, "main", "ps_4_0", &PS);
+
+	dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
+	dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);
+
+	D3D11_INPUT_ELEMENT_DESC ied[] =
+	{
+		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
+	};
+
+	dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
+	devcon->IASetInputLayout(pLayout);
+}
+
+void InitGraphics()
+{
+	HRESULT hr;
+
+	m_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.01f, 1000.0f);
+
+	D3D11_BUFFER_DESC bd;
+	ZeroMemory(&bd, sizeof(bd));
+
+	bd.Usage = D3D11_USAGE_DEFAULT;
+	bd.ByteWidth = sizeof(ConstantBuffer);
+	bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+	bd.CPUAccessFlags = 0;
+
+	hr = dev->CreateBuffer(&bd, nullptr, &pConstantBuffer);
+	if (FAILED(hr))
+		Throwanerror("Constant buffer couldn't be created");
+
+	D3D11_SAMPLER_DESC sampDesc;
+	ZeroMemory(&sampDesc, sizeof(sampDesc));
+	sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+	sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+	sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+	sampDesc.MinLOD = 0;
+	sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
+
+	hr = dev->CreateSamplerState(&sampDesc, &TexSamplerState);
+	if (FAILED(hr))
+		Throwanerror("Texture sampler state couldn't be created");
+
+	XMVECTOR Eye = XMVectorSet(0.0f, 5.0f, -300.0f, 0.0f);
+	XMVECTOR At = XMVectorSet(0.0f, 100.0f, 0.0f, 0.0f);
+	XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
+	m_View = XMMatrixLookAtLH(Eye, At, Up);
+
+	ourModel = new ModelLoader;
+	if (!ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx"))
+		Throwanerror("Model couldn't be loaded");
+}
+
+HRESULT	CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob)
+{
+	UINT compileFlags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR;
+	
+#ifdef _DEBUG
+	compileFlags |= D3DCOMPILE_DEBUG;
+#endif
+
+	ID3DBlob* pErrorBlob = NULL;
+
+	HRESULT result = D3DCompileFromFile(pFileName, pDefines, D3D_COMPILE_STANDARD_FILE_INCLUDE, pEntryPoint, pShaderModel, compileFlags, 0, ppBytecodeBlob, &pErrorBlob);
+	if (FAILED(result))
+	{
+		if (pErrorBlob != NULL)
+			OutputDebugStringA((LPCSTR)pErrorBlob->GetBufferPointer());
+	}
+
+	if (pErrorBlob != NULL)
+		pErrorBlob->Release();
+
+	return result;
+}
+
+void Throwanerror(LPCSTR errormessage)
+{
+	MessageBox(hwnd, errormessage, "Error!", MB_ICONERROR | MB_OK);
+}

+ 28 - 4
test/unit/utObjTools.cpp

@@ -51,13 +51,23 @@ class utObjTools : public ::testing::Test {
 
 class TestObjFileParser : public ObjFileParser {
 public:
-    TestObjFileParser() : ObjFileParser(){}
-    ~TestObjFileParser() {}
+    TestObjFileParser() : ObjFileParser(){
+        // empty
+    }
+
+    ~TestObjFileParser() {
+        // empty
+    }
+    
     void testCopyNextWord( char *pBuffer, size_t length ) {
         copyNextWord( pBuffer, length );
     }
 
+    size_t testGetNumComponentsInDataDefinition() {
+        return getNumComponentsInDataDefinition();
+    }
 };
+
 TEST_F( utObjTools, skipDataLine_OneLine_Success ) {
     std::vector<char> buffer;
     std::string data( "v -0.5 -0.5 0.5\nend" );
@@ -71,7 +81,7 @@ TEST_F( utObjTools, skipDataLine_OneLine_Success ) {
 
 TEST_F( utObjTools, skipDataLine_TwoLines_Success ) {
     TestObjFileParser test_parser;
-    std::string data( "vn -2.061493116917992e-15 -0.9009688496589661 \\n-0.4338837265968323" );
+    std::string data( "vn -2.061493116917992e-15 -0.9009688496589661 \\\n-0.4338837265968323" );
     std::vector<char> buffer;
     buffer.resize( data.size() );
     ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() );
@@ -90,4 +100,18 @@ TEST_F( utObjTools, skipDataLine_TwoLines_Success ) {
 
     test_parser.testCopyNextWord( data_buffer, Size );
     EXPECT_EQ( data_buffer[ 0 ], '-' );
-}
+}
+
+TEST_F( utObjTools, countComponents_TwoLines_Success ) {
+    TestObjFileParser test_parser;
+    std::string data( "-2.061493116917992e-15 -0.9009688496589661 \\\n-0.4338837265968323" );
+    std::vector<char> buffer;
+    buffer.resize( data.size() );
+    ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() );
+    test_parser.setBuffer( buffer );
+    static const size_t Size = 4096UL;
+    char data_buffer[ Size ];
+
+    size_t numComps = test_parser.testGetNumComponentsInDataDefinition();
+    EXPECT_EQ( 3U, numComps );
+}

+ 3 - 2
test/unit/utPMXImporter.cpp

@@ -52,8 +52,9 @@ class utPMXImporter : public AbstractImportExportBase {
 public:
     virtual bool importerTest() {
         Assimp::Importer importer;
-        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/../models-nonbsd/MMD/Alicia_blade.pmx", 0 );
-        return nullptr != scene;
+        /*const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/../models-nonbsd/MMD/Alicia_blade.pmx", 0 );
+        return nullptr != scene;*/
+        return true;
     }
 };
 

+ 2 - 0
tools/assimp_view/Display.cpp

@@ -43,6 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "SceneAnimator.h"
 #include "StringUtils.h"
 
+#include <commdlg.h>
+
 namespace AssimpView {
 
 using namespace Assimp;

+ 2 - 0
tools/assimp_view/LogWindow.cpp

@@ -41,6 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "assimp_view.h"
 #include "richedit.h"
+#include <commoncontrols.h>
+#include <commdlg.h>
 
 namespace AssimpView {
 

+ 2 - 0
tools/assimp_view/MessageProc.cpp

@@ -44,6 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <algorithm>
 
 #include <windowsx.h>
+#include <commdlg.h>
+#include <timeapi.h>
 
 namespace AssimpView {
 

+ 11 - 5
tools/assimp_view/SceneAnimator.h

@@ -72,20 +72,26 @@ struct SceneAnimNode
     size_t mChannelIndex;
 
     //! Default construction
-    SceneAnimNode() {
-        mChannelIndex = -1; mParent = NULL;
+    SceneAnimNode()
+    : mName()
+    , mParent(NULL)
+    , mChannelIndex(-1) {
+        // empty
     }
 
     //! Construction from a given name
     SceneAnimNode( const std::string& pName)
-        : mName( pName) {
-            mChannelIndex = -1; mParent = NULL;
+    : mName( pName)
+    , mParent(NULL)
+    , mChannelIndex( -1 ) {
+        // empty
     }
 
     //! Destruct all children recursively
     ~SceneAnimNode() {
-        for( std::vector<SceneAnimNode*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
+        for (std::vector<SceneAnimNode*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) {
             delete *it;
+        }
     }
 };
 

+ 1 - 0
tools/assimp_view/assimp_view.cpp

@@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "assimp_view.h"
+#include <timeapi.h>
 #include "StringUtils.h"
 #include <map>