Преглед изворни кода

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

aramis_acg пре 16 година
родитељ
комит
adb4ab602e

+ 44 - 1
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)

+ 11 - 10
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);
+	}
 }
 
 // ----------------------------------------------------------------------------------

+ 33 - 2
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;

+ 179 - 0
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

+ 24 - 27
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;
 }

+ 13 - 19
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
 

+ 36 - 1
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 <aiFileIO.h> for the definition of #aiFioeIO.
+ * @note Include <aiFileIO.h> 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.
  *

+ 50 - 5
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.
 	 *

+ 1 - 1
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.

+ 59 - 0
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;

+ 2 - 0
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:
 

+ 4 - 0
workspaces/vc8/assimp.vcproj

@@ -2307,6 +2307,10 @@
 					RelativePath="..\..\code\DefaultIOSystem.h"
 					>
 				</File>
+				<File
+					RelativePath="..\..\code\MemoryIOWrapper.h"
+					>
+				</File>
 				<File
 					RelativePath="..\..\code\StreamReader.h"
 					>