As explained in the previous chapter, every model instance is based on a core model, which therefore must be created first. All the shared data, such as animations, meshes and materials, need to be loaded, and a few additional steps are necessary to finish the setup of the material handling.
The creation of a core model is done by instantiating a CalCoreModel
variable and call its create()
function. This function takes one single
argument which is a description of the core model, and has no other meaning or functionality
otherwise. It is highly recommended to check for errors and act accordingly. Not only at this
stage, but for all Cal3D library calls.
The next step after the creation of the core model is to load the skeleton data. Note that there
can only be one skeleton per core model and it has to be loaded before any other type of data. Use
the loadCoreSkeleton()
function to do so. The single argument is the filename
of a Cal3D skeleton file.
Example 5-3. Skeleton Data Loading
if(!myCoreModel.loadCoreSkeleton("hero.csf")) { // error handling ... }
The animation, mesh and material data can now be loaded in any order. Use the corresponding
loadCoreAnimation()
, loadCoreMesh()
and
loadCoreMaterial()
function to do so. Each of them needs a filename to
a Cal3D data file as argument. A unique identifier is returned which will be used in further
Cal3D library calls.
Example 5-4. Animation Data Loading
int idleAnimationId, walkAnimationId, limpAnimationId, waveAnimationId; idleAnimationId = myCoreModel.loadCoreAnimation("hero_idle.caf"); walkAnimationId = myCoreModel.loadCoreAnimation("hero_walk.caf"); limpAnimationId = myCoreModel.loadCoreAnimation("hero_limp.caf"); waveAnimationId = myCoreModel.loadCoreAnimation("hero_wave.caf"); if((idleAnimationId == -1) || (walkAnimationId == -1) || (limpAnimationId == -1) || (waveAnimationId == -1)) { // error handling ... }
Example 5-5. Mesh Data Loading
int upperBodyMeshId, lowerBodyMeshId, helmetMeshId; upperBodyMeshId = myCoreModel.loadCoreMesh("hero_upperbody.cmf"); lowerBodyMeshId = myCoreModel.loadCoreMesh("hero_lowerbody.cmf"); helmetMeshId = myCoreModel.loadCoreMesh("hero_helmet.cmf"); if((upperBodyMeshId == -1) || (lowerBodyMeshId == -1) || (helmetMeshId == -1)) { // error handling ... }
Example 5-6. Material Data Loading
int upperBodyChainmailMaterialId, upperBodyPlatemailMaterialId; int lowerBodyChainmailMaterialId, lowerBodyPlatemailMaterialId; upperBodyChainmailMaterialId = myCoreModel.loadCoreMaterial("hero_upperbody_chainmail.crf"); upperBodyPlatemailMaterialId = myCoreModel.loadCoreMaterial("hero_upperbody_platemail.crf"); lowerBodyChainmailMaterialId = myCoreModel.loadCoreMaterial("hero_lowerbody_chainmail.crf"); lowerBodyPlatemailMaterialId = myCoreModel.loadCoreMaterial("hero_lowerbody_platemail.crf"); if((upperBodyChainmailMaterialId == -1) || (upperBodyPlatemailMaterialId == -1) || (lowerBodyChainmailMaterialId == -1) || (lowerBodyPlatemailMaterialId == -1)) { // error handling ... }
Depending on the type of model and the needed functionality, a few additional steps must be executed to make the material handling work properly.
Textures are not handled by the Cal3D library itself, because of all the different ways they are needed and managed in the applications. However, there is flexible system in place to support the texture handling as much as possible.
In every map of each material there is an identifier stored. This value is written during the exporting process, and is most likely the filename of a texture. The idea is to use this value to load the texture, and reference it afterwards through a user-defined data that can be stored in every core material map at runtime.
Useful functions to get all the core materials of the core model are
getCoreMaterialCount()
and getCoreMaterial()
.
The number of maps in a core material is returned by the getMapCount()
function. Access to the filename of each map is provided through getMapFilename()
.
User-data, such as an identifier of the loaded texture, can be stored in the core material
map with help of the setMapUserData()
function. It can later be retrieved
by calling getUserMapData()
.
Example 5-7. Texture Loading
// load all textures and store their identifier as user-data in the corresponding core material map int materialId; for(materialId = 0; materialId < myCoreModel.getCoreMaterialCount(); materialId++) { // get the current core material CalCoreMaterial *pCoreMaterial; pCoreMaterial = myCoreModel.getCoreMaterial(materialId); // loop through all the maps of the current core material int mapId; for(mapId = 0; mapId < pCoreMaterial->getMapCount(); mapId++) { // get the filename of the map std::string strFilename; strFilename = pCoreMaterial->getMapFilename(mapId); // load the texture from the file Cal::UserData textureId; textureId = (Cal::UserData)myTextureLoadingFunction(strFilename); // store the texture id in the user data of the map pCoreMaterial->setMapUserData(mapId, textureId); } }
If you want to use the built-in material management system of the Cal3D library
to handle different material sets and threads, you have to initialize it
accordingly. This is done by creating all material threads of the core model by
calling createCoreMaterialThread()
for each of them. Then,
the setCoreMaterialId()
is used to assign a material to a
specific material thread/set pair.
Example 5-8. Material Thread/Set Setup
// create all the material threads const int UPPER_BODY_MATERIAL_THREAD = 0; const int LOWER_BODY_MATERIAL_THREAD = 1; myCoreModel.createCoreMaterialThread(UPPER_BODY_MATERIAL_THREAD); myCoreModel.createCoreMaterialThread(LOWER_BODY_MATERIAL_THREAD); // assign a material for each material thread/set pair const int CHAINMAIL_MATERIAL_SET = 0; const int PLATEMAIL_MATERIAL_SET = 1; myCoreModel.setCoreMaterialId(UPPER_BODY_MATERIAL_THREAD, CHAINMAIL_MATERIAL_SET, upperChainmailMaterialId); myCoreModel.setCoreMaterialId(UPPER_BODY_MATERIAL_THREAD, PLATEMAIL_MATERIAL_SET, upperPlatemailMaterialId); myCoreModel.setCoreMaterialId(LOWER_BODY_MATERIAL_THREAD, CHAINMAIL_MATERIAL_SET, lowerChainmailMaterialId); myCoreModel.setCoreMaterialId(LOWER_BODY_MATERIAL_THREAD, PLATEMAIL_MATERIAL_SET, lowerPlatemailMaterialId);
When a core model is not needed anymore, it must be destroyed by calling the destroy()
function. This will free all data and other resources. Make sure that all the model instances are already
destroyed before doing so with their core model.