Initializing the Scene

The first step in implmenting our scene is to create the initialization function. This function takes a pointer to a BM_Scene instance (provided by the active controller) and returns a BM_Error error code.

The initialization function is responsible for assigning the pointers to the callback functions, initializing audio effects and other necessary initializations that may be needed.

Creating Internal Variables

Before we write the init function, let's add a few variables and definitions that we will be making use of later in this tutorial - namely, the filter parameters and our cat's velocity:

//  BM_Scene_CatPad.c
#include "BM_Scene_CatPad.h"

#define BM_SCENE_CATPAD_MIN_FC 100.f
#define BM_SCENE_CATPAD_MAX_FC 2000.f

#define BM_SCENE_CATPAD_MIN_Q 0.7f
#define BM_SCENE_CATPAD_MAX_Q 16.f

#define BM_SCENE_CATPAD_VELOCITY 2.f    //  Set the cat's velocity to 2 pixels per frame change 

//  Note that these variables are file-scope variables (static)
static MW_AFXUnit_SVFilter _filter;     //  Instance of the SV Filter

As convention, file-scope variable names (marked as static) are prefixed with an underscore, _.

Creating a Sprite Instance

Since we will be adding a sprite (the cat) to the screen, we should create a BM_Sprite instance. This step is not strictly necessary but typically sprites will move around the screen which will require variables to track its current position and velocity (among other things). Instead of individually creating these variables, it is more convenient to wrap this information into a struct like BM_Sprite:

//  BM_Scene_CatPad.c

// --snip--

static MW_AFXUnit_SVFilter _filter;

static BM_Sprite _catSprite;    //  BM_Sprite instance that will store data about the cat sprite

Creating the init Function

Let's start writing the initialization function:

BM_Error BM_Scene_CatPad_init(BM_Scene *scene)
{
    if (scene == NULL)
        return BM_NULLPTR;

    return BM_NO_ERR;
}

Initializing the Filter

The first thing that we will do is initialize our filter:

BM_Error BM_Scene_CatPad_init(BM_Scene *scene)
{
    //  --snip--

    //  Initialize filter
    //  Sampling frequency is defined in BM_Common.h as FS
    int32_t success = MW_AFXUnit_SVFilter_init(&_filter, MW_AFXUNIT_SVFILTER_LPF, FS, BM_SCENE_CATPAD_MIN_FC, BM_SCENE_CATPAD_MIN_Q);
    if (!success)
        return BM_AFXUNIT_INIT_FAIL;

    return BM_NO_ERR;
}

To initialize our filter, we call the MW_AFXUnit_SVFilter_init() function which expects a pointer to our filter instance, _filter, the type of filter (low-pass), sampling frequency, cutoff frequency and Q factor. BitMasher's sampling rate is defined in BM_Common.h as FS (32 kHz).

Initializing the Sprite

The next step is to assign values to our _catSprite struct:

BM_Error BM_Scene_CatPad_init(BM_Scene *scene)
{
    //  --snip--

    //  Initialize _catSprite members
    _catSprite.currentBitmap = BM_Assets_CatPad_cat;
    _catSprite.currentMask = NULL;
    _catSprite.width = BM_Assets_CatPad_catWidth;
    _catSprite.height = BM_Assets_CatPad_catHeight;
    _catSprite.currentXPos = 0.0;
    _catSprite.currentYPos = 0.0;

    return BM_NO_ERR;
}

The BM_Sprite struct contains many members used for different situations but as a basic start, we will only define where the byte data is (currentBitmap), its initial position on the screen (top-left corner) and its dimensional information. currentMask is a pointer to byte data that contains information about a sprite's transparent sections but we will set it to NULL here.

Assigning Callback Functions

The last step is to assign the callback functions in the BM_Scene instance passed to the init function:

BM_Error BM_Scene_CatPad_init(BM_Scene *scene)
{
    //  --snip--

    //  Assign pointers to the callback functions
    scene->update = &BM_Scene_CatPad_update;
    scene->draw = &BM_Scene_CatPad_draw;
    scene->processAudio = &BM_Scene_CatPad_processAudio;
    scene->handleUserIO = &BM_Scene_CatPad_handleUserIO;
    scene->reset = &BM_Scene_CatPad_reset;

    //  Give the scene a name and the pointer to its icon bitmap (NULL)
    scene->sceneName = "Cat Pad";
    scene->iconBitmap = NULL;

    return BM_NO_ERR;
}

In addition to specifying the callback functions, we are also specifying the scene name. In BitMasher's menu system, a scene is typically represented through an icon image. This is optional however and in this example, we will not supply an icon and set iconBitmap to NULL. In the menu, we should see our scene represented as a box with the text, Cat Pad.

Now that we have written our initialization function, we need to actually implement the callback functions starting with the BM_Scene_CatPad_draw() function.