以下文章来源于嵌入式小书虫 ,作者FledgingSu 支离苏
前两篇我们讲完了Arm-2D Tile的用法,有了Tile与子Tile的思想,我们也玩一下Arm-2D的高级功能rotation(旋转)和抗锯齿。
说到旋转,我首先就想到了仪表指针的旋转,好那我们就用Arm-2D制作一个自己的智能手表,并给他开启美颜功能。
啥,还有美颜。
对啊,Arm-2D的旋转函数为我们提供了抠图功能(masking)、半透明显示的透明度功能(Opacity),最重要的还提供了抗锯齿功能,这3大功能用好了可不就相当于开启美颜了。
我们要实现的智能手表效果如下图所示:
【旋转接口函数简介】
好,那我们先看看Arm-2D旋转的接口函数,如下
arm_2dp_rgb565_tile_rotation( (arm_2d_op_rotate_t *)&(_->tOP),
ptItem->ptTile, //!< source tile
ptTile, //!< target tile
&(ptItem->tRegion), //!< target region
ptItem->tCentre, //!< center point
ptItem->fAngle, //!< rotation angle
GLCD_COLOR_BLACK, //!< masking colour
ptItem->ptTargetCentre);
- 第1个参数tOP是Arm-2D自己用的,我们不用管
- 第2个参数source Tile就是我们要旋转的表针(Tile)
如下图所示:
- 第3个参数为target Tile(即把source Tile贴到哪)
- 第4个参数target region就是表针旋转之后要显示到目标Tile的哪个区域,如下图所示:
- 注意:这个target region的作用是规定旋转后的图片贴到目标Tile的什么位置(超出部分会被裁剪掉)
有了target Tile和source Tile,那就该设置旋转中心了,即设置第5个参数center point和最后一个参数ptTargetCentre,如下图所示:
- (11,49)为center point,注意:不一定是source Tile中心点哦。
- 注意:ptTargetCentre为NULL时,默认就是目标区域的中心点,ptTargetCentre也可以指定 为目标区域的任意一个坐标点,还是很灵活的。
设置好之后如下图:
- 怎么回事?明明一个旋转中心,怎么设置了两个点。
哈哈哈,这就是Arm-2D设计的优点,你可以把source Tile和target Tile想象成两个纸片,旋转就好比是用一个图钉把两个纸片钉在一起,然后source Tile绕着图钉在 target Tile上旋转。此时,当图钉穿过source Tile和target Tile的时候,会在两个纸片上分别留下一个洞——这个洞就是source Tile和target Tile上各自的旋转圆心。
- 其实有这两个旋转圆心也就确定了source Tile在target Tile上的初始位置(即旋转0度角的位置)。
接下来就该旋转了,即设置旋转角度rotation angle,也就是第6个参数,如下图:
- 第6个参数rotation angle为float类型,且单位为弧度,大家记得把角度转换成弧度哦。
第7个参数masking colour就是大名鼎鼎的抠图功能,
Arm-2D的抠图功能,
是不是觉得很厉害,可以指定一种颜色不显示,如下图所示:
- masking color设置为黑色,也就是source Tile中的黑色都不会被显示出来。
如果你觉得masking color的美颜效果还不够好,Arm-2D还给我们提供了透明度的效果,接口函数如下:
arm_2dp_rgb565_tile_rotation_with_alpha(&(ptItem->tOP),
ptItem->ptTile, //!< source tile
ptTile, //!< target tile
&(ptItem->tRegion), //!< target region
ptItem->tCentre, //!< center point
ptItem->fAngle, //!< rotation angle
GLCD_COLOR_BLACK, //!< masking colour
ptItem->chOpacity, //!< Opacity
ptItem->ptTargetCentre);
- 第8行多了一个Opacity(不透明度)参数,注意是不透明度,取值范围是0~255,也就是0为全透明,255为不透明。
其实,旋转最主要的还是锯齿问题,那Arm-2D有提供抗锯齿吗?
答案是肯定的,
而且开启抗锯齿还很简单,只需要设置一个宏开关,如下
#define __ARM_2D_HAS_INTERPOLATION_ROTATION__ 1
- 注意:开启抗锯齿对单片机的算力还是有一定的要求,建议M4及以上的单片机开启抗锯齿,否则速度会很慢。
【程序实现】
现在我们就用Arm-2D实现我们的智能手表。
首先背景要制作一个好看的图片,如下
arm_2d_rgb16_tile_copy( &c_tilebackground,
ptTile,
&tBox,
ARM_2D_CP_MODE_COPY);
- 用Tile copy显示一张背景图片。
接下来就该使用旋转函数进行表针旋转了,我们先定义一个结构体,存放要给旋转函数传的参数,如下:
typedef struct {
arm_2d_op_rotate_opacity_t tOP;
const arm_2d_tile_t *ptTile;//source Tile
float fAngle;//旋转角度
float fAngleSpeed;//旋转速度
arm_2d_location_t tCentre;//source Tile的圆心
arm_2d_location_t *ptTargetCentre;//Target Tile的圆心
arm_2d_region_t tRegion;//旋转区域
uint8_t chOpacity;//不透明度
} rotation_watch_hand_t;
接下来用这个结构体类型定义一个数组,包含3个元素,即时针、分针、秒针,我以时针为例,如下:
static rotation_watch_hand_t s_tGears[] = {
{
//source Tile
.ptTile = &c_tilePointerhour,
//旋转速度
.fAngleSpeed = 0.1f/60.f,
//source Tile的圆心
.tCentre = {
.iX = 11,
.iY = 49,
},
//旋转区域
.tRegion = {
.tLocation = {
.iX = 23,
.iY = 30,
},
.tSize = {
.iWidth = 200,
.iHeight = 200,
},
},
#if 0 /*! a demo shows how to specifiy the centre of rotation on the target tile */
.ptTargetCentre = (arm_2d_location_t []){
{
.iX = ((APP_SCREEN_WIDTH - 41) >> 1) + 60,
.iY = ((APP_SCREEN_HEIGHT - 41) >>1) + 60,
},
},
#endif
//不透明度
.chOpacity = 205,
},
};
- 注意23~30行,我们没有设置Target Tile的圆心,默认为旋转区域的中心。也可以指定(iX,iY)的值设定Target Tile的圆心。
好了,旋转就很简单了,直接调用函数就可以了,如下:
void watch_hand_rotation(const arm_2d_tile_t *ptTile, bool bIsNewFrame)
{
/*! for each item (ptItem) inside array s_tGears */
arm_foreach (demo_gears_t, s_tGears, ptItem) {
//更新旋转角度
if (bIsNewFrame) {
//角度要转换成弧度
ptItem->fAngle += ARM_2D_ANGLE(ptItem->fAngleSpeed);
||角度取模,防止超出范围
ptItem->fAngle = fmodf(ptItem->fAngle,ARM_2D_ANGLE(360));
}
if (255 == ptItem->chOpacity) {
//旋转不加透明度
arm_2dp_rgb565_tile_rotation((arm_2d_op_rotate_t *)&(ptItem->tOP),
ptItem->ptTile, //!< source tile
ptTile, //!< target tile
&(ptItem->tRegion), //!< target region
ptItem->tCentre, //!< center point
ptItem->fAngle, //!< rotation angle
GLCD_COLOR_BLACK, //!< masking colour
ptItem->ptTargetCentre);
} else {
//旋转加透明度
arm_2dp_rgb565_tile_rotation_with_alpha(
&(ptItem->tOP),
ptItem->ptTile, //!< source tile
ptTile, //!< target tile
&(ptItem->tRegion), //!< target region
ptItem->tCentre, //!< center point
ptItem->fAngle, //!< rotation angle
GLCD_COLOR_BLACK,//GLCD_COLOR_BLACK, //!< masking colour
ptItem->chOpacity, //!< Opacity
ptItem->ptTargetCentre);
}
}
}
- arm_foreach()为封装了for循环的宏函数。
- ARM_2D_ANGLE()为角度转弧度的宏函数
- 到这里我们就制作好了一个智能手表的显示界面,是不是感觉用Arm-2D很简单。
如果你觉得还不够美观,还可以做一个圆形的表盘,用半透明的颜色填充(比如50%的白色),程序如下:
arm_2d_region_t tBox = {.tLocation = {23,30},.tSize = {200, 200},};
arm_2d_rgb565_fill_colour_with_mask_and_opacity(
ptTile,
&tBox,
&c_tileCircleMask,
(arm_2d_color_rgb565_t){GLCD_COLOR_WHITE},
128 );
效果如下图
素材制作也可以参考这篇文章,如下
【例说Arm-2D界面设计】做剪影风也太简单了
备注:本程序参考官方demo修改而来,感兴趣的也可以看看官方提供的demo例程,地址如下:
官方Arm-2D开源地址如下:
https://github.com/ARM-software/EndpointAI
参考demo《examples[pico]watch_panel[pfb]》
【说在后面的话】
表针的旋转在仪器仪表界面中还是很常用的,Arm-2D为我们提供的旋转功能还是非常实用的,相信大家通过上面的讲解已经会用Arm-2D的旋转功能了,使用时需要有几点注意,大家也已经Get到了,总结如下:
目标区域(target region)的作用是规定旋转后的图片贴到目标Tile的什么位置(超出部分会被裁剪掉)
目标圆心(ptTargetCentre)为NULL时,默认就是目标区域的中心点,ptTargetCentre也可以指定为目标区域的任意一个坐标点。
tCentre为source Tile的圆心,但不一定是source Tile的中心。一定要记得圆心不是中心。(* ̄︶ ̄)
好,在举一个仪器仪表界面中target region 为半圆的情况,如下图所示,
- 显然我们的ptTargetCentre不能设置为NULL(默认值)
正确的设置如下图:
- 看到了吧,有了这两个圆心(tCentre,ptTargetCentre)确定旋转中心还是很方便的。
下面我用Arm-2D发了个红包,点了串鞭炮给大家拜年了,视频演示如下:
补充
Arm-2D官方提供的一个小工具img2c.py
img2c.py-->将图片资源转化为Arm-2D可以使用的tile数据结构。
此Python程序在arm-2d\tools目录中有提供。
具体用法官方也在README.md中有说明。我简单说一下他的使用方法:
python img2c.py-i .\picture.png --dim 50 50 --name Circle
- .\picture.png为图片路径
- --dim 50 50这个参数是将图片大小缩放成50 * 50像素,可以不写,默认为图片的大小。
- --name Circle为生成Tile变量的名字
img2c.py官方的说明我也贴到下面:
- 图片格式可以是jpg、bmp、png等
- --rot还可以设置图片的旋转角度
首发:裸机思维
作者:FledgingSu 支离苏
专栏推荐文章
如果你喜欢我的思维,欢迎订阅裸机思维