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

4.15.1 Sprite3D Animation

Written by Michael Voase, [email protected].

After you have created your sprite you are now probably wondering what you can do to bring your creation to life? In this section we explore the two ways in which you can introduce animation sequences to your sprite.

For the Crystal Space developer, there are currently two options for the production and management of sprite animation. The first option is frame based animation, referred to as an action, and the second is skeletal animation (which uses the external CAL3D library).

Introduction

Crystal Space provides two basic mechanisms for animating sprites. The first is frame based animation in which a mesh is defined in each frame and used in a loop (see section Sprite3D Mesh Object). The second method is skeletal animation using the CAL3D library (see section SpriteCal3D Mesh Object).

For the purpose of this document I will describe frame based animation as an action. This name is coined from the class the implements frame animations in the 3D sprite object `iSpriteAction' and has been traditionally referred to as an `action' in the sprite loader plug in.

This document presumes that you have an operational copy of Crystal Space. For details on obtaining and building Crystal Space please refer to the relevant sections on obtaining (see section Where to Get Crystal Space) and building (see section Building and Installing) Crystal Space.

Lastly, actions are specific to sprite 3D. There is no exactly corresponding interface to thing or ball as yet, for example. So I am also presuming you have read to sections prior to this section about sprites, if not, then it would be a good idea to do so before delving into this section.

Sprite Actions

A sprite action is a series of frames which contains the position of each vertex in a sprite for a particular time. This means for each frame, a complete duplicate of the vertex list must be loaded into the sprite for each frame. The positions of the vertices of course will vary, however, the number of vertices in each frame must be equal. We will cover why later.

Creating a Sprite in a Map File

A sprite in a map file consists of two declaration. The first is the declaration for its factory the second is a declaration of its instance in a given sector. The factory declaration is what we are mostly interested in at the moment.

Now if you recall from Mesh Object Concepts (see section MeshObject Concepts), the factory acts as a database of all the vertices, triangles and texels used to define a mesh object. The primary purpose of this is to have a single database for each mesh object. So this is where we will be defining our sprite with its multiple actions.

The declaration starts with the `meshfact' token, and looks something like this:

 
<meshfact name="fact">
  <plugin>crystalspace.mesh.loader.factory.sprite.3d</plugin>
  <params>
    <material>white</material>
    <frame name="first">
      <v x="0" y="0" z="0" u="0" v="0"/>
      <v x="0" y="1" z="0" u="0" v="0"/>
      <v x="1" y="0" z="0" u="0" v="0"/>
      <v x="0" y="0" z="1" u="0" v="0"/>
    </frame>
    <frame name="second">
      <v x="0" y="0" z="0" u="0" v="0"/>
      <v x="0" y="1.2" z="0" u="0" v="0"/>
      <v x="1.2" y="0" z="0" u="0" v="0"/>
      <v x="0" y="0" z="1.2" u="0" v="0"/>
    </frame>
    <frame name="third">
      <v x="0" y="0" z="0" u="0" v="0"/>
      <v x="0" y="1.4" z="0" u="0" v="0"/>
      <v x="1.4" y="0" z="0" u="0" v="0"/>
      <v x="0" y="0" z="1.4" u="0" v="0"/>
    </frame>
    <frame name="fourth">
      <v x="0" y="0" z="0" u="0" v="0"/>
      <v x="0" y="1.2" z="0" u="0" v="0"/>
      <v x="1.2" y="0" z="0" u="0" v="0"/>
      <v x="0" y="0" z="1.2" u="0" v="0"/>
    </frame>
    
    <t t1="0" t2="1" t3="2"/>
    <t t1="0" t2="3" t3="1"/>
    <t t1="0" t2="2" t3="3"/>
    <t t1="1" t2="3" t3="2"/>
    
    <action name="default">
      <f name="first" delay="200"/>
      <f name="second" delay="200"/>
      <f name="third" delay="200"/>
      <f name="fourth" delay="200"/>
    </action>
  </params>
</meshfact>

This example defines a triangular pyramid which grow larger and smaller. To put this sprite into action, you also need to declare an instance of the sprite in a sector. In your map file (somewhere inside a `sector' declaration), place the following mesh object declaration.

 
<meshobj name="test1">
  <plugin>crystalspace.mesh.loader.sprite.3d</plugin>
  <params>
    <factory>fact</factory>
    <action>default</action>
    <tween />
  </params>
  <move>
    <v x="0" y="0" z="5.0" />
  </move>
  <priority>object</priority>
  <zuse />
</meshobj>

After zipping the map file up with your sprite you should see and active sprite five units in front of you.

Meaning of the Sprite

Okay, we have an example of a an animation. As you can see from the example, the sprite factory declaration, the sprite consists of four frames each enclosed in the `frame' keyword. Each frame defines the vertices of the pyramid in each frame. The `v' token stands for vertex. You will also note that each frame contains a name. This is important as the name is used to reference the frame. This applies to both map files and the sprite 3D interface.

After the frames have been defined, a list of triangles is then declared. Note that the `t' tokens are declared after the frames. Trying to define the triangles before the frames will result in an error and will be flagged as such. Each `t' declaration contains three indices to the defined frame vertices. The index starts at zero and has a maximum value equal the number of vertices minus one. During the course of animation the triangle lists are applied to the corresponding frame and are then sent to the graphics renderer. This is one reason why each frame must contain the same number of vertices. Lastly, at the end of the mesh factory declaration, there is an `action' declared.

Action Declaration

The declaration starts with the `action' token and is then followed by the name of the action. Setting the name is important as this is how you will reference the action both in the map file and in the sprite interface. Its also a good idea not to use the same name twice, as you will prevent the second action from being accessed. You can use the same name for an action and a frame, as they are stored in different places. In general though, never use the same name for two items of the same type, whether it be a mesh object, a frame, or whatever.

After the name of the action, we enter into the body of the action where the frame sequences are defined. Each frame of the sequence starts with the `F' token (standing for frame) and contains the name of the frame and the duration that it is valid for. The frame name must be one from the previous list of frames and the duration is in milliseconds. The duration represents how long the frame will be shown for. This sprite contains only one action. It can contain many actions. However, in all cases there must be at least one action (usually called default) defined for the sprite.

Lastly to implement this action, the `action' keyword is used in the mesh object declaration to tell the engine which action to use on this sprite instance. If no action is defined in the mesh object then the engine will use the first action defined in the factory regardless of its name.

Tweening and Actions.

You may have noticed that the animation looks somewhat jumpy when viewed. This is due to the tweening flag on the sprite instance being set to false. To enable tweening, set the tweening flag to true (it is normally enabled). Tweening is a method of producing a smoother animation by interpolating the position of the vertices between frame based on a ratio of the time into the frame and the duration of the frame. Enabling tweening in an animation involves an additional overhead in calculating the interpolated vertices, however, produces a more satisfactory result. This is also the second reason why each frame must have the same number of vertices.

Interfacing with the Sprite

To begin this section, I am assuming here that you are aware of how to obtain the various interfaces from the engine. If not, read the documentation for SCF, the Shared Class Facility. See section Shared Class Facility (SCF). I will be using terminology and concepts which are explained in that section. If you are only interested in writing map files for the engine then you can skip ahead to the next section.

Secondly, I am also presuming that you have loaded your sprite into the engine, and have access to that sprite via the `iEngine' interface. That implies that you have written a basic Crystal Space application (or are hacking up an existing application), and can access your sprite mesh factory using calls similar to the following:

 
iMeshFactoryWrapper *fwrap = Engine->FindMeshFactory("name");
iMeshObjectFactory *fact = fwrap->GetMeshObjectFactory();

iMeshWrapper *mwrap = Engine->FindMeshObject("name");
iMeshObject *mesh = mwrap->GetMeshObject();

With the name being the name of your mesh factory or object, respectively. There are four main interfaces that we will be dealing with in this section,

The declarations for these interfaces can be found in `CS/include/imesh/sprite3d.h'. The first two interfaces can be obtained by using the FindFrame() and FindAction() methods in the `iSprite3dFactoryState' interface (described later). The third interface can be obtained by querying the `iMeshObjectFactory' interface. The `iSprite3DState' interface can be obtained from the `iMeshObject' interface. The following is a summary of the methods in each interface and what they do. An example of obtaining the state interfaces is described below:

 
csRef<iSprite3dFactoryState> fstat =
  scfQueryInterface<iSprite3dFactoryState> (fact);
csRef<iSprite3DState> stat =
  scfQueryInterface<iSprite3DState> (mesh);

The `mesh' and `fact' variables are the ones mentioned earlier in this chapter. The following is summary of the methods and interface that are useful to the sprite animator during production. This summary does not fully document the `iSprite3DState' or `iSprite3DFactoryState' interfaces since they are adequately documented elsewhere. Only methods which are relevant to frame animation are treated here.

iSpriteFrame

Current version: 0.0.2

void SetName(char const*)

Set the name of this frame.

char const* GetName()

Return the name of this frame

int GetAnmIndex()

Returns the index of the first vertex used in this frame. The vertex list is stored in the sprite factory.

int GetTexIndex()

Returns the index to the first texel used in this frame. The texel list is stored in the sprite factory.

iSpriteAction

Current version: 0.0.1

void SetName(char const*)

Set the name of this action.

char const* GetName() const

Return the name of this action.

int GetFrameCount()

Get the total number of frames in this animation.

iSpriteFrame* GetFrame(int)

Returns frame specified by input argument.

iSpriteFrame* GetNextFrame()

Returns the next frame in the sequence.

int GetFrameDelay(int)

Returns the duration of frame specified by input argument.

void AddFrame(iSpriteFrame* frame, int time)

Adds the frame given by `frame' to this action and set the duration to `time' milliseconds. This method is used by the loader to add frames to an action. If you want to "roll your own", you will be using this interface to create your own actions. The frame must already be present in the frame list held by the sprite factory that this action came from.

iSprite3DFactoryState

Current version: 0.0.2

void AddVertices(int number)

Adds `number' vertices to all frames in this sprite factory. The all is emphasized so that you are aware that the actual number of vertices created is `number' multiplied by the number of frames. This is done to satisfy the requirement that all frames must be of an equal size.

iSpriteFrame* AddFrame()

Creates a new frame on the sprite frame list and returns a pointer to the newly created frame. The loader uses this method to load frames into a sprite. For each new frame added, an additional bank of vertices and texels is created for the new frame. Once you have this frame, you will then be using the `iSpriteFrame' interface to operate on the frame.

iSpriteFrame* FindFrame(const char* title)

Finds the frame named `title' in this sprite factory and returns a pointer the frame.

int GetFrameCount()

Returns the number of frames in this sprite factory.

iSpriteFrame* GetFrame(int index) const

Returns a pointer to frame `index'. This frame is part of the list of frames stored in this sprite factory.

iSpriteAction* AddAction()

Create a new action and return a pointer to the action. Once you have obtained the action, you will then be using the `iSpriteAction' interface to modify this action.

iSpriteAction* FindAction(const char* title) const

Returns a pointer to the action named `title'.

iSpriteAction* GetFirstAction() const

Returns a pointer to the first action in this sprite factory.

int GetActionCount() const

Returns the number of actions stored in this sprite factory.

iSpriteAction* GetAction(int index) const

Returns a pointer to action number `index'

void EnableTweening(bool flag)

Enables or disables tweening on this sprite factory depending on `flag'.

bool IsTweeningEnabled()

Returns the current setting for tweening on this sprite factory.

iSprite3DState

Current version: 0.0.4

void SetFrame(int index)

Sets this sprite to frame number `index' in the action current applied to this sprite.

int GetCurFrame() const

Returns the index number of the current frame in the current action applied to this sprite.

int GetFrameCount() const

Returns the number of frames in the current action applied to this sprite.

bool SetAction(const char *title)

Set the current action of this sprite to the action named `title'. Returns a flag indicating if the operation was successful or not.

iSpriteAction* GetCurAction() const

Returns a pointer to the current action applied to this sprite.

EnableTweening(bool flag)

Description: Enables or disables tweening on this sprite according to `flag'.

bool IsTweeningEnabled() const

Returns a flag indicating if tweening is enabled for this sprite.


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

This document was generated using texi2html 1.76.