Alpah-mask Adapter(alpha-mask 适配器)
Alpha-mask 是一个常用于在低层次(像素层次)上实现任意形状裁剪的独立buffer,它有一个专用的adapter类(alpha-mask adapter),通过使用alpha-mash过滤器来调用真实的像素渲染器。通常,alpha-mask是一个和主渲染buffer分辨率一样大的灰度buffer(每个像素一个字节),每个alpha-mask中的像素都是一个额外的像素覆盖值,用于和主像素混合。像copy_hline()这样没有覆盖值参数的函数调用,被转换成相应的带覆盖值参数的函数调用。比如说,copy_hline会取alpha-mask中的水平线段,然后调用blend_solid_hspan()。
以下是怎样声明带alpha-mask adapter的像素渲染器的例子:
#include "agg_pixfmt_rgb24.h"
#include "agg_pixfmt_amask_adaptor.h"
#include "agg_alpha_mask_u8.h"
//. . .
// Allocate the alpha-mask buffer, create the rendering buffer object
// and create the alpha-mask object.
//--------------------------------
agg::int8u* amask_buf = new agg::int8u[frame_width * frame_height];
agg::rendering_buffer amask_rbuf(amask_buf,
frame_width,
frame_height,
frame_width);
agg::amask_no_clip_gray8 amask(amask_rbuf);
// Create the alpha-mask adaptor attached to the alpha-mask object
// and the pixel format renderer. Here pixf is a previously
// created pixel format renderer of type agg::pixfmt_rgb24.
agg::pixfmt_amask_adaptor<agg::pixfmt_rgb24,
agg::amask_no_clip_gray8> pixf_amask(pixf, amask);
请注意这里我们使用了没有裁剪功能的amask_no_clip_gray8,这是因为我们使用的主渲染buffer和alpha-mask buffer分辨率是一样的,所以如果我们没有对主渲染buffer内存做违规操作(如内存越界),那么我们也不会对alpha-mask buffer做内存违规操作。在这种情况下,裁剪是在更高的层面上实现的。如果你的alpha mask buffer分辨率小于主渲染buffer,那么你必须得用alpha_mask_gray8。
以下是完整的例子:
#include <stdio.h>
#include <string.h>
#include "agg_pixfmt_rgb24.h"
#include "agg_pixfmt_amask_adaptor.h"
#include "agg_alpha_mask_u8.h"
enum
{
frame_width = 320,
frame_height = 200
};
// [...write_ppm is skipped...]
int main()
{
// Allocate the main rendering buffer and clear it, for now "manually",
// and create the rendering_buffer object and the pixel format renderer
//--------------------------------
agg::int8u* buffer = new agg::int8u[frame_width * frame_height * 3];
memset(buffer, 255, frame_width * frame_height * 3);
agg::rendering_buffer rbuf(buffer,
frame_width,
frame_height,
frame_width * 3);
agg::pixfmt_rgb24 pixf(rbuf);
// Allocate the alpha-mask buffer, create the rendering buffer object
// and create the alpha-mask object.
//--------------------------------
agg::int8u* amask_buf = new agg::int8u[frame_width * frame_height];
agg::rendering_buffer amask_rbuf(amask_buf,
frame_width,
frame_height,
frame_width);
agg::amask_no_clip_gray8 amask(amask_rbuf);
// Create the alpha-mask adaptor attached to the alpha-mask object
// and the pixel format renderer
agg::pixfmt_amask_adaptor<agg::pixfmt_rgb24,
agg::amask_no_clip_gray8> pixf_amask(pixf, amask);
// Draw something in the alpha-mask buffer.
// In this case we fill the buffer with a simple verical gradient
unsigned i;
for(i = 0; i < frame_height; ++i)
{
unsigned val = 255 * i / frame_height;
memset(amask_rbuf.row_ptr(i), val, frame_width);
}
// Draw the spectrum, write a .ppm and free memory
//----------------------
agg::rgba8 span[frame_width];
for(i = 0; i < frame_width; ++i)
{
agg::rgba c(380.0 + 400.0 * i / frame_width, 0.8);
span[i] = agg::rgba8(c);
}
for(i = 0; i < frame_height; ++i)
{
pixf_amask.blend_color_hspan(0, i, frame_width, span, 0);
}
write_ppm(buffer, frame_width, frame_height, "agg_test.ppm");
delete [] amask_buf;
delete [] buffer;
return 0;
}
下面是程序运行的结果:
请注意我们之前用白色来初始化了主渲染buffer,现在把这行代码
memset(buffer, 255, frame_width * frame_height * 3);
替换成
memset(buffer, 0, frame_width * frame_height * 3);
那么结果变成
也就是说alpha-mask作为一个独立的alpha通道与被渲染的图元混合,事实上alpha-mask的像素包含8位值(一个字节),这允许你以完美的反走样(抗锯齿)和任意形状裁剪所有的图形绘制。