Adding a new actor

Actors are the visual elements of a Met.3D scene. For a full description of the actor class hierarchy, rendering interface, resource lifecycle, and shader loading, see Actors.

Choose a base class:

  • MActor (src/gxfw/mactor.h) — general base. Use for annotation, geometry, or any actor that does not read gridded data from the pipeline.

  • MNWPMultiVarActor (src/gxfw/nwpmultivaractor.h) — extends MActor with managed data variables. Use when the actor needs to load one or more NWP fields.

Deriving from MActor

MExampleActor (src/teaching/) is a minimal, heavily commented example actor. It is the best starting point for a new MActor-derived actor. Enable it with:

cmake -DTEACHING=ON ..

The example actor covers constructor boilerplate, property setup, shader loading, geometry upload, and rendering. Read through it alongside the notes below.

Required static methods

Every actor must implement four static methods used by the registration system:

static QString staticActorType()   { return "MyActor"; }   // session file key
static QString staticDisplayName() { return "My actor"; }  // Create actor menu
static QString staticIconPath()    { return ":/icons/actors/missing.png"; }
static QString staticSettingsID()  { return "MyActor"; }   // config group name

Properties

Declare properties as member variables (MFloatProperty, MColorProperty, MEnumProperty, MBoolProperty, MPointFProperty, MButtonProperty, …), configure them in the constructor, and register them with actorPropertiesSupGroup.addSubProperty(). Property-change callbacks either call &MActor::emitActorChangedSignal (redraw only) or a custom slot that requests data, rebuilds geometry, and so on. See Property Framework for the property framework API.

Shaders

GLSL effect files (*.fx.glsl) live in src/glsl/. Compile them in reloadShaderEffects() and register the result in initializeActorResources(). See ActorsShader loading for the full pattern.

Render methods

Override whichever render method applies to your actor (see ActorsRendering interface for when each is called):

  • renderToCurrentContext() — 3-D geometry in world space (lon/lat/pressure).

  • renderToCurrentFullScreenContext() — full-screen 2-D overlay; enable with setActorSupportsFullScreenVisualisation(true) in the constructor.

  • renderToCurrentContextUiLayer() — 2-D UI elements on top of the 3-D view.

Registration

In src/system/applicationconfiguration.cpp, MApplicationConfigurationManager::registerActorFactories():

#include "actors/myactor.h"

// inside registerActorFactories():
glRM->registerActorFactory<MMyActor>("Base");

Available groups: "Base", "Sections && volumes", "Atmospheric features", "Flow visualization", "Diagrams", "Annotation". Groups map to the context-menu categories in the Create actor dialog.

Deriving from MNWPMultiVarActor

MNWPMultiVarActor adds a managed list of MNWPActorVariable objects to MActor. The base class handles the Add variable / Delete variable UI, data requests, time/member synchronisation, and transfer function wiring. See ActorsMNWPMultiVarActor for a description of actor variables and the data flow.

Pure virtual methods

supportedLevelTypes() returns the level types the actor can handle:

QList<MVerticalLevelType> MMyActor::supportedLevelTypes()
{
    return { PRESSURE_LEVELS_3D, HYBRID_SIGMA_PRESSURE_3D,
             AUXILIARY_PRESSURE_3D, SINGLE_LEVEL };
}

createActorVariable() is a factory called whenever the user adds a variable. Return a new instance of the appropriate typed variable class:

MNWPActorVariable* MMyActor::createActorVariable(
        const MSelectableDataVariable& dataSource)
{
    auto* var = new MNWP3DVolumeActorVariable(this);
    var->dataSourceID  = dataSource.dataSourceID;
    var->levelType     = dataSource.levelType;
    var->variableName  = dataSource.variableName;
    return var;
}

Reacting to new data

Override dataFieldChangedEvent() to update your actor whenever a new data field arrives:

void MMyActor::dataFieldChangedEvent()
{
    // rebuild vertex buffers, recompute derived state, …
    emitActorChangedSignal(); // schedule a redraw
}

Reacting to variable list changes

Override these slots to update internal structures when variables are added, changed, or removed. Always call the base implementation first:

  • onAddActorVariable(MNWPActorVariable *var)

  • onChangeActorVariable(MNWPActorVariable *var)

  • onDeleteActorVariable(MNWPActorVariable *var)

Accessing data in the render method

Iterate over variables and guard every grid access with hasData():

void MMyActor::renderToCurrentContext(MSceneViewGLWidget *sceneView)
{
    for (MNWPActorVariable *baseVar : variables)
    {
        if (!baseVar->hasData()) continue;
        auto *var = static_cast<MNWP3DVolumeActorVariable*>(baseVar);

        // var->grid  — current MStructuredGrid
        // var->transferFunction  — active transfer function
        // … bind shader, upload grid to texture, draw …
    }
}

Registration is the same as for MActor. Add the include and factory call in applicationconfiguration.cpp.

Note

If you think your new actor would be useful to other Met.3D users, we would be happy to include it in the main codebase. Please consider submitting a merge request on GitLab.

Adding an icon

If you would like to create a new icon for your actor, make sure it is:

  • grayscale,

  • 112 × 112 pixels,

  • free of text, letters, and fine structures,

  • simple and conveying the functionality of the actor in an abstract way.

We recommend creating the icon as a vector graphic using Inkscape and exporting it as a PNG with an optional alpha channel. The icons live in resources/icons/actors/. Add the PNG file there and update staticIconPath():

static QString staticIconPath() { return ":/icons/actors/myactor.png"; }