5.2. Core Model Handling

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.

5.2.1. Creation

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.

Example 5-2. Core Model Creation


  CalCoreModel myCoreModel;

  if(!myCoreModel.create("my hero model type"))
  {
    // error handling ...
  }
        

5.2.2. Data Loading

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

5.2.3. Material System Setup

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

5.2.4. Destruction

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.

Example 5-9. Core Model Destruction


  myCoreModel.destroy();