FT8xx的模版(Stencil)和OpenGL中的模版是一个概念,所以具体可以参考OpenGL中描述。下面是网上查找的一些关于模版的说明
首先解释一下什么是模版缓冲区(Stencil Buffer)。
模版缓冲区可以为屏幕上的每个像素点保存一个无符号整数值。这个值的具体意义视程序的具体应用而定。在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值。这个比较的过程被称为模版测试。如果模版测试通过,则相应的像素点更新,否则不更新。就像使用纸板和喷漆一样精确的混图一样,当启动模版测试时,通过模版测试的片段像素点会被替换到颜色缓冲区中,从而显示出来,未通过的则不会保存到颜色缓冲区中,从而达到了过滤的功能。下图描述了模版缓冲区的原理:
FT8xx的模版功能有3条指令相关:STENCIL_FUNC、STENCIL_MASK、STENCIL_OP。
【STENCIL_FUNC】
设定模版测试的功能及参考值。
参数
func: 指定测试功能,指定下列其中一项:NEVER, LESS, LEQUAL, GREATER,GEQUAL, EQUAL, NOTEQUAL或ALWAYS。初始值是ALWAYS。
NEVER |
从来不能通过 |
LESS |
小于参考值可以通过 |
LEQUAL |
小于或者等于可以通过 |
GREATER |
大于通过 |
GEQUAL |
大于等于通过 |
EQUAL |
等于通过 |
NOTEQUAL |
不等于通过 |
ALWAYS |
永远可以通过(默认值) |
ref: 参考值,初始值是0
mask: 掩码值(会与参考值和模版缓冲区内的值先作与操作,再参考func中的参数测试是否通过测试) ,初始值是255
【STENCIL_OP】
设定模版测试的动作
参数
sfail:指定模版测试失败后的动作。
spass: 指定模版测试通过后的动作。
2个参数都指定模版测试失败后的动作,采用下面所列的其中一种:
ZERO |
回零 |
KEEP |
不改变,默认值 |
REPLACE |
使用测试条件中的设定值来代替当前模版值 |
INCR |
增加1,但如果已经是最大值,则保持不变 |
DECR |
减少1,但如果已经是零,则保持不变 |
INVERT |
按位取反 |
【STENCIL_MASK】
控制在模版平面里个别bits的写入
参数
mask:用来启动写入模板bits的遮盖,初始值是255。
举例说明,画一个圆环(中心位置仍然保持背景的图案,背景采用Gradient例子的方式)
代码:
ftWrDispCmd(STENCIL_FUNC(NEVER, 0x00, 0x00));
ftWrDispCmd(STENCIL_OP(INCR, INCR));
ftWrDispCmd(BEGIN(FTPOINTS));
ftWrDispCmd(POINT_SIZE(80 * 16));
ftWrDispCmd(VERTEX2F((PANEL_WIDTH / 2) * 16, (PANEL_HEIGHT / 2) * 16));
ftWrDispCmd(STENCIL_FUNC(NOTEQUAL, 0x01, 0x01));
ftWrDispCmd(POINT_SIZE(90 * 16));
ftWrDispCmd(VERTEX2F((PANEL_WIDTH / 2) * 16, (PANEL_HEIGHT / 2) * 16));
1) 第一个STENCIL_FUNC和STENCIL_OP对后面画圆(蓝色代码部分)的影响是:STENCIL_FUNC的第一个参数NEVER是让圆的所有像素点因为模版值不通过测试而不显示,因为是NEVER,所以后面2个参数无意义(开始时模版值都是0)。STENCIL_OP的参数设为INCR则表示圆的所有像素点所在位置对应模版位置的模版值都加1变为1,而其他没有像素的地方所对应模版位置的模版值保持原值0不变。
如果没有接下来的语句,运行程序是看不到任何圆的显示,所以目前只是做个一个模版。
2) 第二个STENCIL_FUNC对后面画圆的影响是:STENCIL_FUNC的3个参数表示模版中的模版值与第三个参数0x01做与运算并且将结果与第二个参数比较,不相等的就通过(也就是变透明),相等的不通过(即不透明)。所以接下来画圆部分如果像素所在位置对应模版位置的模版值为1的话就不显示,如果为0的话则显示。
这里并没有第二个STENCIL_OP,还是之前的参数INCR,后面的模版仍然是按照第一个STENCIL_OP生成新的模版,下面用图画的方式解释一下模版的变化。
模版开始默认是全0,画了第一个圆后,画圆的地方模版的值变为1,即第二张图中的蓝色部分,画第二个圆时,可以想象中间的蓝色部分是一个挡板,然后喷漆一个大圆,这样就能喷出一个绿色部分的圆环了。
如果我们要在圆环上实现进度条的显示,可以将STENCIL_FUNC和STENCIL_OP设置如下:
ftWrDispCmd(STENCIL_FUNC(EQUAL, 0x01, 0x01));
ftWrDispCmd(STENCIL_OP(KEEP, KEEP));
当显示的图片在上图绿色圈部分时等于1,显示出来,其他位置不等于1则不显示。STENCIL_OP的参数都为KEEP,即模版不做改变。接下来的代码如下,在圆环上画POINT:
ftWrDispCmd(COLOR_RGB(246, 146, 30));
ftWrDispCmd(POINT_SIZE(10 * 16)); //1.5 * 16
for (degree = 0; degree < (gMenuParam.num / 10) * 10; degree += 10)
{
int16_t posX, posY;
posX = (PANEL_WIDTH / 2) * 16 + ((int32_t)170 * 16)* ftQcos((int32_t)degree * 65535 / 360) / 65536;
posY = (PANEL_HEIGHT / 2) * 16 + ((int32_t)170 * 16) * ftQsin((int32_t)degree * 65535 / 360) / 65536;
ftWrDispCmd(VERTEX2F(posX, posY));
}
定时做画点的动作,显示的效果如下: