Using effects in the Kanzi Engine API

You can use the Kanzi Engine API to create effects for 2D nodes.

Assigning effects to nodes

To create an effect:

// An effect that is assigned to a 2D node is an effect prefab.
// Before you can construct an effect prefab, you must create an effect template.
// This example creates an effect template for the ShadowEffect2D effect prefab.
NodeEffectTemplate2DSharedPtr shadowEffectTemplate =
    NodeEffectTemplate2D::create(ShadowEffect2D::getStaticMetaclass()->getName(), "DropShadow");

// Create a node effect prefab from the effect template.
NodeEffectPrefab2DSharedPtr shadowEffectPrefab =
    NodeEffectPrefab2D::create(getDomain(), "DropShadow prefab", shadowEffectTemplate);

To set a 2D node to use an effect:

// To assign an effect prefab to a 2D node, set the Node2D::EffectPrefabProperty.
node2d->setProperty(Node2D::EffectPrefabProperty, shadowEffectPrefab);
// To assign an effect prefab to a 2D node, call the Node2D::setEffectPrefab method.
node2d->setEffectPrefab(shadowEffectPrefab);

To disable an effect:

// Enable an effect on a 2D node by assigning an effect prefab.
node2d->setEffectPrefab(shadowEffectPrefab);
// Disable an effect by assigning a nullptr or an empty shared pointer.
node2d->setEffectPrefab(nullptr);

To set multiple 2D nodes to use the same effect:

// Create an effect template.
NodeEffectTemplate2DSharedPtr shadowEffectTemplate =
    NodeEffectTemplate2D::create(ShadowEffect2D::getStaticMetaclass()->getName(), "DropShadow");

// Create an effect prefab from the effect template.
NodeEffectPrefab2DSharedPtr shadowEffectPrefab =
    NodeEffectPrefab2D::create(getDomain(), "DropShadow prefab", shadowEffectTemplate);

// Set two nodes to use the same effect prefab. The nodes create separate instances
// of NodeEffect2D but share the same NodeEffectPrefab2D instance.
node1->setEffectPrefab(shadowEffectPrefab);
node2->setEffectPrefab(shadowEffectPrefab);

Creating a blur effect

Use the Blur Effect 2D effect to apply a Gaussian blur to a 2D node.

To create a blur effect for a 2D node using the Kanzi Engine API:

// Create a blur effect template.
NodeEffectTemplate2DSharedPtr blurEffectTemplate =
    NodeEffectTemplate2D::create(BlurEffect2D::getStaticMetaclass()->getName(), "BlurEffect");

// Set the value of the RadiusProperty in the blur effect template.
// RadiusProperty defines the amount of blur.
blurEffectTemplate->addPropertyValue(BlurEffect2D::RadiusProperty, Variant(6.f));

// Create a blur effect prefab.
NodeEffectPrefab2DSharedPtr blurEffectPrefab =
    NodeEffectPrefab2D::create(getDomain(), "BlurEffect prefab", blurEffectTemplate);

// Assign the blur effect to a 2D node.
node2d->setEffectPrefab(blurEffectPrefab);

// Get the node-specific effect instance created from the assigned prefab.
BlurEffect2DSharedPtr blurEffect = dynamic_pointer_cast<BlurEffect2D>(node2d->getEffect());

// Set the MaskedProperty to true. Masked mode maintains the original alpha channel and
// prevents the blur from spreading to fully transparent pixels.
blurEffect->setMasked(true);

For details, see the BlurEffect2D class in the Kanzi Engine API reference.

Creating a mask effect

Use the Mask Effect 2D effect to apply a mask to a 2D node.

To create a mask effect for a 2D node using the Kanzi Engine API:

// Create an effect template.
NodeEffectTemplate2DSharedPtr maskEffectTemplate =
    NodeEffectTemplate2D::create(MaskEffect2D::getStaticMetaclass()->getName(), "MaskEffect");

// Set the value of the MaskProperty in the template.
// The MaskProperty defines the mask texture which you must set before you can use the mask effect.
TextureSharedPtr maskTexture = acquireMaskTexture(getDomain());
maskEffectTemplate->addPropertyValue(MaskEffect2D::MaskProperty, Variant(maskTexture));

// Create a mask effect prefab.
NodeEffectPrefab2DSharedPtr maskEffectPrefab =
    NodeEffectPrefab2D::create(getDomain(), "MaskEffect prefab", maskEffectTemplate);

// Assign the mask effect to a 2D node.
node2d->setEffectPrefab(maskEffectPrefab);

// Get the node-specific effect instance created from the assigned prefab.
MaskEffect2DSharedPtr maskEffect = dynamic_pointer_cast<MaskEffect2D>(node2d->getEffect());

// Set the mask stretch mode to uniform.
maskEffect->setStretch(MaskEffect2D::Stretch::Uniform);

For details, see the MaskEffect2D class in the Kanzi Engine API reference.

Creating an outline effect

Use the Outline Effect 2D effect to apply an outline to the content of a 2D node.

To create an outline effect for a 2D node using the Kanzi Engine API:

// Create an outline effect template.
NodeEffectTemplate2DSharedPtr outlineEffectTemplate =
    NodeEffectTemplate2D::create(OutlineEffect2D::getStaticMetaclass()->getName(), "OutlineEffect");

// Set the value of the WidthProperty in the outline effect template.
// The WidthProperty defines the maximum width of the outline outside the content area.
outlineEffectTemplate->addPropertyValue(OutlineEffect2D::WidthProperty, Variant(8));

// Create an outline effect prefab.
NodeEffectPrefab2DSharedPtr outlineEffectPrefab =
    NodeEffectPrefab2D::create(getDomain(), "OutlineEffect prefab", outlineEffectTemplate);

// Assign the outline effect to a 2D node.
node2d->setEffectPrefab(outlineEffectPrefab);

// Get the node-specific effect instance created from the assigned prefab.
OutlineEffect2DSharedPtr outlineEffect = dynamic_pointer_cast<OutlineEffect2D>(node2d->getEffect());

// Set the SoftnessProperty to 0.7 for this node only. This overrides
// the property default value defined by the OutlineEffect2D metaclass.
outlineEffect->setSoftness(0.7f);

For details, see the OutlineEffect2D class in the Kanzi Engine API reference.

Creating a shadow effect

Use the Shadow Effect 2D effect to apply a shadow to the content of a 2D node.

To create a shadow effect for a 2D node using the Kanzi Engine API:

// Create an effect template.
NodeEffectTemplate2DSharedPtr shadowEffectTemplate =
    NodeEffectTemplate2D::create(ShadowEffect2D::getStaticMetaclass()->getName(), "DropShadow");

// Set the value of the AngleProperty in the template. This value serves as the default value
// of the property in instances of the effect prefab.
shadowEffectTemplate->addPropertyValue(ShadowEffect2D::AngleProperty, Variant(35.f));

// Create an effect prefab.
NodeEffectPrefab2DSharedPtr shadowEffectPrefab =
    NodeEffectPrefab2D::create(getDomain(), "DropShadow prefab", shadowEffectTemplate);

// Assign the effect to a 2D node.
node2d->setEffectPrefab(shadowEffectPrefab);

// Get the node-specific effect instance created from the assigned prefab.
ShadowEffect2DSharedPtr shadowEffect = dynamic_pointer_cast<ShadowEffect2D>(node2d->getEffect());

// Set the shadow distance to 15 pixels for this node only. This overrides
// the property default value defined by the ShadowEffect2D metaclass.
shadowEffect->setDistance(15.f);

// Set the direction of the shadow to 55 degrees relative to the positive x axis.
// This overrides the default value of 35 degrees set in the shadow effect template.
shadowEffect->setAngle(55.f);

For details, see the ShadowEffect2D class in the Kanzi Engine API reference.

Creating a custom effect

You can use the Kanzi Engine API to create your own effects for 2D nodes.

To create a custom effect for a 2D node using the Kanzi Engine API:

// To create an effect resource type, inherit a new class from NodeEffect2D
// and define a new associated metaclass. Each effect resource class must
// have an associated renderer class inherited from NodeEffectRenderer2D.

class EmptyEffectRenderer2D;
using EmptyEffectRenderer2DUniquePtr = unique_ptr<EmptyEffectRenderer2D>;

class EmptyEffect2D;
using EmptyEffect2DSharedPtr = shared_ptr<EmptyEffect2D>;

// EmptyEffect2D defines a new effect that defines no properties
// nor padding.
class EmptyEffect2D : public NodeEffect2D
{
public:
    KZ_METACLASS_BEGIN(EmptyEffect2D, NodeEffect2D, "Kanzi.EmptyEffect2D")
    KZ_METACLASS_END()

    // Create an instance of EmptyEffect2D.
    static EmptyEffect2DSharedPtr create(Domain* domain, string_view name)
    {
        return make_polymorphic_shared_ptr<Resource>(new EmptyEffect2D(domain, name));
    }
protected:

    // Constructor.
    explicit EmptyEffect2D(Domain* domain, string_view name) :
        NodeEffect2D(domain, name)
    {
    }

    // NodeEffect2D::createRendererOverride implementation.
    NodeEffectRenderer2DUniquePtr createRendererOverride() override;

    // NodeEffect2D::initializeRendererOverride implementation.
    void initializeRendererOverride() override
    {
    }
};

// EmptyEffectRenderer2D implements the rendering of the effect.
// Because this example effect does not render anything, Kanzi renders
// the original node as is.
class EmptyEffectRenderer2D : public NodeEffectRenderer2D
{
public:
    // Creates an instance of MinimalEffectRenderer2D. Never call this
    // function directly. Instead, use NodeEffect2D::createRenderer().
    static EmptyEffectRenderer2DUniquePtr create(EmptyEffect2DSharedPtr effect)
    {
        return unique_ptr<EmptyEffectRenderer2D>(new EmptyEffectRenderer2D(effect));
    }

private:
    // Constructor.
    explicit EmptyEffectRenderer2D(EmptyEffect2DSharedPtr effect) :
        NodeEffectRenderer2D(effect)
    {
    }

    // Implementation of NodeEffectRenderer2D::beginEffectOverride.
    void beginEffectOverride(Renderer3D& /*renderer*/, CompositionStack& /*compositionStack*/, CompositionManager* /*compositionManager*/,
        const Matrix3x3& /*worldTransform*/, Vector2 /*requiredSize*/, bool /*alphaRequired*/, bool /*depthRequired*/, bool /*stencilRequired*/) override
    {
    }

    // Implementation of NodeEffectRenderer2D::endEffectOverride.
    void endEffectOverride(Renderer3D& /*renderer*/, CompositionStack& /*compositionStack*/, CompositionManager* /*compositionManager*/) override
    {
    }

    // Implementation of NodeEffectRenderer2D::blitEffectOverride.
    void blitEffectOverride(Renderer3D& /*renderer*/, CompositionStack& /*compositionStack*/, CompositionManager* /*compositionManager*/,
        QuadDescription& /*effectQuad*/, const Matrix3x3& /*transform*/, const Matrix4x4* /*perspectiveMatrix*/,
        const Matrix4x4* /*projectionMatrix*/, int /*blendMode*/, bool /*needsClear*/) override
    {
    }

    // Implementation of NodeEffectRenderer2D::restoreResourcesOverride.
    virtual void restoreResourcesOverride() override
    {
    }
};

NodeEffectRenderer2DUniquePtr EmptyEffect2D::createRendererOverride()
{
    return EmptyEffectRenderer2D::create(static_pointer_cast<EmptyEffect2D>(shared_from_this()));
}

For details, see the NodeEffect2D class in the Kanzi Engine API reference.