4

I'm using the Delphi library Graphics32 to draw an audio graphic on the screen, and then represent a series of periods in the audio.

The graph is quite simple: a black background, with the audio waveform filled with a light gray color.

The periods right now are rectangles drawn using FillRectTS with a semitransparent color. I am looking for a way (hopefully a simple one) to draw this using a blend mode like Multiply, so the audio waveform is the one who gets the color, and the background remains black. I haven't found any function in the TBitmap32 class (nor, for instance, the g32_Interface unit) that allows me to do this.

This needs to be done after the audio waveform is painted, as redrawing this on-demand is very time-expensive, and the periods are user-defined on runtime, so drawing the audio waveform directly with the colors is not possible.

Here is a little example of how is it, and how I would like it:

Example graphic

The code right now that draws the periods, the aspect I need to change, is the following:

TColor32 ColorDibujado = Color == 0 ? GetColorDeTipoEvento(PeriodoADibujar->Evento->TipoEvento) : Color;

if (PeriodoADibujar->Habilitado == false)
  ColorDibujado = (ColorDibujado & 0x00ffffff) | 0xAf000000;

Gr32::TRect area;

area.Left   = (PeriodoADibujar->PosicionInicioRelativa * (double)LimitesDestino.Width()) / Proporcion + PosX;
area.Right  = (PeriodoADibujar->PosicionFinRelativa * (double)LimitesDestino.Width()) / Proporcion + PosX;
area.Top    = LimitesDestino.Top;
area.Bottom = LimitesDestino.Bottom;

MapaDestino->FillRectTS(area, ColorDibujado);

ColorDibujado get's the transparency needed depending on different conditions (if the event is selected or not, and the type of event), but the idea at the end is the same. This code draws like the first part of the graphic above.

Solutions (or ideas) in Delphi or C++Builder are fine by me.

Update

I have implemented this directly on the Graphics32 code, using any of the color blend routines it already provides, and it solves my needs. It's an extra set of FillRect functions that takes another parameter for the blend mode to use. I will try to get this into the official project, if it's still alive...

Rodrigo Gómez
  • 1,059
  • 7
  • 22
  • What is your code so far? – EProgrammerNotFound Mar 14 '15 at 02:14
  • @EProgrammerNotFound I will add it, although the part that I need to change is quite simple: it's just a call to FillRectTS – Rodrigo Gómez Mar 14 '15 at 02:15
  • I am going to remove the Delph tag – EProgrammerNotFound Mar 14 '15 at 02:27
  • @EProgrammerNotFound Why? I don't care if somebody posts a solution or some ideas in Delphi, I can easily translate. At the end, the library is Delphi based (and there are much more users in Delphi than in C++Builder) - in a way, I didn't post code originally because this is, in my point of view, code-agnostic. The important call is FillRectTS, and that call is the same for Delphi than C++Builder. – Rodrigo Gómez Mar 14 '15 at 02:28

2 Answers2

2

I added the following code to the Graphics32 sources, so I can fill the required Rect using one of the several blend modes that the library provides:

TBlendMode = (bmAdd, bmSub, bmDiv, bmMod, bmMax, bmMin, bmDif, bmAvg, bmExc, bmSca);

procedure TCustomBitmap32.FillRectTB(X1, Y1, X2, Y2: Integer; Value: TColor32; BlendMode: TBlendMode);
var
  i, j: Integer;
  P: PColor32;
  blend: TBlendReg;
begin

  case BlendMode of
    bmAdd: blend := ColorAdd;
    bmSub: blend := ColorSub;
    bmDiv: blend := ColorDiv;
    bmMod: blend := ColorModulate;
    bmMax: blend := ColorMax;
    bmMin: blend := ColorMin;
    bmDif: blend := ColorDifference;
    bmAvg: blend := ColorAverage;
    bmExc: blend := ColorExclusion;
    bmSca: blend := ColorScale;
    else blend := MergeReg;
  end;

  try
    Dec(Y2);
    Dec(X2);
    for j := Y1 to Y2 do
    begin
      P := GetPixelPtr(X1, j);
      for i := X1 to X2 do
      begin
        P^ := blend(Value, P^);
        Inc(P);
      end;
    end;
  finally
    EMMS;
    Changed(MakeRect(X1, Y1, X2 + 1, Y2 + 1));
  end;
end;

There are also

procedure FillRectTSB(X1, Y1, X2, Y2: Integer; Value: TColor32; BlendMode: TBlendMode); overload;
procedure FillRectSB(const ARect: TRect; Value: TColor32; BlendMode: TBlendMode); overload;
procedure FillRectTSB(const ARect: TRect; Value: TColor32; BlendMode: TBlendMode); overload;

Which are a copy of the ones provided by the Library, but internally call the new FillRectTB procedure. I will get this code into the library maintainers, so it can be incorporated in the official sources, if it makes sense for them.

It doesn't appear to be that easy to get the code into the official library, so I'm attaching here the full patch, in case somebody else finds this usefull.

Link to patch file

I also posted this into the Graphics32.general newsgroup, so it doesn't get lost.

Rodrigo Gómez
  • 1,059
  • 7
  • 22
1

What I would do in your place is split your waveform display into two seperate layers. One layer will be used for background and another for foreground. Why?

By doing this you can resuse your existing code. Just do it in two seperate steps. One for bacground and one for foreground.

But another probably better appraoch would be to simply render the selection using different colors as Cool ditor Pro does.

This way you can get rid of the alpha rendering compleetly which should increase the rendering performance considerably.

Waveform selecion in Cool Editor Pro

SilverWarior
  • 5,651
  • 2
  • 13
  • 19
  • Thanks for your reply. I actually have something like what you mention, but without using layers. I have a buffer with the whole audio waveform (usually 24 hours of audio), and when a redraw is needed, I paint the required section on the display, and later apply the selections and events. That's where I want to do something like blending, not just alpha rendering. I can't redraw the audio on-demand as it is a very time intensive task, and doing it everytime I need to redraw is just not viable. I will study the Layer options, maybe something there can work. – Rodrigo Gómez Mar 14 '15 at 17:01
  • How about generating bitmask from your selection and then using that bitmask for replacing color in your selection. I'm not verry good with Graphics32 but you would use such approach on standard canvas when the use of flod-fill won't do the trick (non conected image parts). – SilverWarior Mar 14 '15 at 18:03
  • I think I'm going to modify the Graphics32 code to provide a way to use one of the [already included] functions to blend colors. I was wondering if there was a way to do this out of the box, being that they do provide the Multiply/Modulate color functions, but so far I haven't found a way to do this, but implementing it shouldn't be so difficult. I already have a more-or-less working version in my own code, just need to port it to Delphi and move it to the Graphics32 unit. – Rodrigo Gómez Mar 14 '15 at 19:06