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) — extendsMActorwith 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 Actors → Shader loading for the full pattern.
Render methods
Override whichever render method applies to your actor (see Actors → Rendering interface for when each is called):
renderToCurrentContext()— 3-D geometry in world space (lon/lat/pressure).renderToCurrentFullScreenContext()— full-screen 2-D overlay; enable withsetActorSupportsFullScreenVisualisation(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
Actors → MNWPMultiVarActor 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"; }