iPlug2 Forum

Bitmaps with RGB tints - via IBlend?

I want to extend the graphics framework for RGB tinting of bitmaps. This way a bitmap can be made brighter/darker, or tinted eg. red.

Any reasons why that wont work? NanoVG at least supports it via imgPaint.innerColor / outerColor (haven’t tried other backends yet).

We could extend the DrawBitmap() calls. But how about adding RGB scales to IBlend instead? That way no call defs need to change (its also backwards compatible) and may be useful in non-bitmap places?

struct IBlend
{
  EBlend mMethod;
  float mWeight;

  float mRscale, mBscale, mGscale;

      IBlend(EBlend type = EBlend::Default, float weight = 1.0f,
             float r_scale = 1.f, float g_scale = 1.f, float b_scale = 1.f)
      : mMethod(type)
      , mWeight(Clip(weight, 0.f, 1.f))
      , mRscale(r_scale)
      , mGscale(g_scale)
      , mBscale(b_scale)
        {}
    };

We prefer it if changes can be applied to all backends - and I’m not aware that this is the case for blending in general, so I think this is unlikely to be viable, unfortunately.

Can you be more specific about what you want to achieve and why? If it is limited to bitmaps there might be other ways to achieve it.

Simple example, I want to change the brightness of a bitmap based control. Maybe to fade it out/in, maybe to overrbrighten or pulse it, or tint it red (say) when it’s clicked) etc. That makes bitmaps way more flexible (you can often re-use a single image for various effects).

I’m already doing it in NanoVG, do the other backends not support an RGB multiplication with a bitmap?

This is the kind of thing I’m doing with it. The meter lights are just 3 bitmaps * RGB animation:

meter2

It depends what you mean - the other vector backends would all support a multiply operation as a composite operation (there isn’t one in IBlend at the moment) but actually NanoVG doesn’t have one - the list of composite methods in NanoVG is much shorter than Cairo/skia/AGG/canvas - see NVGcompositeOperation). Therefore, the other backends could be made to allow a multiply overlay very easily, but NanoVG wouldn’t support that in the same way.

It’s also not clear to me if you are wishing to multiply with values above one, which I think wouldn’t be possible with a multiply operation in most graphics backends.

What I mean (and what NanoVG currently supports) is this GPU shader pseudocode:

float4 bitmap_rgba = <load bitmap>;
float4 tint_rgba   = <load tint constant>;

return bitmap_colour * tint_colour;

In other words, the bitmap colour is directly multiplied with a constant RGB colour (rather than composited via framebuffer blending). This is trivial and efficient in a shader, and what NanoVG already allows (below): Even the pre-shader Direct3D supported a colour constant that could be applied in its old-fashioned pixel pipeline.

NanoVG allows this RGB(A) constant via imgPaint.innerColor / outerColor. The code usually only supplies the blending weight (as the alpha value), but I just populate the RGB fields:

void IGraphicsNanoVG::DrawBitmap(const IBitmap& bitmap, const IRECT& dest, int srcX, int srcY, const IBlend* pBlend)

<snip>

imgPaint.innerColor = imgPaint.outerColor = nvgRGBAf(pBlend->mRscale, pBlend->mGscale, pBlend->mBscale, BlendWeight(pBlend));

I guess as NanoVG is shader-based this is easy. Can you do something similar with the other backends? I took a quick look but it wasn’t immediately obvious.

… and yes to values above one. Easy via shader (which doesn’t clip inputs unless you code it that way).

I believe the Skia backend supports shaders? If there’s no existing solution that would be another option.

(I just tested Skia and found it slow to render - I wonder if custom shaders would speed things up).

Depends what you are doing how the speeds will work out on different backends (plus platform).

As fas as I can see there is no generic way of doing this on all backends that will be fast (not all backends support shaders - even skia can be run on the CPU). For backends without shaders it’d have to be done in software on a bitmap, and thee’s not support for that on master without coding for each backend separately. The fact that the multipliers can be greater than 1 is the most problematic, as it means it can’t be done with composite operations, which will clip the input colours.