From 9eb0a3f3d55cd4d2a0521dbba6cd148ae821a2ce Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 23 May 2017 15:34:02 +0200 Subject: [PATCH 01/62] Fix error when custom CMAKE_C_FLAGS is specified --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c1804159..53585ccbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,7 +178,7 @@ ENDIF( UNIX ) IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) # hide all not-exported symbols SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -std=c++0x") - SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -fPIC) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") SET(LIBSTDC++_LIBRARIES -lstdc++) ELSEIF(MSVC) # enable multi-core compilation with MSVC From 96839bd8607ba0e927979f0a1a24438ed255ebe0 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 26 May 2017 20:29:21 +0200 Subject: [PATCH 02/62] Unittests: fix import material test. --- test/unit/utBlendImportMaterials.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/utBlendImportMaterials.cpp b/test/unit/utBlendImportMaterials.cpp index dd67482ed..6e1033453 100644 --- a/test/unit/utBlendImportMaterials.cpp +++ b/test/unit/utBlendImportMaterials.cpp @@ -86,8 +86,8 @@ TEST_F(BlendImportMaterials, testImportMaterial) ASSERT_PROPERTY_EQ(aiColor3D(0.1f, 0.2f, 0.3f), "diffuse.color", diffuseColor); ASSERT_PROPERTY_EQ(0.4f, "diffuse.intensity", diffuseIntensity); - ASSERT_PROPERTY_EQ(1U, "diffuse.shader", diffuseShader); - ASSERT_PROPERTY_EQ(0U, "diffuse.ramp", diffuseRamp); + ASSERT_PROPERTY_EQ(1, "diffuse.shader", diffuseShader); + ASSERT_PROPERTY_EQ(0, "diffuse.ramp", diffuseRamp); ASSERT_PROPERTY_EQ(aiColor3D(0.5f, 0.6f, 0.7f), "specular.color", specularColor); ASSERT_PROPERTY_EQ(0.8f, "specular.intensity", specularIntensity); From 3d99892b94f1691572a630ad5a1d70fe83b76e46 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 27 May 2017 19:37:28 +0200 Subject: [PATCH 03/62] Opj-Importer: fix coverity finding. --- code/ObjFileParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index b246dc5e5..0dfd8625b 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -64,7 +64,7 @@ ObjFileParser::ObjFileParser() , m_uiLine( 0 ) , m_pIO( nullptr ) , m_progress( nullptr ) -, m_originalObjFileName( "" ) { +, m_originalObjFileName() { // empty } From 8cc80a3d9c067a2fd652af1af7c81636ce1157c6 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 28 May 2017 14:14:22 +0200 Subject: [PATCH 04/62] ObjImporter: fix the build. --- code/ObjFileParser.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/ObjFileParser.h b/code/ObjFileParser.h index ed8e7a032..64dc18c8e 100644 --- a/code/ObjFileParser.h +++ b/code/ObjFileParser.h @@ -154,9 +154,8 @@ private: IOSystem *m_pIO; //! Pointer to progress handler ProgressHandler* m_progress; - /// Path to the current model - // name of the obj file where the buffer comes from - const std::string& m_originalObjFileName; + /// Path to the current model, name of the obj file where the buffer comes from + const std::string m_originalObjFileName; }; } // Namespace Assimp From d30b1e585c10c4b4d4d9137c1ae91d273b22ecd6 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 28 May 2017 22:25:06 +0200 Subject: [PATCH 05/62] Tests how o adress this topic. --- code/ObjFileParser.cpp | 29 ++++++++++++++++++++++++----- code/ObjFileParser.h | 4 ++-- test/unit/utObjTools.cpp | 30 +++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 0dfd8625b..08835debc 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -161,7 +161,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { { ++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); @@ -274,21 +274,40 @@ 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 ) ) { + return false; + } + } else { + return IsLineEnd( tmp ); + } + return false; +} + +size_t ObjFileParser::getNumComponentsInDataDefinition() { size_t numComponents( 0 ); const char* tmp( &m_DataIt[0] ); - while( !IsLineEnd( *tmp ) ) { + while ( !isDataDefinitionEnd( tmp ) ) { + //while( !IsLineEnd( *tmp ) ) { 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 &point3d_array ) { - size_t numComponents = getNumComponentsInLine(); + size_t numComponents = getNumComponentsInDataDefinition(); ai_real x, y, z; if( 2 == numComponents ) { copyNextWord( m_buffer, Buffersize ); diff --git a/code/ObjFileParser.h b/code/ObjFileParser.h index 64dc18c8e..fa5b3ca31 100644 --- a/code/ObjFileParser.h +++ b/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 &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 diff --git a/test/unit/utObjTools.cpp b/test/unit/utObjTools.cpp index cacace49d..f916d7ef4 100644 --- a/test/unit/utObjTools.cpp +++ b/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 buffer; std::string data( "v -0.5 -0.5 0.5\nend" ); @@ -90,4 +100,18 @@ TEST_F( utObjTools, skipDataLine_TwoLines_Success ) { test_parser.testCopyNextWord( data_buffer, Size ); EXPECT_EQ( data_buffer[ 0 ], '-' ); -} \ No newline at end of file +} + +TEST_F( utObjTools, countComponents_TwoLines_Success ) { + TestObjFileParser test_parser; + std::string data( "-2.061493116917992e-15 -0.9009688496589661 \\n-0.4338837265968323" ); + std::vector 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 ); +} From c121cec68ac671c4542fe06c4e52050d1ebc4506 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 29 May 2017 22:00:13 +0200 Subject: [PATCH 06/62] Obj-Importer: introduce working test for line breaks. --- code/Assimp.cpp | 31 ++++++++++++------------------- code/ObjFileParser.cpp | 17 +++++++++++------ test/unit/utObjTools.cpp | 4 ++-- test/unit/utPMXImporter.cpp | 5 +++-- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/code/Assimp.cpp b/code/Assimp.cpp index 11dd5b939..9269f905e 100644 --- a/code/Assimp.cpp +++ b/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( 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; } diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 08835debc..decfacbf5 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -277,11 +277,10 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { static bool isDataDefinitionEnd( const char *tmp ) { if ( *tmp == '\\' ) { tmp++; - if ( IsLineEnd( tmp ) ) { - return false; + if ( IsLineEnd( *tmp ) ) { + tmp++; + return true; } - } else { - return IsLineEnd( tmp ); } return false; } @@ -289,8 +288,14 @@ static bool isDataDefinitionEnd( const char *tmp ) { size_t ObjFileParser::getNumComponentsInDataDefinition() { size_t numComponents( 0 ); const char* tmp( &m_DataIt[0] ); - while ( !isDataDefinitionEnd( tmp ) ) { - //while( !IsLineEnd( *tmp ) ) { + bool end_of_definition = false; + while ( !end_of_definition ) { + //while( !IsLineEnd( *tmp ) ) { + if ( isDataDefinitionEnd( tmp ) ) { + tmp += 2; + } else if ( IsLineEnd( *tmp ) ) { + end_of_definition = true; + } if ( !SkipSpaces( &tmp ) ) { break; } diff --git a/test/unit/utObjTools.cpp b/test/unit/utObjTools.cpp index f916d7ef4..89bb19aa0 100644 --- a/test/unit/utObjTools.cpp +++ b/test/unit/utObjTools.cpp @@ -81,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 buffer; buffer.resize( data.size() ); ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() ); @@ -104,7 +104,7 @@ TEST_F( utObjTools, skipDataLine_TwoLines_Success ) { TEST_F( utObjTools, countComponents_TwoLines_Success ) { TestObjFileParser test_parser; - std::string data( "-2.061493116917992e-15 -0.9009688496589661 \\n-0.4338837265968323" ); + std::string data( "-2.061493116917992e-15 -0.9009688496589661 \\\n-0.4338837265968323" ); std::vector buffer; buffer.resize( data.size() ); ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() ); diff --git a/test/unit/utPMXImporter.cpp b/test/unit/utPMXImporter.cpp index 725279e47..72916b8ef 100644 --- a/test/unit/utPMXImporter.cpp +++ b/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; } }; From 813f3b8248d8b3f7ef8f641b1ef004c99c8bc9fe Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 30 May 2017 21:10:33 +0200 Subject: [PATCH 07/62] ObjLoader: improve performance of obj-import. --- code/IOStreamBuffer.h | 32 +++++++++++++++++++++++--------- code/ObjFileParser.cpp | 17 +++++++---------- code/ObjTools.h | 7 ++++++- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/code/IOStreamBuffer.h b/code/IOStreamBuffer.h index d8c7d00ab..d8728aee3 100644 --- a/code/IOStreamBuffer.h +++ b/code/IOStreamBuffer.h @@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "ParsingUtils.h" +#include + namespace Assimp { // --------------------------------------------------------------------------- @@ -54,6 +56,8 @@ namespace Assimp { template class IOStreamBuffer { public: + typedef typename std::vector::iterator CacheIter; + /// @brief The class constructor. IOStreamBuffer( size_t cache = 4096 * 4096 ); @@ -69,8 +73,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 +100,7 @@ public: /// @brief Will read the next line. /// @param buffer The buffer for the next line. /// @return true if successful. - bool getNextLine( std::vector &buffer ); + bool getNextLine( CacheIter &begin, CacheIter &end ); private: IOStream *m_stream; @@ -106,6 +110,7 @@ private: size_t m_blockIdx; std::vector m_cache; size_t m_cachePos; + CacheIter m_it; size_t m_filePos; }; @@ -118,6 +123,7 @@ IOStreamBuffer::IOStreamBuffer( size_t cache ) , m_numBlocks( 0 ) , m_blockIdx( 0 ) , m_cachePos( 0 ) +, m_it() , m_filePos( 0 ) { m_cache.resize( cache ); std::fill( m_cache.begin(), m_cache.end(), '\n' ); @@ -203,6 +209,7 @@ bool IOStreamBuffer::readNextBlock() { m_filePos += m_cacheSize; m_cachePos = 0; m_blockIdx++; + m_it = m_cache.begin(); return true; } @@ -227,25 +234,32 @@ size_t IOStreamBuffer::getFilePos() const { template inline -bool IOStreamBuffer::getNextLine( std::vector &buffer ) { - buffer.resize( m_cacheSize ); +bool IOStreamBuffer::getNextLine( CacheIter &begin, CacheIter &end ) { if ( m_cachePos == m_cacheSize || 0 == m_filePos ) { if ( !readNextBlock() ) { + begin = m_it; + end = m_it; return false; } + m_it = m_cache.begin(); } - size_t i = 0; + + //size_t i = 0; + begin = m_it; while ( !IsLineEnd( m_cache[ m_cachePos ] ) ) { - buffer[ i ] = m_cache[ m_cachePos ]; m_cachePos++; - i++; + ++m_it; + //i++; if ( m_cachePos >= m_cacheSize ) { if ( !readNextBlock() ) { + begin = m_it; + end = m_it; return false; } } } - buffer[ i ] = '\n'; + ++m_it; + end = m_it; m_cachePos++; return true; diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index decfacbf5..44d171dcc 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -109,7 +109,7 @@ ObjFile::Model *ObjFileParser::GetModel() const { return m_pModel; } -void ignoreNewLines(IOStreamBuffer &streamBuffer, std::vector &buffer) +/*void ignoreNewLines(IOStreamBuffer &streamBuffer, std::vector &buffer) { auto curPosition = buffer.begin(); do @@ -129,7 +129,7 @@ void ignoreNewLines(IOStreamBuffer &streamBuffer, std::vector &buffe std::copy(tempBuf.cbegin(), tempBuf.cend(), ++curPosition); } } while (*curPosition!='\n'); -} +}*/ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { // only update every 100KB or it'll be too slow @@ -141,11 +141,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { unsigned int processed = 0; size_t lastFilePos( 0 ); - std::vector buffer; - while ( streamBuffer.getNextLine( buffer ) ) { - m_DataIt = buffer.begin(); - m_DataItEnd = buffer.end(); - + while ( streamBuffer.getNextLine( m_DataIt, m_DataItEnd ) ) { // Handle progress reporting const size_t filePos( streamBuffer.getFilePos() ); if ( lastFilePos < filePos ) { @@ -245,7 +241,6 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { default: { pf_skip_line: - m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); } break; @@ -595,14 +590,16 @@ void ObjFileParser::getMaterialDesc() { // ------------------------------------------------------------------- // Get a comment, values will be skipped void ObjFileParser::getComment() { - while (m_DataIt != m_DataItEnd) { + m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); + +/* while (m_DataIt != m_DataItEnd) { if ( '\n' == (*m_DataIt)) { ++m_DataIt; break; } else { ++m_DataIt; } - } + }*/ } // ------------------------------------------------------------------- diff --git a/code/ObjTools.h b/code/ObjTools.h index 7b0bdcedf..1be518700 100644 --- a/code/ObjTools.h +++ b/code/ObjTools.h @@ -115,6 +115,9 @@ template inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) { while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) { ++it; + if ( *it == '\n' ) { + ++it; + } } if ( it != end ) { @@ -122,8 +125,10 @@ inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) { ++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; } From 82380084c5c7fcae57dfda452e5cd746371498d6 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 31 May 2017 16:36:08 +0200 Subject: [PATCH 08/62] ObjImporter: next try for multiple line stuff. --- code/IOStreamBuffer.h | 27 ++++++++++++++++++++++++--- code/ObjFileParser.cpp | 4 ++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/code/IOStreamBuffer.h b/code/IOStreamBuffer.h index d8c7d00ab..98ed11267 100644 --- a/code/IOStreamBuffer.h +++ b/code/IOStreamBuffer.h @@ -96,7 +96,7 @@ public: /// @brief Will read the next line. /// @param buffer The buffer for the next line. /// @return true if successful. - bool getNextLine( std::vector &buffer ); + bool getNextDataLine( std::vector &buffer, T continuationToken ); private: IOStream *m_stream; @@ -227,15 +227,35 @@ size_t IOStreamBuffer::getFilePos() const { template inline -bool IOStreamBuffer::getNextLine( std::vector &buffer ) { +bool IOStreamBuffer::getNextDataLine( std::vector &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; + } + if ( IsLineEnd( m_cache[ m_cachePos ] ) ) { + if ( !continuationFound ) { + // the end of the data line + i++; + break; + } else { + // skip line end + while ( m_cache[m_cachePos] != '\n') { + ++m_cachePos; + } + ++m_cachePos; + break; + } + } + buffer[ i ] = m_cache[ m_cachePos ]; m_cachePos++; i++; @@ -245,6 +265,7 @@ bool IOStreamBuffer::getNextLine( std::vector &buffer ) { } } } + buffer[ i ] = '\n'; m_cachePos++; diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index decfacbf5..3289708cf 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -123,7 +123,7 @@ void ignoreNewLines(IOStreamBuffer &streamBuffer, std::vector &buffe std::vector tempBuf; do { - streamBuffer.getNextLine(tempBuf); + streamBuffer.getNextDataLine(tempBuf, '\\' ); } while (tempBuf[0]=='\n'); *curPosition = ' '; std::copy(tempBuf.cbegin(), tempBuf.cend(), ++curPosition); @@ -142,7 +142,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { size_t lastFilePos( 0 ); std::vector buffer; - while ( streamBuffer.getNextLine( buffer ) ) { + while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) { m_DataIt = buffer.begin(); m_DataItEnd = buffer.end(); From 4dc7940ac5d7acce7129041b68b7e535e10b5f2d Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 31 May 2017 20:28:00 +0200 Subject: [PATCH 09/62] ObjImporter: fix dead code. --- code/IOStreamBuffer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/code/IOStreamBuffer.h b/code/IOStreamBuffer.h index bd622b05c..b80810084 100644 --- a/code/IOStreamBuffer.h +++ b/code/IOStreamBuffer.h @@ -231,7 +231,6 @@ template inline bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationToken ) { buffer.resize( m_cacheSize ); - //std::fill( buffer.begin(), buffer.end(), ' ' ); if ( m_cachePos == m_cacheSize || 0 == m_filePos ) { if ( !readNextBlock() ) { return false; From 1207a81b70d0a0cfe6d4eba879d361657bb2ed47 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 31 May 2017 21:37:16 +0200 Subject: [PATCH 10/62] ObjImporter: remove dead code. --- code/ObjFileParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 0dfd8625b..1cefd3c28 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -154,7 +154,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { progressCounter++; m_progress->UpdateFileRead( progressOffset + processed * 2, progressTotal ); } - //ignoreNewLines(streamBuffer, buffer); + // parse line switch (*m_DataIt) { case 'v': // Parse a vertex texture coordinate From 9e98097aae7216119055d117d44b976df1ff57ee Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 31 May 2017 21:43:41 +0200 Subject: [PATCH 11/62] closes https://github.com/assimp/assimp/issues/1244: log error for overflow. --- code/ObjFileParser.cpp | 14 -------------- code/fast_atof.h | 13 ++++++++++--- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 1f333d97f..5f95bb96d 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -289,7 +289,6 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() { const char* tmp( &m_DataIt[0] ); bool end_of_definition = false; while ( !end_of_definition ) { - //while( !IsLineEnd( *tmp ) ) { if ( isDataDefinitionEnd( tmp ) ) { tmp += 2; } else if ( IsLineEnd( *tmp ) ) { @@ -420,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( m_DataIt, m_DataItEnd ); if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) { return; @@ -595,15 +590,6 @@ void ObjFileParser::getMaterialDesc() { // Get a comment, values will be skipped void ObjFileParser::getComment() { m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); - -/* while (m_DataIt != m_DataItEnd) { - if ( '\n' == (*m_DataIt)) { - ++m_DataIt; - break; - } else { - ++m_DataIt; - } - }*/ } // ------------------------------------------------------------------- diff --git a/code/fast_atof.h b/code/fast_atof.h index 965ff0717..be1e59221 100644 --- a/code/fast_atof.h +++ b/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 #include "StringComparison.h" +#include #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; From ca5ac0b5324773a9b4074fdf9fc676cafd0cf566 Mon Sep 17 00:00:00 2001 From: Leo Terziman Date: Thu, 1 Jun 2017 09:47:50 +0200 Subject: [PATCH 12/62] Fixed bug where IFC models with multiple IFCSite only loaded 1 site instead of the complete model --- code/IFCLoader.cpp | 57 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/code/IFCLoader.cpp b/code/IFCLoader.cpp index 24c5452b2..463803ab3 100644 --- a/code/IFCLoader.cpp +++ b/code/IFCLoader.cpp @@ -882,6 +882,7 @@ void ProcessSpatialStructures(ConversionData& conv) } } + std::vector nodes; for(const STEP::LazyObject* lz : *range) { const IfcSpatialStructureElement* const prod = lz->ToPtr(); @@ -890,20 +891,19 @@ void ProcessSpatialStructures(ConversionData& conv) } IFCImporter::LogDebug("looking at spatial structure `" + (prod->Name ? prod->Name.Get() : "unnamed") + "`" + (prod->ObjectType? " which is of type " + prod->ObjectType.Get():"")); - // the primary site is referenced by an IFCRELAGGREGATES element which assigns it to the IFCPRODUCT + // the primary sites are referenced by an IFCRELAGGREGATES element which assigns them to the IFCPRODUCT const STEP::DB::RefMap& refs = conv.db.GetRefs(); - STEP::DB::RefMapRange range = refs.equal_range(conv.proj.GetID()); - for(;range.first != range.second; ++range.first) { - if(const IfcRelAggregates* const aggr = conv.db.GetObject((*range.first).second)->ToPtr()) { + STEP::DB::RefMapRange ref_range = refs.equal_range(conv.proj.GetID()); + for(; ref_range.first != ref_range.second; ++ref_range.first) { + if(const IfcRelAggregates* const aggr = conv.db.GetObject((*ref_range.first).second)->ToPtr()) { for(const IfcObjectDefinition& def : aggr->RelatedObjects) { // comparing pointer values is not sufficient, we would need to cast them to the same type first // as there is multiple inheritance in the game. if (def.GetID() == prod->GetID()) { IFCImporter::LogDebug("selecting this spatial structure as root structure"); - // got it, this is the primary site. - conv.out->mRootNode = ProcessSpatialStructure(NULL,*prod,conv,NULL); - return; + // got it, this is one primary site. + nodes.push_back(ProcessSpatialStructure(NULL, *prod, conv, NULL)); } } @@ -911,19 +911,42 @@ void ProcessSpatialStructures(ConversionData& conv) } } + size_t nb_nodes = nodes.size(); - IFCImporter::LogWarn("failed to determine primary site element, taking the first IfcSite"); - for(const STEP::LazyObject* lz : *range) { - const IfcSpatialStructureElement* const prod = lz->ToPtr(); - if(!prod) { - continue; - } + if (nb_nodes == 0) { + IFCImporter::LogWarn("failed to determine primary site element, taking all the IfcSite"); + for (const STEP::LazyObject* lz : *range) { + const IfcSpatialStructureElement* const prod = lz->ToPtr(); + if (!prod) { + continue; + } - conv.out->mRootNode = ProcessSpatialStructure(NULL,*prod,conv,NULL); - return; - } + nodes.push_back(ProcessSpatialStructure(NULL, *prod, conv, NULL)); + } - IFCImporter::ThrowException("failed to determine primary site element"); + nb_nodes = nodes.size(); + } + + if (nb_nodes == 1) { + conv.out->mRootNode = nodes[0]; + } + else if (nb_nodes > 1) { + conv.out->mRootNode = new aiNode("Root"); + conv.out->mRootNode->mParent = NULL; + conv.out->mRootNode->mNumChildren = static_cast(nb_nodes); + conv.out->mRootNode->mChildren = new aiNode*[conv.out->mRootNode->mNumChildren]; + + for (size_t i = 0; i < nb_nodes; ++i) { + aiNode* node = nodes[i]; + + node->mParent = conv.out->mRootNode; + + conv.out->mRootNode->mChildren[i] = node; + } + } + else { + IFCImporter::ThrowException("failed to determine primary site element"); + } } // ------------------------------------------------------------------------------------------------ From 6782a69d0b46152a1537f8e17637dfda940412c4 Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 19:14:56 +0530 Subject: [PATCH 13/62] Create a.txt --- samples/SimpleTexturedDirectx11/a.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 samples/SimpleTexturedDirectx11/a.txt diff --git a/samples/SimpleTexturedDirectx11/a.txt b/samples/SimpleTexturedDirectx11/a.txt new file mode 100644 index 000000000..ce0136250 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/a.txt @@ -0,0 +1 @@ +hello From 8974a4f326a9a45ba02a15d2ecc5df0e55a3f94e Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 19:15:10 +0530 Subject: [PATCH 14/62] Delete a.txt --- samples/SimpleTexturedDirectx11/a.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 samples/SimpleTexturedDirectx11/a.txt diff --git a/samples/SimpleTexturedDirectx11/a.txt b/samples/SimpleTexturedDirectx11/a.txt deleted file mode 100644 index ce0136250..000000000 --- a/samples/SimpleTexturedDirectx11/a.txt +++ /dev/null @@ -1 +0,0 @@ -hello From 0a35fa0aef8d984cd464029e482951aee2f195fa Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 1 Jun 2017 15:50:19 +0200 Subject: [PATCH 15/62] Update CMakeLists.txt Build: Make windows headers much smaller. --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53585ccbb..1b3dbeb01 100644 --- a/CMakeLists.txt +++ b/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 From f02663fb5bb33e1da4ce02f2d29630c0cf93ce9b Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 19:24:08 +0530 Subject: [PATCH 16/62] Add files via upload --- samples/SimpleTexturedDirectx11.sln | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 samples/SimpleTexturedDirectx11.sln diff --git a/samples/SimpleTexturedDirectx11.sln b/samples/SimpleTexturedDirectx11.sln new file mode 100644 index 000000000..46b37e5ee --- /dev/null +++ b/samples/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 From 4c2385b55ba0154fde850568a4161db65726070e Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 19:24:41 +0530 Subject: [PATCH 17/62] Delete SimpleTexturedDirectx11.sln --- samples/SimpleTexturedDirectx11.sln | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 samples/SimpleTexturedDirectx11.sln diff --git a/samples/SimpleTexturedDirectx11.sln b/samples/SimpleTexturedDirectx11.sln deleted file mode 100644 index 46b37e5ee..000000000 --- a/samples/SimpleTexturedDirectx11.sln +++ /dev/null @@ -1,28 +0,0 @@ - -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 From 629e80ee4a0e614e70840ff9358cb801b4fbee1d Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 19:25:25 +0530 Subject: [PATCH 18/62] Create main.cpp --- samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp | 1 + 1 file changed, 1 insertion(+) create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -0,0 +1 @@ + From 863ae1d80db4400de9965d6cebc26e1c7388956c Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 19:28:25 +0530 Subject: [PATCH 19/62] Add files via upload --- .../SimpleTexturedDirectx11/Mesh.h | 102 +++ .../SimpleTexturedDirectx11/ModelLoader.cpp | 205 ++++++ .../SimpleTexturedDirectx11/ModelLoader.h | 44 ++ .../SimpleTexturedDirectx11/PixelShader.hlsl | 9 + .../SimpleTexturedDirectx11.vcxproj | 146 ++++ .../SimpleTexturedDirectx11.vcxproj.filters | 50 ++ .../SimpleTexturedDirectx11/TextureLoader.cpp | 691 ++++++++++++++++++ .../SimpleTexturedDirectx11/TextureLoader.h | 55 ++ .../SimpleTexturedDirectx11/VertexShader.hlsl | 23 + .../SimpleTexturedDirectx11/main.cpp | 519 ++++++++++++- 10 files changed, 1843 insertions(+), 1 deletion(-) create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h new file mode 100644 index 000000000..985e3cc6f --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h @@ -0,0 +1,102 @@ +#ifndef MESH_H +#define MESH_H + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +using namespace DirectX; + +struct VERTEX { + FLOAT X, Y, Z; + XMFLOAT2 texcoord; +}; + +struct Texture { + string type; + aiString path; + ID3D11ShaderResourceView *texture; +}; + +class Mesh { +public: + vector vertices; + vector indices; + vector textures; + ID3D11Device *dev; + + Mesh(ID3D11Device *dev, vector vertices, vector indices, vector 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 diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp new file mode 100644 index 000000000..2b934ae5b --- /dev/null +++ b/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 vertices; + vector indices; + vector 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 diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + } + + return Mesh(dev, vertices, indices, textures); +} + +vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) +{ + vector 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; + 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(&scene->mTextures[textureindex]->mWidth); + + hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast(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; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h new file mode 100644 index 000000000..020708fbf --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h @@ -0,0 +1,44 @@ +#ifndef MODEL_LOADER_H +#define MODEL_LOADER_H + +#include +#include +#include + +#include +#include +#include + +#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 meshes; + string directory; + vector textures_loaded; + HWND hwnd; + + void processNode(aiNode* node, const aiScene* scene); + Mesh processMesh(aiMesh* mesh, const aiScene* scene); + vector 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 + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl new file mode 100644 index 000000000..2e8b4eeda --- /dev/null +++ b/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; +} \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj new file mode 100644 index 000000000..fc82bc18e --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8} + SimpleTexturedDirectx11 + 10.0.14393.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(IncludePath);E:\OpenGL VS Files\include + $(LibraryPath);E:\OpenGL VS Files\lib + + + + Level3 + Disabled + true + + + assimp-vc140-mt.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + + Pixel + Pixel + Pixel + Pixel + + + Vertex + Vertex + Vertex + Vertex + + + + + + + + + + + \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters new file mode 100644 index 000000000..271300ad8 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters @@ -0,0 +1,50 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {b6a86d3e-70a5-4d1e-ba05-c20902300206} + + + + + Source Files + + + Source Files + + + Source Files + + + + + Shaders + + + Shaders + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp new file mode 100644 index 000000000..13b3195ca --- /dev/null +++ b/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 +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +#include + +#include "TextureLoader.h" + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS) +#define DXGI_1_2_FORMATS +#endif + +//--------------------------------------------------------------------------------- +template 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 cinfo; + if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo))) + return 0; + + WICComponentType type; + if (FAILED(cinfo->GetComponentType(&type))) + return 0; + + if (type != WICPixelFormat) + return 0; + + ScopedObject pfinfo; + if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast(&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(height) / static_cast(width); + if (width > height) + { + twidth = static_cast(maxsize); + theight = static_cast(static_cast(maxsize) * ar); + } + else + { + theight = static_cast(maxsize); + twidth = static_cast(static_cast(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 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(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else if (twidth != width || theight != height) + { + // Resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject 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(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else + { + ScopedObject 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(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + } + else + { + // Format conversion but no resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject 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(rowPitch), static_cast(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(rowPitch); + initData.SysMemSlicePitch = static_cast(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(rowPitch), static_cast(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 stream; + HRESULT hr = pWIC->CreateStream(&stream); + if (FAILED(hr)) + return hr; + + hr = stream->InitializeFromMemory(const_cast(wicData), static_cast(wicDataSize)); + if (FAILED(hr)) + return hr; + + // Initialize WIC + ScopedObject decoder; + hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject 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 decoder; + HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject 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(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + + if (textureView != 0 && *textureView != 0) + { + (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, + static_cast(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + } +#endif + + return hr; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h new file mode 100644 index 000000000..60308d9fa --- /dev/null +++ b/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 + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#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 +); + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl new file mode 100644 index 000000000..cf7ee16ac --- /dev/null +++ b/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; +} \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp index 8b1378917..5c5e8a107 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -1 +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 +#include +#include +#include +#include +#include +#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(&dxgiDevice)); + if (SUCCEEDED(hr)) + { + IDXGIAdapter* adapter = nullptr; + hr = dxgiDevice->GetAdapter(&adapter); + if (SUCCEEDED(hr)) + { + hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&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(&dxgiFactory2)); + if (dxgiFactory2) + { + // DirectX 11.1 or later + hr = dev->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&dev1)); + if (SUCCEEDED(hr)) + { + (void)devcon->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&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(&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); +} \ No newline at end of file From 514244ffc286847db95505d5985a16111796744f Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 19:29:22 +0530 Subject: [PATCH 20/62] Add files via upload --- .../SimpleTexturedDirectx11.sln | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln new file mode 100644 index 000000000..46b37e5ee --- /dev/null +++ b/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 From cab6cdf7b2f9116ee36805c44b07606105d39e2d Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 1 Jun 2017 16:21:23 +0200 Subject: [PATCH 21/62] Viewer: fix the build. --- tools/assimp_view/Display.cpp | 2 ++ tools/assimp_view/LogWindow.cpp | 2 ++ tools/assimp_view/MessageProc.cpp | 2 ++ tools/assimp_view/SceneAnimator.h | 16 +++++++++++----- tools/assimp_view/assimp_view.cpp | 1 + 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index 91ea9573b..21c0c022a 100644 --- a/tools/assimp_view/Display.cpp +++ b/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 + namespace AssimpView { using namespace Assimp; diff --git a/tools/assimp_view/LogWindow.cpp b/tools/assimp_view/LogWindow.cpp index c21c2802e..dba70ee71 100644 --- a/tools/assimp_view/LogWindow.cpp +++ b/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 +#include namespace AssimpView { diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index 4595c58cd..b8c56503b 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -44,6 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include namespace AssimpView { diff --git a/tools/assimp_view/SceneAnimator.h b/tools/assimp_view/SceneAnimator.h index ba79b4faa..afcbac925 100644 --- a/tools/assimp_view/SceneAnimator.h +++ b/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::iterator it = mChildren.begin(); it != mChildren.end(); ++it) + for (std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) { delete *it; + } } }; diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index 811fe47e7..df80e3038 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "assimp_view.h" +#include #include "StringUtils.h" #include From 4456b7ca82fec693cbb6b55f09ec913be57e9168 Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 21:11:48 +0530 Subject: [PATCH 22/62] Update Mesh.h --- samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h index 985e3cc6f..e6a644a94 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h @@ -20,7 +20,7 @@ struct VERTEX { struct Texture { string type; - aiString path; + string path; ID3D11ShaderResourceView *texture; }; From db4b9598689f3021d56440f08ab7fc51ba5cccd5 Mon Sep 17 00:00:00 2001 From: Ias0601 Date: Thu, 1 Jun 2017 21:12:48 +0530 Subject: [PATCH 23/62] Update ModelLoader.cpp --- .../SimpleTexturedDirectx11/ModelLoader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp index 2b934ae5b..801284383 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp @@ -102,7 +102,7 @@ vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureTyp 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) + 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) @@ -128,7 +128,7 @@ vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureTyp MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK); } texture.type = typeName; - texture.path = str; + 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. } From dcc588781747eb1ecd5b3db216f8c74d56214117 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 2 Jun 2017 11:20:48 +0200 Subject: [PATCH 24/62] Update CMakeLists.txt Enable check for OpenMP-support. --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b3dbeb01..fb31946be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,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 From f84851e8931fb04e7074d487c91c3b3faa566994 Mon Sep 17 00:00:00 2001 From: Arkeon Date: Fri, 2 Jun 2017 13:24:56 +0200 Subject: [PATCH 25/62] PLYImporter: - optimize memory and speed on ply importer / change parser to use a file stream - manage texture path in ply import - manage texture coords on faces in ply import - correction on point cloud faces generation IFC : - update poly2tri to avoid crash on some IFC files Collada : - manage missing texture reference in collada import --- code/ColladaLoader.cpp | 16 +- code/IOStreamBuffer.h | 22 + code/PlyLoader.cpp | 1825 ++++++++--------- code/PlyLoader.h | 61 +- code/PlyParser.cpp | 1792 ++++++++-------- code/PlyParser.h | 95 +- code/STLLoader.cpp | 6 +- contrib/poly2tri/poly2tri/common/shapes.cc | 54 +- contrib/poly2tri/poly2tri/common/shapes.h | 58 +- contrib/poly2tri/poly2tri/common/utils.h | 40 +- contrib/poly2tri/poly2tri/poly2tri.h | 5 +- .../poly2tri/sweep/advancing_front.cc | 7 +- .../poly2tri/poly2tri/sweep/advancing_front.h | 6 +- contrib/poly2tri/poly2tri/sweep/cdt.cc | 9 +- contrib/poly2tri/poly2tri/sweep/cdt.h | 34 +- contrib/poly2tri/poly2tri/sweep/sweep.cc | 133 +- contrib/poly2tri/poly2tri/sweep/sweep.h | 49 +- .../poly2tri/poly2tri/sweep/sweep_context.cc | 53 +- .../poly2tri/poly2tri/sweep/sweep_context.h | 34 +- 19 files changed, 2237 insertions(+), 2062 deletions(-) diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index 457b62c20..5cec0a0c6 100644 --- a/code/ColladaLoader.cpp +++ b/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()) diff --git a/code/IOStreamBuffer.h b/code/IOStreamBuffer.h index b80810084..577e3f8a6 100644 --- a/code/IOStreamBuffer.h +++ b/code/IOStreamBuffer.h @@ -100,6 +100,11 @@ public: /// @return true if successful. bool getNextDataLine( std::vector &buffer, T continuationToken ); + /// @brief Will read the next block. + /// @param buffer The buffer for the next block. + /// @return true if successful. + bool getNextBlock( std::vector &buffer ); + private: IOStream *m_stream; size_t m_filesize; @@ -274,4 +279,21 @@ bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationT return true; } +template +inline +bool IOStreamBuffer::getNextBlock( std::vector &buffer) { + //just return the last blockvalue if getNextLine was used before + if ( m_cachePos != 0) { + buffer = std::vector(m_cache.begin() + m_cachePos, m_cache.end()); + m_cachePos = 0; + } + else { + if ( !readNextBlock() ) + return false; + + buffer = std::vector(m_cache.begin(), m_cache.end()); + } + return true; +} + } // !ns Assimp diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index 7cfa06727..d815b2240 100644 --- a/code/PlyLoader.cpp +++ b/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 #include @@ -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,983 @@ static const aiImporterDesc desc = { // Internal stuff namespace { - // ------------------------------------------------------------------------------------------------ - // Checks that property index is within range - template - const T &GetProperty(const std::vector &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 + const T &GetProperty(const std::vector &props, int idx) + { + if (static_cast(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); + 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; + 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 file( pIOHandler->Open( pFile)); + static const std::string mode = "rb"; + std::unique_ptr fileStream(pIOHandler->Open(pFile, mode)); + if (!fileStream.get()) { + throw DeadlyImportError("Failed to open file " + pFile + "."); + } - // Check whether we can read from the file - if( file.get() == NULL) { - throw DeadlyImportError( "Failed to open PLY file " + pFile + "."); + // Get the file-size + size_t fileSize = fileStream->FileSize(); + + IOStreamBuffer streamedBuffer(1024 * 1024); + streamedBuffer.open(fileStream.get()); + + // the beginning of the file must be PLY - magic, magic + std::vector headerCheck; + streamedBuffer.getNextDataLine(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 mBuffer2; + streamedBuffer.getNextDataLine(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)); - // allocate storage and copy the contents of the file to a memory buffer - std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); - mBuffer = (unsigned char*)&mBuffer2[0]; + // 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); - // 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"); - } - - 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 ) ); - - // 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" ); - } + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)"); + } } else { - AI_DEBUG_INVALIDATE_PTR(this->mBuffer); - throw DeadlyImportError( "Invalid .ply file: Missing format specification"); + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); + + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unknown file format"); } - this->pcDOM = &sPlyDom; + } + else + { + AI_DEBUG_INVALIDATE_PTR(this->mBuffer); + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - // now load a list of vertices. This must be successfully in order to procedure - std::vector avPositions; - this->LoadVertices(&avPositions,false); + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Missing format specification"); + } - if ( avPositions.empty() ) { - throw DeadlyImportError( "Invalid .ply file: No vertices found. " - "Unable to parse the data format of the PLY file." ); - } + //free the file buffer + streamedBuffer.close(); - // now load a list of normals. - std::vector avNormals; - LoadVertices(&avNormals,true); + if (mGeneratedMesh == NULL) + { + throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data "); + } - // load the face list - std::vector avFaces; - LoadFaces(&avFaces); - - // if no face list is existing we assume that the vertex - // list is containing a list of triangles - if (avFaces.empty()) + // 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 (avPositions.size() < 3) - { - throw DeadlyImportError( "Invalid .ply file: Not enough " - "vertices to build a proper face list. "); - } + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - 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); - } + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Not enough " + "vertices to build a proper face list. "); } - // now load a list of all materials - std::vector avMaterials; - LoadMaterial(&avMaterials); + const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3; + mGeneratedMesh->mNumFaces = iNum; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; - // now load a list of all vertex color channels - std::vector avColors; - avColors.reserve(avPositions.size()); - LoadVertexColor(&avColors); - - // now try to load texture coordinates - std::vector avTexCoords; - avTexCoords.reserve(avPositions.size()); - LoadTextureCoordinates(&avTexCoords); - - // now replace the default material in all faces and validate all material indices - ReplaceDefaultMaterial(&avFaces,&avMaterials); - - // now convert this to a list of aiMesh instances - std::vector avMeshes; - avMeshes.reserve(avMaterials.size()+1); - ConvertMeshes(&avFaces,&avPositions,&avNormals, - &avColors,&avTexCoords,&avMaterials,&avMeshes); - - if ( avMeshes.empty() ) { - throw DeadlyImportError( "Invalid .ply file: Unable to extract mesh data " ); + for (unsigned int i = 0; i < iNum; ++i) + { + 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; } + } - // 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 ]; - } + // now load a list of all materials + std::vector avMaterials; + std::string defaultTexture; + LoadMaterial(&avMaterials, defaultTexture, pointsOnly); - // 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 ]; - } + // 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]; + } - // generate a simple node structure - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; - pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + // fill the mesh list + pScene->mNumMeshes = 1; + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + pScene->mMeshes[0] = mGeneratedMesh; - for ( unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i ) { - pScene->mRootNode->mMeshes[ i ] = i; - } + // 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; + } } -// ------------------------------------------------------------------------------------------------ -// Split meshes by material IDs -void PLYImporter::ConvertMeshes(std::vector* avFaces, - const std::vector* avPositions, - const std::vector* avNormals, - const std::vector* avColors, - const std::vector* avTexCoords, - const std::vector* avMaterials, - std::vector* avOut) +void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) { - ai_assert(NULL != avFaces); - ai_assert(NULL != avPositions); - ai_assert(NULL != avMaterials); + ai_assert(NULL != pcElement); + ai_assert(NULL != instElement); - // split by materials - std::vector* aiSplit = new std::vector[avMaterials->size()]; + ai_uint aiPositions[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char }; - unsigned int iNum = 0; - for (std::vector::const_iterator i = avFaces->begin();i != avFaces->end();++i,++iNum) - aiSplit[(*i).iMaterialIndex].push_back(iNum); + ai_uint aiNormal[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiNormalTypes[3] = { EDT_Char, EDT_Char, EDT_Char }; - // now generate sub-meshes - for (unsigned int p = 0; p < avMaterials->size();++p) + 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 }; + + unsigned int cnt = 0; + + // now check whether which normal components are available + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) + { + if ((*a).bIsList)continue; + + // Positions + if (PLY::EST_XCoord == (*a).Semantic) { - if (aiSplit[p].size() != 0) - { - // allocate the mesh object - aiMesh* p_pcOut = new aiMesh(); - p_pcOut->mMaterialIndex = p; - - p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); - p_pcOut->mFaces = new aiFace[aiSplit[p].size()]; - - // 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 (!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::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++; - } - - } - // add the mesh to the output list - avOut->push_back(p_pcOut); - } + cnt++; + aiPositions[0] = _a; + aiTypes[0] = (*a).eType; } - delete[] aiSplit; // cleanup + 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; + } + + // 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( + GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]); + } + + if (0xFFFFFFFF != aiPositions[1]) + { + vOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]); + } + + if (0xFFFFFFFF != aiPositions[2]) + { + vOut.z = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]); + } + + // Normals + aiVector3D nOut; + bool haveNormal = false; + if (0xFFFFFFFF != aiNormal[0]) + { + nOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]); + haveNormal = true; + } + + if (0xFFFFFFFF != aiNormal[1]) + { + nOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]); + haveNormal = true; + } + + if (0xFFFFFFFF != aiNormal[2]) + { + nOut.z = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]); + haveNormal = true; + } + + //Colors + aiColor4D cOut; + bool haveColor = false; + if (0xFFFFFFFF != aiColors[0]) + { + cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[0]).avList.front(), aiColorsTypes[0]); + haveColor = true; + } + + if (0xFFFFFFFF != aiColors[1]) + { + cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[1]).avList.front(), aiColorsTypes[1]); + haveColor = true; + } + + if (0xFFFFFFFF != aiColors[2]) + { + cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[2]).avList.front(), aiColorsTypes[2]); + haveColor = true; + } + + // 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]); + + haveColor = true; + } + + //Texture coordinates + aiVector3D tOut; + tOut.z = 0; + bool haveTextureCoords = false; + if (0xFFFFFFFF != aiTexcoord[0]) + { + tOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]); + haveTextureCoords = true; + } + + if (0xFFFFFFFF != aiTexcoord[1]) + { + tOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]); + haveTextureCoords = true; + } + + //create aiMesh if needed + if (mGeneratedMesh == NULL) + { + mGeneratedMesh = new aiMesh(); + mGeneratedMesh->mMaterialIndex = 0; + } + + if (mGeneratedMesh->mVertices == NULL) + { + mGeneratedMesh->mNumVertices = pcElement->NumOccur; + mGeneratedMesh->mVertices = new aiVector3D[mGeneratedMesh->mNumVertices]; + } + + mGeneratedMesh->mVertices[pos] = vOut; + + if (haveNormal) + { + if (mGeneratedMesh->mNormals == NULL) + mGeneratedMesh->mNormals = new aiVector3D[mGeneratedMesh->mNumVertices]; + mGeneratedMesh->mNormals[pos] = nOut; + } + + if (haveColor) + { + if (mGeneratedMesh->mColors[0] == NULL) + mGeneratedMesh->mColors[0] = new aiColor4D[mGeneratedMesh->mNumVertices]; + mGeneratedMesh->mColors[0][pos] = cOut; + } + + if (haveTextureCoords) + { + if (mGeneratedMesh->mTextureCoords[0] == NULL) + { + mGeneratedMesh->mNumUVComponents[0] = 2; + mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices]; + } + mGeneratedMesh->mTextureCoords[0][pos] = tOut; + } + } } -// ------------------------------------------------------------------------------------------------ -// Generate a default material if none was specified and apply it to all vanilla faces -void PLYImporter::ReplaceDefaultMaterial(std::vector* avFaces, - std::vector* avMaterials) -{ - bool bNeedDefaultMat = false; - - for (std::vector::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; - } - } - - if (bNeedDefaultMat) { - // generate a default material - aiMaterial* pcHelper = new aiMaterial(); - - // fill in a default material - int iMode = (int)aiShadingMode_Gouraud; - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - aiColor3D clr; - clr.b = clr.g = clr.r = 0.6f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); - - clr.b = clr.g = clr.r = 0.05f; - pcHelper->AddProperty(&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. - const int two_sided = 1; - pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED); - - avMaterials->push_back(pcHelper); - } -} - -// ------------------------------------------------------------------------------------------------ -void PLYImporter::LoadTextureCoordinates(std::vector* 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::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &this->pcDOM->alElementData[_i]; - - // now check whether which normal components are available - unsigned int _a = 0; - for (std::vector::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 a valid source for the texture coordinates data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - // convert the vertices to sp floats - aiVector2D vOut; - - if (0xFFFFFFFF != aiPositions[0]) - { - vOut.x = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]); - } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.y = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]); - } - // and add them to our nice list - pvOut->push_back(vOut); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Try to extract vertices from the PLY DOM -void PLYImporter::LoadVertices(std::vector* pvOut, bool p_bNormals) -{ - ai_assert(NULL != pvOut); - - 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; - - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &pcDOM->alElementData[_i]; - - // load normal vectors? - if (p_bNormals) - { - // now check whether which normal components are available - unsigned int _a = 0; - for (std::vector::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 - { - // now check whether which coordinate sets are available - unsigned int _a = 0; - for (std::vector::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; - } - } - break; - } - } - // check whether we have a valid source for the vertex data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::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( - GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]); - } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.y = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]); - } - - if (0xFFFFFFFF != aiPositions[2]) - { - vOut.z = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[2]).avList.front(),aiTypes[2]); - } - - // and add them to our nice list - pvOut->push_back(vOut); - } - } -} // ------------------------------------------------------------------------------------------------ // Convert a color component to [0...1] -ai_real PLYImporter::NormalizeColorValue (PLY::PropertyInstance::ValueUnion val, - PLY::EDataType eType) +ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, + PLY::EDataType eType) { - switch (eType) - { - case EDT_Float: - return val.fFloat; - case EDT_Double: - return (ai_real)val.fDouble; + 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; -} - -// ------------------------------------------------------------------------------------------------ -// Try to extract proper vertex colors from the PLY DOM -void PLYImporter::LoadVertexColor(std::vector* pvOut) -{ - 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::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - 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::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; - } - } - // check whether we have a valid source for the vertex data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::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); - } - } + 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; } // ------------------------------------------------------------------------------------------------ // Try to extract proper faces from the PLY DOM -void PLYImporter::LoadFaces(std::vector* pvOut) +void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) { - ai_assert(NULL != pvOut); + ai_assert(NULL != pcElement); + ai_assert(NULL != instElement); - PLY::ElementInstanceList* pcList = NULL; - bool bOne = false; + if (mGeneratedMesh == NULL) + throw DeadlyImportError("Invalid .ply file: Vertices shoud be declared before faces"); - // index of the vertex index list - unsigned int iProperty = 0xFFFFFFFF; - PLY::EDataType eType = EDT_Char; - bool bIsTriStrip = false; + bool bOne = false; - // index of the material index property - unsigned int iMaterialIndex = 0xFFFFFFFF; - PLY::EDataType eType2 = EDT_Char; + // index of the vertex index list + unsigned int iProperty = 0xFFFFFFFF; + PLY::EDataType eType = EDT_Char; + bool bIsTriStrip = false; - // search in the DOM for a face entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) + // index of the material index property + //unsigned int iMaterialIndex = 0xFFFFFFFF; + //PLY::EDataType eType2 = EDT_Char; + + // texture coordinates + unsigned int iTextureCoord = 0xFFFFFFFF; + PLY::EDataType eType3 = EDT_Char; + + // face = unique number of vertex indices + if (PLY::EEST_Face == pcElement->eSemantic) + { + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) { - // face = unique number of vertex indices - if (PLY::EEST_Face == (*i).eSemantic) - { - pcList = &pcDOM->alElementData[_i]; - unsigned int _a = 0; - for (std::vector::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; - } - // triangle strip - // TODO: triangle strip and material index support??? - else if (PLY::EEST_TriStrip == (*i).eSemantic) - { - // find a list property in this ... - pcList = &this->pcDOM->alElementData[_i]; - unsigned int _a = 0; - for (std::vector::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; - } + 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; + } } - // check whether we have at least one per-face information set - if (pcList && bOne) + } + // triangle strip + // TODO: triangle strip and material index support??? + else if (PLY::EEST_TriStrip == pcElement->eSemantic) + { + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) { - if (!bIsTriStrip) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::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::const_iterator p = - GetProperty((*i).alProperties, iProperty).avList.begin(); - - for (unsigned int a = 0; a < iNum;++a,++p) - { - sFace.mIndices[a] = PLY::PropertyInstance::ConvertTo(*p,eType); - } - } - - // parse the material index - if (0xFFFFFFFF != iMaterialIndex) - { - sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, iMaterialIndex).avList.front(),eType2); - } - pvOut->push_back(sFace); - } - } - else // triangle strips - { - // 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::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) { - const std::vector& quak = GetProperty((*i).alProperties, iProperty).avList; - pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); - - int aiTable[2] = {-1,-1}; - for (std::vector::const_iterator a = quak.begin();a != quak.end();++a) { - const int p = PLY::PropertyInstance::ConvertTo(*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; - } - } - } + // must be a dynamic list! + if (!(*a).bIsList) + continue; + iProperty = _a; + bOne = true; + bIsTriStrip = true; + eType = (*a).eType; + break; } + } + + // 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]; + } + + if (!bIsTriStrip) + { + // 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]; + + std::vector::const_iterator p = + GetProperty(instElement->alProperties, iProperty).avList.begin(); + + for (unsigned int a = 0; a < iNum; ++a, ++p) + { + mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo(*p, eType); + } + } + + // parse the material index + // cannot be handled without processing the whole file first + /*if (0xFFFFFFFF != iMaterialIndex) + { + mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2); + }*/ + + if (0xFFFFFFFF != iTextureCoord) + { + const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size(); + + //should be 6 coords + std::vector::const_iterator p = + GetProperty(instElement->alProperties, iTextureCoord).avList.begin(); + + 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) + { + 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(*p, eType3); + else + mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo(*p, eType3); + + mGeneratedMesh->mTextureCoords[0][vindex].z = 0; + } + } + } + } + } + else // triangle strips + { + // 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& 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::const_iterator a = quak.begin(); a != quak.end(); ++a) { + const int p = PLY::PropertyInstance::ConvertTo(*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 (mGeneratedMesh->mFaces == NULL) + { + mGeneratedMesh->mNumFaces = pcElement->NumOccur; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; + } + + 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]; + + if ((flip = !flip)) { + std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]); + } + + aiTable[0] = aiTable[1]; + aiTable[1] = p; + } + } + } } // ------------------------------------------------------------------------------------------------ // Get a RGBA color in [0...1] range void PLYImporter::GetMaterialColor(const std::vector& avList, - unsigned int aiPositions[4], - PLY::EDataType aiTypes[4], - aiColor4D* clrOut) + unsigned int aiPositions[4], + PLY::EDataType aiTypes[4], + aiColor4D* clrOut) { - ai_assert(NULL != clrOut); + 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[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[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]); - } + 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]); - } + // 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]); + } } // ------------------------------------------------------------------------------------------------ // Extract a material from the PLY DOM -void PLYImporter::LoadMaterial(std::vector* pvOut) +void PLYImporter::LoadMaterial(std::vector* pvOut, std::string &defaultTexture, const bool pointsOnly) { - ai_assert(NULL != pvOut); + ai_assert(NULL != pvOut); - // diffuse[4], specular[4], ambient[4] - // rgba order - unsigned int aaiPositions[3][4] = { + // 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}, - }; + { 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; + 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 iPhong = 0xFFFFFFFF; + PLY::EDataType ePhong = EDT_Char; - unsigned int iOpacity = 0xFFFFFFFF; - PLY::EDataType eOpacity = 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::const_iterator i = this->pcDOM->alElements.begin(); - i != this->pcDOM->alElements.end();++i,++_i) + // search in the DOM for a vertex entry + unsigned int _i = 0; + for (std::vector::const_iterator i = this->pcDOM->alElements.begin(); + i != this->pcDOM->alElements.end(); ++i, ++_i) + { + if (PLY::EEST_Material == (*i).eSemantic) { - 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::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::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; + iPhong = _a; + ePhong = (*a).eType; } - } - // check whether we have a valid source for the material data - if (NULL != pcList) { - for (std::vector::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(&clrOut,1,AI_MATKEY_COLOR_DIFFUSE); - - // build the specular material color - GetMaterialColor((*i).alProperties,aaiPositions[1],aaiTypes[1],&clrOut); - pcHelper->AddProperty(&clrOut,1,AI_MATKEY_COLOR_SPECULAR); - - // build the ambient material color - GetMaterialColor((*i).alProperties,aaiPositions[2],aaiTypes[2],&clrOut); - pcHelper->AddProperty(&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(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(&fSpec, 1, AI_MATKEY_SHININESS); - - iMode = (int)aiShadingMode_Phong; - } - } - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - // handle opacity - if (0xFFFFFFFF != iOpacity) { - ai_real fOpacity = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(),eOpacity); - pcHelper->AddProperty(&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); + // 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; } + else if (PLY::EEST_TextureFile == (*i).eSemantic) + { + defaultTexture = (*i).szName; + } + } + // check whether we have a valid source for the material data + if (NULL != pcList) { + for (std::vector::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(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE); + + // build the specular material color + GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut); + pcHelper->AddProperty(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR); + + // build the ambient material color + GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut); + pcHelper->AddProperty(&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(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(&fSpec, 1, AI_MATKEY_SHININESS); + + iMode = (int)aiShadingMode_Phong; + } + } + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + // handle opacity + if (0xFFFFFFFF != iOpacity) { + ai_real fOpacity = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity); + pcHelper->AddProperty(&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); + } + } + else + { + // generate a default material + aiMaterial* pcHelper = new aiMaterial(); + + // fill in a default material + int iMode = (int)aiShadingMode_Gouraud; + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + aiColor3D clr; + clr.b = clr.g = clr.r = 0.6f; + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); + + clr.b = clr.g = clr.r = 0.05f; + pcHelper->AddProperty(&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) + { + 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); + } + + //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); + } + + pvOut->push_back(pcHelper); + } } #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER diff --git a/code/PlyLoader.h b/code/PlyLoader.h index 6c3825aa4..eb64a9036 100644 --- a/code/PlyLoader.h +++ b/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* pvOut, - bool p_bNormals = false); - - // ------------------------------------------------------------------- - /** Extract vertex color channels from the DOM - */ - void LoadVertexColor(std::vector* pvOut); - - // ------------------------------------------------------------------- - /** Extract texture coordinate channels from the DOM - */ - void LoadTextureCoordinates(std::vector* pvOut); - - // ------------------------------------------------------------------- - /** Extract a face list from the DOM - */ - void LoadFaces(std::vector* pvOut); - // ------------------------------------------------------------------- /** Extract a material list from the DOM */ - void LoadMaterial(std::vector* pvOut); - - - // ------------------------------------------------------------------- - /** Validate material indices, replace default material identifiers - */ - void ReplaceDefaultMaterial(std::vector* avFaces, - std::vector* avMaterials); - - - // ------------------------------------------------------------------- - /** Convert all meshes into our ourer representation - */ - void ConvertMeshes(std::vector* avFaces, - const std::vector* avPositions, - const std::vector* avNormals, - const std::vector* avColors, - const std::vector* avTexCoords, - const std::vector* avMaterials, - std::vector* avOut); - + void LoadMaterial(std::vector* 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 diff --git a/code/PlyParser.cpp b/code/PlyParser.cpp index 7e5a07d8e..7d47641b6 100644 --- a/code/PlyParser.cpp +++ b/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 #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 PLY::Property::ParseDataType(std::vector &buffer) { + ai_assert(!buffer.empty()); - PLY::EDataType eOut = PLY::EDT_INVALID; + 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; + 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; + return eOut; } // ------------------------------------------------------------------------------------------------ -PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOut) { - ai_assert (NULL != pCur ); - ai_assert( NULL != pCurOut ); +PLY::ESemantic PLY::Property::ParseSemantic(std::vector &buffer) { + ai_assert(!buffer.empty()); - 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 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)) + { + eOut = PLY::EST_UTextureCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2)) + { + 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 &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; - - // skip leading spaces - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - - // skip the "property" string at the beginning - if (!TokenMatch(pCur,"property",8)) - { - // seems not to be a valid property entry - return false; - } - // get next word - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - if (TokenMatch(pCur,"list",4)) - { - 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 - { - 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; - } - } - - 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; - - DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK"); - pOut->szName = std::string(szCur,iDiff); - } - - SkipSpacesAndLineEnd(pCur,&pCur); - *pCurOut = pCur; - - return true; -} - -// ------------------------------------------------------------------------------------------------ -PLY::EElementSemantic PLY::Element::ParseSemantic(const char* pCur, - const char** pCurOut) -{ - 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; - } -#if 0 - // TODO: maybe implement this? - else if (TokenMatch(pCur,"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; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::Element::ParseElement (const char* pCur, - const char** pCurOut, - PLY::Element* pOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pOut ); - - // Example format: "element vertex 8" - *pCurOut = pCur; - - // skip leading spaces - if (!SkipSpaces(&pCur)) { - 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 - 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 (!SkipSpaces(&pCur))return false; - - //parse the number of occurrences of this element - pOut->NumOccur = strtoul10(pCur,&pCur); - - // go to the next line - SkipSpacesAndLineEnd(pCur,&pCur); - - // now parse all properties of the element - while(true) - { - // skip all comments - PLY::DOM::SkipComments(pCur,&pCur); - - PLY::Property prop; - if(!PLY::Property::ParseProperty(pCur,&pCur,&prop))break; - pOut->alProperties.push_back(prop); - } - *pCurOut = pCur; - - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::SkipComments (const char* pCur, - const char** pCurOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - *pCurOut = pCur; - - // 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; + // Forms supported: + // "property float x" + // "property list uchar int vertex_index" + // skip leading spaces + if (!PLY::DOM::SkipSpaces(buffer)) { return false; -} + } -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut,bool isBinary) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + // 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; - DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin"); - - // after ply and format line - *pCurOut = pCur; - - // parse all elements - while ((*pCur) != '\0') + // seems to be a list. + if (EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(buffer))) { - // skip all comments - PLY::DOM::SkipComments(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); - } + // unable to parse list size data type + PLY::DOM::SkipLine(buffer); + return false; } - if(!isBinary) - { // it would occur an error, if binary data start with values as space or line end. - SkipSpacesAndLineEnd(pCur,&pCur); + if (!PLY::DOM::SkipSpaces(buffer))return false; + if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) + { + // unable to parse list data type + PLY::DOM::SkipLine(buffer); + return false; } - *pCurOut = pCur; + } + else + { + if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) + { + // unable to parse data type. Skip the property + PLY::DOM::SkipLine(buffer); + return false; + } + } - DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded"); - return true; + if (!PLY::DOM::SkipSpaces(buffer)) + return false; + + pOut->Semantic = PLY::Property::ParseSemantic(buffer); + + 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])); + } + + PLY::DOM::SkipSpacesAndLineEnd(buffer); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseElementInstanceLists ( - const char* pCur, - const char** pCurOut) +PLY::EElementSemantic PLY::Element::ParseSemantic(std::vector &buffer) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + ai_assert(!buffer.empty()); - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin"); - *pCurOut = pCur; + 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 (PLY::DOM::TokenMatch(buffer,"range_grid",10)) + { + eOut = PLY::EEST_Face; + } +#endif + 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; + } - alElementData.resize(alElements.size()); - - std::vector::const_iterator i = alElements.begin(); - std::vector::iterator a = alElementData.begin(); - - // parse all element instances - for (;i != alElements.end();++i,++a) - { - (*a).alInstances.resize((*i).NumOccur); - PLY::ElementInstanceList::ParseInstanceList(pCur,&pCur,&(*i),&(*a)); - } - - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded"); - *pCurOut = pCur; - return true; + return eOut; } // ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseElementInstanceListsBinary ( - const char* pCur, - const char** pCurOut, +bool PLY::Element::ParseElement(IOStreamBuffer &streamBuffer, std::vector &buffer, PLY::Element* pOut) +{ + ai_assert(NULL != pOut); + // Example format: "element vertex 8" + + // skip leading spaces + if (!PLY::DOM::SkipSpaces(buffer)) + { + 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; + + // 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])); + } + + if (!PLY::DOM::SkipSpaces(buffer)) + 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 + const char* pCur = (char*)&buffer[0]; + pOut->NumOccur = strtoul10(pCur, &pCur); + + // go to the next line + PLY::DOM::SkipSpacesAndLineEnd(buffer); + + // now parse all properties of the element + while (true) + { + streamBuffer.getNextDataLine(buffer, '\\'); + pCur = (char*)&buffer[0]; + + // skip all comments + PLY::DOM::SkipComments(buffer); + + PLY::Property prop; + if (!PLY::Property::ParseProperty(buffer, &prop)) + break; + + pOut->alProperties.push_back(prop); + } + + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::SkipSpaces(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipSpaces(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipLine(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipLine(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::TokenMatch(std::vector &buffer, const char* token, unsigned int len) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::TokenMatch(pCur, token, len); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipSpacesAndLineEnd(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipComments(std::vector &buffer) +{ + ai_assert(!buffer.empty()); + + std::vector nbuffer = buffer; + // skip spaces + if (!SkipSpaces(nbuffer)) { + return false; + } + + if (TokenMatch(nbuffer, "comment", 7)) + { + if (!SkipSpaces(nbuffer)) + SkipLine(nbuffer); + + if (!TokenMatch(nbuffer, "TextureFile", 11)) + { + SkipLine(nbuffer); + buffer = nbuffer; + return true; + } + + return true; + } + + return false; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseHeader(IOStreamBuffer &streamBuffer, std::vector &buffer, bool isBinary) { + DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin"); + + // parse all elements + while (!buffer.empty()) + { + // skip all comments + PLY::DOM::SkipComments(buffer); + + PLY::Element out; + if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) + { + // add the element to the list of elements + alElements.push_back(out); + } + else if (TokenMatch(buffer, "end_header", 10)) + { + // we have reached the end of the header + break; + } + else + { + // ignore unknown header elements + streamBuffer.getNextDataLine(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::ParseElementInstanceLists(IOStreamBuffer &streamBuffer, std::vector &buffer, PLYImporter* loader) +{ + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin"); + alElementData.resize(alElements.size()); + + std::vector::const_iterator i = alElements.begin(); + std::vector::iterator a = alElementData.begin(); + + // 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) + { + PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), NULL, loader); + } + else + { + (*a).alInstances.resize((*i).NumOccur); + PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), &(*a), NULL); + } + } + + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded"); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseElementInstanceListsBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + PLYImporter* loader, bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut); + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin"); + alElementData.resize(alElements.size()); - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin"); - *pCurOut = pCur; + std::vector::const_iterator i = alElements.begin(); + std::vector::iterator a = alElementData.begin(); - alElementData.resize(alElements.size()); - - std::vector::const_iterator i = alElements.begin(); - std::vector::iterator a = alElementData.begin(); - - // parse all element instances - for (;i != alElements.end();++i,++a) + // parse all element instances + for (; i != alElements.end(); ++i, ++a) + { + if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip) { - (*a).alInstances.resize((*i).NumOccur); - PLY::ElementInstanceList::ParseInstanceListBinary(pCur,&pCur,&(*i),&(*a),p_bBE); - } - - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded"); - *pCurOut = pCur; - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != p_pcOut ); - - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); - - if(!p_pcOut->ParseHeader(pCur,&pCur,true)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); - return false; - } - if(!p_pcOut->ParseElementInstanceListsBinary(pCur,&pCur,p_bBE)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); - return false; - } - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded"); - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseInstance (const char* pCur,DOM* p_pcOut) -{ - ai_assert(NULL != pCur); - ai_assert(NULL != p_pcOut); - - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); - - - if(!p_pcOut->ParseHeader(pCur,&pCur,false)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); - return false; - } - if(!p_pcOut->ParseElementInstanceLists(pCur,&pCur)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); - return false; - } - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded"); - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstanceList::ParseInstanceList ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstanceList* p_pcOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); - - 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) - { - 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; + } + + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded"); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstanceList::ParseInstanceListBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstanceList* p_pcOut, - bool p_bBE /* = false */) +bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer &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); - // 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; + std::vector buffer; + streamBuffer.getNextDataLine(buffer, '\\'); + + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); + + 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::ParseInstance ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstance* p_pcOut) +bool PLY::DOM::ParseInstance(IOStreamBuffer &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); - if (!SkipSpaces(pCur, &pCur)) { - return false; - } + std::vector buffer; + streamBuffer.getNextDataLine(buffer, '\\'); - // allocate enough storage - p_pcOut->alProperties.resize(pcElement->alProperties.size()); + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); - std::vector::iterator i = p_pcOut->alProperties.begin(); - std::vector::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"); + if (!p_pcOut->ParseHeader(streamBuffer, buffer, false)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); + return false; + } - // skip the rest of the instance - SkipLine(pCur, &pCur); - - PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType); - (*i).avList.push_back(v); - } - } - *pCurOut = pCur; - return true; + //get next line after header + streamBuffer.getNextDataLine(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::ElementInstance::ParseInstanceBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstance* p_pcOut, - bool p_bBE /* = false */) +bool PLY::ElementInstanceList::ParseInstanceList( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const PLY::Element* pcElement, + PLY::ElementInstanceList* p_pcOut, + PLYImporter* loader) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); + const char* pCur = (const char*)&buffer[0]; - // allocate enough storage - p_pcOut->alProperties.resize(pcElement->alProperties.size()); - - std::vector::iterator i = p_pcOut->alProperties.begin(); - std::vector::const_iterator a = pcElement->alProperties.begin(); - for (;i != p_pcOut->alProperties.end();++i,++a) + // 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) { - if(!(PLY::PropertyInstance::ParseInstanceBinary(pCur, &pCur,&(*a),&(*i),p_bBE))) - { - DefaultLogger::get()->warn("Unable to parse binary property instance. " - "Skipping this element instance"); - - (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType)); - } + PLY::DOM::SkipComments(buffer); + PLY::DOM::SkipLine(buffer); + streamBuffer.getNextDataLine(buffer, '\\'); + pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; } - *pCurOut = pCur; - return true; + } + 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) + { + //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); + } + } + + streamBuffer.getNextDataLine(buffer, '\\'); + pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; + } + } + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseInstance (const char* pCur,const char** pCurOut, - const PLY::Property* prop, PLY::PropertyInstance* p_pcOut) +bool PLY::ElementInstanceList::ParseInstanceListBinary( + IOStreamBuffer &streamBuffer, + std::vector &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 ); + ai_assert(NULL != pcElement); - *pCurOut = pCur; - - // skip spaces at the beginning - if (!SkipSpaces(pCur, &pCur)) { - return false; - } - - if (prop->bIsList) - { - // 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(v,prop->eFirstType); - - // parse all list elements - p_pcOut->avList.resize(iNum); - for (unsigned int i = 0; i < iNum;++i) - { - if (!SkipSpaces(pCur, &pCur))return false; - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&p_pcOut->avList[i]); - } - } + // 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; + ElementInstance elt; + PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &elt, p_bBE); - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&v); - p_pcOut->avList.push_back(v); + // 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); + } } - 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::ElementInstance::ParseInstance(const char* &pCur, + const PLY::Element* pcElement, + PLY::ElementInstance* p_pcOut) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != prop ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); + ai_assert(NULL != p_pcOut); - if (prop->bIsList) + // allocate enough storage + p_pcOut->alProperties.resize(pcElement->alProperties.size()); + + std::vector::iterator i = p_pcOut->alProperties.begin(); + std::vector::const_iterator a = pcElement->alProperties.begin(); + for (; i != p_pcOut->alProperties.end(); ++i, ++a) + { + if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i)))) { - // parse the number of elements in the list - PLY::PropertyInstance::ValueUnion v; - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eFirstType,&v,p_bBE); + DefaultLogger::get()->warn("Unable to parse property instance. " + "Skipping this element instance"); - // convert to unsigned int - unsigned int iNum = PLY::PropertyInstance::ConvertTo(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); - } + PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType); + (*i).avList.push_back(v); } - 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; + } + return true; } // ------------------------------------------------------------------------------------------------ -PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue( PLY::EDataType eType ) +bool PLY::ElementInstance::ParseInstanceBinary( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + const PLY::Element* pcElement, + PLY::ElementInstance* p_pcOut, + bool p_bBE /* = false */) { - PLY::PropertyInstance::ValueUnion out; + ai_assert(NULL != pcElement); + ai_assert(NULL != p_pcOut); - switch (eType) + // allocate enough storage + p_pcOut->alProperties.resize(pcElement->alProperties.size()); + + std::vector::iterator i = p_pcOut->alProperties.begin(); + std::vector::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_Float: - out.fFloat = 0.f; - return out; + DefaultLogger::get()->warn("Unable to parse binary property instance. " + "Skipping this element instance"); - case EDT_Double: - out.fDouble = 0.; - return out; + (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType)); + } + } + return true; +} - default: ; - }; - out.iUInt = 0; +// ------------------------------------------------------------------------------------------------ +bool PLY::PropertyInstance::ParseInstance(const char* &pCur, + const PLY::Property* prop, PLY::PropertyInstance* p_pcOut) +{ + ai_assert(NULL != prop); + ai_assert(NULL != p_pcOut); + + // skip spaces at the beginning + if (!SkipSpaces(&pCur)) + { + return false; + } + + if (prop->bIsList) + { + // parse the number of elements in the list + PLY::PropertyInstance::ValueUnion v; + PLY::PropertyInstance::ParseValue(pCur, prop->eFirstType, &v); + + // convert to unsigned int + unsigned int iNum = PLY::PropertyInstance::ConvertTo(v, prop->eFirstType); + + // parse all list elements + p_pcOut->avList.resize(iNum); + for (unsigned int i = 0; i < iNum; ++i) + { + if (!SkipSpaces(&pCur)) + return false; + + PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]); + } + } + else + { + // parse the property + PLY::PropertyInstance::ValueUnion v; + + PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v); + p_pcOut->avList.push_back(v); + } + SkipSpacesAndLineEnd(&pCur); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::PropertyInstance::ParseInstanceBinary(IOStreamBuffer &streamBuffer, std::vector &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(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; +} + +// ------------------------------------------------------------------------------------------------ +PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue(PLY::EDataType eType) +{ + PLY::PropertyInstance::ValueUnion out; + + switch (eType) + { + case EDT_Float: + out.fFloat = 0.f; return out; + + case EDT_Double: + out.fDouble = 0.; + return out; + + default:; + }; + out.iUInt = 0; + return out; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseValue( - const char* pCur, - const char** pCurOut, - PLY::EDataType eType, - PLY::PropertyInstance::ValueUnion* out) +bool PLY::PropertyInstance::ParseValue(const char* &pCur, + PLY::EDataType eType, + PLY::PropertyInstance::ValueUnion* out) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != 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; - bool ret = true; - *pCurOut = pCur; - switch (eType) - { - case EDT_UInt: - case EDT_UShort: - case EDT_UChar: + case EDT_UShort: + case EDT_Short: + lsize = 2; + break; - out->iUInt = (uint32_t)strtoul10(pCur, &pCur); - break; + case EDT_UInt: + case EDT_Int: + case EDT_Float: + lsize = 4; + break; - case EDT_Int: - case EDT_Short: - case EDT_Char: + case EDT_Double: + lsize = 8; + break; + } - out->iInt = (int32_t)strtol10(pCur, &pCur); - break; + bool ret = true; + switch (eType) + { + case EDT_UInt: + case EDT_UShort: + case EDT_UChar: - 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(pCur,f); - out->fFloat = (ai_real)f; - break; + out->iUInt = (uint32_t)strtoul10(pCur, &pCur); + break; - case EDT_Double: - double d; - pCur = fast_atoreal_move(pCur,d); - out->fDouble = (double)d; - break; + case EDT_Int: + case EDT_Short: + case EDT_Char: - default: - ret = false; - break; - } - *pCurOut = pCur; + out->iInt = (int32_t)strtol10(pCur, &pCur); + break; - return ret; + 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(pCur, f); + out->fFloat = (ai_real)f; + break; + + case EDT_Double: + double d; + pCur = fast_atoreal_move(pCur, d); + out->fDouble = (double)d; + break; + + default: + ret = false; + break; + } + + return ret; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseValueBinary( - const char* pCur, - const char** pCurOut, - PLY::EDataType eType, - PLY::PropertyInstance::ValueUnion* out, - bool p_bBE) +bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + PLY::EDataType eType, + PLY::PropertyInstance::ValueUnion* out, + bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != out ); + ai_assert(NULL != out); - bool ret = true; - switch (eType) + //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 nbuffer; + if (streamBuffer.getNextBlock(nbuffer)) { - 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; + //concat buffer contents + buffer = std::vector(buffer.end() - bufferSize, buffer.end()); + buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end()); + nbuffer.clear(); + bufferSize = buffer.size(); + pCur = (char*)&buffer[0]; } - *pCurOut = pCur; + else + { + throw DeadlyImportError("Invalid .ply file: File corrupted"); + } + } - return ret; + 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 diff --git a/code/PlyParser.h b/code/PlyParser.h index 930536e2d..b17b07341 100644 --- a/code/PlyParser.h +++ b/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 - 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 &buffer, Property* pOut); // ------------------------------------------------------------------- //! Parse a data type from a string - static EDataType ParseDataType(const char* pCur,const char** pCurOut); + static EDataType ParseDataType(std::vector &buffer); // ------------------------------------------------------------------- //! Parse a semantic from a string - static ESemantic ParseSemantic(const char* pCur,const char** pCurOut); + static ESemantic ParseSemantic(std::vector &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 &streamBuffer, std::vector &buffer, Element* pOut); // ------------------------------------------------------------------- //! Parse a semantic from a string - static EElementSemantic ParseSemantic(const char* pCur, - const char** pCurOut); + static EElementSemantic ParseSemantic(std::vector &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 &streamBuffer, std::vector &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 &streamBuffer, std::vector &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 &streamBuffer, std::vector &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 &streamBuffer, std::vector &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 &streamBuffer, std::vector &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 &streamBuffer, DOM* p_pcOut, PLYImporter* loader); + static bool ParseInstanceBinary(IOStreamBuffer &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 &buffer); + + static bool SkipSpaces(std::vector &buffer); + + static bool SkipLine(std::vector &buffer); + + static bool TokenMatch(std::vector &buffer, const char* token, unsigned int len); + + static bool SkipSpacesAndLineEnd(std::vector &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 &streamBuffer, std::vector &buffer, bool p_bBE); // ------------------------------------------------------------------- //! Read in all element instance lists - bool ParseElementInstanceLists (const char* pCur,const char** pCurOut); + bool ParseElementInstanceLists(IOStreamBuffer &streamBuffer, std::vector &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 mIndices; - - //! Material index - unsigned int iMaterialIndex; + bool ParseElementInstanceListsBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, const char* &pCur, unsigned int &bufferSize, PLYImporter* loader, bool p_bBE); }; // --------------------------------------------------------------------------------- diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index 5c592aaf5..f4d6ddda7 100644 --- a/code/STLLoader.cpp +++ b/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; diff --git a/contrib/poly2tri/poly2tri/common/shapes.cc b/contrib/poly2tri/poly2tri/common/shapes.cc index 4080445a7..d0de13e64 100644 --- a/contrib/poly2tri/poly2tri/common/shapes.cc +++ b/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; } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/common/shapes.h b/contrib/poly2tri/poly2tri/common/shapes.h index 4f691838f..ac7389a2d 100644 --- a/contrib/poly2tri/poly2tri/common/shapes.h +++ b/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); +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(Point* p); +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 \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/common/utils.h b/contrib/poly2tri/poly2tri/common/utils.h index f123fedaf..2424c712c 100644 --- a/contrib/poly2tri/poly2tri/common/utils.h +++ b/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 +#include + +// 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) * */ -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 - diff --git a/contrib/poly2tri/poly2tri/poly2tri.h b/contrib/poly2tri/poly2tri/poly2tri.h index 487755e2e..29a08d052 100644 --- a/contrib/poly2tri/poly2tri/poly2tri.h +++ b/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 \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/advancing_front.cc b/contrib/poly2tri/poly2tri/sweep/advancing_front.cc index 019df4a6e..38723beef 100644 --- a/contrib/poly2tri/poly2tri/sweep/advancing_front.cc +++ b/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() { } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/advancing_front.h b/contrib/poly2tri/poly2tri/sweep/advancing_front.h index bab73d449..645dcec97 100644 --- a/contrib/poly2tri/poly2tri/sweep/advancing_front.h +++ b/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 \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/cdt.cc b/contrib/poly2tri/poly2tri/sweep/cdt.cc index d7838257c..09d088ae3 100644 --- a/contrib/poly2tri/poly2tri/sweep/cdt.cc +++ b/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 polyline) +CDT::CDT(const std::vector& polyline) { sweep_context_ = new SweepContext(polyline); sweep_ = new Sweep; } -void CDT::AddHole(std::vector polyline) +void CDT::AddHole(const std::vector& polyline) { sweep_context_->AddHole(polyline); } @@ -68,5 +68,4 @@ CDT::~CDT() delete sweep_; } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/cdt.h b/contrib/poly2tri/poly2tri/sweep/cdt.h index 3e6f02408..ea3286d9a 100644 --- a/contrib/poly2tri/poly2tri/sweep/cdt.h +++ b/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 * */ - + namespace p2t { class CDT @@ -50,40 +50,40 @@ public: /** * Constructor - add polyline with non repeating points - * + * * @param polyline */ - CDT(std::vector polyline); - + CDT(const std::vector& polyline); + /** * Destructor - clean up memory */ ~CDT(); - + /** * Add a hole - * + * * @param polyline */ - void AddHole(std::vector polyline); - + void AddHole(const std::vector& 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 GetTriangles(); - + /** * Get triangle map */ @@ -94,7 +94,7 @@ public: /** * Internals */ - + SweepContext* sweep_context_; Sweep* sweep_; @@ -102,4 +102,4 @@ public: } -#endif +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/sweep.cc b/contrib/poly2tri/poly2tri/sweep/sweep.cc index ed7c49ac4..826905ceb 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep.cc +++ b/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]; } diff --git a/contrib/poly2tri/poly2tri/sweep/sweep.h b/contrib/poly2tri/poly2tri/sweep/sweep.h index bd98adfc5..33e34a714 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep.h +++ b/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, thahlen@gmail.com + * "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, thahlen@gmail.com */ #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 * */ - 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
- * 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 \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/sweep_context.cc b/contrib/poly2tri/poly2tri/sweep/sweep_context.cc index 184457cf2..a9f1fdf8e 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep_context.cc +++ b/contrib/poly2tri/poly2tri/sweep/sweep_context.cc @@ -34,17 +34,18 @@ namespace p2t { -SweepContext::SweepContext(std::vector polyline) +SweepContext::SweepContext(const std::vector& 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 polyline) +void SweepContext::AddHole(const std::vector& 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 SweepContext::GetTriangles() +std::vector &SweepContext::GetTriangles() { return triangles_; } -std::list SweepContext::GetMap() +std::list &SweepContext::GetMap() { return map_; } @@ -94,16 +95,16 @@ void SweepContext::InitTriangulation() } -void SweepContext::InitEdges(std::vector polyline) +void SweepContext::InitEdges(const std::vector& polyline) { - int num_points = static_cast(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 nodes) +void SweepContext::CreateAdvancingFront(const std::vector& 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 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)); + } } } } diff --git a/contrib/poly2tri/poly2tri/sweep/sweep_context.h b/contrib/poly2tri/poly2tri/sweep/sweep_context.h index 2f7d8e982..ba0d06581 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep_context.h +++ b/contrib/poly2tri/poly2tri/sweep/sweep_context.h @@ -52,47 +52,47 @@ class SweepContext { public: /// Constructor -SweepContext(std::vector polyline); +SweepContext(const std::vector& 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 nodes); +void CreateAdvancingFront(const std::vector& 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 polyline); +void AddHole(const std::vector& polyline); void AddPoint(Point* point); -AdvancingFront* front(); +AdvancingFront* front() const; void MeshClean(Triangle& triangle); -std::vector GetTriangles(); -std::list GetMap(); +std::vector &GetTriangles(); +std::list &GetMap(); std::vector edge_list; @@ -147,18 +147,18 @@ Point* tail_; Node *af_head_, *af_middle_, *af_tail_; void InitTriangulation(); -void InitEdges(std::vector polyline); +void InitEdges(const std::vector& 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(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_; } From 44a9f80e40cd617d139bf4d0bf81500ca67149b0 Mon Sep 17 00:00:00 2001 From: arkeon Date: Fri, 2 Jun 2017 22:19:41 +0200 Subject: [PATCH 26/62] Ply importer with correction from last general trunk merge --- code/IOStreamBuffer.h | 40 ++++++++++++++++++++++++++++++++++++++++ code/PlyLoader.cpp | 9 +++++---- code/PlyParser.cpp | 18 +++++++++--------- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/code/IOStreamBuffer.h b/code/IOStreamBuffer.h index 577e3f8a6..6ca37b6eb 100644 --- a/code/IOStreamBuffer.h +++ b/code/IOStreamBuffer.h @@ -100,6 +100,11 @@ public: /// @return true if successful. bool getNextDataLine( std::vector &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 &buffer); + /// @brief Will read the next block. /// @param buffer The buffer for the next block. /// @return true if successful. @@ -279,6 +284,41 @@ bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationT return true; } +template +inline +bool IOStreamBuffer::getNextLine(std::vector &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 inline bool IOStreamBuffer::getNextBlock( std::vector &buffer) { diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index d815b2240..b62b373d5 100644 --- a/code/PlyLoader.cpp +++ b/code/PlyLoader.cpp @@ -165,7 +165,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, // the beginning of the file must be PLY - magic, magic std::vector headerCheck; - streamedBuffer.getNextDataLine(headerCheck, '\\'); + streamedBuffer.getNextLine(headerCheck); if ((headerCheck.size() >= 3) && (headerCheck[0] != 'P' && headerCheck[0] != 'p') || (headerCheck[1] != 'L' && headerCheck[1] != 'l') || @@ -176,7 +176,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, } std::vector mBuffer2; - streamedBuffer.getNextDataLine(mBuffer2, '\\'); + streamedBuffer.getNextLine(mBuffer2); mBuffer = (unsigned char*)&mBuffer2[0]; char* szMe = (char*)&this->mBuffer[0]; @@ -1019,12 +1019,13 @@ void PLYImporter::LoadMaterial(std::vector* pvOut, std::string &def int iMode = (int)aiShadingMode_Gouraud; pcHelper->AddProperty(&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 = 0.6f; + clr.b = clr.g = clr.r = 1.0f; pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); - clr.b = clr.g = clr.r = 0.05f; + clr.b = clr.g = clr.r = 1.0f; pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT); // The face order is absolutely undefined for PLY, so we have to diff --git a/code/PlyParser.cpp b/code/PlyParser.cpp index 7d47641b6..e29005068 100644 --- a/code/PlyParser.cpp +++ b/code/PlyParser.cpp @@ -200,11 +200,11 @@ PLY::ESemantic PLY::Property::ParseSemantic(std::vector &buffer) { } // 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)) + 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)) + 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; } @@ -393,7 +393,7 @@ bool PLY::Element::ParseElement(IOStreamBuffer &streamBuffer, std::vector< // now parse all properties of the element while (true) { - streamBuffer.getNextDataLine(buffer, '\\'); + streamBuffer.getNextLine(buffer); pCur = (char*)&buffer[0]; // skip all comments @@ -530,7 +530,7 @@ bool PLY::DOM::ParseHeader(IOStreamBuffer &streamBuffer, std::vector else { // ignore unknown header elements - streamBuffer.getNextDataLine(buffer, '\\'); + streamBuffer.getNextLine(buffer); } } @@ -607,7 +607,7 @@ bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer &streamBuffer, DOM* p_pc ai_assert(NULL != loader); std::vector buffer; - streamBuffer.getNextDataLine(buffer, '\\'); + streamBuffer.getNextLine(buffer); DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); @@ -636,7 +636,7 @@ bool PLY::DOM::ParseInstance(IOStreamBuffer &streamBuffer, DOM* p_pcOut, P ai_assert(NULL != loader); std::vector buffer; - streamBuffer.getNextDataLine(buffer, '\\'); + streamBuffer.getNextLine(buffer); DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); @@ -647,7 +647,7 @@ bool PLY::DOM::ParseInstance(IOStreamBuffer &streamBuffer, DOM* p_pcOut, P } //get next line after header - streamBuffer.getNextDataLine(buffer, '\\'); + streamBuffer.getNextLine(buffer); if (!p_pcOut->ParseElementInstanceLists(streamBuffer, buffer, loader)) { DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); @@ -677,7 +677,7 @@ bool PLY::ElementInstanceList::ParseInstanceList( { PLY::DOM::SkipComments(buffer); PLY::DOM::SkipLine(buffer); - streamBuffer.getNextDataLine(buffer, '\\'); + streamBuffer.getNextLine(buffer); pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; } } @@ -711,7 +711,7 @@ bool PLY::ElementInstanceList::ParseInstanceList( } } - streamBuffer.getNextDataLine(buffer, '\\'); + streamBuffer.getNextLine(buffer); pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; } } From ff83701a6fa8fa0838e944dede276f1a2be0cdc4 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 3 Jun 2017 09:25:20 +0200 Subject: [PATCH 27/62] Sample: update dx11 texture loader. --- .../SimpleTexturedDirectx11/Mesh.h | 204 +-- .../SimpleTexturedDirectx11/ModelLoader.cpp | 410 ++--- .../SimpleTexturedDirectx11/ModelLoader.h | 88 +- .../SimpleTexturedDirectx11/TextureLoader.cpp | 1382 ++++++++--------- .../SimpleTexturedDirectx11/TextureLoader.h | 110 +- .../SimpleTexturedDirectx11/main.cpp | 1034 ++++++------ 6 files changed, 1614 insertions(+), 1614 deletions(-) diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h index e6a644a94..87433219f 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h @@ -1,102 +1,102 @@ -#ifndef MESH_H -#define MESH_H - -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include -using namespace DirectX; - -struct VERTEX { - FLOAT X, Y, Z; - XMFLOAT2 texcoord; -}; - -struct Texture { - string type; - string path; - ID3D11ShaderResourceView *texture; -}; - -class Mesh { -public: - vector vertices; - vector indices; - vector textures; - ID3D11Device *dev; - - Mesh(ID3D11Device *dev, vector vertices, vector indices, vector 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 +#ifndef MESH_H +#define MESH_H + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +using namespace DirectX; + +struct VERTEX { + FLOAT X, Y, Z; + XMFLOAT2 texcoord; +}; + +struct Texture { + string type; + string path; + ID3D11ShaderResourceView *texture; +}; + +class Mesh { +public: + vector vertices; + vector indices; + vector textures; + ID3D11Device *dev; + + Mesh(ID3D11Device *dev, vector vertices, vector indices, vector 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 diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp index 801284383..a2d3faeb3 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp @@ -1,205 +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 vertices; - vector indices; - vector 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 diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); - textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); - } - - return Mesh(dev, vertices, indices, textures); -} - -vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) -{ - vector 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(&scene->mTextures[textureindex]->mWidth); - - hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast(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; -} +#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 vertices; + vector indices; + vector 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 diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + } + + return Mesh(dev, vertices, indices, textures); +} + +vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) +{ + vector 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(&scene->mTextures[textureindex]->mWidth); + + hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast(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; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h index 020708fbf..9b4a53c27 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h @@ -1,44 +1,44 @@ -#ifndef MODEL_LOADER_H -#define MODEL_LOADER_H - -#include -#include -#include - -#include -#include -#include - -#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 meshes; - string directory; - vector textures_loaded; - HWND hwnd; - - void processNode(aiNode* node, const aiScene* scene); - Mesh processMesh(aiMesh* mesh, const aiScene* scene); - vector 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 - +#ifndef MODEL_LOADER_H +#define MODEL_LOADER_H + +#include +#include +#include + +#include +#include +#include + +#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 meshes; + string directory; + vector textures_loaded; + HWND hwnd; + + void processNode(aiNode* node, const aiScene* scene); + Mesh processMesh(aiMesh* mesh, const aiScene* scene); + vector 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 + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp index 13b3195ca..c3269d290 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp @@ -1,691 +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 -#include - -#pragma warning(push) -#pragma warning(disable : 4005) -#include -#pragma warning(pop) - -#include - -#include "TextureLoader.h" - -#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS) -#define DXGI_1_2_FORMATS -#endif - -//--------------------------------------------------------------------------------- -template 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 cinfo; - if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo))) - return 0; - - WICComponentType type; - if (FAILED(cinfo->GetComponentType(&type))) - return 0; - - if (type != WICPixelFormat) - return 0; - - ScopedObject pfinfo; - if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast(&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(height) / static_cast(width); - if (width > height) - { - twidth = static_cast(maxsize); - theight = static_cast(static_cast(maxsize) * ar); - } - else - { - theight = static_cast(maxsize); - twidth = static_cast(static_cast(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 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(rowPitch), static_cast(imageSize), temp.get()); - if (FAILED(hr)) - return hr; - } - else if (twidth != width || theight != height) - { - // Resize - IWICImagingFactory* pWIC = _GetWIC(); - if (!pWIC) - return E_NOINTERFACE; - - ScopedObject 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(rowPitch), static_cast(imageSize), temp.get()); - if (FAILED(hr)) - return hr; - } - else - { - ScopedObject 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(rowPitch), static_cast(imageSize), temp.get()); - if (FAILED(hr)) - return hr; - } - } - else - { - // Format conversion but no resize - IWICImagingFactory* pWIC = _GetWIC(); - if (!pWIC) - return E_NOINTERFACE; - - ScopedObject 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(rowPitch), static_cast(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(rowPitch); - initData.SysMemSlicePitch = static_cast(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(rowPitch), static_cast(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 stream; - HRESULT hr = pWIC->CreateStream(&stream); - if (FAILED(hr)) - return hr; - - hr = stream->InitializeFromMemory(const_cast(wicData), static_cast(wicDataSize)); - if (FAILED(hr)) - return hr; - - // Initialize WIC - ScopedObject decoder; - hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder); - if (FAILED(hr)) - return hr; - - ScopedObject 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 decoder; - HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder); - if (FAILED(hr)) - return hr; - - ScopedObject 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(strnlen_s(pstrName, MAX_PATH)), - pstrName - ); - } - - if (textureView != 0 && *textureView != 0) - { - (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, - static_cast(strnlen_s(pstrName, MAX_PATH)), - pstrName - ); - } - } -#endif - - return hr; -} +//-------------------------------------------------------------------------------------- +// 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 +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +#include + +#include "TextureLoader.h" + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS) +#define DXGI_1_2_FORMATS +#endif + +//--------------------------------------------------------------------------------- +template 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 cinfo; + if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo))) + return 0; + + WICComponentType type; + if (FAILED(cinfo->GetComponentType(&type))) + return 0; + + if (type != WICPixelFormat) + return 0; + + ScopedObject pfinfo; + if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast(&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(height) / static_cast(width); + if (width > height) + { + twidth = static_cast(maxsize); + theight = static_cast(static_cast(maxsize) * ar); + } + else + { + theight = static_cast(maxsize); + twidth = static_cast(static_cast(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 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(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else if (twidth != width || theight != height) + { + // Resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject 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(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else + { + ScopedObject 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(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + } + else + { + // Format conversion but no resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject 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(rowPitch), static_cast(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(rowPitch); + initData.SysMemSlicePitch = static_cast(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(rowPitch), static_cast(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 stream; + HRESULT hr = pWIC->CreateStream(&stream); + if (FAILED(hr)) + return hr; + + hr = stream->InitializeFromMemory(const_cast(wicData), static_cast(wicDataSize)); + if (FAILED(hr)) + return hr; + + // Initialize WIC + ScopedObject decoder; + hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject 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 decoder; + HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject 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(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + + if (textureView != 0 && *textureView != 0) + { + (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, + static_cast(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + } +#endif + + return hr; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h index 60308d9fa..c2e0b5214 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h @@ -1,55 +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 - -#pragma warning(push) -#pragma warning(disable : 4005) -#include -#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 -); - +//-------------------------------------------------------------------------------------- +// 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 + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#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 +); + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp index 5c5e8a107..2d847095a 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -1,518 +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 -#include -#include -#include -#include -#include -#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(&dxgiDevice)); - if (SUCCEEDED(hr)) - { - IDXGIAdapter* adapter = nullptr; - hr = dxgiDevice->GetAdapter(&adapter); - if (SUCCEEDED(hr)) - { - hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&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(&dxgiFactory2)); - if (dxgiFactory2) - { - // DirectX 11.1 or later - hr = dev->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&dev1)); - if (SUCCEEDED(hr)) - { - (void)devcon->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&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(&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); +// --------------------------------------------------------------------------- +// 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 +#include +#include +#include +#include +#include +#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(&dxgiDevice)); + if (SUCCEEDED(hr)) + { + IDXGIAdapter* adapter = nullptr; + hr = dxgiDevice->GetAdapter(&adapter); + if (SUCCEEDED(hr)) + { + hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&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(&dxgiFactory2)); + if (dxgiFactory2) + { + // DirectX 11.1 or later + hr = dev->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&dev1)); + if (SUCCEEDED(hr)) + { + (void)devcon->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&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(&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); } \ No newline at end of file From 19d59b630b28793d272b5a80195f1b24e2cd135e Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 6 Jun 2017 11:37:02 +0200 Subject: [PATCH 28/62] SpatialSort: use much easier reabability. --- code/SpatialSort.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/SpatialSort.cpp b/code/SpatialSort.cpp index fa78d8bb6..35724c2cd 100644 --- a/code/SpatialSort.cpp +++ b/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) From 1f88310f17cfaac0e601c5a84111fb832cfdd114 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 6 Jun 2017 11:38:08 +0200 Subject: [PATCH 29/62] travis-ci: enable oxs-build. --- .travis.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 66523f6a3..04f80a753 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +language: cpp + before_install: - sudo apt-get update -qq - sudo apt-get install cmake @@ -17,6 +19,8 @@ branches: only: - master +osx_image: xcode8.3 + env: global: - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc=" @@ -27,8 +31,6 @@ env: - LINUX=1 SHARED_BUILD=ON ENABLE_COVERALLS=OFF - LINUX=1 SHARED_BUILD=OFF ENABLE_COVERALLS=OFF - ANDROID=1 - -language: cpp compiler: - gcc @@ -46,7 +48,10 @@ 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 From 6730d658d7c9573d64b55a8068ee509ec89c14e4 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 6 Jun 2017 11:58:36 +0200 Subject: [PATCH 30/62] Fix build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 04f80a753..de522950b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ script: - . ./.travis.sh os: - linux - - osx + #- osx after_success: - cd ${TRAVIS_BUILD_DIR} From 4d37f90ea58fbacf9d992b96e13ce4c509b06dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9verin=20Lemaignan?= Date: Tue, 6 Jun 2017 15:14:18 +0100 Subject: [PATCH 31/62] Revert "Installing assimp library as well" This reverts commit 33bd5cfcfb0f27794a333273b20b60a7a550d184. Installing the assimp library from setup.py is *not* a good idea as it will break every packaging effort. Besides, the original commit relies on an hard-coded path to find the library that may not exist. --- port/PyAssimp/pyassimp/helper.py | 5 +---- port/PyAssimp/setup.py | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index 99d0b1758..b281e94cf 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/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 """ diff --git a/port/PyAssimp/setup.py b/port/PyAssimp/setup.py index 8f3cdcae2..e683f7a81 100644 --- a/port/PyAssimp/setup.py +++ b/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'] ) From 074caf971b9d502ba5910542bad0d8d8fd1b4ce0 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 6 Jun 2017 16:57:19 +0200 Subject: [PATCH 32/62] travis-ci: reenable osx. --- .travis.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index de522950b..2e0ddcf07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,8 @@ 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 freeglut3-dev libxmu-dev libxi-dev - 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} @@ -50,7 +48,7 @@ script: - . ./.travis.sh os: - linux - #- osx + - osx after_success: - cd ${TRAVIS_BUILD_DIR} From 846fa1f55ed31fbf6cbe782bf0f977c321578655 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 6 Jun 2017 21:41:39 +0200 Subject: [PATCH 33/62] travis-ci: add missing close bracket for if block. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2e0ddcf07..be9614c23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: cpp before_install: - 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 freeglut3-dev libxmu-dev libxi-dev + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install cmake python3 freeglut3-dev libxmu-dev libxi-dev; 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} From e08577adf78953a93b0346339d11b50c1b2df5a5 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 6 Jun 2017 23:58:00 +0200 Subject: [PATCH 34/62] travis-ci: use correct package name. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index be9614c23..55761937d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: cpp before_install: - 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 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} From a687354674afce87566cd5ff602b1825ad78e3a7 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 7 Jun 2017 09:32:48 +0200 Subject: [PATCH 35/62] travis-ci: disable coverage test for osx. --- .travis.yml | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 55761937d..9f4099a29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,7 @@ before_install: - 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: @@ -28,7 +22,7 @@ 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 +# - ANDROID=1 compiler: - gcc @@ -38,9 +32,8 @@ 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 @@ -51,11 +44,7 @@ os: - 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: From 098e2ffaf921660b0c310809cc0b0d36a5774ba2 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 7 Jun 2017 10:30:40 +0200 Subject: [PATCH 36/62] travis-ci: disable tests for osx. --- .travis.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.sh b/.travis.sh index c2852855f..65f55737a 100755 --- a/.travis.sh +++ b/.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 [ $LINUX ]; then generate \ && make -j4 \ && sudo make install \ From 1792333031ef8fe8211df4468d93e66acd6213d1 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 7 Jun 2017 11:48:00 +0200 Subject: [PATCH 37/62] travis-ci: fix unittest executor. --- .travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.sh b/.travis.sh index 65f55737a..7161fd28d 100755 --- a/.travis.sh +++ b/.travis.sh @@ -6,7 +6,7 @@ function generate() if [ $ANDROID ]; then ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni fi -if [ $LINUX ]; then +if [ "$TRAVIS_OS_NAME" = "linux" ]; then generate \ && make -j4 \ && sudo make install \ From 548c09271b0810f8ce3e5de705ac121b1e677a24 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 7 Jun 2017 14:06:38 +0200 Subject: [PATCH 38/62] ply-exporter: add unittest. --- code/PlyExporter.h | 6 ++---- test/unit/utPLYImportExport.cpp | 23 ++++++++++++++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/code/PlyExporter.h b/code/PlyExporter.h index ce242692c..d1d4eafbb 100644 --- a/code/PlyExporter.h +++ b/code/PlyExporter.h @@ -51,14 +51,12 @@ struct aiScene; struct aiNode; struct aiMesh; -namespace Assimp -{ +namespace Assimp { // ------------------------------------------------------------------------------------------------ /** Helper class to export a given scene to a Stanford Ply file. */ // ------------------------------------------------------------------------------------------------ -class PlyExporter -{ +class PlyExporter { public: /// The class constructor for a specific scene to export PlyExporter(const char* filename, const aiScene* pScene, bool binary = false); diff --git a/test/unit/utPLYImportExport.cpp b/test/unit/utPLYImportExport.cpp index 7ac15edac..5ab809530 100644 --- a/test/unit/utPLYImportExport.cpp +++ b/test/unit/utPLYImportExport.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include +#include #include "AbstractImportExportBase.h" using namespace ::Assimp; @@ -52,12 +53,32 @@ public: const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0 ); return nullptr != scene; } + +#ifndef ASSIMP_BUILD_NO_EXPORT + virtual bool exporterTest() { + Importer importer; + Exporter exporter; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0); + EXPECT_NE(nullptr, scene); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/ply/cube_test.ply")); + + return true; + } +#endif // ASSIMP_BUILD_NO_EXPORT }; -TEST_F( utPLYImportExport, importTest ) { +TEST_F( utPLYImportExport, importTest_Success ) { EXPECT_TRUE( importerTest() ); } +#ifndef ASSIMP_BUILD_NO_EXPORT + +TEST_F(utPLYImportExport, exportTest_Success ) { + EXPECT_TRUE(exporterTest()); +} + +#endif // ASSIMP_BUILD_NO_EXPORT + TEST_F( utPLYImportExport, vertexColorTest ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/float-color.ply", 0 ); From 0d3e826182ba001ca7352e674e5ad665483b2755 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 7 Jun 2017 20:23:50 +0200 Subject: [PATCH 39/62] Matrix: some reformattings. --- include/assimp/matrix4x4.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/assimp/matrix4x4.h b/include/assimp/matrix4x4.h index 77e295436..4311fa118 100644 --- a/include/assimp/matrix4x4.h +++ b/include/assimp/matrix4x4.h @@ -224,7 +224,7 @@ public: * @return Reference to the output matrix */ static aiMatrix4x4t& Rotation(TReal a, const aiVector3t& 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& v, aiMatrix4x4t& out); + static aiMatrix4x4t& Translation( const aiVector3t& 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& from, - const aiVector3t& to, aiMatrix4x4t& out); + const aiVector3t& to, aiMatrix4x4t& out); public: TReal a1, a2, a3, a4; From ab9aa67c4934f5edbb65bdb31f7292b463755073 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 7 Jun 2017 21:10:52 +0200 Subject: [PATCH 40/62] travis: exclose some build env to avoid double tests. --- .travis.yml | 7 +++++-- include/assimp/color4.inl | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f4099a29..70ae9e6b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +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 - + exclude: + - os: linux + compiler: clang + - os: osx + compiler: gcc compiler: - gcc - clang diff --git a/include/assimp/color4.inl b/include/assimp/color4.inl index 6f4bf0261..b242c4e77 100644 --- a/include/assimp/color4.inl +++ b/include/assimp/color4.inl @@ -77,7 +77,6 @@ AI_FORCE_INLINE const aiColor4t& aiColor4t::operator /= (TReal f) // ------------------------------------------------------------------------------------------------ template AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { - //return *(&r + i); switch ( i ) { case 0: return r; @@ -93,7 +92,6 @@ AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { // ------------------------------------------------------------------------------------------------ template AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { -// return *(&r + i); switch ( i ) { case 0: return r; From 1eb1c5ed4e47d86596053b41db2bfce14205e3a1 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 8 Jun 2017 09:13:44 +0200 Subject: [PATCH 41/62] Create .travis.yml Fix build. --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70ae9e6b6..2aae1a706 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,11 +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 - exclude: - - os: linux - compiler: clang - - os: osx - compiler: gcc + #exclude: + # - os: linux + # compiler: clang + # - os: osx + # compiler: gcc compiler: - gcc - clang From ad74bfc260d19762556ef9e9d59b86ede0e1cc0f Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 9 Jun 2017 20:20:24 +0200 Subject: [PATCH 42/62] Unitetsts: reformats. --- test/unit/TestIOSystem.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/unit/TestIOSystem.h b/test/unit/TestIOSystem.h index a821c29ec..40d894a21 100644 --- a/test/unit/TestIOSystem.h +++ b/test/unit/TestIOSystem.h @@ -53,14 +53,18 @@ static const string Sep = "/"; class TestIOSystem : public IOSystem { public: TestIOSystem() - : IOSystem() { + : IOSystem() { // empty } - virtual ~TestIOSystem() {} + virtual ~TestIOSystem() { + // empty + } + virtual bool Exists( const char* ) const { return true; } + virtual char getOsSeparator() const { return Sep[ 0 ]; } From 616a18b0c77a9cc3614806bd20252f6ac00ef776 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 9 Jun 2017 21:57:41 +0200 Subject: [PATCH 43/62] Unittests: fix uppercase typo in export path for ply export test. --- test/unit/utPLYImportExport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/utPLYImportExport.cpp b/test/unit/utPLYImportExport.cpp index 5ab809530..1ef8b6803 100644 --- a/test/unit/utPLYImportExport.cpp +++ b/test/unit/utPLYImportExport.cpp @@ -60,7 +60,7 @@ public: Exporter exporter; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0); EXPECT_NE(nullptr, scene); - EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/ply/cube_test.ply")); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/PLY/cube_test.ply")); return true; } From 4399922ea10d95056cfda09a8830f4a8da590d9b Mon Sep 17 00:00:00 2001 From: Tomas Maly Date: Sat, 10 Jun 2017 20:12:12 +0200 Subject: [PATCH 44/62] fixed CMAKE_MODULE_PATH overwriting previous values --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb31946be..3742eb01a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,7 +168,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/include ) -SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" ) +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" ) SET(LIBASSIMP_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}" ) SET(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}-dev" ) SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev) From a5a53433042ae9f9f7d2f9d25312b46fd09702a4 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 13 Jun 2017 20:29:25 +0200 Subject: [PATCH 45/62] travis ci: enable sudo support. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 2aae1a706..bce90dff1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +sudo: required language: cpp before_install: From 51520cb5f1adcb588a2533d450aace480c7cc3d4 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 15 Jun 2017 08:37:44 +0200 Subject: [PATCH 46/62] unittest: Fix compiler warning --- test/unit/utObjTools.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/utObjTools.cpp b/test/unit/utObjTools.cpp index 89bb19aa0..e888d2ce5 100644 --- a/test/unit/utObjTools.cpp +++ b/test/unit/utObjTools.cpp @@ -110,7 +110,6 @@ TEST_F( utObjTools, countComponents_TwoLines_Success ) { ::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 ); From 79818145a72fa7bdbf2dcc73acd9ffc9ec7ee6ff Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 15 Jun 2017 20:24:10 +0200 Subject: [PATCH 47/62] ObjImporter: remove dead code. --- code/ObjFileParser.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 5f95bb96d..bd73a88d9 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -109,28 +109,6 @@ ObjFile::Model *ObjFileParser::GetModel() const { return m_pModel; } -/*void ignoreNewLines(IOStreamBuffer &streamBuffer, std::vector &buffer) -{ - auto curPosition = buffer.begin(); - do - { - while (*curPosition!='\n'&&*curPosition!='\\') - { - ++curPosition; - } - if (*curPosition=='\\') - { - std::vector tempBuf; - do - { - streamBuffer.getNextDataLine(tempBuf, '\\' ); - } while (tempBuf[0]=='\n'); - *curPosition = ' '; - std::copy(tempBuf.cbegin(), tempBuf.cend(), ++curPosition); - } - } while (*curPosition!='\n'); -}*/ - void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { // only update every 100KB or it'll be too slow //const unsigned int updateProgressEveryBytes = 100 * 1024; From 6e1034996e0a65f22407d55bd94e1458a98abae0 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 16 Jun 2017 16:43:39 +0200 Subject: [PATCH 48/62] UTF8Encoding: introduce new lib. --- code/BaseImporter.cpp | 44 +- code/SIBImporter.cpp | 31 +- contrib/utf8cpp/doc/ReleaseNotes | 12 + contrib/utf8cpp/doc/utf8cpp.html | 1789 +++++++++++++++++++++++ contrib/utf8cpp/source/utf8.h | 34 + contrib/utf8cpp/source/utf8/checked.h | 327 +++++ contrib/utf8cpp/source/utf8/core.h | 329 +++++ contrib/utf8cpp/source/utf8/unchecked.h | 228 +++ 8 files changed, 2768 insertions(+), 26 deletions(-) create mode 100644 contrib/utf8cpp/doc/ReleaseNotes create mode 100644 contrib/utf8cpp/doc/utf8cpp.html create mode 100644 contrib/utf8cpp/source/utf8.h create mode 100644 contrib/utf8cpp/source/utf8/checked.h create mode 100644 contrib/utf8cpp/source/utf8/core.h create mode 100644 contrib/utf8cpp/source/utf8/unchecked.h diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index e8d547783..ba5faed80 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -303,10 +303,11 @@ void BaseImporter::GetExtensionList(std::set& extensions) return false; } -#include "../contrib/ConvertUTF/ConvertUTF.h" +//#include "../contrib/ConvertUTF/ConvertUTF.h" +#include "../contrib/utf8cpp/source/utf8.h" // ------------------------------------------------------------------------------------------------ -void ReportResult(ConversionResult res) +/*void ReportResult(ConversionResult res) { if(res == sourceExhausted) { DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails"); @@ -314,13 +315,13 @@ void ReportResult(ConversionResult res) else if(res == sourceIllegal) { DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails"); } -} +}*/ // ------------------------------------------------------------------------------------------------ // Convert to UTF8 data void BaseImporter::ConvertToUTF8(std::vector& data) { - ConversionResult result; + //ConversionResult result; if(data.size() < 8) { throw DeadlyImportError("File is too small"); } @@ -333,7 +334,8 @@ void BaseImporter::ConvertToUTF8(std::vector& data) data.resize(data.size()-3); return; } - + + // UTF 32 BE with BOM if(*((uint32_t*)&data.front()) == 0xFFFE0000) { @@ -348,20 +350,23 @@ void BaseImporter::ConvertToUTF8(std::vector& data) DefaultLogger::get()->debug("Found UTF-32 BOM ..."); const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1; - char* dstart,*dend; +// char* dstart,*dend; std::vector output; - do { + int *ptr = (int*)&data[ 0 ]; + int *end = ptr + ( data.size() / sizeof(int) ) +1; + utf8::utf32to8( ptr, end, back_inserter(output)); +/* do { output.resize(output.size()?output.size()*3/2:data.size()/2); dstart = &output.front(),dend = &output.back()+1; - result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); - } while(result == targetExhausted); + ///result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); + } while(result == targetExhausted);*/ - ReportResult(result); + // ReportResult(result); // copy to output buffer. - const size_t outlen = (size_t)(dstart-&output.front()); - data.assign(output.begin(),output.begin()+outlen); +// const size_t outlen = (size_t)(dstart-&output.front()); +// data.assign(output.begin(),output.begin()+outlen); return; } @@ -379,13 +384,18 @@ void BaseImporter::ConvertToUTF8(std::vector& data) DefaultLogger::get()->debug("Found UTF-16 BOM ..."); const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1); - char* dstart,*dend; - std::vector output; - do { +// char* dstart,*dend; + std::vector output; + int16_t *ptr = (int16_t*) &data[ 0 ]; + int16_t *end = ptr + (data.size() / sizeof(int)) + 1; + + utf8::utf16to8(data.begin(), data.end(), back_inserter(output)); +/* do { output.resize(output.size()?output.size()*3/2:data.size()*3/4); dstart = &output.front(),dend = &output.back()+1; - result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); + utf8::utf16to8(data.begin(), data.end(), output); + } while(result == targetExhausted); ReportResult(result); @@ -393,7 +403,7 @@ void BaseImporter::ConvertToUTF8(std::vector& data) // copy to output buffer. const size_t outlen = (size_t)(dstart-&output.front()); data.assign(output.begin(),output.begin()+outlen); - return; + return;*/ } } diff --git a/code/SIBImporter.cpp b/code/SIBImporter.cpp index 87e0d1585..6cd398f48 100644 --- a/code/SIBImporter.cpp +++ b/code/SIBImporter.cpp @@ -58,7 +58,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ByteSwapper.h" #include "StreamReader.h" #include "TinyFormatter.h" -#include "../contrib/ConvertUTF/ConvertUTF.h" +//#include "../contrib/ConvertUTF/ConvertUTF.h" +#include "../contrib/utf8cpp/source/utf8.h" #include #include #include @@ -177,21 +178,33 @@ static void UnknownChunk(StreamReaderLE* stream, const SIBChunk& chunk) // Reads a UTF-16LE string and returns it at UTF-8. static aiString ReadString(StreamReaderLE* stream, uint32_t numWChars) { + if ( 0 == numWChars ) { + static const aiString empty; + return empty; + } // Allocate buffers (max expansion is 1 byte -> 4 bytes for UTF-8) - UTF16* temp = new UTF16[numWChars]; - UTF8* str = new UTF8[numWChars * 4 + 1]; + //UTF16* temp = new UTF16[numWChars]; + std::vector str; + str.reserve(numWChars * 4 + 1); + //unsigned char* str = new unsigned char[numWChars * 4 + 1]; + uint16_t *temp = new uint16_t[numWChars]; for (uint32_t n=0;nGetU2(); // Convert it and NUL-terminate. - const UTF16 *start = temp, *end = temp + numWChars; - UTF8 *dest = str, *limit = str + numWChars*4; - ConvertUTF16toUTF8(&start, end, &dest, limit, lenientConversion); - *dest = '\0'; + //const UTF16 *start = temp, *end = temp + numWChars; + const uint16_t *start = temp, *end = temp + numWChars; + utf8::utf16to8(start, end, back_inserter(str)); + + //UTF8 *dest = str, *limit = str + numWChars*4; + //ConvertUTF16toUTF8(&start, end, &dest, limit, lenientConversion); + //*dest = '\0'; + + str[str.size()-1] = '\0'; // Return the final string. - aiString result = aiString((const char *)str); - delete[] str; + aiString result = aiString((const char *)&str[0]); + //delete[] str; delete[] temp; return result; } diff --git a/contrib/utf8cpp/doc/ReleaseNotes b/contrib/utf8cpp/doc/ReleaseNotes new file mode 100644 index 000000000..364411a23 --- /dev/null +++ b/contrib/utf8cpp/doc/ReleaseNotes @@ -0,0 +1,12 @@ +utf8 cpp library +Release 2.3.4 + +A minor bug fix release. Thanks to all who reported bugs. + +Note: Version 2.3.3 contained a regression, and therefore was removed. + +Changes from version 2.3.2 +- Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';' +- Bug fix [36]: replace_invalid() only works with back_inserter + +Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes diff --git a/contrib/utf8cpp/doc/utf8cpp.html b/contrib/utf8cpp/doc/utf8cpp.html new file mode 100644 index 000000000..6f2aacbe7 --- /dev/null +++ b/contrib/utf8cpp/doc/utf8cpp.html @@ -0,0 +1,1789 @@ + + + + + + + + + UTF8-CPP: UTF-8 with C++ in a Portable Way + + + + +

+ UTF8-CPP: UTF-8 with C++ in a Portable Way +

+

+ The Sourceforge project page +

+ +

+ Introduction +

+

+ Many C++ developers miss an easy and portable way of handling Unicode encoded + strings. The original C++ Standard (known as C++98 or C++03) is Unicode agnostic. + C++11 provides some support for Unicode on core language and library level: + u8, u, and U character and string literals, char16_t and char32_t character types, + u16string and u32string library classes, and codecvt support for conversions + between Unicode encoding forms. + In the meantime, developers use third party libraries like ICU, OS specific capabilities, or simply + roll out their own solutions. +

+

+ In order to easily handle UTF-8 encoded Unicode strings, I came up with a small + generic library. For anybody used to work with STL algorithms and iterators, it should be + easy and natural to use. The code is freely available for any purpose - check out + the license at the beginning of the utf8.h file. If you run into + bugs or performance issues, please let me know and I'll do my best to address them. +

+

+ The purpose of this article is not to offer an introduction to Unicode in general, + and UTF-8 in particular. If you are not familiar with Unicode, be sure to check out + Unicode Home Page or some other source of + information for Unicode. Also, it is not my aim to advocate the use of UTF-8 + encoded strings in C++ programs; if you want to handle UTF-8 encoded strings from + C++, I am sure you have good reasons for it. +

+

+ Examples of use +

+

+ Introductionary Sample +

+

+ To illustrate the use of the library, let's start with a small but complete program + that opens a file containing UTF-8 encoded text, reads it line by line, checks each line + for invalid UTF-8 byte sequences, and converts it to UTF-16 encoding and back to UTF-8: +

+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include "utf8.h"
+using namespace std;
+int main(int argc, char** argv)
+{
+    if (argc != 2) {
+        cout << "\nUsage: docsample filename\n";
+        return 0;
+    }
+
+    const char* test_file_path = argv[1];
+    // Open the test file (contains UTF-8 encoded text)
+    ifstream fs8(test_file_path);
+    if (!fs8.is_open()) {
+    cout << "Could not open " << test_file_path << endl;
+    return 0;
+    }
+
+    unsigned line_count = 1;
+    string line;
+    // Play with all the lines in the file
+    while (getline(fs8, line)) {
+       // check for invalid utf-8 (for a simple yes/no check, there is also utf8::is_valid function)
+        string::iterator end_it = utf8::find_invalid(line.begin(), line.end());
+        if (end_it != line.end()) {
+            cout << "Invalid UTF-8 encoding detected at line " << line_count << "\n";
+            cout << "This part is fine: " << string(line.begin(), end_it) << "\n";
+        }
+
+        // Get the line length (at least for the valid part)
+        int length = utf8::distance(line.begin(), end_it);
+        cout << "Length of line " << line_count << " is " << length <<  "\n";
+
+        // Convert it to utf-16
+        vector<unsigned short> utf16line;
+        utf8::utf8to16(line.begin(), end_it, back_inserter(utf16line));
+
+        // And back to utf-8
+        string utf8line; 
+        utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8line));
+
+        // Confirm that the conversion went OK:
+        if (utf8line != string(line.begin(), end_it))
+            cout << "Error in UTF-16 conversion at line: " << line_count << "\n";        
+
+        line_count++;
+    }
+    return 0;
+}
+
+

+ In the previous code sample, for each line we performed + a detection of invalid UTF-8 sequences with find_invalid; the number + of characters (more precisely - the number of Unicode code points, including the end + of line and even BOM if there is one) in each line was + determined with a use of utf8::distance; finally, we have converted + each line to UTF-16 encoding with utf8to16 and back to UTF-8 with + utf16to8. +

+

Checking if a file contains valid UTF-8 text

+

+Here is a function that checks whether the content of a file is valid UTF-8 encoded text without +reading the content into the memory: +

+
    
+bool valid_utf8_file(iconst char* file_name)
+{
+    ifstream ifs(file_name);
+    if (!ifs)
+        return false; // even better, throw here
+
+    istreambuf_iterator<char> it(ifs.rdbuf());
+    istreambuf_iterator<char> eos;
+
+    return utf8::is_valid(it, eos);
+}
+
+

+Because the function utf8::is_valid() works with input iterators, we were able +to pass an istreambuf_iterator to it and read the content of the file directly +without loading it to the memory first.

+

+Note that other functions that take input iterator arguments can be used in a similar way. For +instance, to read the content of a UTF-8 encoded text file and convert the text to UTF-16, just +do something like: +

+
+    utf8::utf8to16(it, eos, back_inserter(u16string));
+
+

Ensure that a string contains valid UTF-8 text

+

+If we have some text that "probably" contains UTF-8 encoded text and we want to +replace any invalid UTF-8 sequence with a replacement character, something like +the following function may be used: +

+
+void fix_utf8_string(std::string& str)
+{
+    std::string temp;
+    utf8::replace_invalid(str.begin(), str.end(), back_inserter(temp));
+    str = temp;
+}
+
+

The function will replace any invalid UTF-8 sequence with a Unicode replacement character. +There is an overloaded function that enables the caller to supply their own replacement character. +

+

+ Reference +

+

+ Functions From utf8 Namespace +

+

+ utf8::append +

+

+ Available in version 1.0 and later. +

+

+ Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence + to a UTF-8 string. +

+
+template <typename octet_iterator>
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+
+

+ octet_iterator: an output iterator.
+ cp: a 32 bit integer representing a code point to append to the + sequence.
+ result: an output iterator to the place in the sequence where to + append the code point.
+ Return value: an iterator pointing to the place + after the newly appended sequence. +

+

+ Example of use: +

+
+unsigned char u[5] = {0,0,0,0,0};
+unsigned char* end = append(0x0448, u);
+assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);
+
+

+ Note that append does not allocate any memory - it is the burden of + the caller to make sure there is enough memory allocated for the operation. To make + things more interesting, append can add anywhere between 1 and 4 + octets to the sequence. In practice, you would most often want to use + std::back_inserter to ensure that the necessary memory is allocated. +

+

+ In case of an invalid code point, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::next +

+

+ Available in version 1.0 and later. +

+

+ Given the iterator to the beginning of the UTF-8 sequence, it returns the code + point and moves the iterator to the next position. +

+
+template <typename octet_iterator> 
+uint32_t next(octet_iterator& it, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + beginning of the next code point.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = next(w, twochars + 6);
+assert (cp == 0x65e5);
+assert (w == twochars + 3);
+
+

+ This function is typically used to iterate through a UTF-8 encoded string. +

+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. +

+

+ utf8::peek_next +

+

+ Available in version 2.1 and later. +

+

+ Given the iterator to the beginning of the UTF-8 sequence, it returns the code + point for the following sequence without changing the value of the iterator. +

+
+template <typename octet_iterator> 
+uint32_t peek_next(octet_iterator it, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ it: an iterator pointing to the beginning of an UTF-8 + encoded code point.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = peek_next(w, twochars + 6);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. +

+

+ utf8::prior +

+

+ Available in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 sequence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator> 
+uint32_t prior(octet_iterator& it, octet_iterator start);
+   
+
+

+ octet_iterator: a bidirectional iterator.
+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ start: an iterator to the beginning of the sequence where the search + for the beginning of a code point is performed. It is a + safety measure to prevent passing the beginning of the string in the search for a + UTF-8 lead octet.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars + 3;
+int cp = prior (w, twochars);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This function has two purposes: one is two iterate backwards through a UTF-8 + encoded string. Note that it is usually a better idea to iterate forward instead, + since utf8::next is faster. The second purpose is to find a beginning + of a UTF-8 sequence if we have a random position within a string. Note that in that + case utf8::prior may not detect an invalid UTF-8 sequence in some scenarios: + for instance if there are superfluous trail octets, it will just skip them. +

+

+ it will typically point to the beginning of + a code point, and start will point to the + beginning of the string to ensure we don't go backwards too far. it is + decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence + beginning with that octet is decoded to a 32 bit representation and returned. +

+

+ In case start is reached before a UTF-8 lead octet is hit, or if an + invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 + exception is thrown. +

+

In case start equals it, a not_enough_room + exception is thrown. +

+ utf8::previous +

+

+ Deprecated in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator> 
+uint32_t previous(octet_iterator& it, octet_iterator pass_start);
+   
+
+

+ octet_iterator: a random access iterator.
+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ pass_start: an iterator to the point in the sequence where the search + for the beginning of a code point is aborted if no result was reached. It is a + safety measure to prevent passing the beginning of the string in the search for a + UTF-8 lead octet.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars + 3;
+int cp = previous (w, twochars - 1);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ utf8::previous is deprecated, and utf8::prior should + be used instead, although the existing code can continue using this function. + The problem is the parameter pass_start that points to the position + just before the beginning of the sequence. Standard containers don't have the + concept of "pass start" and the function can not be used with their iterators. +

+

+ it will typically point to the beginning of + a code point, and pass_start will point to the octet just before the + beginning of the string to ensure we don't go backwards too far. it is + decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence + beginning with that octet is decoded to a 32 bit representation and returned. +

+

+ In case pass_start is reached before a UTF-8 lead octet is hit, or if an + invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 + exception is thrown +

+

+ utf8::advance +

+

+ Available in version 1.0 and later. +

+

+ Advances an iterator by the specified number of code points within an UTF-8 + sequence. +

+
+template <typename octet_iterator, typename distance_type> 
+void advance (octet_iterator& it, distance_type n, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ distance_type: an integral type convertible to octet_iterator's difference type.
+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + nth following code point.
+ n: a positive integer that shows how many code points we want to + advance.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars;
+advance (w, 2, twochars + 6);
+assert (w == twochars + 5);
+
+

+ This function works only "forward". In case of a negative n, there is + no effect. +

+

+ In case of an invalid code point, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::distance +

+

+ Available in version 1.0 and later. +

+

+ Given the iterators to two UTF-8 encoded code points in a seqence, returns the + number of code points between them. +

+
+template <typename octet_iterator> 
+typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);
+   
+
+

+ octet_iterator: an input iterator.
+ first: an iterator to a beginning of a UTF-8 encoded code point.
+ last: an iterator to a "post-end" of the last UTF-8 encoded code + point in the sequence we are trying to determine the length. It can be the + beginning of a new code point, or not.
+ Return value the distance between the iterators, + in code points. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+size_t dist = utf8::distance(twochars, twochars + 5);
+assert (dist == 2);
+
+

+ This function is used to find the length (in code points) of a UTF-8 encoded + string. The reason it is called distance, rather than, say, + length is mainly because developers are used that length is an + O(1) function. Computing the length of an UTF-8 string is a linear operation, and + it looked better to model it after std::distance algorithm. +

+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If last does not point to the past-of-end of a UTF-8 seqence, + a utf8::not_enough_room exception is thrown. +

+

+ utf8::utf16to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-16 encoded string to UTF-8. +

+
+template <typename u16bit_iterator, typename octet_iterator>
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+
+

+ u16bit_iterator: an input iterator.
+ octet_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-16 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-16 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
+vector<unsigned char> utf8result;
+utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
+assert (utf8result.size() == 10);    
+
+

+ In case of invalid UTF-16 sequence, a utf8::invalid_utf16 exception is + thrown. +

+

+ utf8::utf8to16 +

+

+ Available in version 1.0 and later. +

+

+ Converts an UTF-8 encoded string to UTF-16 +

+
+template <typename u16bit_iterator, typename octet_iterator>
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+
+

+ octet_iterator: an input iterator.
+ u16bit_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert. < br /> end: an iterator pointing to + pass-the-end of the UTF-8 encoded string to convert.
+ result: an output iterator to the place in the UTF-16 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-16 string. +

+

+ Example of use: +

+
+char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
+vector <unsigned short> utf16result;
+utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
+assert (utf16result.size() == 4);
+assert (utf16result[2] == 0xd834);
+assert (utf16result[3] == 0xdd1e);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If end does not point to the past-of-end of a UTF-8 seqence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::utf32to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-32 encoded string to UTF-8. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+
+

+ octet_iterator: an output iterator.
+ u32bit_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-32 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-32 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+int utf32string[] = {0x448, 0x65E5, 0x10346, 0};
+vector<unsigned char> utf8result;
+utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
+assert (utf8result.size() == 9);
+
+

+ In case of invalid UTF-32 string, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::utf8to32 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-8 encoded string to UTF-32. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+
+

+ octet_iterator: an input iterator.
+ u32bit_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-8 encoded string + to convert.
+ result: an output iterator to the place in the UTF-32 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-32 string. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+vector<int> utf32result;
+utf8to32(twochars, twochars + 5, back_inserter(utf32result));
+assert (utf32result.size() == 2);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If end does not point to the past-of-end of a UTF-8 seqence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::find_invalid +

+

+ Available in version 1.0 and later. +

+

+ Detects an invalid sequence within a UTF-8 string. +

+
+template <typename octet_iterator> 
+octet_iterator find_invalid(octet_iterator start, octet_iterator end);
+
+

+ octet_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + test for validity.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to test + for validity.
+ Return value: an iterator pointing to the first + invalid octet in the UTF-8 string. In case none were found, equals + end. +

+

+ Example of use: +

+
+char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
+char* invalid = find_invalid(utf_invalid, utf_invalid + 6);
+assert (invalid == utf_invalid + 5);
+
+

+ This function is typically used to make sure a UTF-8 string is valid before + processing it with other functions. It is especially important to call it if before + doing any of the unchecked operations on it. +

+

+ utf8::is_valid +

+

+ Available in version 1.0 and later. +

+

+ Checks whether a sequence of octets is a valid UTF-8 string. +

+
+template <typename octet_iterator> 
+bool is_valid(octet_iterator start, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + test for validity.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to test + for validity.
+ Return value: true if the sequence + is a valid UTF-8 string; false if not. +

+ Example of use: +
+char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
+bool bvalid = is_valid(utf_invalid, utf_invalid + 6);
+assert (bvalid == false);
+
+

+ is_valid is a shorthand for find_invalid(start, end) == + end;. You may want to use it to make sure that a byte seqence is a valid + UTF-8 string without the need to know where it fails if it is not valid. +

+

+ utf8::replace_invalid +

+

+ Available in version 2.0 and later. +

+

+ Replaces all invalid UTF-8 sequences within a string with a replacement marker. +

+
+template <typename octet_iterator, typename output_iterator>
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement);
+template <typename octet_iterator, typename output_iterator>
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out);
+   
+
+

+ octet_iterator: an input iterator.
+ output_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + look for invalid UTF-8 sequences.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to look + for invalid UTF-8 sequences.
+ out: An output iterator to the range where the result of replacement + is stored.
+ replacement: A Unicode code point for the replacement marker. The + version without this parameter assumes the value 0xfffd
+ Return value: An iterator pointing to the place + after the UTF-8 string with replaced invalid sequences. +

+

+ Example of use: +

+
+char invalid_sequence[] = "a\x80\xe0\xa0\xc0\xaf\xed\xa0\x80z";
+vector<char> replace_invalid_result;
+replace_invalid (invalid_sequence, invalid_sequence + sizeof(invalid_sequence), back_inserter(replace_invalid_result), '?');
+bvalid = is_valid(replace_invalid_result.begin(), replace_invalid_result.end());
+assert (bvalid);
+char* fixed_invalid_sequence = "a????z";
+assert (std::equal(replace_invalid_result.begin(), replace_invalid_result.end(), fixed_invalid_sequence));
+
+

+ replace_invalid does not perform in-place replacement of invalid + sequences. Rather, it produces a copy of the original string with the invalid + sequences replaced with a replacement marker. Therefore, out must not + be in the [start, end] range. +

+

+ If end does not point to the past-of-end of a UTF-8 sequence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::starts_with_bom +

+

+ Available in version 2.3 and later. Relaces deprecated is_bom() function. +

+

+ Checks whether an octet sequence starts with a UTF-8 byte order mark (BOM) +

+
+template <typename octet_iterator> 
+bool starts_with_bom (octet_iterator it, octet_iterator end);
+
+

+ octet_iterator: an input iterator.
+ it: beginning of the octet sequence to check
+ end: pass-end of the sequence to check
+ Return value: true if the sequence + starts with a UTF-8 byte order mark; false if not. +

+

+ Example of use: +

+
+unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
+bool bbom = starts_with_bom(byte_order_mark, byte_order_mark + sizeof(byte_order_mark));
+assert (bbom == true);
+
+

+ The typical use of this function is to check the first three bytes of a file. If + they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 + encoded text. +

+

+ utf8::is_bom +

+

+ Available in version 1.0 and later. Deprecated in version 2.3. starts_with_bom() should be used + instead. +

+

+ Checks whether a sequence of three octets is a UTF-8 byte order mark (BOM) +

+
+template <typename octet_iterator> 
+bool is_bom (octet_iterator it);  // Deprecated
+
+

+ octet_iterator: an input iterator.
+ it: beginning of the 3-octet sequence to check
+ Return value: true if the sequence + is UTF-8 byte order mark; false if not. +

+

+ Example of use: +

+
+unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
+bool bbom = is_bom(byte_order_mark);
+assert (bbom == true);
+
+

+ The typical use of this function is to check the first three bytes of a file. If + they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 + encoded text. +

+

+ If a sequence is + shorter than three bytes, an invalid iterator will be dereferenced. Therefore, this function is deprecated + in favor of starts_with_bom()that takes the end of sequence as an argument. +

+

+ Types From utf8 Namespace +

+

utf8::exception +

+

+ Available in version 2.3 and later. +

+

+ Base class for the exceptions thrown by UTF CPP library functions. +

+
+class exception : public std::exception {};
+
+

+ Example of use: +

+
+try {
+  code_that_uses_utf_cpp_library();
+}
+catch(const utf8::exception& utfcpp_ex) {
+  cerr << utfcpp_ex.what();
+}
+
+ +

utf8::invalid_code_point +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as advance and next if an UTF-8 sequence represents and invalid code point. +

+ +
+class invalid_code_point : public exception {
+public: 
+    uint32_t code_point() const;
+};
+
+
+

+ Member function code_point() can be used to determine the invalid code point that + caused the exception to be thrown. +

+

utf8::invalid_utf8 +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as next and prior if an invalid UTF-8 sequence + is detected during decoding. +

+ +
+class invalid_utf8 : public exception {
+public: 
+    uint8_t utf8_octet() const;
+};
+
+ +

+ Member function utf8_octet() can be used to determine the beginning of the byte + sequence that caused the exception to be thrown. +

+ +

utf8::invalid_utf16 +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP function utf16to8 if an invalid UTF-16 sequence + is detected during decoding. +

+ +
+class invalid_utf16 : public exception {
+public: 
+    uint16_t utf16_word() const;
+};
+
+ +

+ Member function utf16_word() can be used to determine the UTF-16 code unit + that caused the exception to be thrown. +

+

utf8::not_enough_room +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as next if the end of the decoded UTF-8 sequence + was reached before the code point was decoded. +

+ +
+class not_enough_room : public exception {};
+
+

+ utf8::iterator +

+

+ Available in version 2.0 and later. +

+

+ Adapts the underlying octet iterator to iterate over the sequence of code points, + rather than raw octets. +

+
+template <typename octet_iterator>
+class iterator;
+
+ +
Member functions
+
+
iterator();
the deafult constructor; the underlying octet_iterator is + constructed with its default constructor. +
explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end);
a constructor + that initializes the underlying octet_iterator with octet_it + and sets the range in which the iterator is considered valid. +
octet_iterator base () const;
returns the + underlying octet_iterator. +
uint32_t operator * () const;
decodes the utf-8 sequence + the underlying octet_iterator is pointing to and returns the code point. +
bool operator == (const iterator& rhs) + const;
returns true + if the two underlaying iterators are equal. +
bool operator != (const iterator& rhs) + const;
returns true + if the two underlaying iterators are not equal. +
iterator& operator ++ ();
the prefix increment - moves + the iterator to the next UTF-8 encoded code point. +
iterator operator ++ (int);
+ the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one. +
iterator& operator -- ();
the prefix decrement - moves + the iterator to the previous UTF-8 encoded code point. +
iterator operator -- (int);
+ the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one. +
+

+ Example of use: +

+
+char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
+utf8::iterator<char*> it(threechars, threechars, threechars + 9);
+utf8::iterator<char*> it2 = it;
+assert (it2 == it);
+assert (*it == 0x10346);
+assert (*(++it) == 0x65e5);
+assert ((*it++) == 0x65e5);
+assert (*it == 0x0448);
+assert (it != it2);
+utf8::iterator<char*> endit (threechars + 9, threechars, threechars + 9);  
+assert (++it == endit);
+assert (*(--it) == 0x0448);
+assert ((*it--) == 0x0448);
+assert (*it == 0x65e5);
+assert (--it == utf8::iterator<char*>(threechars, threechars, threechars + 9));
+assert (*it == 0x10346);
+
+

+ The purpose of utf8::iterator adapter is to enable easy iteration as well as the use of STL + algorithms with UTF-8 encoded strings. Increment and decrement operators are implemented in terms of + utf8::next() and utf8::prior() functions. +

+

+ Note that utf8::iterator adapter is a checked iterator. It operates on the range specified in + the constructor; any attempt to go out of that range will result in an exception. Even the comparison operators + require both iterator object to be constructed against the same range - otherwise an exception is thrown. Typically, + the range will be determined by sequence container functions begin and end, i.e.: +

+
+std::string s = "example";
+utf8::iterator i (s.begin(), s.begin(), s.end());
+
+

+ Functions From utf8::unchecked Namespace +

+

+ utf8::unchecked::append +

+

+ Available in version 1.0 and later. +

+

+ Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence + to a UTF-8 string. +

+
+template <typename octet_iterator>
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+
+

+ cp: A 32 bit integer representing a code point to append to the + sequence.
+ result: An output iterator to the place in the sequence where to + append the code point.
+ Return value: An iterator pointing to the place + after the newly appended sequence. +

+

+ Example of use: +

+
+unsigned char u[5] = {0,0,0,0,0};
+unsigned char* end = unchecked::append(0x0448, u);
+assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);
+
+

+ This is a faster but less safe version of utf8::append. It does not + check for validity of the supplied code point, and may produce an invalid UTF-8 + sequence. +

+

+ utf8::unchecked::next +

+

+ Available in version 1.0 and later. +

+

+ Given the iterator to the beginning of a UTF-8 sequence, it returns the code point + and moves the iterator to the next position. +

+
+template <typename octet_iterator>
+uint32_t next(octet_iterator& it);
+   
+
+

+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + beginning of the next code point.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = unchecked::next(w);
+assert (cp == 0x65e5);
+assert (w == twochars + 3);
+
+

+ This is a faster but less safe version of utf8::next. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::peek_next +

+

+ Available in version 2.1 and later. +

+

+ Given the iterator to the beginning of a UTF-8 sequence, it returns the code point. +

+
+template <typename octet_iterator>
+uint32_t peek_next(octet_iterator it);
+   
+
+

+ it: an iterator pointing to the beginning of an UTF-8 + encoded code point.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = unchecked::peek_next(w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This is a faster but less safe version of utf8::peek_next. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::prior +

+

+ Available in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator>
+uint32_t prior(octet_iterator& it);
+   
+
+

+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars + 3;
+int cp = unchecked::prior (w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This is a faster but less safe version of utf8::prior. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::previous (deprecated, see utf8::unchecked::prior) +

+

+ Deprecated in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator>
+uint32_t previous(octet_iterator& it);
+   
+
+

+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars + 3;
+int cp = unchecked::previous (w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ The reason this function is deprecated is just the consistency with the "checked" + versions, where prior should be used instead of previous. + In fact, unchecked::previous behaves exactly the same as + unchecked::prior +

+

+ This is a faster but less safe version of utf8::previous. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::advance +

+

+ Available in version 1.0 and later. +

+

+ Advances an iterator by the specified number of code points within an UTF-8 + sequence. +

+
+template <typename octet_iterator, typename distance_type>
+void advance (octet_iterator& it, distance_type n);
+   
+
+

+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + nth following code point.
+ n: a positive integer that shows how many code points we want to + advance.
+

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+unchecked::advance (w, 2);
+assert (w == twochars + 5);
+
+

+ This function works only "forward". In case of a negative n, there is + no effect. +

+

+ This is a faster but less safe version of utf8::advance. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::distance +

+

+ Available in version 1.0 and later. +

+

+ Given the iterators to two UTF-8 encoded code points in a seqence, returns the + number of code points between them. +

+
+template <typename octet_iterator>
+typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);
+
+

+ first: an iterator to a beginning of a UTF-8 encoded code point.
+ last: an iterator to a "post-end" of the last UTF-8 encoded code + point in the sequence we are trying to determine the length. It can be the + beginning of a new code point, or not.
+ Return value the distance between the iterators, + in code points. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+size_t dist = utf8::unchecked::distance(twochars, twochars + 5);
+assert (dist == 2);
+
+

+ This is a faster but less safe version of utf8::distance. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::utf16to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-16 encoded string to UTF-8. +

+
+template <typename u16bit_iterator, typename octet_iterator>
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-16 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-16 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
+vector<unsigned char> utf8result;
+unchecked::utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
+assert (utf8result.size() == 10);    
+
+

+ This is a faster but less safe version of utf8::utf16to8. It does not + check for validity of the supplied UTF-16 sequence. +

+

+ utf8::unchecked::utf8to16 +

+

+ Available in version 1.0 and later. +

+

+ Converts an UTF-8 encoded string to UTF-16 +

+
+template <typename u16bit_iterator, typename octet_iterator>
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert. < br /> end: an iterator pointing to + pass-the-end of the UTF-8 encoded string to convert.
+ result: an output iterator to the place in the UTF-16 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-16 string. +

+

+ Example of use: +

+
+char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
+vector <unsigned short> utf16result;
+unchecked::utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
+assert (utf16result.size() == 4);
+assert (utf16result[2] == 0xd834);
+assert (utf16result[3] == 0xdd1e);
+
+

+ This is a faster but less safe version of utf8::utf8to16. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::utf32to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-32 encoded string to UTF-8. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-32 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-32 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+int utf32string[] = {0x448, 0x65e5, 0x10346, 0};
+vector<unsigned char> utf8result;
+utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
+assert (utf8result.size() == 9);
+
+

+ This is a faster but less safe version of utf8::utf32to8. It does not + check for validity of the supplied UTF-32 sequence. +

+

+ utf8::unchecked::utf8to32 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-8 encoded string to UTF-32. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-8 encoded string + to convert.
+ result: an output iterator to the place in the UTF-32 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-32 string. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+vector<int> utf32result;
+unchecked::utf8to32(twochars, twochars + 5, back_inserter(utf32result));
+assert (utf32result.size() == 2);
+
+

+ This is a faster but less safe version of utf8::utf8to32. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ Types From utf8::unchecked Namespace +

+

+ utf8::iterator +

+

+ Available in version 2.0 and later. +

+

+ Adapts the underlying octet iterator to iterate over the sequence of code points, + rather than raw octets. +

+
+template <typename octet_iterator>
+class iterator;
+
+ +
Member functions
+
+
iterator();
the deafult constructor; the underlying octet_iterator is + constructed with its default constructor. +
explicit iterator (const octet_iterator& octet_it); +
a constructor + that initializes the underlying octet_iterator with octet_it +
octet_iterator base () const;
returns the + underlying octet_iterator. +
uint32_t operator * () const;
decodes the utf-8 sequence + the underlying octet_iterator is pointing to and returns the code point. +
bool operator == (const iterator& rhs) + const;
returns true + if the two underlaying iterators are equal. +
bool operator != (const iterator& rhs) + const;
returns true + if the two underlaying iterators are not equal. +
iterator& operator ++ ();
the prefix increment - moves + the iterator to the next UTF-8 encoded code point. +
iterator operator ++ (int);
+ the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one. +
iterator& operator -- ();
the prefix decrement - moves + the iterator to the previous UTF-8 encoded code point. +
iterator operator -- (int);
+ the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one. +
+

+ Example of use: +

+
+char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
+utf8::unchecked::iterator<char*> un_it(threechars);
+utf8::unchecked::iterator<char*> un_it2 = un_it;
+assert (un_it2 == un_it);
+assert (*un_it == 0x10346);
+assert (*(++un_it) == 0x65e5);
+assert ((*un_it++) == 0x65e5);
+assert (*un_it == 0x0448);
+assert (un_it != un_it2);
+utf8::::unchecked::iterator<char*> un_endit (threechars + 9);  
+assert (++un_it == un_endit);
+assert (*(--un_it) == 0x0448);
+assert ((*un_it--) == 0x0448);
+assert (*un_it == 0x65e5);
+assert (--un_it == utf8::unchecked::iterator<char*>(threechars));
+assert (*un_it == 0x10346);
+
+

+ This is an unchecked version of utf8::iterator. It is faster in many cases, but offers + no validity or range checks. +

+

+ Points of interest +

+

+ Design goals and decisions +

+

+ The library was designed to be: +

+
    +
  1. + Generic: for better or worse, there are many C++ string classes out there, and + the library should work with as many of them as possible. +
  2. +
  3. + Portable: the library should be portable both accross different platforms and + compilers. The only non-portable code is a small section that declares unsigned + integers of different sizes: three typedefs. They can be changed by the users of + the library if they don't match their platform. The default setting should work + for Windows (both 32 and 64 bit), and most 32 bit and 64 bit Unix derivatives. +
  4. +
  5. + Lightweight: follow the "pay only for what you use" guideline. +
  6. +
  7. + Unintrusive: avoid forcing any particular design or even programming style on the + user. This is a library, not a framework. +
  8. +
+

+ Alternatives +

+

+ In case you want to look into other means of working with UTF-8 strings from C++, + here is the list of solutions I am aware of: +

+
    +
  1. + ICU Library. It is very powerful, + complete, feature-rich, mature, and widely used. Also big, intrusive, + non-generic, and doesn't play well with the Standard Library. I definitelly + recommend looking at ICU even if you don't plan to use it. +
  2. +
  3. + C++11 language and library features. Still far from complete, and not widely + supported by compiler vendors. +
  4. +
  5. + Glib::ustring. + A class specifically made to work with UTF-8 strings, and also feel like + std::string. If you prefer to have yet another string class in your + code, it may be worth a look. Be aware of the licensing issues, though. +
  6. +
  7. + Platform dependent solutions: Windows and POSIX have functions to convert strings + from one encoding to another. That is only a subset of what my library offers, + but if that is all you need it may be good enough. +
  8. +
+ +
    +
  1. + The Unicode Consortium. +
  2. +
  3. + ICU Library. +
  4. +
  5. + UTF-8 at Wikipedia +
  6. +
  7. + UTF-8 and Unicode FAQ for + Unix/Linux +
  8. +
+ + diff --git a/contrib/utf8cpp/source/utf8.h b/contrib/utf8cpp/source/utf8.h new file mode 100644 index 000000000..82b13f59f --- /dev/null +++ b/contrib/utf8cpp/source/utf8.h @@ -0,0 +1,34 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "utf8/checked.h" +#include "utf8/unchecked.h" + +#endif // header guard diff --git a/contrib/utf8cpp/source/utf8/checked.h b/contrib/utf8cpp/source/utf8/checked.h new file mode 100644 index 000000000..133115513 --- /dev/null +++ b/contrib/utf8cpp/source/utf8/checked.h @@ -0,0 +1,327 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" +#include + +namespace utf8 +{ + // Base for the exceptions that may be thrown from the library + class exception : public ::std::exception { + }; + + // Exceptions that may be thrown from the library functions. + class invalid_code_point : public exception { + uint32_t cp; + public: + invalid_code_point(uint32_t cp) : cp(cp) {} + virtual const char* what() const throw() { return "Invalid code point"; } + uint32_t code_point() const {return cp;} + }; + + class invalid_utf8 : public exception { + uint8_t u8; + public: + invalid_utf8 (uint8_t u) : u8(u) {} + virtual const char* what() const throw() { return "Invalid UTF-8"; } + uint8_t utf8_octet() const {return u8;} + }; + + class invalid_utf16 : public exception { + uint16_t u16; + public: + invalid_utf16 (uint16_t u) : u16(u) {} + virtual const char* what() const throw() { return "Invalid UTF-16"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!utf8::internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = utf8::internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + out = utf8::append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + out = utf8::append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (start != end && utf8::internal::is_trail(*start)) + ++start; + break; + } + } + return out; + } + + template + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); + return utf8::replace_invalid(start, end, out, replacement_marker); + } + + template + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return utf8::next(it, end); + } + + template + uint32_t prior(octet_iterator& it, octet_iterator start) + { + // can't do much if it == start + if (it == start) + throw not_enough_room(); + + octet_iterator end = it; + // Go back until we hit either a lead octet or start + while (utf8::internal::is_trail(*(--it))) + if (it == start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + return utf8::peek_next(it, end); + } + + /// Deprecated in versions that include "prior" + template + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (utf8::internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return utf8::next(temp, end); + } + + template + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + utf8::next(it, end); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::next(first, last); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = utf8::internal::mask16(*start++); + // Take care of surrogate pairs first + if (utf8::internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = utf8::internal::mask16(*start++); + if (utf8::internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (utf8::internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = utf8::append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = utf8::next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start != end) + (*result++) = utf8::next(start, end); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {} + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return utf8::next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + utf8::next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + utf8::next(it, range_end); + return temp; + } + iterator& operator -- () + { + utf8::prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + utf8::prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/contrib/utf8cpp/source/utf8/core.h b/contrib/utf8cpp/source/utf8/core.h new file mode 100644 index 000000000..693d388c0 --- /dev/null +++ b/contrib/utf8cpp/source/utf8/core.h @@ -0,0 +1,329 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((utf8::internal::mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); + } + + template + inline typename std::iterator_traits::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = utf8::internal::mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + template + inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// Helper for get_sequence_x + template + utf_error increase_safely(octet_iterator& it, octet_iterator end) + { + if (++it == end) + return NOT_ENOUGH_ROOM; + + if (!utf8::internal::is_trail(*it)) + return INCOMPLETE_SEQUENCE; + + return UTF8_OK; + } + + #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} + + /// get_sequence_x functions decode utf-8 sequences of the length x + template + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + return UTF8_OK; + } + + template + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); + + return UTF8_OK; + } + + template + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + template + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR + + template + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits::difference_type octet_difference_type; + const octet_difference_type length = utf8::internal::sequence_length(it); + + // Get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 0: + return INVALID_LEAD; + case 1: + err = utf8::internal::get_sequence_1(it, end, cp); + break; + case 2: + err = utf8::internal::get_sequence_2(it, end, cp); + break; + case 3: + err = utf8::internal::get_sequence_3(it, end, cp); + break; + case 4: + err = utf8::internal::get_sequence_4(it, end, cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (utf8::internal::is_code_point_valid(cp)) { + if (!utf8::internal::is_overlong_sequence(cp, length)){ + // Passed! Return here. + code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + uint32_t ignored; + return utf8::internal::validate_next(it, end, ignored); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (utf8::find_invalid(start, end) == end); + } + + template + inline bool starts_with_bom (octet_iterator it, octet_iterator end) + { + return ( + ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && + ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && + ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) + ); + } + + //Deprecated in release 2.3 + template + inline bool is_bom (octet_iterator it) + { + return ( + (utf8::internal::mask8(*it++)) == bom[0] && + (utf8::internal::mask8(*it++)) == bom[1] && + (utf8::internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/contrib/utf8cpp/source/utf8/unchecked.h b/contrib/utf8cpp/source/utf8/unchecked.h new file mode 100644 index 000000000..cb2427166 --- /dev/null +++ b/contrib/utf8cpp/source/utf8/unchecked.h @@ -0,0 +1,228 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" + +namespace utf8 +{ + namespace unchecked + { + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it) + { + uint32_t cp = utf8::internal::mask8(*it); + typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); + switch (length) { + case 1: + break; + case 2: + it++; + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + break; + case 3: + ++it; + cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + ++it; + cp += (*it) & 0x3f; + break; + case 4: + ++it; + cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + ++it; + cp += (utf8::internal::mask8(*it) << 6) & 0xfff; + ++it; + cp += (*it) & 0x3f; + break; + } + ++it; + return cp; + } + + template + uint32_t peek_next(octet_iterator it) + { + return utf8::unchecked::next(it); + } + + template + uint32_t prior(octet_iterator& it) + { + while (utf8::internal::is_trail(*(--it))) ; + octet_iterator temp = it; + return utf8::unchecked::next(temp); + } + + // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) + template + inline uint32_t previous(octet_iterator& it) + { + return utf8::unchecked::prior(it); + } + + template + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + utf8::unchecked::next(it); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::unchecked::next(first); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = utf8::internal::mask16(*start++); + // Take care of surrogate pairs first + if (utf8::internal::is_lead_surrogate(cp)) { + uint32_t trail_surrogate = utf8::internal::mask16(*start++); + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + } + result = utf8::unchecked::append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start < end) { + uint32_t cp = utf8::unchecked::next(start); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::unchecked::append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = utf8::unchecked::next(start); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + public: + iterator () {} + explicit iterator (const octet_iterator& octet_it): it(octet_it) {} + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return utf8::unchecked::next(temp); + } + bool operator == (const iterator& rhs) const + { + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + ::std::advance(it, utf8::internal::sequence_length(it)); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + ::std::advance(it, utf8::internal::sequence_length(it)); + return temp; + } + iterator& operator -- () + { + utf8::unchecked::prior(it); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + utf8::unchecked::prior(it); + return temp; + } + }; // class iterator + + } // namespace utf8::unchecked +} // namespace utf8 + + +#endif // header guard + From d7e13e67c4015b81492272b6399238db2da2441b Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 17 Jun 2017 19:38:47 +0200 Subject: [PATCH 49/62] Utf8: integrate new lib. --- code/BaseImporter.cpp | 1 - code/BaseImporter.h | 6 +- code/CMakeLists.txt | 6 - code/MMDPmxParser.cpp | 12 +- code/STEPFileEncoding.cpp | 59 ++-- contrib/ConvertUTF/ConvertUTF.c | 539 -------------------------------- contrib/ConvertUTF/ConvertUTF.h | 151 --------- contrib/ConvertUTF/readme.txt | 43 --- 8 files changed, 39 insertions(+), 778 deletions(-) delete mode 100644 contrib/ConvertUTF/ConvertUTF.c delete mode 100644 contrib/ConvertUTF/ConvertUTF.h delete mode 100644 contrib/ConvertUTF/readme.txt diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index ba5faed80..9a57f860d 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -303,7 +303,6 @@ void BaseImporter::GetExtensionList(std::set& extensions) return false; } -//#include "../contrib/ConvertUTF/ConvertUTF.h" #include "../contrib/utf8cpp/source/utf8.h" // ------------------------------------------------------------------------------------------------ diff --git a/code/BaseImporter.h b/code/BaseImporter.h index 06ed0691f..cee54c1ad 100644 --- a/code/BaseImporter.h +++ b/code/BaseImporter.h @@ -61,7 +61,6 @@ class BaseProcess; class SharedPostProcessInfo; class IOStream; - // utility to do char4 to uint32 in a portable manner #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \ (string[1] << 16) + (string[2] << 8) + string[3])) @@ -194,14 +193,11 @@ public: const Importer* pImp ); - // ------------------------------------------------------------------- /** Called by #Importer::GetImporterInfo to get a description of * some loader features. Importers must provide this information. */ virtual const aiImporterDesc* GetInfo() const = 0; - - // ------------------------------------------------------------------- /** Called by #Importer::GetExtensionList for each loaded importer. * Take the extension list contained in the structure returned by @@ -317,7 +313,7 @@ public: // static utilities * @param Size of one token, in bytes. Maximally 16 bytes. * @return true if one of the given tokens was found * - * @note For convinence, the check is also performed for the + * @note For convenience, the check is also performed for the * byte-swapped variant of all tokens (big endian). Only for * tokens of size 2,4. */ diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index de515ba94..017420d5d 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -695,11 +695,6 @@ SET( Extra_SRCS ) SOURCE_GROUP( Extra FILES ${Extra_SRCS}) -SET( ConvertUTF_SRCS - ../contrib/ConvertUTF/ConvertUTF.h - ../contrib/ConvertUTF/ConvertUTF.c -) -SOURCE_GROUP( ConvertUTF FILES ${ConvertUTF_SRCS}) SET( Clipper_SRCS ../contrib/clipper/clipper.hpp @@ -835,7 +830,6 @@ SET( assimp_src # Third-party libraries ${IrrXML_SRCS} - ${ConvertUTF_SRCS} ${unzip_compile_SRCS} ${Poly2Tri_SRCS} ${Clipper_SRCS} diff --git a/code/MMDPmxParser.cpp b/code/MMDPmxParser.cpp index 352259df5..89a4ea6fc 100644 --- a/code/MMDPmxParser.cpp +++ b/code/MMDPmxParser.cpp @@ -1,7 +1,7 @@ #include #include "MMDPmxParser.h" +#include "../contrib/utf8cpp/source/utf8.h" #include "Exceptional.h" -#include "../contrib/ConvertUTF/ConvertUTF.h" namespace pmx { @@ -60,15 +60,17 @@ namespace pmx const unsigned int targetSize = size * 3; // enough to encode char* targetStart = new char[targetSize](); const char* targetReserved = targetStart; - ConversionFlags flags = ConversionFlags::lenientConversion; +// ConversionFlags flags = ConversionFlags::lenientConversion; - ConversionResult conversionResult; - if( ( conversionResult = ConvertUTF16toUTF8( + //ConversionResult conversionResult; + /*if( ( conversionResult = ConvertUTF16toUTF8( (const UTF16**)&sourceStart, (const UTF16*)(sourceStart + size), (UTF8**)&targetStart, (UTF8*)(targetStart + targetSize), flags) ) != ConversionResult::conversionOK) { throw DeadlyImportError( "Convert " + std::string(sourceStart) + " to UTF8 is not valid." ); - } + }*/ + + utf8::utf16to8( sourceStart, sourceStart + size, targetStart ); result.assign(targetReserved, targetStart - targetReserved); delete[] targetReserved; diff --git a/code/STEPFileEncoding.cpp b/code/STEPFileEncoding.cpp index 0bf868d1c..bb0cb646a 100644 --- a/code/STEPFileEncoding.cpp +++ b/code/STEPFileEncoding.cpp @@ -44,14 +44,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "STEPFileEncoding.h" #include "fast_atof.h" +#include "../contrib/utf8cpp/source/utf8.h" -#include "../contrib/ConvertUTF/ConvertUTF.h" +//#include "../contrib/ConvertUTF/ConvertUTF.h" #include using namespace Assimp; // roman1 to utf16 table -static const UTF16 mac_codetable[] = { +static const uint16_t mac_codetable[] = { // 0x20 unassig./nonprint. slots 0x0020 , 0x0021 , @@ -309,14 +310,15 @@ bool STEP::StringToUTF8(std::string& s) ai_assert(sizeof(mac_codetable) / sizeof(mac_codetable[0]) == 0x100-0x20); - const UTF32 unival = mac_codetable[macval - 0x20], *univalp = &unival; + const uint32_t unival = mac_codetable[macval - 0x20], *univalp = &unival; - UTF8 temp[5], *tempp = temp; - ai_assert(sizeof(UTF8) == 1); + unsigned char temp[5], *tempp = temp; + ai_assert(sizeof( unsigned char ) == 1); - if(ConvertUTF32toUTF8(&univalp, univalp+1, &tempp, tempp+sizeof(temp), lenientConversion) != conversionOK) { + utf8::utf32to8( univalp, univalp + 1, tempp ); + /*if(ConvertUTF32toUTF8(&univalp, univalp+1, &tempp, tempp+sizeof(temp), lenientConversion) != conversionOK) { return false; - } + }*/ const size_t outcount = static_cast(tempp-temp); @@ -355,28 +357,29 @@ bool STEP::StringToUTF8(std::string& s) } const size_t count = (j-basei)/4; - std::unique_ptr src(new UTF16[count]); + std::unique_ptr src(new uint16_t[count]); const char* cur = s.c_str() + basei; for (size_t k = 0; k < count; ++k, cur += 4) { - src[k] = (static_cast(HexOctetToDecimal(cur)) << 8u) | - static_cast(HexOctetToDecimal(cur+2)); + src[k] = (static_cast(HexOctetToDecimal(cur)) << 8u) | + static_cast(HexOctetToDecimal(cur+2)); } const size_t dcount = count * 3; // this is enough to hold all possible outputs - std::unique_ptr dest(new UTF8[dcount]); + std::unique_ptr dest(new unsigned char[dcount]); - const UTF16* srct = src.get(); - UTF8* destt = dest.get(); - if(ConvertUTF16toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { + const uint16_t* srct = src.get(); + unsigned char* destt = dest.get(); + utf8::utf16to8( srct, srct + count, destt ); + /*if(ConvertUTF16toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { return false; - } + }*/ const size_t outcount = static_cast(destt-dest.get()); s.erase(i,(j+4-i)); - ai_assert(sizeof(UTF8) == 1); + ai_assert(sizeof(unsigned char) == 1); s.insert(i, reinterpret_cast(dest.get()), outcount); i += outcount; @@ -388,37 +391,37 @@ bool STEP::StringToUTF8(std::string& s) } const size_t count = (j-basei)/8; - std::unique_ptr src(new UTF32[count]); + std::unique_ptr src(new uint32_t[count]); const char* cur = s.c_str() + basei; for (size_t k = 0; k < count; ++k, cur += 8) { - src[k] = (static_cast(HexOctetToDecimal(cur )) << 24u) | - (static_cast(HexOctetToDecimal(cur+2)) << 16u) | - (static_cast(HexOctetToDecimal(cur+4)) << 8u) | - (static_cast(HexOctetToDecimal(cur+6))); + src[k] = (static_cast(HexOctetToDecimal(cur )) << 24u) | + (static_cast(HexOctetToDecimal(cur+2)) << 16u) | + (static_cast(HexOctetToDecimal(cur+4)) << 8u) | + (static_cast(HexOctetToDecimal(cur+6))); } const size_t dcount = count * 5; // this is enough to hold all possible outputs - std::unique_ptr dest(new UTF8[dcount]); + std::unique_ptr dest(new unsigned char[dcount]); - const UTF32* srct = src.get(); - UTF8* destt = dest.get(); - if(ConvertUTF32toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { + const uint32_t* srct = src.get(); + unsigned char* destt = dest.get(); + utf8::utf32to8( srct, srct + count, destt ); + /*if(ConvertUTF32toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { return false; - } + }*/ const size_t outcount = static_cast(destt-dest.get()); s.erase(i,(j+4-i)); - ai_assert(sizeof(UTF8) == 1); + ai_assert(sizeof(unsigned char) == 1); s.insert(i, reinterpret_cast(dest.get()), outcount); i += outcount; continue; } } - break; // TODO: other encoding patterns? diff --git a/contrib/ConvertUTF/ConvertUTF.c b/contrib/ConvertUTF/ConvertUTF.c deleted file mode 100644 index 9b3deebd6..000000000 --- a/contrib/ConvertUTF/ConvertUTF.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Source code file. - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. - June 2002: Tim Dodd added detection and handling of incomplete - source sequences, enhanced error detection, added casts - to eliminate compiler warnings. - July 2003: slight mods to back out aggressive FFFE detection. - Jan 2004: updated switches in from-UTF8 conversions. - Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. - - See the header file "ConvertUTF.h" for complete documentation. - ------------------------------------------------------------------------- */ - - -#include "ConvertUTF.h" -#ifdef CVTUTF_DEBUG -#include -#endif - -static const int halfShift = 10; /* used for shifting by 10 bits */ - -static const UTF32 halfBase = 0x0010000UL; -static const UTF32 halfMask = 0x3FFUL; - -#define UNI_SUR_HIGH_START (UTF32)0xD800 -#define UNI_SUR_HIGH_END (UTF32)0xDBFF -#define UNI_SUR_LOW_START (UTF32)0xDC00 -#define UNI_SUR_LOW_END (UTF32)0xDFFF -#define false 0 -#define true 1 - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - if (target >= targetEnd) { - result = targetExhausted; break; - } - ch = *source++; - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_LEGAL_UTF32) { - if (flags == strictConversion) { - result = sourceIllegal; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - --source; /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF32* target = *targetStart; - UTF32 ch, ch2; - while (source < sourceEnd) { - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - if (target >= targetEnd) { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; break; - } - *target++ = ch; - } - *sourceStart = source; - *targetStart = target; -#ifdef CVTUTF_DEBUG -if (result == sourceIllegal) { - fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); - fflush(stderr); -} -#endif - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Index into the table below with the first byte of a UTF-8 sequence to - * get the number of trailing bytes that are supposed to follow it. - * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is - * left as-is for anyone who may want to do such conversion, which was - * allowed in earlier algorithms. - */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 -}; - -/* - * Magic values subtracted from a buffer value during UTF8 conversion. - * This table contains as many values as there might be trailing bytes - * in a UTF-8 sequence. - */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; - -/* - * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed - * into the first byte, depending on how many bytes follow. There are - * as many entries in this table as there are UTF-8 sequence types. - * (I.e., one byte sequence, two byte... etc.). Remember that sequencs - * for *legal* UTF-8 will be 4 or fewer bytes total. - */ -static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -/* --------------------------------------------------------------------- */ - -/* The interface converts a whole buffer to avoid function-call overhead. - * Constants have been gathered. Loops & conditionals have been removed as - * much as possible for efficiency, in favor of drop-through switches. - * (See "Note A" at the bottom of the file for equivalent code.) - * If your compiler supports it, the "isLegalUTF8" call can be turned - * into an inline function. - */ - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - UTF32 ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - } - - target += bytesToWrite; - if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Utility routine to tell whether a sequence of bytes is legal UTF-8. - * This must be called with the length pre-determined by the first byte. - * If not calling this from ConvertUTF8to*, then the length can be set by: - * length = trailingBytesForUTF8[*source]+1; - * and the sequence is illegal right away if there aren't that many bytes - * available. - * If presented with a length > 4, this returns false. The Unicode - * definition of UTF-8 goes up to 4-byte sequences. - */ - -static Boolean isLegalUTF8(const UTF8 *source, int length) { - UTF8 a; - const UTF8 *srcptr = source+length; - switch (length) { - default: return false; - /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; - - switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xED: if (a > 0x9F) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } - - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - } - if (*source > 0xF4) return false; - return true; -} - -/* --------------------------------------------------------------------- */ - -/* - * Exported function to return whether a UTF-8 sequence is legal or not. - * This is not used here; it's just exported. - */ -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { - int length = trailingBytesForUTF8[*source]+1; - if (source+length > sourceEnd) { - return false; - } - return isLegalUTF8(source, length); -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { - result = sourceIllegal; - source -= (extraBytesToRead+1); /* return to the start */ - break; /* Bail out; shouldn't continue */ - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - ch = *source++; - if (flags == strictConversion ) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* - * Figure out how many bytes the result will require. Turn any - * illegally large UTF32 things (> Plane 17) into replacement chars. - */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; - } - - target += bytesToWrite; - if (target > targetEnd) { - --source; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF32* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up the source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_LEGAL_UTF32) { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = ch; - } - } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- - - Note A. - The fall-through switches in UTF-8 reading code save a - temp variable, some decrements & conditionals. The switches - are equivalent to the following loop: - { - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); - } - In UTF-8 writing code, the switches on "bytesToWrite" are - similarly unrolled loops. - - --------------------------------------------------------------------- */ diff --git a/contrib/ConvertUTF/ConvertUTF.h b/contrib/ConvertUTF/ConvertUTF.h deleted file mode 100644 index 05e800ad8..000000000 --- a/contrib/ConvertUTF/ConvertUTF.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ -#ifndef CONVERTUTF_H -#define CONVERTUTF_H -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Header file. - - Several funtions are included here, forming a complete set of - conversions between the three formats. UTF-7 is not included - here, but is handled in a separate source file. - - Each of these routines takes pointers to input buffers and output - buffers. The input buffers are const. - - Each routine converts the text between *sourceStart and sourceEnd, - putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. - *(sourceEnd - 1) is the last item. - - The return result indicates whether the conversion was successful, - and if not, whether the problem was in the source or target buffers. - (Only the first encountered problem is indicated.) - - After the conversion, *sourceStart and *targetStart are both - updated to point to the end of last text successfully converted in - the respective buffers. - - Input parameters: - sourceStart - pointer to a pointer to the source buffer. - The contents of this are modified on return so that - it points at the next thing to be converted. - targetStart - similarly, pointer to pointer to the target buffer. - sourceEnd, targetEnd - respectively pointers to the ends of the - two buffers, for overflow checking only. - - These conversion functions take a ConversionFlags argument. When this - flag is set to strict, both irregular sequences and isolated surrogates - will cause an error. When the flag is set to lenient, both irregular - sequences and isolated surrogates are converted. - - Whether the flag is strict or lenient, all illegal sequences will cause - an error return. This includes sequences such as: , , - or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code - must check for illegal sequences. - - When the flag is set to lenient, characters over 0x10FFFF are converted - to the replacement character; otherwise (when the flag is set to strict) - they constitute an error. - - Output parameters: - The value "sourceIllegal" is returned from some routines if the input - sequence is malformed. When "sourceIllegal" is returned, the source - value will point to the illegal value that caused the problem. E.g., - in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. - - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Fixes & updates, Sept 2001. - ------------------------------------------------------------------------- */ - -/* --------------------------------------------------------------------- - The following 4 definitions are compiler-specific. - The C standard does not guarantee that wchar_t has at least - 16 bits, so wchar_t is no less portable than unsigned short! - All should be unsigned values to avoid sign extension during - bit mask & shift operations. ------------------------------------------------------------------------- */ - -typedef unsigned long UTF32; /* at least 32 bits */ -typedef unsigned short UTF16; /* at least 16 bits */ -typedef unsigned char UTF8; /* typically 8 bits */ -typedef unsigned char Boolean; /* 0 or 1 */ - -/* Some fundamental constants */ -#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD -#define UNI_MAX_BMP (UTF32)0x0000FFFF -#define UNI_MAX_UTF16 (UTF32)0x0010FFFF -#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF -#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF - -typedef enum { - conversionOK, /* conversion successful */ - sourceExhausted, /* partial character in source, but hit end */ - targetExhausted, /* insuff. room in target for conversion */ - sourceIllegal /* source sequence is illegal/malformed */ -} ConversionResult; - -typedef enum { - strictConversion = 0, - lenientConversion -} ConversionFlags; - -/* This is for C++ and does no harm in C */ -#ifdef __cplusplus -extern "C" { -#endif - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); - -#ifdef __cplusplus -} -#endif - -/* --------------------------------------------------------------------- */ -#endif // CONVERTUTF_H diff --git a/contrib/ConvertUTF/readme.txt b/contrib/ConvertUTF/readme.txt deleted file mode 100644 index b9f17fb81..000000000 --- a/contrib/ConvertUTF/readme.txt +++ /dev/null @@ -1,43 +0,0 @@ - -The accompanying C source code file "ConvertUTF.c" and the associated header -file "ConvertUTF.h" provide for conversion between various transformation -formats of Unicode characters. The following conversions are supported: - - UTF-32 to UTF-16 - UTF-32 to UTF-8 - UTF-16 to UTF-32 - UTF-16 to UTF-8 - UTF-8 to UTF-16 - UTF-8 to UTF-32 - -In addition, there is a test harness which runs various tests. - -The files "CVTUTF7.C" and "CVTUTF7.H" are for archival and historical purposes -only. They have not been updated to Unicode 3.0 or later and should be -considered obsolescent. "CVTUTF7.C" contains two functions that can convert -between UCS2 (i.e., the BMP characters only) and UTF-7. Surrogates are -not supported, the code has not been tested, and should be considered -unsuitable for general purpose use. - -Please submit any bug reports about these programs here: - - http://www.unicode.org/unicode/reporting.html - -Version 1.0: initial version. - -Version 1.1: corrected some minor problems; added stricter checks. - -Version 1.2: corrected switch statements associated with "extraBytesToRead" - in 4 & 5 byte cases, in functions for conversion from UTF8. - Note: formally, the 4 & 5 byte cases are illegal in the latest - UTF8, but the table and this code has always catered for those, - cases since at one time they were legal. - -Version 1.3: Updated UTF-8 legality check; - updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions - Updated UTF-8 legality tests in harness.c - - -Last update: October 19, 2004 - - From 64cbc6933710586f611f571b83e570f350aaf860 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 17 Jun 2017 20:36:59 +0200 Subject: [PATCH 50/62] remove dead code. --- code/BaseImporter.cpp | 40 +------------------------------ code/MMDCpp14.h | 40 +++++++++++++++++++++++++++++++ code/MMDPmdParser.h | 40 +++++++++++++++++++++++++++++++ code/MMDPmxParser.cpp | 50 +++++++++++++++++++++++++++++++-------- code/MMDPmxParser.h | 40 +++++++++++++++++++++++++++++++ code/MMDVmdParser.h | 40 +++++++++++++++++++++++++++++++ code/STEPFileEncoding.cpp | 14 ++--------- 7 files changed, 203 insertions(+), 61 deletions(-) diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index 9a57f860d..7cef43cf6 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -305,17 +305,6 @@ void BaseImporter::GetExtensionList(std::set& extensions) #include "../contrib/utf8cpp/source/utf8.h" -// ------------------------------------------------------------------------------------------------ -/*void ReportResult(ConversionResult res) -{ - if(res == sourceExhausted) { - DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails"); - } - else if(res == sourceIllegal) { - DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails"); - } -}*/ - // ------------------------------------------------------------------------------------------------ // Convert to UTF8 data void BaseImporter::ConvertToUTF8(std::vector& data) @@ -349,23 +338,10 @@ void BaseImporter::ConvertToUTF8(std::vector& data) DefaultLogger::get()->debug("Found UTF-32 BOM ..."); const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1; -// char* dstart,*dend; std::vector output; int *ptr = (int*)&data[ 0 ]; int *end = ptr + ( data.size() / sizeof(int) ) +1; utf8::utf32to8( ptr, end, back_inserter(output)); -/* do { - output.resize(output.size()?output.size()*3/2:data.size()/2); - dstart = &output.front(),dend = &output.back()+1; - - ///result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); - } while(result == targetExhausted);*/ - - // ReportResult(result); - - // copy to output buffer. -// const size_t outlen = (size_t)(dstart-&output.front()); -// data.assign(output.begin(),output.begin()+outlen); return; } @@ -383,26 +359,12 @@ void BaseImporter::ConvertToUTF8(std::vector& data) DefaultLogger::get()->debug("Found UTF-16 BOM ..."); const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1); -// char* dstart,*dend; std::vector output; int16_t *ptr = (int16_t*) &data[ 0 ]; int16_t *end = ptr + (data.size() / sizeof(int)) + 1; utf8::utf16to8(data.begin(), data.end(), back_inserter(output)); -/* do { - output.resize(output.size()?output.size()*3/2:data.size()*3/4); - dstart = &output.front(),dend = &output.back()+1; - - utf8::utf16to8(data.begin(), data.end(), output); - - } while(result == targetExhausted); - - ReportResult(result); - - // copy to output buffer. - const size_t outlen = (size_t)(dstart-&output.front()); - data.assign(output.begin(),output.begin()+outlen); - return;*/ + return; } } diff --git a/code/MMDCpp14.h b/code/MMDCpp14.h index ad112de0f..f6f81f827 100644 --- a/code/MMDCpp14.h +++ b/code/MMDCpp14.h @@ -1,3 +1,43 @@ +/* +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, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ #pragma once #ifndef MMD_CPP14_H diff --git a/code/MMDPmdParser.h b/code/MMDPmdParser.h index 375c323df..44b64585a 100644 --- a/code/MMDPmdParser.h +++ b/code/MMDPmdParser.h @@ -1,3 +1,43 @@ +/* +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, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ #pragma once #include diff --git a/code/MMDPmxParser.cpp b/code/MMDPmxParser.cpp index 89a4ea6fc..6a76c2c7f 100644 --- a/code/MMDPmxParser.cpp +++ b/code/MMDPmxParser.cpp @@ -1,3 +1,43 @@ +/* +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, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ #include #include "MMDPmxParser.h" #include "../contrib/utf8cpp/source/utf8.h" @@ -60,16 +100,6 @@ namespace pmx const unsigned int targetSize = size * 3; // enough to encode char* targetStart = new char[targetSize](); const char* targetReserved = targetStart; -// ConversionFlags flags = ConversionFlags::lenientConversion; - - //ConversionResult conversionResult; - /*if( ( conversionResult = ConvertUTF16toUTF8( - (const UTF16**)&sourceStart, (const UTF16*)(sourceStart + size), - (UTF8**)&targetStart, (UTF8*)(targetStart + targetSize), - flags) ) != ConversionResult::conversionOK) { - throw DeadlyImportError( "Convert " + std::string(sourceStart) + " to UTF8 is not valid." ); - }*/ - utf8::utf16to8( sourceStart, sourceStart + size, targetStart ); result.assign(targetReserved, targetStart - targetReserved); diff --git a/code/MMDPmxParser.h b/code/MMDPmxParser.h index 7cb94b9b6..4aff7f8eb 100644 --- a/code/MMDPmxParser.h +++ b/code/MMDPmxParser.h @@ -1,3 +1,43 @@ +/* +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, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ #pragma once #include diff --git a/code/MMDVmdParser.h b/code/MMDVmdParser.h index 380a10c5d..c5057ef47 100644 --- a/code/MMDVmdParser.h +++ b/code/MMDVmdParser.h @@ -1,3 +1,43 @@ +/* +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, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ #pragma once #include diff --git a/code/STEPFileEncoding.cpp b/code/STEPFileEncoding.cpp index bb0cb646a..f9a9dd1ce 100644 --- a/code/STEPFileEncoding.cpp +++ b/code/STEPFileEncoding.cpp @@ -40,13 +40,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file STEPFileEncoding.cpp - * @brief STEP character handling, string unescaping + * @brief STEP character handling, string un-escaping */ #include "STEPFileEncoding.h" #include "fast_atof.h" -#include "../contrib/utf8cpp/source/utf8.h" +#include -//#include "../contrib/ConvertUTF/ConvertUTF.h" #include using namespace Assimp; @@ -316,9 +315,6 @@ bool STEP::StringToUTF8(std::string& s) ai_assert(sizeof( unsigned char ) == 1); utf8::utf32to8( univalp, univalp + 1, tempp ); - /*if(ConvertUTF32toUTF8(&univalp, univalp+1, &tempp, tempp+sizeof(temp), lenientConversion) != conversionOK) { - return false; - }*/ const size_t outcount = static_cast(tempp-temp); @@ -371,9 +367,6 @@ bool STEP::StringToUTF8(std::string& s) const uint16_t* srct = src.get(); unsigned char* destt = dest.get(); utf8::utf16to8( srct, srct + count, destt ); - /*if(ConvertUTF16toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { - return false; - }*/ const size_t outcount = static_cast(destt-dest.get()); @@ -407,9 +400,6 @@ bool STEP::StringToUTF8(std::string& s) const uint32_t* srct = src.get(); unsigned char* destt = dest.get(); utf8::utf32to8( srct, srct + count, destt ); - /*if(ConvertUTF32toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { - return false; - }*/ const size_t outcount = static_cast(destt-dest.get()); From 51b915c97bcb375e2483cde6ed32575754f9fe90 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 19 Jun 2017 21:07:18 +0200 Subject: [PATCH 51/62] openddlparser: closes https://github.com/assimp/assimp/issues/1271. --- contrib/openddlparser/code/DDLNode.cpp | 16 ++- contrib/openddlparser/code/OpenDDLCommon.cpp | 44 ++++-- contrib/openddlparser/code/OpenDDLExport.cpp | 2 +- contrib/openddlparser/code/OpenDDLParser.cpp | 133 ++++++++++-------- contrib/openddlparser/code/Value.cpp | 31 ++-- .../include/openddlparser/DDLNode.h | 3 + .../include/openddlparser/OpenDDLCommon.h | 7 +- .../include/openddlparser/OpenDDLParser.h | 2 +- .../openddlparser/OpenDDLParserUtils.h | 44 ++++-- 9 files changed, 176 insertions(+), 106 deletions(-) diff --git a/contrib/openddlparser/code/DDLNode.cpp b/contrib/openddlparser/code/DDLNode.cpp index 0cc95bdfc..3955e3fd9 100644 --- a/contrib/openddlparser/code/DDLNode.cpp +++ b/contrib/openddlparser/code/DDLNode.cpp @@ -68,8 +68,8 @@ DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, } DDLNode::~DDLNode() { - releaseDataType( m_properties ); - releaseDataType( m_value ); + delete m_properties; + delete m_value; releaseReferencedNames( m_references ); delete m_dtArrayList; @@ -77,6 +77,9 @@ DDLNode::~DDLNode() { if( s_allocatedNodes[ m_idx ] == this ) { s_allocatedNodes[ m_idx ] = ddl_nullptr; } + for ( size_t i = 0; i::iterator it; - it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this ); + if( ddl_nullptr != m_parent ) { + DDLNodeIt it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this ); if( m_parent->m_children.end() != it ) { m_parent->m_children.erase( it ); } @@ -126,6 +128,8 @@ const std::string &DDLNode::getName() const { } void DDLNode::setProperties( Property *prop ) { + if(m_properties!=ddl_nullptr) + delete m_properties; m_properties = prop; } @@ -197,7 +201,7 @@ DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLN void DDLNode::releaseNodes() { if( s_allocatedNodes.size() > 0 ) { - for( DllNodeList::iterator it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) { + for( DDLNodeIt it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) { if( *it ) { delete *it; } diff --git a/contrib/openddlparser/code/OpenDDLCommon.cpp b/contrib/openddlparser/code/OpenDDLCommon.cpp index 13a96f7a8..5c341a780 100644 --- a/contrib/openddlparser/code/OpenDDLCommon.cpp +++ b/contrib/openddlparser/code/OpenDDLCommon.cpp @@ -22,6 +22,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include #include +#include BEGIN_ODDLPARSER_NS @@ -84,7 +85,14 @@ Name::~Name() { m_id = ddl_nullptr; } -Reference::Reference() +Name::Name( const Name &name ){ + m_type=name.m_type; + m_id=new Text(name.m_id->m_buffer,name.m_id->m_len); +} + + + + Reference::Reference() : m_numRefs( 0 ) , m_referencedName( ddl_nullptr ) { // empty @@ -96,8 +104,16 @@ Reference::Reference( size_t numrefs, Name **names ) if ( numrefs > 0 ) { m_referencedName = new Name *[ numrefs ]; for ( size_t i = 0; i < numrefs; i++ ) { - Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id ); - m_referencedName[ i ] = name; + m_referencedName[ i ] = names[i]; + } + } +} +Reference::Reference(const Reference &ref) { + m_numRefs=ref.m_numRefs; + if(m_numRefs!=0){ + m_referencedName = new Name*[m_numRefs]; + for ( size_t i = 0; i < m_numRefs; i++ ) { + m_referencedName[i] = new Name(*ref.m_referencedName[i]); } } } @@ -107,6 +123,7 @@ Reference::~Reference() { delete m_referencedName[ i ]; } m_numRefs = 0; + delete [] m_referencedName; m_referencedName = ddl_nullptr; } @@ -135,21 +152,30 @@ Property::Property( Text *id ) } Property::~Property() { - m_key = ddl_nullptr; - m_value = ddl_nullptr; - m_ref = ddl_nullptr;; - m_next = ddl_nullptr;; + delete m_key; + if(m_value!=ddl_nullptr) + delete m_value; + if(m_ref!=ddl_nullptr) + delete(m_ref); + if(m_next!=ddl_nullptr) + delete m_next; } DataArrayList::DataArrayList() : m_numItems( 0 ) , m_dataList( ddl_nullptr ) -, m_next( ddl_nullptr ) { +, m_next( ddl_nullptr ) +, m_refs(ddl_nullptr) +, m_numRefs(0){ // empty } DataArrayList::~DataArrayList() { - // empty + delete m_dataList; + if(m_next!=ddl_nullptr) + delete m_next; + if(m_refs!=ddl_nullptr) + delete m_refs; } size_t DataArrayList::size() { diff --git a/contrib/openddlparser/code/OpenDDLExport.cpp b/contrib/openddlparser/code/OpenDDLExport.cpp index 49207c044..35036cc6a 100644 --- a/contrib/openddlparser/code/OpenDDLExport.cpp +++ b/contrib/openddlparser/code/OpenDDLExport.cpp @@ -280,7 +280,7 @@ bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std: statement += "["; char buffer[ 256 ]; ::memset( buffer, '\0', 256 * sizeof( char ) ); - sprintf( buffer, "%d", int(numItems) ); + sprintf( buffer, "%d", static_cast( numItems ) ); statement += buffer; statement += "]"; } diff --git a/contrib/openddlparser/code/OpenDDLParser.cpp b/contrib/openddlparser/code/OpenDDLParser.cpp index 6f471be36..e9032980b 100644 --- a/contrib/openddlparser/code/OpenDDLParser.cpp +++ b/contrib/openddlparser/code/OpenDDLParser.cpp @@ -36,7 +36,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS -static const char *Version = "0.3.0"; +static const char *Version = "0.4.0"; namespace Grammar { static const char *OpenBracketToken = "{"; @@ -49,7 +49,7 @@ namespace Grammar { static const char *BoolFalse = "false"; static const char *CommaSeparator = ","; - static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = { + static const char *PrimitiveTypeToken[ Value::ddl_types_max ] = { "bool", "int8", "int16", @@ -74,8 +74,8 @@ const char *getTypeToken( Value::ValueType type ) { static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) { std::stringstream stream; stream << "Invalid token \"" << *in << "\"" << " expected \"" << exp << "\"" << std::endl; - std::string full(in); - std::string part(full.substr(0,50)); + std::string full( in ); + std::string part( full.substr( 0, 50 ) ); stream << part; callback( ddl_error_msg, stream.str() ); } @@ -85,6 +85,7 @@ static bool isIntegerType( Value::ValueType integerType ) { integerType != Value::ddl_int32 && integerType != Value::ddl_int64 ) { return false; } + return true; } @@ -105,7 +106,7 @@ static DDLNode *createDDLNode( Text *id, OpenDDLParser *parser ) { const std::string type( id->m_buffer ); DDLNode *parent( parser->top() ); DDLNode *node = DDLNode::create( type, "", parent ); - + return node; } @@ -193,10 +194,11 @@ size_t OpenDDLParser::getBufferSize() const { void OpenDDLParser::clear() { m_buffer.resize( 0 ); if( ddl_nullptr != m_context ) { - m_context->m_root = ddl_nullptr; + delete m_context; + m_context=ddl_nullptr; } - DDLNode::releaseNodes(); +// DDLNode::releaseNodes(); } bool OpenDDLParser::parse() { @@ -212,11 +214,11 @@ bool OpenDDLParser::parse() { // do the main parsing char *current( &m_buffer[ 0 ] ); - char *end( &m_buffer[ m_buffer.size() - 1 ] + 1 ); + char *end( &m_buffer[m_buffer.size() - 1 ] + 1 ); size_t pos( current - &m_buffer[ 0 ] ); while( pos < m_buffer.size() ) { current = parseNextNode( current, end ); - if(current==ddl_nullptr) { + if ( current == ddl_nullptr ) { return false; } pos = current - &m_buffer[ 0 ]; @@ -245,7 +247,7 @@ static void dumpId( Identifier *id ) { if( ddl_nullptr != id ) { if ( ddl_nullptr != id->m_text.m_buffer ) { std::cout << id->m_text.m_buffer << std::endl; - } + } } } #endif @@ -271,14 +273,17 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) { } else { std::cerr << "nullptr returned by creating DDLNode." << std::endl; } + delete id; Name *name(ddl_nullptr); in = OpenDDLParser::parseName(in, end, &name); if( ddl_nullptr != name && ddl_nullptr != node ) { const std::string nodeName( name->m_id->m_buffer ); node->setName( nodeName ); + delete name; } + Property *first(ddl_nullptr); in = lookForNextToken(in, end); if (*in == Grammar::OpenPropertyToken[0]) { @@ -303,7 +308,7 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) { prev = prop; } } - in++; + ++in; } // set the properties @@ -330,9 +335,9 @@ char *OpenDDLParser::parseStructure( char *in, char *end ) { return ddl_nullptr; } } while ( *in != '}' ); - in++; + ++in; } else { - in++; + ++in; logInvalidTokenError( in, std::string( Grammar::OpenBracketToken ), m_logCallback ); error = true; return ddl_nullptr; @@ -373,7 +378,7 @@ static void setNodeDataArrayList( DDLNode *currentNode, DataArrayList *dtArrayLi char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) { if( !isNumeric( *in ) && !isCharacter( *in ) ) { - in++; + ++in; } in = lookForNextToken( in, end ); @@ -431,7 +436,6 @@ DDLNode *OpenDDLParser::popNode() { DDLNode *topNode( top() ); m_stack.pop_back(); - return topNode; } @@ -467,7 +471,14 @@ void OpenDDLParser::normalizeBuffer( std::vector &buffer) { for( size_t readIdx = 0; readIdx( c, end ) && !isNewLine( *c ) ) { + if (isCommentOpenTag(c, end)) { + ++readIdx; + while (!isCommentCloseTag(&buffer[readIdx], end)) { + ++readIdx; + } + ++readIdx; + ++readIdx; + } else if( !isComment( c, end ) && !isNewLine( *c ) ) { newBuffer.push_back( buffer[ readIdx ] ); } else { if( isComment( c, end ) ) { @@ -535,8 +546,7 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Text **id ) { } const size_t len( idLen ); - Text *newId = new Text( start, len ); - *id = newId; + *id = new Text( start, len ); return in; } @@ -567,14 +577,14 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy bool ok( true ); if( *in == Grammar::OpenArrayToken[ 0 ] ) { ok = false; - in++; + ++in; char *start( in ); while ( in != end ) { - in++; + ++in; if( *in == Grammar::CloseArrayToken[ 0 ] ) { len = ::atoi( start ); ok = true; - in++; + ++in; break; } } @@ -623,10 +633,10 @@ char *OpenDDLParser::parseBooleanLiteral( char *in, char *end, Value **boolean ) char *start( in ); size_t len( 0 ); while( !isSeparator( *in ) && in != end ) { - in++; - len++; + ++in; + ++len; } - len++; + ++len; int res = ::strncmp( Grammar::BoolTrue, start, strlen( Grammar::BoolTrue ) ); if( 0 != res ) { res = ::strncmp( Grammar::BoolFalse, start, strlen( Grammar::BoolFalse ) ); @@ -657,7 +667,7 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, in = lookForNextToken( in, end ); char *start( in ); while( !isSeparator( *in ) && in != end ) { - in++; + ++in; } if( isNumeric( *start ) ) { @@ -671,29 +681,29 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, *integer = ValueAllocator::allocPrimData( integerType ); switch( integerType ) { case Value::ddl_int8: - ( *integer )->setInt8( (int8) value ); - break; + ( *integer )->setInt8( (int8) value ); + break; case Value::ddl_int16: - ( *integer )->setInt16( ( int16 ) value ); - break; + ( *integer )->setInt16( ( int16 ) value ); + break; case Value::ddl_int32: - ( *integer )->setInt32( ( int32 ) value ); - break; + ( *integer )->setInt32( ( int32 ) value ); + break; case Value::ddl_int64: - ( *integer )->setInt64( ( int64 ) value ); - break; + ( *integer )->setInt64( ( int64 ) value ); + break; case Value::ddl_unsigned_int8: - ( *integer )->setUnsignedInt8( (uint8) uvalue ); - break; + ( *integer )->setUnsignedInt8( (uint8) uvalue ); + break; case Value::ddl_unsigned_int16: - ( *integer )->setUnsignedInt16( ( uint16 ) uvalue ); - break; + ( *integer )->setUnsignedInt16( ( uint16 ) uvalue ); + break; case Value::ddl_unsigned_int32: - ( *integer )->setUnsignedInt32( ( uint32 ) uvalue ); - break; + ( *integer )->setUnsignedInt32( ( uint32 ) uvalue ); + break; case Value::ddl_unsigned_int64: - ( *integer )->setUnsignedInt64( ( uint64 ) uvalue ); - break; + ( *integer )->setUnsignedInt64( ( uint64 ) uvalue ); + break; default: break; } @@ -711,7 +721,7 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating in = lookForNextToken( in, end ); char *start( in ); while( !isSeparator( *in ) && in != end ) { - in++; + ++in; } // parse the float value @@ -732,8 +742,7 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating } if( ok ) { - if(floatType == Value::ddl_double) - { + if ( floatType == Value::ddl_double ) { const double value( atof( start ) ); *floating = ValueAllocator::allocPrimData( Value::ddl_double ); ( *floating )->setDouble( value ); @@ -757,17 +766,17 @@ char *OpenDDLParser::parseStringLiteral( char *in, char *end, Value **stringData size_t len( 0 ); char *start( in ); if( *start == '\"' ) { - start++; - in++; + ++start; + ++in; while( *in != '\"' && in != end ) { - in++; - len++; + ++in; + ++len; } *stringData = ValueAllocator::allocPrimData( Value::ddl_string, len ); ::strncpy( ( char* ) ( *stringData )->m_data, start, len ); ( *stringData )->m_data[len] = '\0'; - in++; + ++in; } return in; @@ -791,12 +800,12 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) { return in; } - in++; + ++in; if( *in != 'x' && *in != 'X' ) { return in; } - in++; + ++in; bool ok( true ); char *start( in ); int pos( 0 ); @@ -805,8 +814,8 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) { ok = false; break; } - pos++; - in++; + ++pos; + ++in; } if( !ok ) { @@ -816,9 +825,9 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) { int value( 0 ); while( pos > 0 ) { int v = hex2Decimal( *start ); - pos--; + --pos; value = ( value << 4 ) | v; - start++; + ++start; } *data = ValueAllocator::allocPrimData( Value::ddl_unsigned_int64 ); @@ -841,7 +850,7 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { if( ddl_nullptr != id ) { in = lookForNextToken( in, end ); if( *in == '=' ) { - in++; + ++in; in = getNextToken( in, end ); Value *primData( ddl_nullptr ); if( isInteger( in, end ) ) { @@ -862,6 +871,8 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { ( *prop )->m_ref = ref; } } + } else { + delete id; } } @@ -878,7 +889,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, in = lookForNextToken( in, end ); if( *in == '{' ) { - in++; + ++in; Value *current( ddl_nullptr ), *prev( ddl_nullptr ); while( '}' != *in ) { current = ddl_nullptr; @@ -934,7 +945,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, prev->setNext( current ); prev = current; } - numValues++; + ++numValues; } in = getNextSeparator( in, end ); @@ -942,7 +953,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, break; } } - in++; + ++in; } return in; @@ -972,7 +983,7 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType ty in = lookForNextToken( in, end ); if( *in == Grammar::OpenBracketToken[ 0 ] ) { - in++; + ++in; Value *currentValue( ddl_nullptr ); Reference *refs( ddl_nullptr ); DataArrayList *prev( ddl_nullptr ), *currentDataList( ddl_nullptr ); @@ -995,7 +1006,7 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType ty } } while( Grammar::CommaSeparator[ 0 ] == *in && in != end ); in = lookForNextToken( in, end ); - in++; + ++in; } return in; diff --git a/contrib/openddlparser/code/Value.cpp b/contrib/openddlparser/code/Value.cpp index 3e251c508..408cdd456 100644 --- a/contrib/openddlparser/code/Value.cpp +++ b/contrib/openddlparser/code/Value.cpp @@ -110,7 +110,17 @@ Value::Value( ValueType type ) } Value::~Value() { - // empty + if(m_data!=ddl_nullptr) { + if (m_type == ddl_ref ) { + Reference *tmp = (Reference *) m_data; + if (tmp != ddl_nullptr) + delete tmp; + }else + delete[] m_data; + + } + if(m_next!=ddl_nullptr) + delete m_next; } void Value::setBool( bool value ) { @@ -273,13 +283,7 @@ void Value::setRef( Reference *ref ) { delete [] m_data; } - m_data = new unsigned char[ sizeof( Reference ) ]; - Reference *myRef = ( Reference * ) m_data; - myRef->m_numRefs = ref->m_numRefs; - myRef->m_referencedName = new Name *[ myRef->m_numRefs ]; - for ( size_t i = 0; i < myRef->m_numRefs; i++ ) { - myRef->m_referencedName[ i ] = new Name( ref->m_referencedName[ i ]->m_type, ref->m_referencedName[ i ]->m_id ); - } + m_data = (unsigned char*) new Reference(*ref); } } } @@ -366,7 +370,6 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { } Value *data = new Value( type ); - data->m_type = type; switch( type ) { case Value::ddl_bool: data->m_size = sizeof( bool ); @@ -405,10 +408,10 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { data->m_size = sizeof( double ); break; case Value::ddl_string: - data->m_size = sizeof( char ); + data->m_size = sizeof( char )*(len+1); break; case Value::ddl_ref: - data->m_size = sizeof( char ); + data->m_size = 0; break; case Value::ddl_none: case Value::ddl_types_max: @@ -417,12 +420,8 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { } if( data->m_size ) { - size_t len1( len ); - if( Value::ddl_string == type ) { - len1++; - } - data->m_size *= len1; data->m_data = new unsigned char[ data->m_size ]; + ::memset(data->m_data,0,data->m_size); } return data; diff --git a/contrib/openddlparser/include/openddlparser/DDLNode.h b/contrib/openddlparser/include/openddlparser/DDLNode.h index 137135604..184cd0171 100644 --- a/contrib/openddlparser/include/openddlparser/DDLNode.h +++ b/contrib/openddlparser/include/openddlparser/DDLNode.h @@ -53,6 +53,9 @@ public: /// @brief The child-node-list type. typedef std::vector DllNodeList; + /// @brief The child-node-list iterator. + typedef std::vector::iterator DDLNodeIt; + public: /// @brief The class destructor. ~DDLNode(); diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h b/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h index d3e0fb458..bec62cc9d 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h @@ -148,12 +148,12 @@ struct DLL_ODDLPARSER_EXPORT Name { /// @param type [in] The name type. /// @param id [in] The id. Name( NameType type, Text *id ); - + Name( const Name &name ); /// @brief The destructor. ~Name(); private: - Name( const Name & ) ddl_no_copy; + Name &operator = ( const Name& ) ddl_no_copy; }; @@ -164,7 +164,7 @@ struct DLL_ODDLPARSER_EXPORT Reference { /// @brief The default constructor. Reference(); - + Reference( const Reference &ref ); /// @brief The constructor with an array of ref names. /// @param numrefs [in] The number of ref names. /// @param names [in] The ref names. @@ -178,7 +178,6 @@ struct DLL_ODDLPARSER_EXPORT Reference { size_t sizeInBytes(); private: - Reference( const Reference & ) ddl_no_copy; Reference &operator = ( const Reference & ) ddl_no_copy; }; diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h index efeab6026..7241c74d8 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h @@ -47,7 +47,7 @@ struct Property; template inline T *lookForNextToken( T *in, T *end ) { - while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) { + while( ( in != end ) && ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) ) { in++; } return in; diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h b/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h index 778a1b46e..64897436e 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h @@ -84,7 +84,7 @@ static const unsigned char chartype_table[ 256 ] = { template inline bool isNumeric( const T in ) { - return ( chartype_table[ static_cast( in ) ] == 1 ); + return ( chartype_table[ static_cast( in ) ] == 1 ); } template @@ -98,7 +98,7 @@ inline bool isInteger( T *in, T *end ) { if( in != end ) { if( *in == '-' ) { - in++; + ++in; } } @@ -108,7 +108,7 @@ bool isInteger( T *in, T *end ) { if( !result ) { break; } - in++; + ++in; } return result; @@ -119,7 +119,7 @@ inline bool isFloat( T *in, T *end ) { if( in != end ) { if( *in == '-' ) { - in++; + ++in; } } @@ -134,12 +134,12 @@ bool isFloat( T *in, T *end ) { if( !result ) { return false; } - in++; + ++in; } // check for 1<.>0f if( *in == '.' ) { - in++; + ++in; } else { return false; } @@ -150,7 +150,7 @@ bool isFloat( T *in, T *end ) { if( !result ) { return false; } - in++; + ++in; } return result; @@ -208,7 +208,7 @@ template inline static T *getNextSeparator( T *in, T *end ) { while( !isSeparator( *in ) || in == end ) { - in++; + ++in; } return in; } @@ -250,5 +250,33 @@ bool isComment( T *in, T *end ) { return false; } +template +inline +bool isCommentOpenTag(T *in, T *end ) { + if (*in == '/') { + if (in + 1 != end) { + if (*(in + 1) == '*') { + return true; + } + } + } + + return false; +} + +template +inline +bool isCommentCloseTag(T *in, T *end) { + if (*in == '*') { + if (in + 1 != end) { + if (*(in + 1) == '/') { + return true; + } + } + } + + return false; +} + END_ODDLPARSER_NS From 323e470b3e1a59883a179615d32a69b90d6c2248 Mon Sep 17 00:00:00 2001 From: Petr Petrovich Petrov Date: Tue, 20 Jun 2017 14:29:16 +0300 Subject: [PATCH 52/62] Fixed bug in material color processing Thanks to @evgeny-panasyuk --- include/assimp/material.inl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/include/assimp/material.inl b/include/assimp/material.inl index 6c4d16f7b..2c31fd571 100644 --- a/include/assimp/material.inl +++ b/include/assimp/material.inl @@ -48,6 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATERIAL_INL_INC #define AI_MATERIAL_INL_INC +// --------------------------------------------------------------------------- +inline aiPropertyTypeInfo ai_real_to_property_type_info(float) +{ + return aiPTI_Float; +} + +inline aiPropertyTypeInfo ai_real_to_property_type_info(double) +{ + return aiPTI_Double; +} +// --------------------------------------------------------------------------- + //! @cond never // --------------------------------------------------------------------------- @@ -223,7 +235,7 @@ inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiUVTransform), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->mRotation)); } // --------------------------------------------------------------------------- @@ -235,7 +247,7 @@ inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor4D), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->a)); } // --------------------------------------------------------------------------- @@ -247,7 +259,7 @@ inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor3D), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->b)); } // --------------------------------------------------------------------------- @@ -259,7 +271,7 @@ inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiVector3D), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->x)); } // --------------------------------------------------------------------------- From 612ac234c53874ee152f672ce0129d2bc746d463 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 21 Jun 2017 14:21:16 +0200 Subject: [PATCH 53/62] SceneCombiner: move header for scenecombiner to public folder. --- code/CMakeLists.txt | 2 +- {code => include/assimp}/SceneCombiner.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) rename {code => include/assimp}/SceneCombiner.h (99%) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 017420d5d..6df6655fc 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -96,6 +96,7 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/Exporter.hpp ${HEADER_PATH}/DefaultIOStream.h ${HEADER_PATH}/DefaultIOSystem.h + ${HEADER_PATH}/SceneCombiner.h ) SET( Core_SRCS @@ -148,7 +149,6 @@ SET( Common_SRCS SpatialSort.cpp SpatialSort.h SceneCombiner.cpp - SceneCombiner.h ScenePreprocessor.cpp ScenePreprocessor.h SkeletonMeshBuilder.cpp diff --git a/code/SceneCombiner.h b/include/assimp/SceneCombiner.h similarity index 99% rename from code/SceneCombiner.h rename to include/assimp/SceneCombiner.h index af008b134..ca4e68c7f 100644 --- a/code/SceneCombiner.h +++ b/include/assimp/SceneCombiner.h @@ -143,7 +143,6 @@ struct NodeAttachmentInfo */ #define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10 - typedef std::pair BoneSrcIndex; // --------------------------------------------------------------------------- @@ -153,7 +152,6 @@ struct BoneWithHash : public std::pair { std::vector pSrcBones; }; - // --------------------------------------------------------------------------- /** @brief Utility for SceneCombiner */ From b727420cf235d17d914335092d728c5eff934a7e Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 21 Jun 2017 14:31:37 +0200 Subject: [PATCH 54/62] SceneCOmbiner: Fix the build. --- code/3DSExporter.cpp | 2 +- code/AMFImporter_Postprocess.cpp | 2 +- code/BlenderModifier.cpp | 4 ++-- code/IRRLoader.cpp | 2 +- code/IRRLoader.h | 2 +- code/LWSLoader.cpp | 2 +- code/LWSLoader.h | 2 +- code/MD3Loader.cpp | 2 +- code/StepExporter.cpp | 3 ++- code/XFileExporter.cpp | 3 ++- 10 files changed, 13 insertions(+), 11 deletions(-) diff --git a/code/3DSExporter.cpp b/code/3DSExporter.cpp index 4be83355a..642f7dc57 100644 --- a/code/3DSExporter.cpp +++ b/code/3DSExporter.cpp @@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "3DSExporter.h" #include "3DSLoader.h" #include "3DSHelper.h" -#include "SceneCombiner.h" +#include #include "SplitLargeMeshes.h" #include "StringComparison.h" #include diff --git a/code/AMFImporter_Postprocess.cpp b/code/AMFImporter_Postprocess.cpp index 3a48d3b42..085336c51 100644 --- a/code/AMFImporter_Postprocess.cpp +++ b/code/AMFImporter_Postprocess.cpp @@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AMFImporter.hpp" // Header files, Assimp. -#include "SceneCombiner.h" +#include #include "StandardShapes.h" #include "StringUtils.h" diff --git a/code/BlenderModifier.cpp b/code/BlenderModifier.cpp index d71ae5098..161028b6b 100644 --- a/code/BlenderModifier.cpp +++ b/code/BlenderModifier.cpp @@ -43,10 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of some blender modifiers (i.e subdivision, mirror). */ - #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER + #include "BlenderModifier.h" -#include "SceneCombiner.h" +#include #include "Subdivision.h" #include #include diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index 0a1edf253..8cc4acaad 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "fast_atof.h" #include "GenericProperty.h" -#include "SceneCombiner.h" +#include #include "StandardShapes.h" #include "Importer.h" diff --git a/code/IRRLoader.h b/code/IRRLoader.h index b8f0df918..d07199c0b 100644 --- a/code/IRRLoader.h +++ b/code/IRRLoader.h @@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_IRRLOADER_H_INCLUDED #include "IRRShared.h" -#include "SceneCombiner.h" +#include #include "Importer.h" #include "StringUtils.h" #include diff --git a/code/LWSLoader.cpp b/code/LWSLoader.cpp index aa05d63c9..302228556 100644 --- a/code/LWSLoader.cpp +++ b/code/LWSLoader.cpp @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ParsingUtils.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include "GenericProperty.h" #include "SkeletonMeshBuilder.h" #include "ConvertToLHProcess.h" diff --git a/code/LWSLoader.h b/code/LWSLoader.h index 28b4495df..e36d27b77 100644 --- a/code/LWSLoader.h +++ b/code/LWSLoader.h @@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_LWSLOADER_H_INCLUDED #include "LWOFileData.h" -#include "SceneCombiner.h" +#include #include "BaseImporter.h" struct aiImporterDesc; diff --git a/code/MD3Loader.cpp b/code/MD3Loader.cpp index 8047b82ba..f6a3a85dd 100644 --- a/code/MD3Loader.cpp +++ b/code/MD3Loader.cpp @@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_MD3_IMPORTER #include "MD3Loader.h" -#include "SceneCombiner.h" +#include #include "GenericProperty.h" #include "RemoveComments.h" #include "ParsingUtils.h" diff --git a/code/StepExporter.cpp b/code/StepExporter.cpp index ae5c12a4c..acf1b6dad 100644 --- a/code/StepExporter.cpp +++ b/code/StepExporter.cpp @@ -43,12 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER + #include "StepExporter.h" #include "ConvertToLHProcess.h" #include "Bitmap.h" #include "BaseImporter.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include #include #include diff --git a/code/XFileExporter.cpp b/code/XFileExporter.cpp index df22f0f45..7de494daf 100644 --- a/code/XFileExporter.cpp +++ b/code/XFileExporter.cpp @@ -43,12 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_X_EXPORTER + #include "XFileExporter.h" #include "ConvertToLHProcess.h" #include "Bitmap.h" #include "BaseImporter.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include #include #include From 439409bef2d623131ba2a6371dbe0e7b0606980e Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 21 Jun 2017 15:24:06 +0200 Subject: [PATCH 55/62] SceneCombiner: fix the build. --- code/AssimpCExport.cpp | 3 ++- code/ColladaExporter.cpp | 2 +- code/Exporter.cpp | 2 +- code/OptimizeGraph.cpp | 2 +- code/OptimizeMeshes.cpp | 2 +- code/PretransformVertices.cpp | 2 +- code/SceneCombiner.cpp | 2 +- code/Subdivision.cpp | 2 +- code/glTFExporter.cpp | 2 +- 9 files changed, 10 insertions(+), 9 deletions(-) diff --git a/code/AssimpCExport.cpp b/code/AssimpCExport.cpp index d3c3d3298..b8d3264a1 100644 --- a/code/AssimpCExport.cpp +++ b/code/AssimpCExport.cpp @@ -45,8 +45,9 @@ Assimp C export interface. See Exporter.cpp for some notes. */ #ifndef ASSIMP_BUILD_NO_EXPORT + #include "CInterfaceIOWrapper.h" -#include "SceneCombiner.h" +#include #include "ScenePrivate.h" #include diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index 1b8a60883..d701f905a 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include "Bitmap.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include "StringUtils.h" #include "XMLTools.h" #include diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 5f0e75200..bae4d7f80 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -54,7 +54,7 @@ Here we implement only the C++ interface (Assimp::Exporter). #ifndef ASSIMP_BUILD_NO_EXPORT #include "BlobIOSystem.h" -#include "SceneCombiner.h" +#include #include "BaseProcess.h" #include "Importer.h" // need this for GetPostProcessingStepInstanceList() diff --git a/code/OptimizeGraph.cpp b/code/OptimizeGraph.cpp index 8b3df0820..04971af5e 100644 --- a/code/OptimizeGraph.cpp +++ b/code/OptimizeGraph.cpp @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "OptimizeGraph.h" #include "ProcessHelper.h" -#include "SceneCombiner.h" +#include #include "Exceptional.h" #include diff --git a/code/OptimizeMeshes.cpp b/code/OptimizeMeshes.cpp index efbd51bd0..65a3cadce 100644 --- a/code/OptimizeMeshes.cpp +++ b/code/OptimizeMeshes.cpp @@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "OptimizeMeshes.h" #include "ProcessHelper.h" -#include "SceneCombiner.h" +#include #include "Exceptional.h" using namespace Assimp; diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index 26b8aee34..1339053f7 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "PretransformVertices.h" #include "ProcessHelper.h" -#include "SceneCombiner.h" +#include #include "Exceptional.h" using namespace Assimp; diff --git a/code/SceneCombiner.cpp b/code/SceneCombiner.cpp index a879f3123..9bcce4275 100644 --- a/code/SceneCombiner.cpp +++ b/code/SceneCombiner.cpp @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OptimizeGraph step. */ // ---------------------------------------------------------------------------- -#include "SceneCombiner.h" +#include #include "StringUtils.h" #include "fast_atof.h" #include "Hash.h" diff --git a/code/Subdivision.cpp b/code/Subdivision.cpp index ef5840dac..bc5292dbe 100644 --- a/code/Subdivision.cpp +++ b/code/Subdivision.cpp @@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Subdivision.h" -#include "SceneCombiner.h" +#include #include "SpatialSort.h" #include "ProcessHelper.h" #include "Vertex.h" diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 1fbd17d1b..695fda76e 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -48,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ByteSwapper.h" #include "SplitLargeMeshes.h" -#include "SceneCombiner.h" +#include #include #include #include From 7e45c639017294e6235cbe97e7014a46aecea6bb Mon Sep 17 00:00:00 2001 From: jamesgk Date: Tue, 20 Jun 2017 14:15:41 -0700 Subject: [PATCH 56/62] GLTF exporter: ensure buffer view byte offsets are correctly aligned --- code/glTFExporter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 695fda76e..aeb5069aa 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -185,8 +185,11 @@ inline Ref ExportData(Asset& a, std::string& meshName, Ref& bu unsigned int bytesPerComp = ComponentTypeSize(compType); size_t offset = buffer->byteLength; + // make sure offset is correctly byte-aligned, as required by spec + size_t padding = offset % bytesPerComp; + offset += padding; size_t length = count * numCompsOut * bytesPerComp; - buffer->Grow(length); + buffer->Grow(length + padding); // bufferView Ref bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view")); From 5011e382c7c405d220c05355da900b4e35f6647e Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 21 Jun 2017 23:02:26 +0200 Subject: [PATCH 57/62] unittest: fix compiler warning. --- test/unit/utObjTools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/utObjTools.cpp b/test/unit/utObjTools.cpp index e888d2ce5..b359cfa3a 100644 --- a/test/unit/utObjTools.cpp +++ b/test/unit/utObjTools.cpp @@ -109,8 +109,8 @@ TEST_F( utObjTools, countComponents_TwoLines_Success ) { buffer.resize( data.size() ); ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() ); test_parser.setBuffer( buffer ); - static const size_t Size = 4096UL; size_t numComps = test_parser.testGetNumComponentsInDataDefinition(); EXPECT_EQ( 3U, numComps ); } + From bd2af6591f20fd8777332d510056a037fbfa0df5 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 21 Jun 2017 23:02:46 +0200 Subject: [PATCH 58/62] Fix compiler warnings. --- code/BaseImporter.cpp | 4 -- code/HalfLifeFileData.h | 5 +- code/MD3FileData.h | 27 ++++----- code/MDCFileData.h | 2 +- code/MDLFileData.h | 127 ++++++++++++++++------------------------ 5 files changed, 66 insertions(+), 99 deletions(-) diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index 7cef43cf6..9598e8e9a 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -337,7 +337,6 @@ void BaseImporter::ConvertToUTF8(std::vector& data) if(*((uint32_t*)&data.front()) == 0x0000FFFE) { DefaultLogger::get()->debug("Found UTF-32 BOM ..."); - const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1; std::vector output; int *ptr = (int*)&data[ 0 ]; int *end = ptr + ( data.size() / sizeof(int) ) +1; @@ -358,11 +357,8 @@ void BaseImporter::ConvertToUTF8(std::vector& data) if(*((uint16_t*)&data.front()) == 0xFEFF) { DefaultLogger::get()->debug("Found UTF-16 BOM ..."); - const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1); std::vector output; int16_t *ptr = (int16_t*) &data[ 0 ]; - int16_t *end = ptr + (data.size() / sizeof(int)) + 1; - utf8::utf16to8(data.begin(), data.end(), back_inserter(output)); return; } diff --git a/code/HalfLifeFileData.h b/code/HalfLifeFileData.h index 9a498d14c..3a36d2422 100644 --- a/code/HalfLifeFileData.h +++ b/code/HalfLifeFileData.h @@ -66,8 +66,7 @@ namespace MDL { * \brief Data structure for the HL2 main header */ // --------------------------------------------------------------------------- -struct Header_HL2 -{ +struct Header_HL2 { //! magic number: "IDST"/"IDSQ" char ident[4]; @@ -139,7 +138,7 @@ struct Header_HL2 //! Number of animation transitions int32_t numtransitions; int32_t transitionindex; -} PACK_STRUCT; +} /* PACK_STRUCT */; #include "./../include/assimp/Compiler/poppack1.h" diff --git a/code/MD3FileData.h b/code/MD3FileData.h index 262d75322..19740c30e 100644 --- a/code/MD3FileData.h +++ b/code/MD3FileData.h @@ -142,14 +142,14 @@ struct Frame //! name of frame char name[ AI_MD3_MAXFRAME ]; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------- -/** @brief Data structure for the tag header +/** + * @brief Data structure for the tag header */ -struct Tag -{ +struct Tag { //! name of the tag char NAME[ AI_MD3_MAXQPATH ]; @@ -157,14 +157,13 @@ struct Tag aiVector3D origin; ai_real orientation[3][3]; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------- /** @brief Data structure for the surface header */ -struct Surface -{ +struct Surface { //! magic number int32_t IDENT; @@ -186,7 +185,6 @@ struct Surface //! number of triangles in the surface uint32_t NUM_TRIANGLES; - //! offset to the triangle data uint32_t OFS_TRIANGLES; @@ -201,19 +199,18 @@ struct Surface //! offset to the end of the Surface object int32_t OFS_END; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- /** @brief Data structure for a shader defined in there */ -struct Shader -{ +struct Shader { //! filename of the shader char NAME[ AI_MD3_MAXQPATH ]; //! index of the shader uint32_t SHADER_INDEX; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- @@ -223,7 +220,7 @@ struct Triangle { //! triangle indices uint32_t INDEXES[3]; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- @@ -233,7 +230,7 @@ struct TexCoord { //! UV coordinates ai_real U,V; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- @@ -246,7 +243,7 @@ struct Vertex //! encoded normal vector uint16_t NORMAL; -} PACK_STRUCT; +} /*PACK_STRUCT*/; #include "./../include/assimp/Compiler/poppack1.h" diff --git a/code/MDCFileData.h b/code/MDCFileData.h index 2ce96db5a..9ea3d8f5e 100644 --- a/code/MDCFileData.h +++ b/code/MDCFileData.h @@ -157,7 +157,7 @@ struct Frame //! Name of the frame char name [ 16 ] ; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // --------------------------------------------------------------------------- /** \brief Data structure for a MDC triangle diff --git a/code/MDLFileData.h b/code/MDLFileData.h index 6ba5b5aa2..a691851be 100644 --- a/code/MDLFileData.h +++ b/code/MDLFileData.h @@ -53,10 +53,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MDLFILEHELPER_H_INC #define AI_MDLFILEHELPER_H_INC +#include +#include +#include #include "ByteSwapper.h" -#include "./../include/assimp/anim.h" -#include "./../include/assimp/mesh.h" -#include "./../include/assimp/Compiler/pushpack1.h" #include #include @@ -90,7 +90,6 @@ namespace MDL { #define AI_MDL_MAGIC_NUMBER_BE_GS7 AI_MAKE_MAGIC("MDL7") #define AI_MDL_MAGIC_NUMBER_LE_GS7 AI_MAKE_MAGIC("7LDM") - // common limitations for Quake1 meshes. The loader does not check them, // (however it warns) but models should not exceed these limits. #if (!defined AI_MDL_VERSION) @@ -119,8 +118,7 @@ namespace MDL { /** \struct Header * \brief Data structure for the MDL main header */ -struct Header -{ +struct Header { //! magic number: "IDPO" uint32_t ident; @@ -166,15 +164,14 @@ struct Header //! Could be the total size of the file (and not a float) float size; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Header_MDL7 * \brief Data structure for the MDL 7 main header */ -struct Header_MDL7 -{ +struct Header_MDL7 { //! magic number: "MDL7" char ident[4]; @@ -226,15 +223,14 @@ struct Header_MDL7 //! Size of the Frame_MDL7 data structure used in the file uint16_t frame_stc_size; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Bone_MDL7 * \brief Data structure for a bone in a MDL7 file */ -struct Bone_MDL7 -{ +struct Bone_MDL7 { //! Index of the parent bone of *this* bone. 0xffff means: //! "hey, I have no parent, I'm an orphan" uint16_t parent_index; @@ -246,7 +242,7 @@ struct Bone_MDL7 //! Optional name of the bone char name[1 /* DUMMY SIZE */]; -} PACK_STRUCT; +} /* PACK_STRUCT */; #if (!defined AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS) # define AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_20_CHARS (16 + 20) @@ -268,8 +264,7 @@ struct Bone_MDL7 /** \struct Group_MDL7 * \brief Group in a MDL7 file */ -struct Group_MDL7 -{ +struct Group_MDL7 { //! = '1' -> triangle based Mesh unsigned char typ; @@ -295,7 +290,7 @@ struct Group_MDL7 //! Number of frames int32_t numframes; -} PACK_STRUCT; +} /* PACK_STRUCT */; #define AI_MDL7_SKINTYPE_MIPFLAG 0x08 #define AI_MDL7_SKINTYPE_MATERIAL 0x10 @@ -310,41 +305,36 @@ struct Group_MDL7 /** \struct Deformer_MDL7 * \brief Deformer in a MDL7 file */ -struct Deformer_MDL7 -{ +struct Deformer_MDL7 { int8_t deformer_version; // 0 int8_t deformer_typ; // 0 - bones int8_t _unused_[2]; int32_t group_index; int32_t elements; int32_t deformerdata_size; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct DeformerElement_MDL7 * \brief Deformer element in a MDL7 file */ -struct DeformerElement_MDL7 -{ +struct DeformerElement_MDL7 { //! bei deformer_typ==0 (==bones) element_index == bone index int32_t element_index; char element_name[AI_MDL7_MAX_BONENAMESIZE]; int32_t weights; -} PACK_STRUCT; - +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct DeformerWeight_MDL7 * \brief Deformer weight in a MDL7 file */ -struct DeformerWeight_MDL7 -{ +struct DeformerWeight_MDL7 { //! for deformer_typ==0 (==bones) index == vertex index int32_t index; float weight; -} PACK_STRUCT; - +} /* PACK_STRUCT */; // don't know why this was in the original headers ... typedef int32_t MD7_MATERIAL_ASCDEFSIZE; @@ -353,17 +343,15 @@ typedef int32_t MD7_MATERIAL_ASCDEFSIZE; /** \struct ColorValue_MDL7 * \brief Data structure for a color value in a MDL7 file */ -struct ColorValue_MDL7 -{ +struct ColorValue_MDL7 { float r,g,b,a; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Material_MDL7 * \brief Data structure for a Material in a MDL7 file */ -struct Material_MDL7 -{ +struct Material_MDL7 { //! Diffuse base color of the material ColorValue_MDL7 Diffuse; @@ -378,15 +366,13 @@ struct Material_MDL7 //! Phong power float Power; -} PACK_STRUCT; - +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Skin * \brief Skin data structure #1 - used by Quake1, MDL2, MDL3 and MDL4 */ -struct Skin -{ +struct Skin { //! 0 = single (Skin), 1 = group (GroupSkin) //! For MDL3-5: Defines the type of the skin and there //! fore the size of the data to skip: @@ -402,7 +388,7 @@ struct Skin //! Texture data uint8_t *data; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- @@ -410,11 +396,10 @@ struct Skin * \brief Skin data structure #2 - used by MDL5, MDL6 and MDL7 * \see Skin */ -struct Skin_MDL5 -{ +struct Skin_MDL5 { int32_t size, width, height; uint8_t *data; -} PACK_STRUCT; +} /* PACK_STRUCT */; // maximum length of texture file name #if (!defined AI_MDL7_MAX_TEXNAMESIZE) @@ -425,44 +410,40 @@ struct Skin_MDL5 /** \struct Skin_MDL7 * \brief Skin data structure #3 - used by MDL7 and HMP7 */ -struct Skin_MDL7 -{ +struct Skin_MDL7 { uint8_t typ; int8_t _unused_[3]; int32_t width; int32_t height; char texture_name[AI_MDL7_MAX_TEXNAMESIZE]; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct RGB565 * \brief Data structure for a RGB565 pixel in a texture */ -struct RGB565 -{ +struct RGB565 { uint16_t r : 5; uint16_t g : 6; uint16_t b : 5; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct ARGB4 * \brief Data structure for a ARGB4444 pixel in a texture */ -struct ARGB4 -{ +struct ARGB4 { uint16_t a : 4; uint16_t r : 4; uint16_t g : 4; uint16_t b : 4; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------------- /** \struct GroupSkin * \brief Skin data structure #2 (group of pictures) */ -struct GroupSkin -{ +struct GroupSkin { //! 0 = single (Skin), 1 = group (GroupSkin) int32_t group; @@ -474,14 +455,13 @@ struct GroupSkin //! Data of each image uint8_t **data; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct TexCoord * \brief Texture coordinate data structure used by the Quake1 MDL format */ -struct TexCoord -{ +struct TexCoord { //! Is the vertex on the noundary between front and back piece? int32_t onseam; @@ -490,33 +470,31 @@ struct TexCoord //! Texture coordinate in the ty direction int32_t t; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct TexCoord_MDL3 * \brief Data structure for an UV coordinate in the 3DGS MDL3 format */ -struct TexCoord_MDL3 -{ +struct TexCoord_MDL3 { //! position, horizontally in range 0..skinwidth-1 int16_t u; //! position, vertically in range 0..skinheight-1 int16_t v; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct TexCoord_MDL7 * \brief Data structure for an UV coordinate in the 3DGS MDL7 format */ -struct TexCoord_MDL7 -{ +struct TexCoord_MDL7 { //! position, horizontally in range 0..1 float u; //! position, vertically in range 0..1 float v; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct SkinSet_MDL7 @@ -532,7 +510,7 @@ struct SkinSet_MDL7 //! Material index int32_t material; // size 4 -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Triangle @@ -545,7 +523,7 @@ struct Triangle //! Vertex indices int32_t vertex[3]; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Triangle_MDL3 @@ -558,7 +536,7 @@ struct Triangle_MDL3 //! Index of 3 skin vertices in range 0..numskinverts uint16_t index_uv[3]; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Triangle_MDL7 @@ -571,7 +549,7 @@ struct Triangle_MDL7 //! Two skinsets. The second will be used for multi-texturing SkinSet_MDL7 skinsets[2]; -} PACK_STRUCT; +} /* PACK_STRUCT */; #if (!defined AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV) # define AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV (6+sizeof(SkinSet_MDL7)-sizeof(uint32_t)) @@ -599,7 +577,7 @@ struct Vertex { uint8_t v[3]; uint8_t normalIndex; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- @@ -625,8 +603,7 @@ struct Vertex_MDL7 uint8_t norm162index; float norm[3]; }; -} PACK_STRUCT; - +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct BoneTransform_MDL7 @@ -643,12 +620,11 @@ struct BoneTransform_MDL7 //! I HATE 3DGS AND THE SILLY DEVELOPER WHO DESIGNED //! THIS STUPID FILE FORMAT! int8_t _unused_[2]; -} PACK_STRUCT; +} /* PACK_STRUCT */; #define AI_MDL7_MAX_FRAMENAMESIZE 16 - // ------------------------------------------------------------------------------------- /** \struct Frame_MDL7 * \brief Frame data structure used by MDL7 files @@ -678,7 +654,7 @@ struct SimpleFrame //! Vertex list of the frame Vertex *verts; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct Frame @@ -691,7 +667,7 @@ struct Frame //! Frame data SimpleFrame frame; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- @@ -708,7 +684,7 @@ struct SimpleFrame_MDLn_SP //! Vertex list of the frame Vertex_MDL4 *verts; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------------- /** \struct GroupFrame @@ -730,7 +706,7 @@ struct GroupFrame //! List of single frames SimpleFrame *frames; -} PACK_STRUCT; +} /* PACK_STRUCT */; #include "./../include/assimp/Compiler/poppack1.h" @@ -738,8 +714,7 @@ struct GroupFrame /** \struct IntFace_MDL7 * \brief Internal data structure to temporarily represent a face */ -struct IntFace_MDL7 -{ +struct IntFace_MDL7 { // provide a constructor for our own convenience IntFace_MDL7() { From 735e64309bafa3ee624a7da862545c98f2258fa1 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 21 Jun 2017 23:06:53 +0200 Subject: [PATCH 59/62] LWO: use forward declaration in header. --- code/LWOAnimation.cpp | 1 + code/LWOAnimation.h | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/LWOAnimation.cpp b/code/LWOAnimation.cpp index cbd12fe1a..4862876fc 100644 --- a/code/LWOAnimation.cpp +++ b/code/LWOAnimation.cpp @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "LWOFileData.h" +#include using namespace Assimp; using namespace Assimp::LWO; diff --git a/code/LWOAnimation.h b/code/LWOAnimation.h index 11f71bd93..f0c578ad9 100644 --- a/code/LWOAnimation.h +++ b/code/LWOAnimation.h @@ -48,11 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_LWO_ANIMATION_INCLUDED #define AI_LWO_ANIMATION_INCLUDED -#include +// #include #include struct aiNodeAnim; +struct aiVectorKey; namespace Assimp { namespace LWO { @@ -166,7 +167,6 @@ struct Envelope //! Keyframes for this envelope std::vector keys; - // temporary data for AnimResolver size_t old_first,old_last; }; @@ -198,8 +198,7 @@ public: * @param Output tick rate, per second * @note The input envelopes are possibly modified. */ - AnimResolver(std::list& envelopes, - double tick); + AnimResolver(std::list& envelopes, double tick); public: From f6c4edeb7d49c6fe536aec997304e9302b571601 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 22 Jun 2017 10:07:02 +0200 Subject: [PATCH 60/62] Update Readme.md Add the donation button. --- Readme.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index 2dc024a52..449a69e87 100644 --- a/Readme.md +++ b/Readme.md @@ -15,14 +15,13 @@ APIs are provided for C and C++. There are various bindings to other languages ( Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. -This is the development trunk containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [assimp.sf.net](http://assimp.sf.net) or from *nix package repositories. -The current build status is: +This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). + +One-off donations via PayPal: +
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4) Gitter chat: [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type -> /join #assetimporterlib -
__[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__ From 56a9d5c659abc7bd7122a492e4e9c531ea106c96 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 22 Jun 2017 10:11:54 +0200 Subject: [PATCH 61/62] Update Readme.md Inproved readme. --- Readme.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 449a69e87..1e8e66b92 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ Open Asset Import Library (assimp) ================================== - +### Current build status ### [![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp) @@ -9,6 +9,7 @@ Open Asset Import Library (assimp) Patreon donate button [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master) +[![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. @@ -20,10 +21,7 @@ This is the development repo containing the latest features and bugfixes. For pr One-off donations via PayPal:
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4) -Gitter chat: [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-
-__[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__ Please check our Wiki as well: https://github.com/assimp/assimp/wiki @@ -99,6 +97,9 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak * [Pascal](port/AssimpPascal/Readme.md) * [Javascript (Alpha)](https://github.com/makc/assimp2json) +### Other tools ### +[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities. + #### Repository structure #### Open Asset Import Library is implemented in C++. The directory structure is: From afb2f3036e6200101be63baeaaed182bf8533d29 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 25 Jun 2017 13:21:36 +0200 Subject: [PATCH 62/62] OpenDDLParser: latest greatest. --- code/CMakeLists.txt | 2 + contrib/openddlparser/CMakeLists.txt | 122 ++++++++++++++++-- contrib/openddlparser/CREDITS | 3 + contrib/openddlparser/README.md | 4 +- contrib/openddlparser/code/DDLNode.cpp | 4 + contrib/openddlparser/code/OpenDDLExport.cpp | 54 -------- contrib/openddlparser/code/OpenDDLParser.cpp | 12 +- contrib/openddlparser/code/OpenDDLStream.cpp | 96 ++++++++++++++ contrib/openddlparser/code/Value.cpp | 4 +- .../include/openddlparser/DDLNode.h | 26 ++-- .../include/openddlparser/OpenDDLExport.h | 30 +---- .../include/openddlparser/OpenDDLParser.h | 10 ++ .../include/openddlparser/OpenDDLStream.h | 89 +++++++++++++ .../include/openddlparser/Value.h | 10 +- 14 files changed, 356 insertions(+), 110 deletions(-) create mode 100644 contrib/openddlparser/code/OpenDDLStream.cpp create mode 100644 contrib/openddlparser/include/openddlparser/OpenDDLStream.h diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 6df6655fc..82497467a 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -732,10 +732,12 @@ SET ( openddl_parser_SRCS ../contrib/openddlparser/code/OpenDDLCommon.cpp ../contrib/openddlparser/code/OpenDDLExport.cpp ../contrib/openddlparser/code/Value.cpp + ../contrib/openddlparser/code/OpenDDLStream.cpp ../contrib/openddlparser/include/openddlparser/OpenDDLParser.h ../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h ../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h ../contrib/openddlparser/include/openddlparser/OpenDDLExport.h + ../contrib/openddlparser/include/openddlparser/OpenDDLStream.h ../contrib/openddlparser/include/openddlparser/DDLNode.h ../contrib/openddlparser/include/openddlparser/Value.h ) diff --git a/contrib/openddlparser/CMakeLists.txt b/contrib/openddlparser/CMakeLists.txt index a39d0219f..9e903ca3f 100644 --- a/contrib/openddlparser/CMakeLists.txt +++ b/contrib/openddlparser/CMakeLists.txt @@ -3,18 +3,40 @@ PROJECT( OpenDDL-Parser ) SET ( OPENDDL_PARSER_VERSION_MAJOR 0 ) SET ( OPENDDL_PARSER_VERSION_MINOR 1 ) SET ( OPENDDL_PARSER_VERSION_PATCH 0 ) -SET ( OPENDDL_PARSER_VERSION ${CPPCORE_VERSION_MAJOR}.${CPPCORE_VERSION_MINOR}.${CPPCORE_VERSION_PATCH} ) +SET ( OPENDDL_PARSER_VERSION ${OPENDDL_PARSER_VERSION_MAJOR}.${OPENDDL_PARSER_VERSION_MINOR}.${OPENDDL_PARSER_VERSION_PATCH} ) SET ( PROJECT_VERSION "${OPENDDL_PARSER_VERSION}" ) +option( DDL_USE_CPP11 "Set to ON to use C++11 features ( always on on windows )." ON ) +option( DDL_DEBUG_OUTPUT "Set to ON to use output debug texts" OFF ) +option( DDL_STATIC_LIBRARY "Set to ON to build static libary of OpenDDL Parser." ON ) +option( COVERALLS "Generate coveralls data" OFF ) + +if ( DDL_USE_CPP11 ) + if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) + set( OPENDDL_CXXFLAGS -std=c++0x ) + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set( OPENDDL_CXXFLAGS --std=c++11 ) + endif() +else( DDL_USE_CPP11 ) + add_definitions( -DOPENDDL_NO_USE_CPP11 ) +endif( DDL_USE_CPP11) + if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) find_package(Threads) else() add_definitions( -D_CRT_SECURE_NO_WARNINGS ) endif() +if ( DDL_STATIC_LIBRARY ) + add_definitions( -DOPENDDL_STATIC_LIBARY ) +endif() + add_definitions( -DOPENDDLPARSER_BUILD ) -add_definitions( -DOPENDDL_NO_USE_CPP11 ) add_definitions( -D_VARIADIC_MAX=10 ) +add_definitions( -DGTEST_HAS_PTHREAD=0 ) +if ( DDL_DEBUG_OUTPUT ) + add_definitions( -DDDL_DEBUG_HEADER_NAME) +endif() INCLUDE_DIRECTORIES( ./ @@ -24,9 +46,10 @@ INCLUDE_DIRECTORIES( ) link_directories( - ./ + ${CMAKE_HOME_DIRECTORY}/lib ) +set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin ) @@ -40,18 +63,38 @@ if( WIN32 AND NOT CYGWIN ) endif() elseif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) # Update if necessary - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS}") elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS} -Wwrite-strings") endif() +if (COVERALLS) + include(Coveralls) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +endif() + +# Include the doc component. +FIND_PACKAGE( doxygen ) +IF ( DOXYGEN_FOUND ) + CONFIGURE_FILE( doc/openddlparser_doc.in doc/doxygenfile @ONLY ) + ADD_CUSTOM_TARGET( doc ALL ${DOXYGEN_EXECUTABLE} doc/doxygenfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" VERBATIM ) +ENDIF ( DOXYGEN_FOUND ) + SET ( openddl_parser_src + code/OpenDDLCommon.cpp + code/OpenDDLExport.cpp code/OpenDDLParser.cpp + code/OpenDDLStream.cpp code/DDLNode.cpp code/Value.cpp + include/openddlparser/OpenDDLCommon.h + include/openddlparser/OpenDDLExport.h include/openddlparser/OpenDDLParser.h include/openddlparser/OpenDDLParserUtils.h - include/openddlparser/OpenDDLCommon.h + include/openddlparser/OpenDDLStream.h include/openddlparser/DDLNode.h include/openddlparser/Value.h README.md @@ -59,6 +102,69 @@ SET ( openddl_parser_src SOURCE_GROUP( code FILES ${openddl_parser_src} ) -ADD_LIBRARY( openddl_parser SHARED - ${openddl_parser_src} +if ( DDL_STATIC_LIBRARY ) + ADD_LIBRARY( openddl_parser STATIC + ${openddl_parser_src} + ) +else() + ADD_LIBRARY( openddl_parser SHARED + ${openddl_parser_src} + ) +endif() + +SET ( GTEST_PATH contrib/gtest-1.7.0 ) + +SET ( gtest_src + ${GTEST_PATH}/src/gtest-death-test.cc + ${GTEST_PATH}/src/gtest-filepath.cc + ${GTEST_PATH}/src/gtest-internal-inl.h + ${GTEST_PATH}/src/gtest-port.cc + ${GTEST_PATH}/src/gtest-printers.cc + ${GTEST_PATH}/src/gtest-test-part.cc + ${GTEST_PATH}/src/gtest-typed-test.cc + ${GTEST_PATH}/src/gtest.cc + ${GTEST_PATH}/src/gtest_main.cc ) + +SET( openddl_parser_unittest_src + test/UnitTestCommon.h + test/DDLNodeTest.cpp + test/OpenDDLCommonTest.cpp + test/OpenDDLExportTest.cpp + test/OpenDDLParserTest.cpp + test/OpenDDLParserUtilsTest.cpp + test/OpenDDLStreamTest.cpp + test/OpenDDLIntegrationTest.cpp + test/ValueTest.cpp + test/OpenDDLDefectsTest.cpp +) + +SOURCE_GROUP( code FILES ${openddl_parser_unittest_src} ) +SOURCE_GROUP( gtest FILES ${gtest_src} ) + +ADD_EXECUTABLE( openddl_parser_unittest + ${gtest_src} + ${openddl_parser_unittest_src} +) + +target_link_libraries( openddl_parser_unittest openddl_parser ${CMAKE_THREAD_LIBS_INIT} ) + +SET( openddl_parser_demo_src + demo/main.cpp +) + +if (COVERALLS) + set(COVERAGE_SRCS ${gtest_src} ${openddl_parser_unittest_src} ) + + # Create the coveralls target. + coveralls_setup( + "${COVERAGE_SRCS}" # The source files. + ON # If we should upload. + "${PROJECT_SOURCE_DIR}/cmake/") # (Optional) Alternate project cmake module path. +endif() + +ADD_EXECUTABLE( openddl_parser_demo + ${openddl_parser_demo_src} +) + +target_link_libraries( openddl_parser_demo openddl_parser ) diff --git a/contrib/openddlparser/CREDITS b/contrib/openddlparser/CREDITS index a2b01eb13..d3936af83 100644 --- a/contrib/openddlparser/CREDITS +++ b/contrib/openddlparser/CREDITS @@ -12,5 +12,8 @@ Improvements value interface, serveral bugfixes. - Henry Read ( henrya2 ): Static build option, Interface improvements +- (wise86-android) +fix several mem-leaks + - Paul Holland ( pkholland ): Bugfixes. diff --git a/contrib/openddlparser/README.md b/contrib/openddlparser/README.md index 619747d23..a48ea1be0 100644 --- a/contrib/openddlparser/README.md +++ b/contrib/openddlparser/README.md @@ -11,7 +11,7 @@ Current coverity check status: Coverity Scan Build Status - +Current test coverage:[![Coverage Status](https://coveralls.io/repos/github/kimkulling/openddl-parser/badge.svg?branch=master)](https://coveralls.io/github/kimkulling/openddl-parser?branch=cpp_coveralls) Get the source code =================== You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command: @@ -25,7 +25,7 @@ After installing it you can open a console and enter: > cmake CMakeLists.txt -This command will generate a build environment for your installed build enrironment ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ). +This command will generate a build environment for your preferred build tool ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ). When using an IDE open the IDE and run the build. When using GNU-make type in your console: > make diff --git a/contrib/openddlparser/code/DDLNode.cpp b/contrib/openddlparser/code/DDLNode.cpp index 3955e3fd9..6548cdf24 100644 --- a/contrib/openddlparser/code/DDLNode.cpp +++ b/contrib/openddlparser/code/DDLNode.cpp @@ -191,6 +191,10 @@ Reference *DDLNode::getReferences() const { return m_references; } +void DDLNode::dump(IOStreamBase &stream) { + // Todo! +} + DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLNode *parent ) { const size_t idx( s_allocatedNodes.size() ); DDLNode *node = new DDLNode( type, name, idx, parent ); diff --git a/contrib/openddlparser/code/OpenDDLExport.cpp b/contrib/openddlparser/code/OpenDDLExport.cpp index 35036cc6a..a85bc5676 100644 --- a/contrib/openddlparser/code/OpenDDLExport.cpp +++ b/contrib/openddlparser/code/OpenDDLExport.cpp @@ -29,60 +29,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS -StreamFormatterBase::StreamFormatterBase() { - -} - -StreamFormatterBase::~StreamFormatterBase() { - -} - -std::string StreamFormatterBase::format( const std::string &statement ) { - std::string tmp( statement ); - return tmp; -} - -IOStreamBase::IOStreamBase( StreamFormatterBase *formatter ) -: m_formatter( formatter ) -, m_file( ddl_nullptr ) { - if (ddl_nullptr == m_formatter) { - m_formatter = new StreamFormatterBase; - } -} - -IOStreamBase::~IOStreamBase() { - delete m_formatter; - m_formatter = ddl_nullptr; -} - -bool IOStreamBase::open( const std::string &name ) { - m_file = ::fopen( name.c_str(), "a" ); - if (m_file == ddl_nullptr) { - return false; - } - - return true; -} - -bool IOStreamBase::close() { - if (ddl_nullptr == m_file) { - return false; - } - - ::fclose( m_file ); - m_file = ddl_nullptr; - - return true; -} - -size_t IOStreamBase::write( const std::string &statement ) { - if (ddl_nullptr == m_file) { - return 0; - } - std::string formatStatement = m_formatter->format( statement ); - return ::fwrite( formatStatement.c_str(), sizeof( char ), formatStatement.size(), m_file ); -} - struct DDLNodeIterator { const DDLNode::DllNodeList &m_childs; size_t m_idx; diff --git a/contrib/openddlparser/code/OpenDDLParser.cpp b/contrib/openddlparser/code/OpenDDLParser.cpp index e9032980b..dab976fad 100644 --- a/contrib/openddlparser/code/OpenDDLParser.cpp +++ b/contrib/openddlparser/code/OpenDDLParser.cpp @@ -327,14 +327,14 @@ char *OpenDDLParser::parseStructure( char *in, char *end ) { bool error( false ); in = lookForNextToken( in, end ); - if( *in == '{' ) { + if( *in == *Grammar::OpenBracketToken) { // loop over all children ( data and nodes ) do { in = parseStructureBody( in, end, error ); if(in == ddl_nullptr){ return ddl_nullptr; } - } while ( *in != '}' ); + } while ( *in != *Grammar::CloseBracketToken); ++in; } else { ++in; @@ -540,7 +540,11 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Text **id ) { // get size of id size_t idLen( 0 ); char *start( in ); - while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != Grammar::OpenPropertyToken[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] && *in != '$' ) { + while( !isSeparator( *in ) && + !isNewLine( *in ) && ( in != end ) && + *in != Grammar::OpenPropertyToken[ 0 ] && + *in != Grammar::ClosePropertyToken[ 0 ] && + *in != '$' ) { ++in; ++idLen; } @@ -562,7 +566,7 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy for( unsigned int i = 0; i < Value::ddl_types_max; i++ ) { prim_len = strlen( Grammar::PrimitiveTypeToken[ i ] ); if( 0 == strncmp( in, Grammar::PrimitiveTypeToken[ i ], prim_len ) ) { - type = ( Value::ValueType ) i; + type = static_cast( i ); break; } } diff --git a/contrib/openddlparser/code/OpenDDLStream.cpp b/contrib/openddlparser/code/OpenDDLStream.cpp new file mode 100644 index 000000000..7ea8331bd --- /dev/null +++ b/contrib/openddlparser/code/OpenDDLStream.cpp @@ -0,0 +1,96 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2014-2015 Kim Kulling + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-----------------------------------------------------------------------------------------------*/ +#include + +BEGIN_ODDLPARSER_NS + +StreamFormatterBase::StreamFormatterBase() { + // empty +} + +StreamFormatterBase::~StreamFormatterBase() { + // empty +} + +std::string StreamFormatterBase::format(const std::string &statement) { + std::string tmp(statement); + return tmp; +} + +IOStreamBase::IOStreamBase(StreamFormatterBase *formatter) + : m_formatter(formatter) + , m_file(ddl_nullptr) { + if (ddl_nullptr == m_formatter) { + m_formatter = new StreamFormatterBase; + } +} + +IOStreamBase::~IOStreamBase() { + delete m_formatter; + m_formatter = ddl_nullptr; +} + +bool IOStreamBase::open(const std::string &name) { + m_file = ::fopen(name.c_str(), "a"); + if (m_file == ddl_nullptr) { + return false; + } + + return true; +} + +bool IOStreamBase::close() { + if (ddl_nullptr == m_file) { + return false; + } + + ::fclose(m_file); + m_file = ddl_nullptr; + + return true; +} + +bool IOStreamBase::isOpen() const { + return ( ddl_nullptr != m_file ); +} + +size_t IOStreamBase::read( size_t sizeToRead, std::string &statement ) { + if (ddl_nullptr == m_file) { + return 0; + } + + statement.resize(sizeToRead); + const size_t readBytes = ::fread( &statement[0], 1, sizeToRead, m_file ); + + return readBytes; +} + +size_t IOStreamBase::write(const std::string &statement) { + if (ddl_nullptr == m_file) { + return 0; + } + std::string formatStatement = m_formatter->format(statement); + return ::fwrite(formatStatement.c_str(), sizeof(char), formatStatement.size(), m_file); +} + +END_ODDLPARSER_NS diff --git a/contrib/openddlparser/code/Value.cpp b/contrib/openddlparser/code/Value.cpp index 408cdd456..3c8b06a10 100644 --- a/contrib/openddlparser/code/Value.cpp +++ b/contrib/openddlparser/code/Value.cpp @@ -294,7 +294,7 @@ Reference *Value::getRef() const { return (Reference*) m_data; } -void Value::dump() { +void Value::dump( IOStreamBase &stream ) { switch( m_type ) { case ddl_none: std::cout << "None" << std::endl; @@ -354,7 +354,7 @@ Value *Value::getNext() const { return m_next; } -size_t Value::size(){ +size_t Value::size() const{ size_t result=1; Value *n=m_next; while( n!=ddl_nullptr) { diff --git a/contrib/openddlparser/include/openddlparser/DDLNode.h b/contrib/openddlparser/include/openddlparser/DDLNode.h index 184cd0171..915bd3041 100644 --- a/contrib/openddlparser/include/openddlparser/DDLNode.h +++ b/contrib/openddlparser/include/openddlparser/DDLNode.h @@ -29,6 +29,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS +// Forward declarations +class IOStreamBase; class Value; class OpenDDLParser; @@ -84,7 +86,7 @@ public: const std::string &getType() const; /// Set the name of the DDLNode instance. - /// @param type [in] The name. + /// @param name [in] The name. void setName( const std::string &name ); /// @brief Returns the name of the DDLNode instance. @@ -92,7 +94,7 @@ public: const std::string &getName() const; /// @brief Set a new property set. - /// @param prop [in] The first element of the property set. + /// @param prop [in] The first element of the property set. void setProperties( Property *prop ); /// @brief Returns the first element of the assigned property set. @@ -100,7 +102,7 @@ public: Property *getProperties() const; /// @brief Looks for a given property. - /// @param name [in] The name for the property to look for. + /// @param name [in] The name for the property to look for. /// @return true, if a corresponding property is assigned to the node, false if not. bool hasProperty( const std::string &name ); @@ -109,12 +111,12 @@ public: bool hasProperties() const; /// @brief Search for a given property and returns it. Will return ddl_nullptr if no property was found. - /// @param name [in] The name for the property to look for. + /// @param name [in] The name for the property to look for. /// @return The property or ddl_nullptr if no property was found. Property *findPropertyByName( const std::string &name ); /// @brief Set a new value set. - /// @param val [in] The first value instance of the value set. + /// @param val [in] The first value instance of the value set. void setValue( Value *val ); /// @brief Returns the first element of the assigned value set. @@ -122,7 +124,7 @@ public: Value *getValue() const; /// @brief Set a new DataArrayList. - /// @param val [in] The DataArrayList instance. + /// @param dtArrayList [in] The DataArrayList instance. void setDataArrayList( DataArrayList *dtArrayList ); /// @brief Returns the DataArrayList. @@ -130,17 +132,21 @@ public: DataArrayList *getDataArrayList() const; /// @brief Set a new Reference set. - /// @param val [in] The first value instance of the Reference set. + /// @param refs [in] The first value instance of the Reference set. void setReferences( Reference *refs ); /// @brief Returns the first element of the assigned Reference set. /// @return The first property of the assigned Reference set. Reference *getReferences() const; + /// @brief Will dump the node into the stream. + /// @param stream [in] The stream to write to. + void dump(IOStreamBase &stream); + /// @brief The creation method. - /// @param type [in] The DDLNode type. - /// @param name [in] The name for the new DDLNode instance. - /// @param parent [in] The parent node instance or ddl_nullptr if no parent node is there. + /// @param type [in] The DDLNode type. + /// @param name [in] The name for the new DDLNode instance. + /// @param parent [in] The parent node instance or ddl_nullptr if no parent node is there. /// @return The new created node instance. static DDLNode *create( const std::string &type, const std::string &name, DDLNode *parent = ddl_nullptr ); diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLExport.h b/contrib/openddlparser/include/openddlparser/OpenDDLExport.h index 8ede537d9..020d662a0 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLExport.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLExport.h @@ -23,37 +23,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #pragma once #include +#include #include BEGIN_ODDLPARSER_NS -//------------------------------------------------------------------------------------------------- -/// @ingroup IOStreamBase -/// @brief This class represents the stream to write out. -//------------------------------------------------------------------------------------------------- -class DLL_ODDLPARSER_EXPORT StreamFormatterBase { -public: - StreamFormatterBase(); - virtual ~StreamFormatterBase(); - virtual std::string format( const std::string &statement ); -}; - -//------------------------------------------------------------------------------------------------- -/// @ingroup IOStreamBase -/// @brief This class represents the stream to write out. -//------------------------------------------------------------------------------------------------- -class DLL_ODDLPARSER_EXPORT IOStreamBase { -public: - IOStreamBase( StreamFormatterBase *formatter = ddl_nullptr ); - virtual ~IOStreamBase(); - virtual bool open( const std::string &anme ); - virtual bool close(); - virtual size_t write( const std::string &statement ); - -private: - StreamFormatterBase *m_formatter; - FILE *m_file; -}; +// Forward declarations +class IOStreamBase; //------------------------------------------------------------------------------------------------- /// diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h index 7241c74d8..e9ac665b5 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h @@ -39,6 +39,16 @@ struct Identifier; struct Reference; struct Property; +template +inline +bool isEmbeddedCommentOpenTag( T *in, T *end ) { + if ( in == '/' && in+1 == '*' ) { + return true; + } + + return false; +} + /// @brief Utility function to search for the next token or the end of the buffer. /// @param in [in] The start position in the buffer. /// @param end [in] The end position in the buffer. diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLStream.h b/contrib/openddlparser/include/openddlparser/OpenDDLStream.h new file mode 100644 index 000000000..93370da03 --- /dev/null +++ b/contrib/openddlparser/include/openddlparser/OpenDDLStream.h @@ -0,0 +1,89 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2014-2015 Kim Kulling + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-----------------------------------------------------------------------------------------------*/ +#pragma once + +#include + +BEGIN_ODDLPARSER_NS + +//------------------------------------------------------------------------------------------------- +/// @ingroup IOStreamBase +/// @brief This class represents the stream to write out. +//------------------------------------------------------------------------------------------------- +class DLL_ODDLPARSER_EXPORT StreamFormatterBase { +public: + /// @brief The class constructor. + StreamFormatterBase(); + + /// @brief The class destructor, virtual. + virtual ~StreamFormatterBase(); + + /// @brief Will format the sring and return the new formatted result. + /// @param statement [in] The string to reformat. + /// @return The reformatted result. + virtual std::string format(const std::string &statement); +}; + +//------------------------------------------------------------------------------------------------- +/// @ingroup IOStreamBase +/// @brief This class represents the stream to write out. +//------------------------------------------------------------------------------------------------- +class DLL_ODDLPARSER_EXPORT IOStreamBase { +public: + /// @brief The class constructor with the formatter. + /// @param formatter [in] The formatter to use. + explicit IOStreamBase(StreamFormatterBase *formatter = ddl_nullptr); + + /// @brief The class destructor, virtual. + virtual ~IOStreamBase(); + + /// @brief Will open the stream. + /// @param name [in] The name for the stream. + /// @return true, if the stream was opened successfully, false if not. + virtual bool open(const std::string &name); + + /// @brief Will close the stream. + /// @return true, if the stream was closed successfully, false if not. + virtual bool close(); + + /// @brief Returns true, if the stream is open. + /// @return true, if the stream is open, false if not. + virtual bool isOpen() const; + + /// @brief Will read a string from the stream. + /// @param sizeToRead [in] The size to read in bytes. + /// @param statement [out] The read statements. + /// @return The bytes read from the stream. + virtual size_t read( size_t sizeToRead, std::string &statement ); + + /// @brief Will write a string into the stream. + /// @param statement [in] The string to write. + /// @return The bytes written into the stream. + virtual size_t write(const std::string &statement); + +private: + StreamFormatterBase *m_formatter; + FILE *m_file; +}; + +END_ODDLPARSER_NS diff --git a/contrib/openddlparser/include/openddlparser/Value.h b/contrib/openddlparser/include/openddlparser/Value.h index 242ec8781..77c6da06b 100644 --- a/contrib/openddlparser/include/openddlparser/Value.h +++ b/contrib/openddlparser/include/openddlparser/Value.h @@ -28,8 +28,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS +// Forward declarations struct ValueAllocator; +class IOStreamBase; + ///------------------------------------------------------------------------------------------------ /// @brief This class implements a value. /// @@ -213,7 +216,7 @@ public: double getDouble() const; /// @brief Assigns a std::string to the value. - /// @param value [in] The value. + /// @param str [in] The value. void setString( const std::string &str ); /// @brief Returns the std::string value. @@ -229,7 +232,8 @@ public: Reference *getRef() const; /// @brief Dumps the value. - void dump(); + /// @param stream [in] The stream to write in. + void dump( IOStreamBase &stream ); /// @brief Assigns the next value. /// @param next [n] The next value. @@ -241,7 +245,7 @@ public: /// @brief Gets the length of the array. /// @return The number of items in the array. - size_t size(); + size_t size() const; ValueType m_type; size_t m_size;