Skip to content
Snippets Groups Projects
dox.h 74.7 KiB
Newer Older
</table>

@section cpp C++-API

Retrieving a property from a material is done using various utility functions. For C++ it's simply calling aiMaterial::Get()

@code

aiMaterial* mat = .....

// The generic way
if(AI_SUCCESS != mat->Get(<material-key>,<where-to-store>)) {
   // handle epic failure here
}

@endcode

Simple, isn't it? To get the name of a material you would use

@code

aiString name;
mat->Get(AI_MATKEY_NAME,name);

@endcode

Or for the diffuse color ('color' won't be modified if the property is not set)

@code

aiColor3D color (0.f,0.f,0.f);
mat->Get(AI_MATKEY_COLOR_DIFFUSE,color);

@endcode

<b>Note:</b> Get() is actually a template with explicit specializations for aiColor3D, aiColor4D, aiString, float, int and some others.
Make sure that the type of the second parameter matches the expected data type of the material property (no compile-time check yet!). 
Don't follow this advice if you wish to encounter very strange results.

@section C C-API

For good old C it's slightly different. Take a look at the aiGetMaterialGet<data-type> functions.

@code

aiMaterial* mat = .....

if(AI_SUCCESS != aiGetMaterialFloat(mat,<material-key>,<where-to-store>)) {
   // handle epic failure here
}

@endcode

To get the name of a material you would use

@code

aiString name;
aiGetMaterialString(mat,AI_MATKEY_NAME,&name);

@endcode

Or for the diffuse color ('color' won't be modified if the property is not set)

@code

aiColor3D color (0.f,0.f,0.f);
aiGetMaterialColor(mat,AI_MATKEY_COLOR_DIFFUSE,&color);

@endcode

@section uvwsrc How to map UV channels to textures (MATKEY_UVWSRC)

The MATKEY_UVWSRC property is only present if the source format doesn't specify an explicit mapping from
aramis_acg's avatar
aramis_acg committed
textures to UV channels. Many formats don't do this and assimp is not aware of a perfect rule either.

Your handling of UV channels needs to be flexible therefore. Our recommendation is to use logic like this
to handle most cases properly:

@verbatim
have only one uv channel?
   assign channel 0 to all textures and break

for all textures
   have uvwsrc for this texture?
      assign channel specified in uvwsrc
   else
      assign channels in ascending order for all texture stacks, 
	    i.e. diffuse1 gets channel 1, opacity0 gets channel 0.

@endverbatim

@section pseudo Pseudo Code Listing

For completeness, the following is a very rough pseudo-code sample showing how to evaluate Assimp materials in your 
shading pipeline. You'll probably want to limit your handling of all those material keys to a reasonable subset suitable for your purposes 
(for example most 3d engines won't support highly complex multi-layer materials, but many 3d modellers do).

Also note that this sample is targeted at a (shader-based) rendering pipeline for real time graphics.

@code

// ---------------------------------------------------------------------------------------
// Evaluate multiple textures stacked on top of each other
float3 EvaluateStack(stack)
{
  // For the 'diffuse' stack stack.base_color would be COLOR_DIFFUSE
  // and TEXTURE(aiTextureType_DIFFUSE,n) the n'th texture.

  float3 base = stack.base_color;
  for (every texture in stack)
  {
    // assuming we have explicit & pretransformed UVs for this texture
    float3 color = SampleTexture(texture,uv); 

    // scale by texture blend factor
    color *= texture.blend;

    if (texture.op == add)
      base += color;
    else if (texture.op == multiply)
      base *= color;
    else // other blend ops go here
  }
  return base;
}

// ---------------------------------------------------------------------------------------
// Compute the diffuse contribution for a pixel
float3 ComputeDiffuseContribution()
{
  if (shading == none)
     return float3(1,1,1);

  float3 intensity (0,0,0);
  for (all lights in range)
  {
    float fac = 1.f;
    if (shading == gouraud)
      fac =  lambert-term ..
    else // other shading modes go here

    // handling of different types of lights, such as point or spot lights
    // ...

    // and finally sum the contribution of this single light ...
    intensity += light.diffuse_color * fac;
  }
  // ... and combine the final incoming light with the diffuse color
  return EvaluateStack(diffuse) * intensity;
}

// ---------------------------------------------------------------------------------------
// Compute the specular contribution for a pixel
float3 ComputeSpecularContribution()
{
  if (shading == gouraud || specular_strength == 0 || specular_exponent == 0)
    return float3(0,0,0);

  float3 intensity (0,0,0);
  for (all lights in range)
  {
    float fac = 1.f;
    if (shading == phong)
      fac =  phong-term ..
    else // other specular shading modes go here

    // handling of different types of lights, such as point or spot lights
    // ...

    // and finally sum the specular contribution of this single light ...
    intensity += light.specular_color * fac;
  }
  // ... and combine the final specular light with the specular color
  return EvaluateStack(specular) * intensity * specular_strength;
}

// ---------------------------------------------------------------------------------------
// Compute the ambient contribution for a pixel
float3 ComputeAmbientContribution()
{
  if (shading == none)
     return float3(0,0,0);

  float3 intensity (0,0,0);
  for (all lights in range)
  {
    float fac = 1.f;

    // handling of different types of lights, such as point or spot lights
    // ...

    // and finally sum the ambient contribution of this single light ...
    intensity += light.ambient_color * fac;
  }
  // ... and combine the final ambient light with the ambient color
  return EvaluateStack(ambient) * intensity;
}

// ---------------------------------------------------------------------------------------
// Compute the final color value for a pixel
// @param prev Previous color at that position in the framebuffer
float4 PimpMyPixel (float4 prev)
{
  // .. handle displacement mapping per vertex
  // .. handle bump/normal mapping

  // Get all single light contribution terms
  float3 diff = ComputeDiffuseContribution();
  float3 spec = ComputeSpecularContribution(); 
  float3 ambi = ComputeAmbientContribution();

  // .. and compute the final color value for this pixel
  float3 color = diff + spec + ambi;
  float3 opac  = EvaluateStack(opacity);

  // note the *slightly* strange meaning of additive and multiplicative blending here ...
  // those names will most likely be changed in future versions
  if (blend_func == add)
       return prev+color*opac;
  else if (blend_func == multiply)
       return prev*(1.0-opac)+prev*opac;

   return color;
aramis_acg's avatar
aramis_acg committed
This page discusses general performance issues related to assimp.
aramis_acg's avatar
aramis_acg committed
assimp has built-in support for <i>very</i> basic profiling and time measurement. To turn it on, set the <tt>GLOB_MEASURE_TIME</tt>
configuration switch to <tt>true</tt> (nonzero). Results are dumped to the log file, so you need to setup
an appropriate logger implementation with at least one output stream first (see the @link logging Logging Page @endlink
for the details.). 

Note that these measurements are based on a single run of the importer and each of the post processing steps, so 
a single result set is far away from being significant in a statistic sense. While precision can be improved
by running the test multiple times, the low accuracy of the timings may render the results useless
for smaller files.
A sample report looks like this (some unrelated log messages omitted, entries grouped for clarity):

@verbatim
Debug, T5488: START `total`
Info,  T5488: Found a matching importer for this file format
Debug, T5488: START `import`
Info,  T5488: BlendModifier: Applied the `Subdivision` modifier to `OBMonkey`
Debug, T5488: END   `import`, dt= 3.516 s


Debug, T5488: START `preprocess`
Debug, T5488: END   `preprocess`, dt= 0.001 s
Info,  T5488: Entering post processing pipeline
Debug, T5488: START `postprocess`
Debug, T5488: RemoveRedundantMatsProcess begin
Debug, T5488: RemoveRedundantMatsProcess finished 
Debug, T5488: END   `postprocess`, dt= 0.001 s
Debug, T5488: START `postprocess`
Debug, T5488: TriangulateProcess begin
Info,  T5488: TriangulateProcess finished. All polygons have been triangulated.
Debug, T5488: END   `postprocess`, dt= 3.415 s
Debug, T5488: START `postprocess`
Debug, T5488: SortByPTypeProcess begin
Info,  T5488: Points: 0, Lines: 0, Triangles: 1, Polygons: 0 (Meshes, X = removed)
Debug, T5488: START `postprocess`
Debug, T5488: JoinVerticesProcess begin
Debug, T5488: Mesh 0 (unnamed) | Verts in: 503808 out: 126345 | ~74.922
Info,  T5488: JoinVerticesProcess finished | Verts in: 503808 out: 126345 | ~74.9
Debug, T5488: END   `postprocess`, dt= 2.052 s

Debug, T5488: START `postprocess`
Debug, T5488: FlipWindingOrderProcess begin
Debug, T5488: FlipWindingOrderProcess finished
Debug, T5488: END   `postprocess`, dt= 0.006 s
Debug, T5488: START `postprocess`
Debug, T5488: LimitBoneWeightsProcess begin
Debug, T5488: LimitBoneWeightsProcess end
Debug, T5488: END   `postprocess`, dt= 0.001 s
Debug, T5488: START `postprocess`
Debug, T5488: ImproveCacheLocalityProcess begin
Debug, T5488: Mesh 0 | ACMR in: 0.851622 out: 0.718139 | ~15.7
Info,  T5488: Cache relevant are 1 meshes (251904 faces). Average output ACMR is 0.718139
Debug, T5488: ImproveCacheLocalityProcess finished. 
Debug, T5488: END   `postprocess`, dt= 1.903 s
Info,  T5488: Leaving post processing pipeline
Debug, T5488: END   `total`, dt= 11.269 s
@endverbatim

In this particular example only one fourth of the total import time was spent on the actual importing, while the rest of the
time got consumed by the #aiProcess_Triangulate, #aiProcess_JoinIdenticalVertices and #aiProcess_ImproveCacheLocality 
postprocessing steps. A wise selection of postprocessing steps is therefore essential to getting good performance. 
aramis_acg's avatar
aramis_acg committed
Of course this depends on the individual requirements of your application, in many of the typical use cases of assimp performance won't 
matter (i.e. in an offline content pipeline).
aramis_acg's avatar
aramis_acg committed
This page discusses both assimps scalability in threaded environments and the precautions to be taken in order to
use it from multiple threads concurrently.
@section threadsafety Thread-safety / using Assimp concurrently from several threads

The library can be accessed by multiple threads simultaneously, as long as the
following prerequisites are fulfilled: 

 - Users of the C++-API should ensure that they use a dedicated #Assimp::Importer instance for each thread. Constructing instances of #Assimp::Importer is expensive, so it might be a good idea to
   let every thread maintain its own thread-local instance (which can be used to
   load as many files as necessary).
aramis_acg's avatar
aramis_acg committed
 - The C-API is thread safe.
 - When supplying custom IO logic, one must make sure the underlying implementation is thread-safe.
 - Custom log streams or logger replacements have to be thread-safe, too.




Multiple concurrent imports may or may not be beneficial, however. For certain file formats in conjunction with 
little or no post processing IO times tend to be the performance bottleneck. Intense post processing together 
with 'slow' file formats like X or Collada might scale well with multiple concurrent imports.  
Internal multi-threading is not currently implemented.
jonathanklein's avatar
jonathanklein committed
/**
aramis_acg's avatar
aramis_acg committed
This page lists some useful resources for assimp. Note that, even though the core team has an eye on them, 
we cannot guarantee the accuracy of third-party information. If in doubt, it's best to ask either on the 
mailing list or on our forums on SF.net.

aramis_acg's avatar
aramis_acg committed
 - assimp comes with some sample applications, these can be found in the <i>./samples</i> folder. Don't forget to read the <i>README</i> file.
 - http://www.drivenbynostalgia.com/files/AssimpOpenGLDemo.rar - OpenGl animation sample using the library's animation import facilities.
 - http://nolimitsdesigns.com/game-design/open-asset-import-library-animation-loader/ is another utility to
   simplify animation playback.
 - http://ogldev.atspace.co.uk/www/tutorial22/tutorial22.html - Tutorial "Loading models using the Open Asset Import Library", out of a series of OpenGl tutorials.

*/


/**
aramis_acg's avatar
aramis_acg committed
@page importer_notes Importer Notes
This section contains implementation notes for the Blender3D importer. 
aramis_acg's avatar
aramis_acg committed
assimp provides a self-contained reimplementation of Blender's so called SDNA system (http://www.blender.org/development/architecture/notes-on-sdna/). 
SDNA allows Blender to be fully backward and forward compatible and to exchange
files across all platforms. The BLEND format is thus a non-trivial binary monster and the loader tries to read the most of it, 
naturally limited by the scope of the #aiScene output data structure.
Consequently, if Blender is the only modeling tool in your asset work flow, consider writing a 
aramis_acg's avatar
aramis_acg committed
custom exporter from Blender if assimps format coverage does not meet the requirements.
The Blender loader does not support animations yet, but is apart from that considered relatively stable.
When filing bugs on the Blender loader, always give the Blender version (or, even better, post the file caused the error).
This section contains implementation notes on the IFC-STEP importer. 
The library provides a partial implementation of the IFC2x3 industry standard for automatized exchange of CAE/architectural 
data sets. See http://en.wikipedia.org/wiki/Industry_Foundation_Classes for more information on the format. We aim 
at getting as much 3D data out of the files as possible. 
@subsection ifc_status Current status

IFC support is new and considered experimental. Please report any bugs you may encounter.

@subsection ifc_notes Notes

- Only the STEP-based encoding is supported. IFCZIP and IFCXML are not (but IFCZIP can simply be unzipped to get a STEP file).
- The importer leaves vertex coordinates untouched, but applies a global scaling to the root transform to
  convert from whichever unit the IFC file uses to <i>metres</i>.
- If multiple geometric representations are provided, the choice which one to load is based on how expensive a representation seems 
 to be in terms of import time. The loader also avoids representation types for which it has known deficits.
- Not supported are arbitrary binary operations (binary clipping is implemented, though). 
- Of the various relationship types that IFC knows, only aggregation, containment and material assignment are resolved and mapped to
  the output graph.
- The implementation knows only about IFC2X3 and applies this rule set to all models it encounters, 
  regardless of their actual version. Loading of older or newer files may fail with parsing errors.
Alexander Gessler's avatar
Alexander Gessler committed
@subsection ifc_metadata Metadata

IFC file properties (IfcPropertySet) are kept as per-node metadata, see aiNode::mMetaData. 

*ATTENTION*: The Ogre-Loader is currently under development, many things have changed after this documentation was written, but they are not final enough to rewrite the documentation. So things may have changed by now!

This section contains implementations notes for the OgreXML importer. 
jonathanklein's avatar
jonathanklein committed
Ogre importer is currently optimized for the Blender Ogre exporter, because thats the only one that I use. You can find the Blender Ogre exporter at: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=45922

@subsection what What will be loaded?

jonathanklein's avatar
jonathanklein committed
Mesh: Faces, Positions, Normals and all TexCoords. The Materialname will be used to load the material.

Material: The right material in the file will be searched, the importer should work with materials who
have 1 technique and 1 pass in this technique. From there, the texturename (for 1 color- and 1 normalmap) and the
materialcolors (but not in custom materials) will be loaded. Also, the materialname will be set.

Skeleton: Skeleton with Bone hierarchy (Position and Rotation, but no Scaling in the skeleton is supported), names and transformations,
animations with rotation, translation and scaling keys.

@subsection export_Blender How to export Files from Blender
You can find informations about how to use the Ogreexporter by your own, so here are just some options that you need, so the assimp
importer will load everything correctly:
- Use either "Rendering Material" or "Custom Material" see @ref material
- do not use "Flip Up Axies to Y"
- use "Skeleton name follow mesh"


@subsection xml XML Format
There is a binary and a XML mesh Format from Ogre. This loader can only
jonathanklein's avatar
jonathanklein committed
Handle xml files, but don't panic, there is a command line converter, which you can use
to create XML files from Binary Files. Just look on the Ogre page for it.

Currently you can only load meshes. So you will need to import the *.mesh.xml file, the loader will
try to find the appendant material and skeleton file.

The skeleton file must have the same name as the mesh file, e.g. fish.mesh.xml and fish.skeleton.xml.

@subsection material Materials
jonathanklein's avatar
jonathanklein committed
The material file can have the same name as the mesh file (if the file is model.mesh or model.mesh.xml the
loader will try to load model.material),
or you can use Importer::Importer::SetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "materiafile.material")
to specify the name of the material file. This is especially usefull if multiply materials a stored in a single file.
jonathanklein's avatar
jonathanklein committed
The importer will first try to load the material with the same name as the mesh and only if this can't be open try
to load the alternate material file. The default material filename is "Scene.material".

We suggest that you use custom materials, because they support multiple textures (like colormap and normalmap). First of all you
should read the custom material sektion in the Ogre Blender exporter Help File, and than use the assimp.tlp template, which you
can find in scripts/OgreImpoter/Assimp.tlp in the assimp source. If you don't set all values, don't worry, they will be ignored during import.
If you want more properties in custom materials, you can easily expand the ogre material loader, it will be just a few lines for each property.
jonathanklein's avatar
jonathanklein committed
Just look in OgreImporterMaterial.cpp
@subsection Importer Properties
-	IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME: Normally, a texture is loaded as a colormap, if no
	target is specified in the
	materialfile. Is this switch is enabled, texture names ending with _n, _l, _s
	are used as normalmaps, lightmaps or specularmaps. 
	<br>
	Property type: Bool. Default value: false.
-	IMPORT_OGRE_MATERIAL_FILE: Ogre Meshes contain only the MaterialName, not the MaterialFile.
	If there 
	is no material file with the same name as the material, Ogre Importer will 
	try to load this file and search the material in it.
	<br>
	Property type: String. Default value: guessed.

@subsection todo Todo
- Load colors in custom materials
- extend custom and normal material loading
- fix bone hierarchy bug
jonathanklein's avatar
jonathanklein committed
- test everything elaboratly
- check for non existent animation keys (what happens if a one time not all bones have a key?)
*/


/**
@page extend Extending the Library

@section General

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:

<ul>
<li>Create a header (<tt><i>FormatName</i>Importer.h</tt>) and a unit (<tt><i>FormatName</i>Importer.cpp</tt>) in the <tt>&lt;root&gt;/code/</tt> directory</li>
<li>Add them to the following workspaces: vc8 and vc9 (the files are in the workspaces directory), CMAKE (code/CMakeLists.txt, create a new
source group for your importer and put them also to ADD_LIBRARY( assimp SHARED))</li>
<li>Include <i>AssimpPCH.h</i> - this is the PCH file, and it includes already most Assimp-internal stuff. </li>
<li>Open Importer.cpp and include your header just below the <i>(include_new_importers_here)</i> line, 
guarded by a #define 
@code
aramis_acg's avatar
aramis_acg committed
#if (!defined assimp_BUILD_NO_FormatName_IMPORTER)
	...
#endif
@endcode
Wrap the same guard around your .cpp!</li>

<li>Now advance to the <i>(register_new_importers_here)</i> line in the Importer.cpp and register your importer there - just like all the others do.</li>
<li>Setup a suitable test environment (i.e. use AssimpView or your own application), make sure to enable 
the #aiProcess_ValidateDataStructure flag and enable verbose logging. That is, simply call before you import anything:
@code
DefaultLogger::create("AssimpLog.txt",Logger::VERBOSE)
@endcode
</li>
<li>
Implement the Assimp::BaseImporter::CanRead(), Assimp::BaseImporter::InternReadFile() and Assimp::BaseImporter::GetExtensionList(). 
Just copy'n'paste the template from Appendix A and adapt it for your needs.
</li>
<li>For error handling, throw a dynamic allocated ImportErrorException (see Appendix A) for critical errors, and log errors, warnings, infos and debuginfos
with DefaultLogger::get()->[error, warn, debug, info].
</li>
<li>
Make sure that your loader compiles against all build configurations on all supported platforms. This includes <i>-noboost</i>! To avoid problems,
see the boost section on this page for a list of all 'allowed' boost classes (again, this grew historically when we had to accept that boost
is not THAT widely spread that one could rely on it being available everywhere).
</li>
<li>
Provide some _free_ test models in <tt>&lt;root&gt;/test/models/&lt;FormatName&gt;/</tt> and credit their authors.
Test files for a file format shouldn't be too large (<i>~500 KiB in total</i>), and not too repetive. Try to cover all format features with test data.
</li>
<li>
Done! Please, share your loader that everyone can profit from it!
</li>
</ul>

@section properties Properties

You can use properties to chance the behavior of you importer. In order to do so, you have to overide BaseImporter::SetupProperties, and specify
aramis_acg's avatar
aramis_acg committed
you custom properties in config.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.

@section tnote Notes for text importers

<ul>
<li>Try to make your parser as flexible as possible. Don't rely on particular layout, whitespace/tab style,
except if the file format has a strict definition, in which case you should always warn about spec violations.
But the general rule of thumb is <i>be strict in what you write and tolerant in what you accept</i>.</li>
<li>Call Assimp::BaseImporter::ConvertToUTF8() before you parse anything to convert foreign encodings to UTF-8. 
 That's not necessary for XML importers, which must use the provided IrrXML for reading. </li>
</ul>

@section bnote Notes for binary importers

<ul>
<li>
Take care of endianess issues! Assimp importers mostly support big-endian platforms, which define the <tt>AI_BUILD_BIG_ENDIAN</tt> constant.
See the next section for a list of utilities to simplify this task.
</li>
<li>
Don't trust the input data! Check all offsets!
</li>
</ul>

@section util Utilities

Mixed stuff for internal use by loaders, mostly documented (most of them are already included by <i>AssimpPCH.h</i>):
<ul>
<li><b>ByteSwap</b> (<i>ByteSwap.h</i>) - manual byte swapping stuff for binary loaders.</li>
<li><b>StreamReader</b> (<i>StreamReader.h</i>) - safe, endianess-correct, binary reading.</li>
<li><b>IrrXML</b> (<i>irrXMLWrapper.h</i>)  - for XML-parsing (SAX.</li>
<li><b>CommentRemover</b> (<i>RemoveComments.h</i>) - remove single-line and multi-line comments from a text file.</li>
<li>fast_atof, strtoul10, strtoul16, SkipSpaceAndLineEnd, SkipToNextToken .. large family of low-level 
parsing functions, mostly declared in <i>fast_atof.h</i>, <i>StringComparison.h</i> and <i>ParsingUtils.h</i> (a collection that grew
historically, so don't expect perfect organization). </li>
<li><b>ComputeNormalsWithSmoothingsGroups()</b> (<i>SmoothingGroups.h</i>) - Computes normal vectors from plain old smoothing groups. </li>
<li><b>SkeletonMeshBuilder</b> (<i>SkeletonMeshBuilder.h</i>) - generate a dummy mesh from a given (animation) skeleton. </li>
<li><b>StandardShapes</b> (<i>StandardShapes.h</i>) - generate meshes for standard solids, such as platonic primitives, cylinders or spheres. </li>
<li><b>BatchLoader</b> (<i>BaseImporter.h</i>) - manage imports from external files. Useful for file formats
which spread their data across multiple files. </li>
<li><b>SceneCombiner</b> (<i>SceneCombiner.h</i>) - exhaustive toolset to merge multiple scenes. Useful for file formats
which spread their data across multiple files. </li>
</ul>

@section mat Filling materials

The required definitions zo set/remove/query keys in #aiMaterial structures are declared in <i>MaterialSystem.h</i>, in a
#aiMaterial derivate called #aiMaterial. The header is included by AssimpPCH.h, so you don't need to bother.

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
@endcode

@section boost Boost

The boost whitelist:
<ul>
<li><i>boost.scoped_ptr</i></li>
<li><i>boost.scoped_array</i></li>
<li><i>boost.format</i> </li>
<li><i>boost.random</i> </li>
<li><i>boost.common_factor</i> </li>
<li><i>boost.foreach</i> </li>
<li><i>boost.tuple</i></li>
</ul>

(if you happen to need something else, i.e. boost::thread, make this an optional feature.
aramis_acg's avatar
aramis_acg committed
<tt>assimp_BUILD_BOOST_WORKAROUND</tt> is defined for <i>-noboost</i> builds)

@section appa Appendix A - Template for BaseImporter's abstract methods

@code
// -------------------------------------------------------------------------------
// 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.
}

@endcode

 
 /**
 @page AnimationOverview Animation Overview
 \section Transformations
 This diagram shows how you can calculate your transformationmatrices for an animated character:
 <img src="AnimationOverview.png" />
 
 **/