Skip to content
Snippets Groups Projects
dox.h 72.9 KiB
Newer Older
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
</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
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;
}

@endcode

*/




/**
@page perf Performance

@section perf_overview Overview

This page discusses general performance issues related to assimp.

@section perf_profile Profiling

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: SortByPTypeProcess finished

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.
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).
*/

/**
@page threading Threading

@section overview Overview

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).
 - 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.


@section automt Internal threading

Internal multi-threading is not currently implemented.
*/

/**
@page res Resources

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.

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

*/


/**
@page importer_notes Importer Notes

<hr>
@section blender Blender

This section contains implementation notes for the Blender3D importer.
@subsection bl_overview Overview

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
custom exporter from Blender if assimps format coverage does not meet the requirements.

@subsection bl_status Current status

The Blender loader does not support animations yet, but is apart from that considered relatively stable.

@subsection bl_notes Notes

When filing bugs on the Blender loader, always give the Blender version (or, even better, post the file caused the error).

<hr>
@section ifc IFC

This section contains implementation notes on the IFC-STEP importer.
@subsection ifc_overview Overview

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.

@subsection ifc_metadata Metadata

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

<hr>
@section ogre Ogre
*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.
@subsection overview Overview
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?

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
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
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")
Eric Engestrom's avatar
Eric Engestrom committed
to specify the name of the material file. This is especially useful if multiply materials a stored in a single file.
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.
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
- 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
#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
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>
Eric Engestrom's avatar
Eric Engestrom committed
Take care of endianness 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>ByteSwapper</b> (<i>ByteSwapper.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.

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

 **/