From adb4ab602e67c9e86910fc028ffd36c069e241be Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Sun, 21 Jun 2009 19:44:48 +0000 Subject: [PATCH] Adding Importer::ReadFileFromMemory to make Chromanoid happy. Updating unit test suite to verify the newly added stuff for correctness. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@444 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/Assimp.cpp | 45 +++++- code/DefaultIOStream.cpp | 21 +-- code/Importer.cpp | 35 +++- code/MemoryIOWrapper.h | 179 +++++++++++++++++++++ code/VertexTriangleAdjacency.cpp | 51 +++--- include/IOStream.h | 32 ++-- include/assimp.h | 37 ++++- include/assimp.hpp | 55 ++++++- samples/SimpleOpenGL/Sample_SimpleOpenGL.c | 2 +- test/unit/utImporter.cpp | 59 +++++++ test/unit/utImporter.h | 2 + workspaces/vc8/assimp.vcproj | 4 + 12 files changed, 456 insertions(+), 66 deletions(-) create mode 100644 code/MemoryIOWrapper.h diff --git a/code/Assimp.cpp b/code/Assimp.cpp index ff08efac2..0de80fcf3 100644 --- a/code/Assimp.cpp +++ b/code/Assimp.cpp @@ -264,7 +264,7 @@ const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, { ai_assert(NULL != pFile); // create an Importer for this file - Assimp::Importer* imp = new Assimp::Importer; + Assimp::Importer* imp = new Assimp::Importer(); #ifdef AI_C_THREADSAFE boost::mutex::scoped_lock lock(gMutex); @@ -303,6 +303,49 @@ const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, return scene; } +// ------------------------------------------------------------------------------------------------ +const aiScene* aiImportFileFromMemory( + const char* pBuffer, + unsigned int pLength, + unsigned int pFlags, + const char* pHint) +{ + ai_assert(NULL != pBuffer && 0 != pLength); + + // create an Importer for this file + Assimp::Importer* imp = new Assimp::Importer(); + +#ifdef AI_C_THREADSAFE + boost::mutex::scoped_lock lock(gMutex); +#endif + // copy the global property lists to the Importer instance + imp->pimpl->mIntProperties = gIntProperties; + imp->pimpl->mFloatProperties = gFloatProperties; + imp->pimpl->mStringProperties = gStringProperties; + +#ifdef AI_C_THREADSAFE + lock.unlock(); +#endif + + // and have it read the file from the memory buffer + const aiScene* scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint); + + // if succeeded, place it in the collection of active processes + if( scene) { +#ifdef AI_C_THREADSAFE + lock.lock(); +#endif + gActiveImports[scene] = imp; + } + else { + // if failed, extract error code and destroy the import + gLastErrorString = imp->GetErrorString(); + delete imp; + } + // return imported data. If the import failed the pointer is NULL anyways + return scene; +} + // ------------------------------------------------------------------------------------------------ // Releases all resources associated with the given import process. void aiReleaseImport( const aiScene* pScene) diff --git a/code/DefaultIOStream.cpp b/code/DefaultIOStream.cpp index ca0e02af9..d2977288a 100644 --- a/code/DefaultIOStream.cpp +++ b/code/DefaultIOStream.cpp @@ -53,11 +53,11 @@ using namespace Assimp; // ---------------------------------------------------------------------------------- DefaultIOStream::~DefaultIOStream() { - if (mFile) + if (mFile) { ::fclose(mFile); + } } - // ---------------------------------------------------------------------------------- size_t DefaultIOStream::Read(void* pvBuffer, size_t pSize, @@ -67,7 +67,6 @@ size_t DefaultIOStream::Read(void* pvBuffer, return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0); } - // ---------------------------------------------------------------------------------- size_t DefaultIOStream::Write(const void* pvBuffer, size_t pSize, @@ -77,13 +76,13 @@ size_t DefaultIOStream::Write(const void* pvBuffer, return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0); } - // ---------------------------------------------------------------------------------- aiReturn DefaultIOStream::Seek(size_t pOffset, aiOrigin pOrigin) { - if (!mFile) + if (!mFile) { return AI_FAILURE; + } // Just to check whether our enum maps one to one with the CRT constants BOOST_STATIC_ASSERT(aiOrigin_CUR == SEEK_CUR && @@ -93,20 +92,21 @@ aiReturn DefaultIOStream::Seek(size_t pOffset, return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE); } - // ---------------------------------------------------------------------------------- size_t DefaultIOStream::Tell() const { - if (!mFile)return 0; + if (!mFile) { + return 0; + } return ::ftell(mFile); } - // ---------------------------------------------------------------------------------- size_t DefaultIOStream::FileSize() const { - if (! mFile || mFilename.empty()) + if (! mFile || mFilename.empty()) { return 0; + } if (0xffffffff == cachedSize) { @@ -131,8 +131,9 @@ size_t DefaultIOStream::FileSize() const // ---------------------------------------------------------------------------------- void DefaultIOStream::Flush() { - if (mFile) + if (mFile) { ::fflush(mFile); + } } // ---------------------------------------------------------------------------------- diff --git a/code/Importer.cpp b/code/Importer.cpp index 69b1a94cb..5d6410b80 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -65,6 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "GenericProperty.h" #include "ProcessHelper.h" #include "ScenePreprocessor.h" +#include "MemoryIOWrapper.h" // ....................................................................................... // Importers @@ -698,6 +699,37 @@ bool Importer::ValidateFlags(unsigned int pFlags) return true; } +// ------------------------------------------------------------------------------------------------ +const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, + size_t pLength, + unsigned int pFlags, + const char* pHint /*= ""*/) +{ + if (!pHint) { + pHint = ""; + } + + if (!pBuffer || !pLength || strlen(pHint) > 100) { + pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; + return NULL; + } + + // prevent deletion of the previous IOHandler + IOSystem* io = pimpl->mIOHandler; + pimpl->mIOHandler = NULL; + + SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength)); + + // read the file and recover the previous IOSystem + char fbuff[128]; + sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint); + + ReadFile(fbuff,pFlags); + SetIOHandler(io); + + return pimpl->mScene; +} + // ------------------------------------------------------------------------------------------------ // Reads the given file and returns its contents if successful. const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) @@ -755,8 +787,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } } // Put a proper error message if no suitable importer was found - if( !imp) - { + if( !imp) { pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; DefaultLogger::get()->error(pimpl->mErrorString); return NULL; diff --git a/code/MemoryIOWrapper.h b/code/MemoryIOWrapper.h new file mode 100644 index 000000000..122fbfa26 --- /dev/null +++ b/code/MemoryIOWrapper.h @@ -0,0 +1,179 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development 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 Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file MemoryIOWrapper.h + * Handy IOStream/IOSystem implemetation to read directly from a memory buffer */ +#ifndef AI_MEMORYIOSTREAM_H_INC +#define AI_MEMORYIOSTREAM_H_INC +namespace Assimp { +#define AI_MEMORYIO_MAGIC_FILENAME "$$$___magic___$$$" +#define AI_MEMORYIO_MAGIC_FILENAME_LENGTH 17 + +// ---------------------------------------------------------------------------------- +/** Implementation of IOStream to read directly from a memory buffer */ +class MemoryIOStream : public IOStream { + friend class MemoryIOSystem; +protected: + MemoryIOStream (const uint8_t* buff, size_t len) + : buffer (buff), length(len), pos((size_t)0) { + } + +public: + ~MemoryIOStream () { + } + + // ------------------------------------------------------------------- + // Read from stream + size_t Read(void* pvBuffer, size_t pSize, size_t pCount) { + const size_t cnt = std::min(pCount,(length-pos)/pSize),ofs = pSize*cnt; + + memcpy(pvBuffer,buffer+pos,ofs); + pos += ofs; + + return cnt; + } + + // ------------------------------------------------------------------- + // Write to stream + size_t Write(const void* pvBuffer, size_t pSize,size_t pCount) { + ai_assert(false); // won't be needed + return 0; + } + + // ------------------------------------------------------------------- + // Seek specific position + aiReturn Seek(size_t pOffset, aiOrigin pOrigin) { + if (aiOrigin_SET == pOrigin) { + if (pOffset >= length) { + return AI_FAILURE; + } + pos = pOffset; + } + else if (aiOrigin_END == pOrigin) { + if (pOffset >= length) { + return AI_FAILURE; + } + pos = length-pOffset; + } + else { + if (pOffset+pos >= length) { + return AI_FAILURE; + } + pos += pOffset; + } + return AI_SUCCESS; + } + + // ------------------------------------------------------------------- + // Get current seek position + size_t Tell() const { + return pos; + } + + // ------------------------------------------------------------------- + // Get size of file + size_t FileSize() const { + return length; + } + + // ------------------------------------------------------------------- + // Flush file contents + void Flush() { + ai_assert(false); // won't be needed + } + +private: + const uint8_t* buffer; + size_t length,pos; +}; + +// --------------------------------------------------------------------------- +/** Dummy IO system to read from a memory buffer */ +class MemoryIOSystem : public IOSystem +{ +public: + /** Constructor. */ + MemoryIOSystem (const uint8_t* buff, size_t len) + : buffer (buff), length(len) { + } + + /** Destructor. */ + ~MemoryIOSystem() { + } + + // ------------------------------------------------------------------- + /** Tests for the existence of a file at the given path. */ + bool Exists( const char* pFile) const { + return !strncmp(pFile,AI_MEMORYIO_MAGIC_FILENAME,AI_MEMORYIO_MAGIC_FILENAME_LENGTH); + } + + // ------------------------------------------------------------------- + /** Returns the directory separator. */ + char getOsSeparator() const { + return '/'; // why not? it doesn't care + } + + // ------------------------------------------------------------------- + /** Open a new file with a given path. */ + IOStream* Open( const char* pFile, const char* pMode = "rb") { + if (strncmp(pFile,AI_MEMORYIO_MAGIC_FILENAME,AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) { + return NULL; + } + return new MemoryIOStream(buffer,length); + } + + // ------------------------------------------------------------------- + /** Closes the given file and releases all resources associated with it. */ + void Close( IOStream* pFile) { + } + + // ------------------------------------------------------------------- + /** Compare two paths */ + bool ComparePaths (const char* one, const char* second) const { + return false; + } + +private: + const uint8_t* buffer; + size_t length; +}; +} // end namespace Assimp + +#endif diff --git a/code/VertexTriangleAdjacency.cpp b/code/VertexTriangleAdjacency.cpp index 20354038a..402889269 100644 --- a/code/VertexTriangleAdjacency.cpp +++ b/code/VertexTriangleAdjacency.cpp @@ -57,10 +57,9 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, { // compute the number of referenced vertices if it wasn't specified by the caller const aiFace* const pcFaceEnd = pcFaces + iNumFaces; - if (!iNumVertices) - { - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) - { + if (!iNumVertices) { + + for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) { ai_assert(3 == pcFace->mNumIndices); iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]); iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]); @@ -70,17 +69,15 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, unsigned int* pi; // allocate storage - if (bComputeNumTriangles) - { - pi = this->mLiveTriangles = new unsigned int[iNumVertices+1]; - ::memset(this->mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1)); - this->mOffsetTable = new unsigned int[iNumVertices+2]+1; + if (bComputeNumTriangles) { + pi = mLiveTriangles = new unsigned int[iNumVertices+1]; + memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1)); + mOffsetTable = new unsigned int[iNumVertices+2]+1; } - else - { - pi = this->mOffsetTable = new unsigned int[iNumVertices+2]+1; - ::memset(this->mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1)); - this->mLiveTriangles = NULL; // important, otherwise the d'tor would crash + else { + pi = mOffsetTable = new unsigned int[iNumVertices+2]+1; + memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1)); + mLiveTriangles = NULL; // important, otherwise the d'tor would crash } // get a pointer to the end of the buffer @@ -98,8 +95,8 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, // second pass: compute the final offset table unsigned int iSum = 0; unsigned int* piCurOut = this->mOffsetTable; - for (unsigned int* piCur = pi; piCur != piEnd;++piCur,++piCurOut) - { + for (unsigned int* piCur = pi; piCur != piEnd;++piCur,++piCurOut) { + unsigned int iLastSum = iSum; iSum += *piCur; *piCurOut = iLastSum; @@ -109,27 +106,27 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, // third pass: compute the final table this->mAdjacencyTable = new unsigned int[iSum]; iSum = 0; - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace,++iSum) - { + for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace,++iSum) { + unsigned int idx = pcFace->mIndices[0]; - this->mAdjacencyTable[pi[idx]++] = iSum; + mAdjacencyTable[pi[idx]++] = iSum; idx = pcFace->mIndices[1]; - this->mAdjacencyTable[pi[idx]++] = iSum; + mAdjacencyTable[pi[idx]++] = iSum; idx = pcFace->mIndices[2]; - this->mAdjacencyTable[pi[idx]++] = iSum; + mAdjacencyTable[pi[idx]++] = iSum; } // fourth pass: undo the offset computations made during the third pass // We could do this in a separate buffer, but this would be TIMES slower. - --this->mOffsetTable; - *this->mOffsetTable = 0u; + --mOffsetTable; + *mOffsetTable = 0u; } // ------------------------------------------------------------------------------------------------ VertexTriangleAdjacency::~VertexTriangleAdjacency() { - // delete all allocated storage - delete[] this->mOffsetTable; - delete[] this->mAdjacencyTable; - delete[] this->mLiveTriangles; + // delete allocated storage + delete[] mOffsetTable; + delete[] mAdjacencyTable; + delete[] mLiveTriangles; } diff --git a/include/IOStream.h b/include/IOStream.h index 60651cf94..06977b167 100644 --- a/include/IOStream.h +++ b/include/IOStream.h @@ -77,10 +77,9 @@ public: // ------------------------------------------------------------------- /** @brief Read from the file - * - * See fread() for more details - * This fails for write-only files - */ + * + * See fread() for more details + * This fails for write-only files */ virtual size_t Read(void* pvBuffer, size_t pSize, size_t pCount) = 0; @@ -89,39 +88,34 @@ public: /** @brief Write to the file * * See fwrite() for more details - * This fails for read-only files - */ + * This fails for read-only files */ virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) = 0; // ------------------------------------------------------------------- /** @brief Set the read/write cursor of the file - * - * See fseek() for more details - */ + * + * Note that the offset is _negative_ for aiOrigin_END. + * See fseek() for more details */ virtual aiReturn Seek(size_t pOffset, aiOrigin pOrigin) = 0; // ------------------------------------------------------------------- /** @brief Get the current position of the read/write cursor - * - * See ftell() for more details - */ + * + * See ftell() for more details */ virtual size_t Tell() const = 0; // ------------------------------------------------------------------- /** @brief Returns filesize - * - * Returns the filesize. - */ + * Returns the filesize. */ virtual size_t FileSize() const = 0; // ------------------------------------------------------------------- - /** @brief Flush the contents of the file buffer (for writers) - * - * See fflush() for more details. - */ + /** @brief Flush the contents of the file buffer (for writers) + * See fflush() for more details. + */ virtual void Flush() = 0; }; //! class IOStream diff --git a/include/assimp.h b/include/assimp.h index 1311b4e38..e9b3f6df1 100644 --- a/include/assimp.h +++ b/include/assimp.h @@ -115,13 +115,48 @@ ASSIMP_API const C_STRUCT aiScene* aiImportFile( * @param pFS aiFileIO structure. Will be used to open the model file itself * and any other files the loader needs to open. * @return Pointer to the imported data or NULL if the import failed. - * @note Include for the definition of #aiFioeIO. + * @note Include for the definition of #aiFileIO. */ ASSIMP_API const C_STRUCT aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, C_STRUCT aiFileIO* pFS); +// -------------------------------------------------------------------------------- +/** Reads the given file from a given memory buffer, + * + * If the call succeeds, the contents of the file are returned as a pointer to an + * aiScene object. The returned data is intended to be read-only, the importer keeps + * ownership of the data and will destroy it upon destruction. If the import fails, + * NULL is returned. + * A human-readable error description can be retrieved by calling aiGetErrorString(). + * @param pBuffer Pointer to the file data + * @param pLength Length of pBuffer, in bytes + * @param pFlags Optional post processing steps to be executed after + * a successful import. Provide a bitwise combination of the + * #aiPostProcessSteps flags. If you wish to inspect the imported + * scene first in order to fine-tune your post-processing setup, + * consider to use #aiApplyPostProcessing(). + * @param pHint An additional hint to the library. If this is a non empty string, + * the library looks for a loader to support the file extension specified by pHint + * and passes the file to the first matching loader. If this loader is unable to + * completely the request, the library continues and tries to determine the file + * format on its own, a task that may or may not be successful. + * Check the return value, and you'll know ... + * @return A pointer to the imported data, NULL if the import failed. + * + * @note This is a straightforward way to decode models from memory buffers, but it + * doesn't handle model formats spreading their data across multiple files or even + * directories. Examples include OBJ or MD3, which outsource parts of their material + * stuff into external scripts. f you need the full functionality, provide a custom + * IOSystem to make Assimp find these files. + */ +ASSIMP_API const C_STRUCT aiScene* aiImportFileFromMemory( + const char* pBuffer, + unsigned int pLength, + unsigned int pFlags, + const char* pHint); + // -------------------------------------------------------------------------------- /** Apply post-processing to an already-imported scene. * diff --git a/include/assimp.hpp b/include/assimp.hpp index 86b02ec30..da60850c6 100644 --- a/include/assimp.hpp +++ b/include/assimp.hpp @@ -82,6 +82,8 @@ namespace Assimp { struct aiScene; struct aiFileIO; extern "C" ASSIMP_API const aiScene* aiImportFileEx( const char*, unsigned int, aiFileIO*); +extern "C" ASSIMP_API const aiScene* aiImportFileFromMemory( const char*, + unsigned int,unsigned int,const char*); namespace Assimp { @@ -109,12 +111,14 @@ namespace Assimp { * @note One Importer instance is not thread-safe. If you use multiple * threads for loading, each thread should maintain its own Importer instance. */ -class ASSIMP_API Importer -{ - // used internally +class ASSIMP_API Importer { + + // for internal use friend class BaseProcess; friend class BatchLoader; friend const aiScene* ::aiImportFileEx( const char*, unsigned int, aiFileIO*); + friend const aiScene* ::aiImportFileFromMemory( const char*, + unsigned int,unsigned int,const char*); public: @@ -321,11 +325,52 @@ public: * instance. Use GetOrphanedScene() to take ownership of it. * * @note Assimp is able to determine the file format of a file - * automatically. However, you should make sure that the input file - * does not even have a file extension at all to enable this feature. + * automatically. However, to enable automatic detection of the file + * format, the input path *must* not have an extension at all. */ const aiScene* ReadFile( const char* pFile, unsigned int pFlags); + // ------------------------------------------------------------------- + /** Reads the given file from a memory buffer and returns its + * contents if successful. + * + * If the call succeeds, the contents of the file are returned as a + * pointer to an aiScene object. The returned data is intended to be + * read-only, the importer object keeps ownership of the data and will + * destroy it upon destruction. If the import fails, NULL is returned. + * A human-readable error description can be retrieved by calling + * GetErrorString(). The previous scene will be deleted during this call. + * Calling this method doesn't affect the active IOSystem. + * @param pBuffer Pointer to the file data + * @param pLength Length of pBuffer, in bytes + * @param pFlags Optional post processing steps to be executed after + * a successful import. Provide a bitwise combination of the + * #aiPostProcessSteps flags. If you wish to inspect the imported + * scene first in order to fine-tune your post-processing setup, + * consider to use #ApplyPostProcessing(). + * @param pHint An additional hint to the library. If this is a non + * empty string, the library looks for a loader to support + * the file extension specified by pHint and passes the file to + * the first matching loader. If this loader is unable to completely + * the request, the library continues and tries to determine the + * file format on its own, a task that may or may not be successful. + * Check the return value, and you'll know ... + * @return A pointer to the imported data, NULL if the import failed. + * The pointer to the scene remains in possession of the Importer + * instance. Use GetOrphanedScene() to take ownership of it. + * + * @note This is a straightforward way to decode models from memory + * buffers, but it doesn't handle model formats spreading their + * data across multiple files or even directories. Examples include + * OBJ or MD3, which outsource parts of their material stuff into + * external scripts. f you need the full functionality, provide + * a custom IOSystem to make Assimp find these files. + */ + const aiScene* ReadFileFromMemory( const void* pBuffer, + size_t pLength, + unsigned int pFlags, + const char* pHint = ""); + // ------------------------------------------------------------------- /** Apply post-processing to an already-imported scene. * diff --git a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c index 90f1cf778..1f5caede4 100644 --- a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c +++ b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c @@ -5,7 +5,7 @@ // settings and displays it. // // If you intend to _use_ this code sample in your app, do yourself a favour -// and replace glVertex3D with VBOs ... +// and replace immediate mode calls with VBOs ... // // The vc8 solution links against assimp-release-dll_win32 - be sure to // have this configuration built. diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index e0a21da59..4c57e58da 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -3,6 +3,55 @@ #include "utImporter.h" +#define InputData_BLOCK_SIZE 1310 + +// test data for Importer::ReadFileFromMemory() - ./test/3DS/CameraRollAnim.3ds +static unsigned char InputData_abRawBlock[1310] = { +77,77,30,5,0,0,2,0,10,0,0,0,3,0,0,0,61,61,91,3,0,0,62,61,10,0,0,0,3,0,0,0, +0,1,10,0,0,0,0,0,128,63,0,64,254,2,0,0,66,111,120,48,49,0,0,65,242,2,0,0,16,65,64,1, +0,0,26,0,102,74,198,193,102,74,198,193,0,0,0,0,205,121,55,66,102,74,198,193,0,0,0,0,102,74,198,193, +138,157,184,65,0,0,0,0,205,121,55,66,138,157,184,65,0,0,0,0,102,74,198,193,102,74,198,193,90,252,26,66, +205,121,55,66,102,74,198,193,90,252,26,66,102,74,198,193,138,157,184,65,90,252,26,66,205,121,55,66,138,157,184,65, +90,252,26,66,102,74,198,193,102,74,198,193,0,0,0,0,205,121,55,66,102,74,198,193,0,0,0,0,205,121,55,66, +102,74,198,193,90,252,26,66,205,121,55,66,102,74,198,193,90,252,26,66,102,74,198,193,102,74,198,193,90,252,26,66, +102,74,198,193,102,74,198,193,0,0,0,0,205,121,55,66,138,157,184,65,0,0,0,0,205,121,55,66,102,74,198,193, +90,252,26,66,205,121,55,66,138,157,184,65,0,0,0,0,102,74,198,193,138,157,184,65,0,0,0,0,102,74,198,193, +138,157,184,65,90,252,26,66,102,74,198,193,138,157,184,65,90,252,26,66,205,121,55,66,138,157,184,65,90,252,26,66, +205,121,55,66,138,157,184,65,0,0,0,0,102,74,198,193,138,157,184,65,0,0,0,0,102,74,198,193,102,74,198,193, +90,252,26,66,102,74,198,193,102,74,198,193,90,252,26,66,102,74,198,193,138,157,184,65,0,0,0,0,64,65,216,0, +0,0,26,0,0,0,128,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,128,63,0,0,0,0, +0,0,128,63,0,0,0,0,0,0,0,0,0,0,128,63,0,0,0,0,0,0,0,0,0,0,128,63,0,0,128,63, +0,0,128,63,0,0,0,0,0,0,0,0,0,0,128,63,0,0,0,0,0,0,128,63,0,0,128,63,0,0,128,63, +0,0,128,63,0,0,0,0,0,0,128,63,0,0,0,0,0,0,0,0,0,0,128,63,0,0,0,0,0,0,0,0, +0,0,128,63,0,0,0,0,0,0,0,0,0,0,128,63,0,0,0,0,0,0,128,63,0,0,128,63,0,0,128,63, +0,0,128,63,0,0,0,0,0,0,128,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63, +0,0,128,63,0,0,128,63,0,0,128,63,0,0,0,0,0,0,0,0,96,65,54,0,0,0,0,0,128,63,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,53,169, +40,65,176,205,90,191,0,0,0,0,32,65,158,0,0,0,12,0,0,0,2,0,3,0,6,0,3,0,1,0,0,0, +6,0,4,0,5,0,7,0,6,0,7,0,6,0,4,0,6,0,8,0,9,0,10,0,6,0,11,0,12,0,13,0, +6,0,1,0,14,0,7,0,6,0,7,0,15,0,1,0,6,0,16,0,17,0,18,0,6,0,19,0,20,0,21,0, +6,0,22,0,0,0,23,0,6,0,24,0,6,0,25,0,6,0,80,65,54,0,0,0,2,0,0,0,2,0,0,0, +4,0,0,0,4,0,0,0,8,0,0,0,8,0,0,0,16,0,0,0,16,0,0,0,32,0,0,0,32,0,0,0, +64,0,0,0,64,0,0,0,0,64,67,0,0,0,67,97,109,101,114,97,48,49,0,0,71,52,0,0,0,189,19,25, +195,136,104,81,64,147,56,182,65,96,233,20,194,67,196,97,190,147,56,182,65,0,0,0,0,85,85,85,66,32,71,14, +0,0,0,0,0,0,0,0,0,122,68,0,176,179,1,0,0,10,176,21,0,0,0,5,0,77,65,88,83,67,69,78, +69,0,44,1,0,0,8,176,14,0,0,0,0,0,0,0,44,1,0,0,9,176,10,0,0,0,128,2,0,0,2,176, +168,0,0,0,48,176,8,0,0,0,0,0,16,176,18,0,0,0,66,111,120,48,49,0,0,64,0,0,255,255,19,176, +18,0,0,0,0,0,0,128,0,0,0,128,0,0,0,128,32,176,38,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,53,169,40,65,176,205,90,191,0,0,0,0,33,176,42,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,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, +34,176,38,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0, +128,63,0,0,128,63,3,176,143,0,0,0,48,176,8,0,0,0,1,0,16,176,21,0,0,0,67,97,109,101,114,97, +48,49,0,0,64,0,0,255,255,32,176,38,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,189,19,25,195,136,104,81,64,147,56,182,65,35,176,30,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,52,66,36,176,40,0,0,0,0,0,0,0,0,0,120,0,0,0,2,0,0, +0,0,0,0,0,0,0,120,13,90,189,120,0,0,0,0,0,99,156,154,194,4,176,73,0,0,0,48,176,8,0,0, +0,2,0,16,176,21,0,0,0,67,97,109,101,114,97,48,49,0,0,64,0,0,255,255,32,176,38,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,96,233,20,194,67,196,97,190,147,56,182,65, +}; + + + CPPUNIT_TEST_SUITE_REGISTRATION (ImporterTest); #define AIUT_DEF_ERROR_TEXT "sorry, this is a test" @@ -44,6 +93,16 @@ void ImporterTest :: tearDown (void) delete pImp; } +void ImporterTest :: testMemoryRead (void) +{ + const aiScene* sc = pImp->ReadFileFromMemory(InputData_abRawBlock,InputData_BLOCK_SIZE, + aiProcessPreset_TargetRealtime_Quality,"3ds"); + + CPPUNIT_ASSERT(sc != NULL); + CPPUNIT_ASSERT(sc->mRootNode->mName == aiString("<3DSRoot>")); + CPPUNIT_ASSERT(sc->mNumMeshes == 1 && sc->mMeshes[0]->mNumVertices ==24 && sc->mMeshes[0]->mNumFaces ==12); +} + void ImporterTest :: testIntProperty (void) { bool b; diff --git a/test/unit/utImporter.h b/test/unit/utImporter.h index 57ec0efeb..5e2be6fd3 100644 --- a/test/unit/utImporter.h +++ b/test/unit/utImporter.h @@ -18,6 +18,7 @@ class ImporterTest : public CPPUNIT_NS :: TestFixture CPPUNIT_TEST (testStringProperty); CPPUNIT_TEST (testPluginInterface); CPPUNIT_TEST (testExtensionCheck); + CPPUNIT_TEST (testMemoryRead); CPPUNIT_TEST_SUITE_END (); public: @@ -32,6 +33,7 @@ class ImporterTest : public CPPUNIT_NS :: TestFixture void testPluginInterface (void); void testExtensionCheck (void); + void testMemoryRead (void); private: diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index 416d10893..69db8f4f3 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -2307,6 +2307,10 @@ RelativePath="..\..\code\DefaultIOSystem.h" > + +