I’ve seen that reference implementation has a “strange” behavior in several cases, different from the one specified in the official OpenVG 1.0 specification document.
Here are two of them:
- Src, SrcIn, DstIn blend modes coupled with alpha masking.
The example below shows a path filled with a red color (r=1, g=0, b=0, a=1) and alpha masking enabled. First drawing surface has been cleared with a black color (r=0, g=0, b=0, a=1) and is in the non-linear premultiplied format, then path is drawn using a Src blend mode.
Image used as alpha mask is totally filled with alpha value equal to 102 (0.4 in the range [0; 1]).
So according to specifications:
“The mask alpha values are multiplied by the corresponding alpha values of each primitive being drawn in the clipping and masking stage (stage 5) of the rendering pipeline (see Section 2.5). The masking step is equivalent to replacing the source image with the result of the Porter-Duff operation “Src in Mask” (see Section 12.2).”
So the final color must be:
Dca’ = Sca * alphaMask -> (r = 1 * 1 * 0.4, g = 0 * 1 * 0.4, b = 0 * 1 * 0.4) -> (r = 0.4, g = 0, b = 0)
Da’ = Sa * alphaMask -> (a = 1 * 0.4) -> (a = 0.4)
It seems that reference produces a correct result only for Dca’, and a wrong result for Da’.
A similar behavior can be seen for SrcIn and DstIn blend modes coupled with alpha masking.
Others blend modes seem ok.
vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER);
vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_BETTER);
vgSeti(VG_SCISSORING, VG_FALSE);
col[0] = 0.0f;
col[1] = 0.0f;
col[2] = 0.0f;
col[3] = 1.0f;
vgSetfv(VG_CLEAR_COLOR, 4, col);
vgClear(0, 0, 256, 256);
// create image and load external data
imgSrc = vgCreateImage(VG_lRGBA_8888, imgAlphaWidth, imgAlphaHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
vgImageSubData(imgSrc, (const void *)&imgAlphaData[imgAlphaWidth * (imgAlphaHeight - 1)], -imgAlphaDataStride, imgAlphaFormat, 0, 0, imgAlphaWidth, imgAlphaHeight);
vgMask(imgSrc, VG_SET_MASK, 0, 0, 256, 256);
vgSeti(VG_MASKING, VG_TRUE);
// create a path
path0 = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
pathSegs[0] = VG_MOVE_TO_ABS;
pathData[0] = -20.0f;
pathData[1] = 20.0f;
pathSegs[1] = VG_CUBIC_TO_ABS;
pathData[2] = -200.0f;
pathData[3] = 170.0f;
pathData[4] = -200.0f;
pathData[5] = -170.0f;
pathData[6] = -20.0f;
pathData[7] = -20.0f;
pathSegs[2] = VG_CUBIC_TO_ABS;
pathData[8] = -170.0f;
pathData[9] = -200.0f;
pathData[10] = 170.0f;
pathData[11] = -200.0f;
pathData[12] = 20.0f;
pathData[13] = -20.0f;
pathSegs[3] = VG_CUBIC_TO_ABS;
pathData[14] = 200.0f;
pathData[15] = -170.0f;
pathData[16] = 200.0f;
pathData[17] = 170.0f;
pathData[18] = 20.0f;
pathData[19] = 20.0f;
pathSegs[4] = VG_CUBIC_TO_ABS;
pathData[20] = 170.0f;
pathData[21] = 200.0f;
pathData[22] = -170.0f;
pathData[23] = 200.0f;
pathData[24] = -20.0f;
pathData[25] = 20.0f;
pathSegs[5] = VG_CLOSE_PATH;
vgAppendPathData(path0, 6, pathSegs, pathData);
// create and set a paint for fill
fillPaint = vgCreatePaint();
col[0] = 1.0f;
col[1] = 0.0f;
col[2] = 0.0f;
col[3] = 1.0f;
vgSetParameterfv(fillPaint, VG_PAINT_COLOR, 4, col);
vgSetParameteri(fillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
vgSetPaint(fillPaint, VG_FILL_PATH);
vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
vgLoadIdentity();
vgTranslate(128.0f, 128.0f);
vgScale(0.8f, 0.8f);
vgDrawPath(path0, VG_FILL_PATH);
eglSwapBuffers(display, surface);
vgDestroyImage(imgSrc);
vgDestroyPath(path0);
vgDestroyPaint(fillPaint);
To see the produced results and the used alpha image, please follow these urls (please, use a webbrowser that supports PNG transparency):
http://www.amanithvg.com/pub_files/repo … nithvg.png
http://www.amanithvg.com/pub_files/repo … erence.png
http://www.amanithvg.com/pub_files/repo … a_mask.png
- Color ramp interpolation.
Interpolating premultiplied color stops is not equal, nor correct, to produce premultiplied colors from the interpolation output.
The example below shows a linear gradient made of three stops in the format (t, r, g, b, a):
(0.0, 1.0, 1.0, 1.0, 1.0) - (0.5, 0.0, 1.0, 1.0, 0.0) - (1.0, 1.0, 1.0, 1.0, 1.0).
// initial settings and clear the screen
vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER);
vgSeti(VG_SCISSORING, VG_FALSE);
vgSeti(VG_MASKING, VG_FALSE);
col[0] = 0.0f;
col[1] = 0.0f;
col[2] = 0.0f;
col[3] = 1.0f;
vgSetfv(VG_CLEAR_COLOR, 4, col);
vgClear(0, 0, 256, 256);
// create a path
path0 = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
pathSegs[0] = VG_MOVE_TO_ABS;
pathData[0] = -20.0f;
pathData[1] = 20.0f;
pathSegs[1] = VG_CUBIC_TO_ABS;
pathData[2] = -200.0f;
pathData[3] = 170.0f;
pathData[4] = -200.0f;
pathData[5] = -170.0f;
pathData[6] = -20.0f;
pathData[7] = -20.0f;
pathSegs[2] = VG_CUBIC_TO_ABS;
pathData[8] = -170.0f;
pathData[9] = -200.0f;
pathData[10] = 170.0f;
pathData[11] = -200.0f;
pathData[12] = 20.0f;
pathData[13] = -20.0f;
pathSegs[3] = VG_CUBIC_TO_ABS;
pathData[14] = 200.0f;
pathData[15] = -170.0f;
pathData[16] = 200.0f;
pathData[17] = 170.0f;
pathData[18] = 20.0f;
pathData[19] = 20.0f;
pathSegs[4] = VG_CUBIC_TO_ABS;
pathData[20] = 170.0f;
pathData[21] = 200.0f;
pathData[22] = -170.0f;
pathData[23] = 200.0f;
pathData[24] = -20.0f;
pathData[25] = 20.0f;
pathSegs[5] = VG_CLOSE_PATH;
vgAppendPathData(path0, 6, pathSegs, pathData);
// create and set a paint for fill
fillPaint = vgCreatePaint();
colStops[0] = 0.0f;
colStops[1] = 1.0f;
colStops[2] = 1.0f;
colStops[3] = 1.0f;
colStops[4] = 1.0f;
colStops[5] = 0.5f;
colStops[6] = 0.0f;
colStops[7] = 1.0f;
colStops[8] = 1.0f;
colStops[9] = 0.0f;
colStops[10] = 1.0f;
colStops[11] = 1.0f;
colStops[12] = 1.0f;
colStops[13] = 1.0f;
colStops[14] = 1.0f;
linGrad[0] = -150.0f;
linGrad[1] = 0.0f;
linGrad[2] = 150.0f;
linGrad[3] = 0.0f;
vgSetParameteri(fillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
vgSetParameteri(fillPaint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
vgSetParameterfv(fillPaint, VG_PAINT_COLOR_RAMP_STOPS, 15, colStops);
vgSetParameterfv(fillPaint, VG_PAINT_LINEAR_GRADIENT, 4, linGrad);
vgSetPaint(fillPaint, VG_FILL_PATH);
vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
vgLoadIdentity();
vgTranslate(128.0f, 128.0f);
vgScale(0.8f, 0.8f);
vgRotate(45.0f);
vgDrawPath(path0, VG_FILL_PATH);
eglSwapBuffers(display, surface);
vgDestroyPath(path0);
vgDestroyPaint(fillPaint);
To see the produced results, please refer to AmanithVG site:
http://www.amanithvg.com/performance.html