Newer
Older

Wil Shipley
committed
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
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
</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")
to specify the name of the material file. This is especially usefull 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><root>/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><root>/test/models/<FormatName>/</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>
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>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" />
**/