[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 4.9.2 Using Mesh Objects

Written by Jorrit Tyberghein, jorrit.tyberghein@gmail.com.

This section explains how to use Mesh Objects in general. It doesn't go into detail about the specific Mesh Object Types that Crystal Space supports.

#### General

When the engine works with instances of Mesh Objects it does so through the ``iMeshWrapper'` interface. ``iMeshWrapper'` holds the reference to the ``iMeshObject'` instances implementing the particular type of Mesh Object. ``iMeshWrapper'` is responsible for deciding when to draw a Mesh Object and when to light it. ``iMeshWrapper'` also manages the position of the object in the world and manages possible hierarchical transformations (i.e. ``iMeshWrapper'` has an array of ``iMeshWrapper'` children).

#### Loading From Map File

The easiest way to use Mesh Objects is to simply specify them in the map file for your level. There are two things that you need to do for that. First you have to specify an entry at top-level (directly inside the ``world'` statement) like this (this example uses the fountain plug-in to make a fountain):

    <meshfact name="fountainFactory">
      <plugin>crystalspace.mesh.loader.factory.fountain</plugin>
      <params />
    </meshfact>

This will use the mesh object loader plug-in which is identified by the SCF name mentioned by the ``plugin'` statement to load a factory (type ``iMeshObjectFactory'`) and register it with the engine. There are no parameters for the fountain's Mesh Object Factory so that's why the ``params'` block is empty. But you still have to specify it. Other mesh object factories may accept parameters.

Because the fountain defines no parameters for the Mesh Object Factory you only have to create one factory in order to make all fountains you need. But in some cases you may have to create multiple factories depending on the object characteristics you want.

To place a fountain in some room (sector) you use a ``meshobj'` statement, within the definition of a room or sector, like this:

    <meshobj name="fountain">
      <plugin>crystalspace.mesh.loader.fountain</plugin>
      <params>
        <factory>fountainFactory</factory>
        <number>300</number>
        <material>spark</material>
        <origin x="0" y="0" z="0"/>
        <dropsize w=".05" h=".05"/>
        <color red="0.7" green="0.9" blue="1.0"/>
        <accel x="0" y="-.1" z="0"/>
        <falltime>3</falltime>
        <speed>1</speed>
        <elevation>1.5</elevation>
        <azimuth>0</azimuth>
        <opening>.2</opening>
        <mixmode>
          <add />
        </mixmode>
      </params>
      <move>
        <v x="-10" y="-1" z="14"/>
        <matrix>
          <rot x="1.5"/>
        </matrix>
      </move>
    </meshobj>

This code fragment uses the ``crystalspace.mesh.loader.fountain'` loader plug-in named to load a Mesh Object (type ``iMeshObject'`) and register it with the engine (while placing it in the current sector). In this case there are many parameters. The first parameter should always be the name of the factory. This is true for all Mesh Objects regardless of their type. For a complete list of parameters available, you should refer to the fountain documentation.

The ``move'` statement is outside of the ``params'` block. The reason for this is that the position of Mesh Objects is controlled by the engine and not by the Mesh Object itself.

In addition to the above statements you can also nest other ``meshobj'` statements to create a hierarchy of Mesh Objects (not shown in the example above). If you do that, then the ``move'` statement must be interpreted relative to the parent.

When you have Mesh Objects loaded into Crystal Space using the map file syntax illustrated above, then you can query the parameters from your application by using the standard API in the ``iEngine'` interface.

#### Using Directly From Code

You can also create Mesh Objects directly from your application. The engine has a few convenience functions you can use for that (`iEngine::CreateMeshwrapper()` and `iEngine::CreateMeshFactory()`). But here we show you the full way to create meshes from code:

- Load the Mesh Object Type with `csLoadPlugin` (preferably after checking if it is already loaded, by calling `csQueryPluginClass`).
- Create at least one Mesh Object Factory by calling `NewFactory()` on the Mesh Object Type instance.
- If the factory has parameters you can call `scfQueryInterface` to get a handle to the ``iSomethingFactoryState'` interface (replace Something with whatever the type name of the Mesh Object is). Then you set the parameters you want on that factory.
- Create one or more Mesh Object instances by using one of your factories and calling `NewInstance()` on them.
- If the object has parameters you use `scfQueryInterface` to get a handle to the ``iSomethingState'` interface (replace Something with whatever the type name of the Mesh Object is). Then set the parameters you want on the Mesh Object. Note that there are Mesh Object implementations which have multiple interfaces like this (for example, the particle systems implement both ``iParticleState'` plus another particle system-dependent interface).
- For every instance of ``iMeshObject'` you need to create a ``iMeshWrapper'` instance for the engine. Then you set up the ``iMeshWrapper'` by placing it in the sector that you want it and setup its position and rotation (transformation).

Here is a code example for creating an instance of the genmesh plug-in.

    void Initialize ()
    {
      ...
      // First create the factory:
      csRef<iMeshFactoryWrapper> fact = engine->CreateMeshFactory (
        "crystalspace.mesh.object.genmesh", "cubeFact");
      csRef<iGeneralFactoryState> factstate = scfQueryInterface<iGeneralFactoryState> (
        fact->GetMeshObjectFactory ());

      csEllipsoid ellips (csVector3 (0, 0, 0), csVector3 (1, 1, 1));
      factstate->GenerateSphere (ellips, 8);
      factstate->CalculateNormals ();
      ...
    }
    ...
    void SetupWorld ()
    {
      ...
      // Make a ball using the genmesh plug-in.
      csRef<iMeshWrapper> ball =
        engine->CreateMeshWrapper (fact, "ball", room, csVector3 (-3, 5, -3));
      csRef<iGeneralMeshState> ballstate = scfQueryInterface<iGeneralMeshState> (
        ball->GetMeshObject ());
      ballstate->SetMaterialWrapper (myMaterial);
      ...
    }

This example will load a ball using the plug-in and place it at (-3,5,-3) in ``room'`.

`iGeneralFactoryState` and `iGeneralMeshState` are the state interfaces for setting the characteristics of genmesh Mesh Objects.

#### Generic Mesh Creation Code

In general you should use the following code to create any kind of mesh:

      // First create the factory:
      csRef<iMeshFactoryWrapper> fact = engine->CreateMeshFactory (
    	"crystalspace.mesh.object.meshtype", "factoryName");
      csRef<iMeshtypeFactoryState> factstate = scfQueryInterface<
      	iMeshtypeFactoryState> (fact->GetMeshObjectFactory ());
      ...
      // Then make one or more meshes:
      csRef<iMeshWrapper> mesh = engine->CreateMeshWrapper (
      	fact, "meshName", sector, csVector3 (-3, 5, -3));
      csRef<iMeshtypeObjectState> meshstate = scfQueryInterface<
      	iMeshtypeObjectState> (mesh->GetMeshObject ());
      ...

Replace ``meshtype'` with the correct mesh type (like ``genmesh'`, ``thing'`, ...). Replace `iMeshtypeFactoryState` with the correct factory state and `iMeshtypeObjectState` with the correct object state.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ]

This document was generated using texi2html 1.76.