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位值(一個字節),這允許你以完美的反走樣(抗鋸齒)和任意形狀裁剪所有的圖形繪製。