Blending HOWTO

From DirectFBWiki

Table of contents

Introduction


This document describes a simple step by step usage of the DirectFB API for alpha blending.


Alpha Blending


This section will give a very short overview of alpha blending, based on the Porter-Duff article.

The key concepts:

  1. A transparency value (alpha value) is stored with every pixel.
  2. When writing a pixel to an existing surface, the pixel can be merged in different ways with the existing pixel. For the purpose of this HowTo we will distinguish three methods:
    1. CLEAR
    2. SRC
    3. SRC_OVER
  3. For all compositing rules all pixel values must have the color components pre multiplied by the alpha value. This means that for an original rgb tuple Co=(r, g, b) with an alpha value of a (0.0 ≤ a ≤ 1.0), the pre multiplied pixel value is Cp=(r*a, g*a, b*a, a). Pre multiplying pixel values makes blending more efficient and is necessary for hardware acceleration.
  4. Extra Alpha

This is a “global” alpha value that can be used to influence all pixels in a blitting operation.

Compositing rules

The original pixel value Co, is expressed as Co=(ro, go, bo, a). The pre multiplied value is expressed as Cp=( ro*a, go*a, bo*a, a), extra alpha is Aextra.

All pixel values used below are assumed to be pre multiplied.

Cd = “destination pixel value” Cs = “source pixel value” Ad = “destination alpha value” As = “source alpha value” If “extraAlpha” is used all alpha values are multiplied with Aextra, i.e.

As’ = As *Aextra

CLEAR

Clear the destination pixel

Cd = Cs * 0.0 + Cd * 0.0 = (0, 0, 0, 0)

SRC

Overwrite the destination pixel with the source pixel.

Cd = Cs * 1.0 + Cd * 0.0 = Cs

SRC_OVER

Blend the destination pixel with the source pixel as follows:

Cd = Cs * 1.0 + Cd * (1-As)

DirectFB

In the example below all pixel values being used as colors are already pre multiplied, hence the use of the flag DSCAPS_PREMULTIPLIED and the lack of the blitting flag DSBLIT_[SRC|DST]_PREMULTIPLY. If you were to use this last flag, DirectFB will do the multiplication for you.

The flag DSCAPS_PREMULTIPLIED is only used when the window stacking is being repainted by DirectFB. It is a hint to the system that the values are already pre multiplied.

If you want to use “extraAlpha”, you need to set up the blitting flags to do this for you, i.e. add the flag DSBLIT_SRC_PREMULTCOLOR.

Setting up the primary surface

DFBCHECK(DirectFBInit( &argc, &argv ));

/* create the super interface */
DFBCHECK(DirectFBCreate( &dfb ));

/* set our cooperative level to DFSCL_FULLSCREEN
for exclusive access to the primary layer */
dfb->SetCooperativeLevel( dfb, DFSCL_FULLSCREEN );


/* get the primary surface, i.e. the surface of the
primary layer we have exclusive access to */
sdsc.flags = DSDESC_CAPS;
sdsc.caps = DSCAPS_PRIMARY | DSCAPS_PREMULTIPLIED;

DFBCHECK(dfb->CreateSurface( dfb, &sdsc, &primary ));


Performing a drawing operation

Perform a drawing operation with pre-multiplied colors in SetColor()

// blend
primary->SetDrawingFlags(primary, DSDRAW_BLEND);
// specify porter duff rule, this will setup the drawing functions
// for you, you can also set them directly using 
// Set[Src|Dst]BlendFunction()
primary->SetPorterDuff(primary, DSPD_SRC);
// Red, semi-transparent (r,g,b,a) pre multiplied, thus the original
// pixel value would be (0xFF, 0x0, 0x0, 0x80)
primary->SetColor(primary, 0x80, 0x0, 0x0, 0x80); 
primary->DrawLine(primary, 10, 10, 300, 200);

Perform a drawing operation with non-pre-multiplied colors in SetColor()

Changes:

1. Specify DSDRAW_SRC_PREMULTIPLY as the drawingflag
   primary->SetDrawingFlags(primary, DSDRAW_SRC_PREMULTIPLY);
2. Use a non-premultiplied color
   primary->SetColor(primary, 0xFF, 0x0, 0x0, 0x80);

Performing a blit operation

Setup a new surface that will be blitted to the primary surface.

/* create a surface */
sdsc.flags = DSDESC_CAPS | DSDESC_PIXELFORMAT | DSDESC_WIDTH | 
DSDESC_HEIGHT;
sdsc.caps = DSCAPS_PREMULTIPLIED;
sdsc.pixelformat = DSPF_ARGB;
sdsc.width = screen_width;
sdsc.height = screen_height;

DFBCHECK(dfb->CreateSurface( dfb, &sdsc, &blitsurf ));


primary->SetDrawingFlags(primary, DSDRAW_BLEND);
// Porter Duff
blitsurf->SetPorterDuff(blitsurf, DSPD_SRC_OVER);

// Draw a rectangle in the blit surface, blue semi-transparent.
// (a,r,g,b) pre multiplied. thus the original
// pixel value would be (0x80, 0x0, 0x0, 0xFF)
blitsurf->SetColor(blitsurf, 0x80, 0x0, 0x0, 0x80);
blitsurf->FillRectangle(blitsurf, 10, 10, 200, 300);

// The alpha value of the color set with SetColor() will be used for 
// the “extraAlpha”. ExtraAlpha is a global alpha value applied to 
// all pixels when blitting. To use this add ‘DSBLIT_SRC_PREMULTCOLOR’ 
// to the blitting flags.
primary->SetBlittingFlags(blitsurf, DSBLIT_BLEND_ALPHACHANNEL);

// Now blit it to the primary surface
primary->Blit(primary, blitsurf, NULL, 15, 15);

--Marc 20:49, 30 Jun 2006 (CEST)