Assimp
v2.0 (November 2010)
|
Or - how to write your own loaders. It's easy. You just need to implement the Assimp::BaseImporter class, which defines a few abstract methods, register your loader, test it carefully and provide test models for it.
OK, that sounds too easy :-). The whole procedure for a new loader merely looks like this:
FormatNameImporter.h
) and a unit (FormatNameImporter.cpp
) in the <root>/code/
directory Open Importer.cpp and include your header just below the (include_new_importers_here) line, guarded by a #define
#if (!defined ASSIMP_BUILD_NO_FormatName_IMPORTER)
...
#endif
Wrap the same guard around your .cpp!
DefaultLogger::create("AssimpLog.txt",Logger::VERBOSE)
<root>/test/models/<FormatName>/
and credit their authors. Test files for a file format shouldn't be too large (~500 KiB in total), and not too repetive. Try to cover all format features with test data. You can use properties to chance the behavior of you importer. In order to do so, you have to overide BaseImporter::SetupProperties, and specify you custom properties in aiConfig.h. Just have a look to the other AI_CONFIG_IMPORT_* defines and you will understand, how it works.
The properties can be set with Importer::SetProperty***() and can be accessed in your SetupProperties function with Importer::GetProperty***(). You can store the properties as a member variable of your importer, they are thread safe.
AI_BUILD_BIG_ENDIAN
constant. See the next section for a list of utilities to simplify this task. Mixed stuff for internal use by loaders, mostly documented (most of them are already included by AssimpPCH.h):
The required definitions zo set/remove/query keys in aiMaterial structures are declared in MaterialSystem.h, in a aiMaterial derivate called aiMaterial. The header is included by AssimpPCH.h, so you don't need to bother.
aiMaterial* mat = new aiMaterial(); const float spec = 16.f; mat->AddProperty(&spec, 1, AI_MATKEY_SHININESS); //set the name of the material: NewMaterial->AddProperty(&aiString(MaterialName.c_str()), AI_MATKEY_NAME);//MaterialName is a std::string //set the first diffuse texture NewMaterial->AddProperty(&aiString(Texturename.c_str()), AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));//again, Texturename is a std::string
The boost whitelist:
(if you happen to need something else, i.e. boost::thread, make this an optional feature. ASSIMP_BUILD_BOOST_WORKAROUND
is defined for -noboost builds)
// ------------------------------------------------------------------------------- // Returns whether the class can handle the format of the given file. bool xxxxImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { const std::string extension = GetExtension(pFile); if(extension == "xxxx") { return true; } if (!extension.length() || checkSig) { // no extension given, or we're called a second time because no // suitable loader was found yet. This means, we're trying to open // the file and look for and hints to identify the file format. // #Assimp::BaseImporter provides some utilities: // // #Assimp::BaseImporter::SearchFileHeaderForToken - for text files. // It reads the first lines of the file and does a substring check // against a given list of 'magic' strings. // // #Assimp::BaseImporter::CheckMagicToken - for binary files. It goes // to a particular offset in the file and and compares the next words // against a given list of 'magic' tokens. // These checks MUST be done (even if !checkSig) if the file extension // is not exclusive to your format. For example, .xml is very common // and (co)used by many formats. } return false; } // ------------------------------------------------------------------------------- // Get list of file extensions handled by this loader void xxxxImporter::GetExtensionList(std::set<std::string>& extensions) { extensions.insert("xxx"); } // ------------------------------------------------------------------------------- void xxxxImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); // Check whether we can read from the file if( file.get() == NULL) { throw DeadlyImportError( "Failed to open xxxx file " + pFile + "."); } // Your task: fill pScene // Throw a ImportErrorException with a meaningful (!) error message if // something goes wrong. }