Oh well. I tried to implement the stencil draw mode, but I have lots of troubles to get anything usefull output. What I get (my implementation), and what I get when I run test codes on the reference implementation differ a lot!


These are some tests, and I was able to break down the problem to a single pixel blend. Here are some colors:

[0.2, 0.4, 0.6, 1.0] -> Dest-Color (some nice blue)
[0.0, 1.0, 0.0, 1.0] -> Image-Color (Pure Green)
[0.0, 0.0, 0.0, 1.0] -> Paint Color (e.g. Black)

Note: All alpha values are 1, so it does not matter if we're talking about premultiplied colors or not (at least for now).

Now I take the equation from chapter 10.8 (the one that shows the stencil mode in combination with SRC_OVER). I leave out the division by AlphaTemp. it's 1 in any case, and the equations are already confusing enough.

For the case of a single color channel (in this case green):

Gdst = ((Aimg * Apaint * Gimg * Gpaint) + Adst * Gdst * (1- Aimg * Apaint * Gimg).

I plug in the constants (e.g. anything that does not change per channel, like dest-alpha and Paint Alpha ect:

Gdst = ((1 * 1 * Gimg * Gpaint) + 1 * Gdst * (1- 1*1* Gimg).

Simplify:

Gdst = ((Gimg * Gpaint) + Gdst * (1- Gimg).

So it will do simple linear interpolation between Paint-color and Dest-color based on the image color channel, at least for this simplified case, where all Alpha values are one.

If I apply this equations to the test colors I've listed above I ought to get:

[0, 0.4, 0, 1.0] -> Output-Color (some medium green)

However, the reference implementation gives me this color:

[0.2, 0.13, 0.6, 1.0]. That's a totally different result. Not even close..


Could anyone please help me and give a detailes answer what the stencil draw mode is supposed to do? For the reference, I also attached the test code I've used:

Code :
void printcolor (char * name, unsigned char * buffer)
{
  float r = buffer[3] / 255.0f;
  float g = buffer[2] / 255.0f;
  float b = buffer[1] / 255.0f;
  float a = buffer[0] / 255.0f;
  printf ("%s [%f, %f, %f, %f]\n", name, r,g,b,a);
}
 
 
void stenciltest2 (void)
{
  unsigned char buffer[4]; // to read back colors:
 
  VGuint testdata[] = { 
    0x00ff00ff // Full alpha Green
  };
 
  VGfloat clearColor[4] = {0.2,0.4,0.6,1};
 
  // Create the Image:
  VGImage stencil = vgCreateImage (VG_sRGBA_8888, 1,1, VG_IMAGE_QUALITY_NONANTIALIASED);
  vgImageSubData (stencil, testdata, 1, VG_sRGBA_8888, 0,0,1,1);
 
  // Create the Paint:
  VGImage paint = vgCreatePaint ();
  vgSetPaint (paint, VG_FILL_PATH);
  vgSetColor (paint, 0x000000ff); // Full alpha black:
 
  // set a known destination color:
  vgSetfv (VG_CLEAR_COLOR, 4, clearColor);
  vgClear (0,0,10,10);
 
  vgReadPixels  (buffer, 4, VG_sRGBA_8888_PRE, 0, 0, 1, 1);
  printcolor ("Destination = ", buffer);
 
  vgSeti (VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
  vgSeti (VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
  vgLoadIdentity();
  vgScale (10,10);
  vgSeti (VG_BLEND_MODE, VG_BLEND_SRC_OVER);
  vgDrawImage (stencil);
 
  vgReadPixels  (buffer, 4, VG_sRGBA_8888_PRE, 0, 0, 1, 1);
  printcolor ("Output  = ", buffer);
 
  vgDestroyImage (stencil);
  vgDestroyPaint (paint);
}