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- 11 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:
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]
", 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);
}