Skip to content
This repository has been archived by the owner on Aug 6, 2021. It is now read-only.

Implementing an own brush

DarthAffe edited this page Jan 15, 2017 · 6 revisions

Implementing an own brush is done by implementing the IBrush-Interface, but since a lot of logic regarding effects and general configuration is the same for all brushes you should always start by deriving from AbstractBrush.

You should always start by deriving from AbstractBrush! If you don't do this you'll have to make sure to take care of the logic regarding effects and rendering.

Starting here, there are two ways to create your own logic.

No mather what way you choose, you should always take a look at the CUE.NET.Helper-namespace! It contains a few helpers with quite some useful methods.

The simple way

This should be the preferred way for almost every case since it's possible to achieve nearly everything without much effort. Every basic-brush shipped with CUE.NET is implemented this way.

You start by simply deriving from AbstractBrush and implement the GetColorAtPoint-Method which should contain the logic your brush needs to decide which color goes where. The easiest example here is the SolidColorBrush. It stores a color-property containing the color which is simply returned on every call to GetColorAtPoint, coloring the whole region in a single color.

public class SolidColorBrush : AbstractBrush
{
    public CorsairColor Color { get; set; }

    protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
    {
        return Color;
    }
}

As you can see the SolidColorBrush doesn't care about what key or rectangle is rendered and therefore just ignores the passed parameters.
In most cases we want to draw something though, so we need to calculate our color from the given information. A good example here is the LinearGradientBrush.

protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
    if (Gradient == null) return CorsairColor.Transparent;

    PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height);
    PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height);
    
    float offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, renderTarget.Point); 
    return Gradient.GetColor(offset);
}

First it uses the size of the provided rectangle to calculate a start- and end-point for the gradient. After wards it using the Point (which reflects the center of the requested key) provided by the renderTarget to calculate the offset which is finally used to return the color on the gradient.
Note that you can not only get the point of the renderTarget but also the whole rectangle representing the key and the Id of the key.

The advanced way

To understand what writing an advanced brush means, you need to know how brushes are processed.
In CUE.NET brushes perform two passes.

  1. The render-pass
    This is initiated by calling the PerformRender-Method. This method calculates the color for every requested LED by calling GetColorAtPoint (we know that one from the simple way) for every single one and builds up a list of processed BrushRenderTargets.
  2. The finalize-pass
    This is initiated by calling the PerformFinalize-Method. This method is calling FinalizeColor for every BrushRenderTargets in the list created in the render-pass.
    The FinalizeColor-Method applies brush-wide modifications (color-correction, brightness and opacity) to every processed color.

All four of this methods can be overwritten to hook deeper into that process.

You should prefer to always call the base-method after your logic when overwriting one of the virtual methods if possible. If not you need to take care of doing logically the same as the original method or you might get unexpected behaviors.

An example of such an advanced brush can be found in the ambilight-example.
It overwrites PerformRender and FinalizeColor.

PerformRender is used to create some data needed by every GetcolorAtPointCall and is therefore calculated before the rendering for performance reasons. At the end the original render-sequence is initiated by the 'base.PerformRender'-call.

FinalizeColor is overwritten to replace the original color-correction-logic with one that works better with the settings passed to the brush. This is a use-case-specific implementation to reduce overhead. The rest of the code is just a copy from the base-method since it should behave the same except the color-correction part.

Clone this wiki locally