Assimp: Usage

assimp - Open Asset Import Library

Assimp  v3.1.1 (June 2014)
Usage

Access by C++ class interface

The assimp library can be accessed by both a class or flat function interface. The C++ class interface is the preferred way of interaction: you create an instance of class Assimp::Importer, maybe adjust some settings of it and then call Assimp::Importer::ReadFile(). The class will read the files and process its data, handing back the imported data as a pointer to an aiScene to you. You can now extract the data you need from the file. The importer manages all the resources for itsself. If the importer is destroyed, all the data that was created/read by it will be destroyed, too. So the easiest way to use the Importer is to create an instance locally, use its results and then simply let it go out of scope.

C++ example:

#include <assimp/Importer.hpp> // C++ importer interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
bool DoTheImportThing( const std::string& pFile)
{
// Create an instance of the Importer class
Assimp::Importer importer;
// And have it read the given file with some example postprocessing
// Usually - if speed is not the most important aspect for you - you'll
// probably to request more postprocessing than we do in this example.
const aiScene* scene = importer.ReadFile( pFile,
// If the import failed, report it
if( !scene)
{
DoTheErrorLogging( importer.GetErrorString());
return false;
}
// Now we can access the file's contents.
DoTheSceneProcessing( scene);
// We're done. Everything will be cleaned up by the importer destructor
return true;
}

What exactly is read from the files and how you interpret it is described at the Data Structures page. The post processing steps that the assimp library can apply to the imported data are listed at aiPostProcessSteps. See the pp Post proccessing page for more details.

Note that the aiScene data structure returned is declared 'const'. Yes, you can get rid of these 5 letters with a simple cast. Yes, you may do that. No, it's not recommended (and it's suicide in DLL builds if you try to use new or delete on any of the arrays in the scene).

Access by plain-c function interface

The plain function interface is just as simple, but requires you to manually call the clean-up after you're done with the imported data. To start the import process, call aiImportFile() with the filename in question and the desired postprocessing flags like above. If the call is successful, an aiScene pointer with the imported data is handed back to you. When you're done with the extraction of the data you're interested in, call aiReleaseImport() on the imported scene to clean up all resources associated with the import.

C example:

#include <assimp/cimport.h> // Plain-C interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
bool DoTheImportThing( const char* pFile)
{
// Start the import on the given file with some example postprocessing
// Usually - if speed is not the most important aspect for you - you'll t
// probably to request more postprocessing than we do in this example.
const aiScene* scene = aiImportFile( pFile,
// If the import failed, report it
if( !scene)
{
DoTheErrorLogging( aiGetErrorString());
return false;
}
// Now we can access the file's contents
DoTheSceneProcessing( scene);
// We're done. Release all resources associated with this import
aiReleaseImport( scene);
return true;
}

Using custom IO logic with the C++ class interface

The assimp library needs to access files internally. This of course applies to the file you want to read, but also to additional files in the same folder for certain file formats. By default, standard C/C++ IO logic is used to access these files. If your application works in a special environment where custom logic is needed to access the specified files, you have to supply custom implementations of IOStream and IOSystem. A shortened example might look like this:

// My own implementation of IOStream
class MyIOStream : public Assimp::IOStream
{
friend class MyIOSystem;
protected:
// Constructor protected for private usage by MyIOSystem
MyIOStream(void);
public:
~MyIOStream(void);
size_t Read( void* pvBuffer, size_t pSize, size_t pCount) { ... }
size_t Write( const void* pvBuffer, size_t pSize, size_t pCount) { ... }
aiReturn Seek( size_t pOffset, aiOrigin pOrigin) { ... }
size_t Tell() const { ... }
size_t FileSize() const { ... }
void Flush () { ... }
};
// Fisher Price - My First Filesystem
class MyIOSystem : public Assimp::IOSystem
{
MyIOSystem() { ... }
~MyIOSystem() { ... }
// Check whether a specific file exists
bool Exists( const std::string& pFile) const {
..
}
// Get the path delimiter character we'd like to see
char GetOsSeparator() const {
return '/';
}
// ... and finally a method to open a custom stream
IOStream* Open( const std::string& pFile, const std::string& pMode) {
return new MyIOStream( ... );
}
void Close( IOStream* pFile) { delete pFile; }
};

Now that your IO system is implemented, supply an instance of it to the Importer object by calling Assimp::Importer::SetIOHandler().

void DoTheImportThing( const std::string& pFile)
{
Assimp::Importer importer;
// put my custom IO handling in place
importer.SetIOHandler( new MyIOSystem());
// the import process will now use this implementation to access any file
importer.ReadFile( pFile, SomeFlag | SomeOtherFlag);
}

Using custom IO logic with the plain-c function interface

The C interface also provides a way to override the file system. Control is not as fine-grained as for C++ although surely enough for almost any purpose. The process is simple:

  • Include cfileio.h
  • Fill an aiFileIO structure with custom file system callbacks (they're self-explanatory as they work similar to the CRT's fXXX functions)
  • .. and pass it as parameter to aiImportFileEx

Logging

The assimp library provides an easy mechanism to log messages. For instance if you want to check the state of your import and you just want to see, after which preprocessing step the import-process was aborted you can take a look into the log. Per default the assimp-library provides a default log implementation, where you can log your user specific message by calling it as a singleton with the requested logging-type. To see how this works take a look to this:

using namespace Assimp;
// Create a logger instance
// Now I am ready for logging my stuff
DefaultLogger::get()->info("this is my info-call");
// Kill it after the work is done

At first you have to create the default-logger-instance (create). Now you are ready to rock and can log a little bit around. After that you should kill it to release the singleton instance.

If you want to integrate the assimp-log into your own GUI it my be helpful to have a mechanism writing the logs into your own log windows. The logger interface provides this by implementing an interface called LogStream. You can attach and detach this log stream to the default-logger instance or any implementation derived from Logger. Just derivate your own logger from the abstract base class LogStream and overwrite the write-method:

// Example stream
class myStream :
public LogStream
{
public:
// Constructor
myStream()
{
// empty
}
// Destructor
~myStream()
{
// empty
}
// Write womethink using your own functionality
void write(const char* message)
{
::printf("%s\n", message);
}
};
// Select the kinds of messages you want to receive on this log stream
const unsigned int severity = Logger::DEBUGGING|Logger::INFO|Logger::ERR|Logger::WARN;
// Attaching it to the default logger
Assimp::DefaultLogger::get()->attachStream( new myStream(), severity );

The severity level controls the kind of message which will be written into the attached stream. If you just want to log errors and warnings set the warn and error severity flag for those severities. It is also possible to remove a self defined logstream from an error severity by detaching it with the severity flag set:

unsigned int severity = 0;
severity |= Logger::DEBUGGING;
// Detach debug messages from you self defined stream
Assimp::DefaultLogger::get()->attachStream( new myStream(), severity );

If you want to implement your own logger just derive from the abstract base class #Logger and overwrite the methods debug, info, warn and error.

If you want to see the debug-messages in a debug-configured build, the Logger-interface provides a logging-severity. You can set it calling the following method:

Assimp::DefaultLogger::get()->setLogSeverity( LogSeverity log_severity );

The normal logging severity supports just the basic stuff like, info, warnings and errors. In the verbose level very fine-grained debug messages will be logged, too. Note that this kind kind of logging might decrease import performance.

Generated on Sun Feb 21 2016 19:42:29 for Assimp by   doxygen 1.8.11