背景:
公司的一个老产品,2410平台的,使用psbios引导2.4内核。客户想要一个圆形的带启动百分比的progressbar,该进度条反映bootloader和内核的启动进度。
总结一下实现过程:
① 画点函数;
② 三角函数;
③ 扇形绘制函数;
④ 由定点数实现。
下面就以上面的几个关键点为骨架脉络,来实现主要的函数。
(1) 画点函数的实现:
此函数为图形绘制的根本,需要最先实现。要实现此函数,需要知道LCD或framebuffer的base_addr、分辨率以及bpp。以800x600、16bpp为例,实现方法如下:
unsigned short (*framebuffer_800600_16bpp)[800];
framebuffer_800600_16bpp = (unsigned short(*)[800])base_addr;
void Draw_pixel (unsigned short x, unsignedshort y, unsigned short color)
{
Fb_writew(color,(&framebuffer_800600_16bpp[(y)][(x)]));
}
(2) 画任意直线函数:
其中,Lcd_Draw_HLine(y0,y1, x0, FillColor)和Lcd_Draw_VLine(y0, y1, x0, FillColor)分别为画水平和垂直直线函数,这里不再赘述,下面是花任意角度的直线的函数实现。
/**********************************************************
画任意角度的直线:
x0,y0:起始点;
x1,y1:结束点;
FillColor: 填充颜色
***********************************************************/
void Lcd_Fill_Line(U16 x0, U16 y0, U16 x1,U16 y1,U16 FillColor)
{
U16 x;
if(x0 == x1)
{
Lcd_Draw_VLine(y0, y1, x0, FillColor);
}
else
{
if (y0 == y1)
{
Lcd_Draw_HLine(x0, x1, y0, FillColor);
}
else if (y0 < y1)
{
if (x0 < x1)
{
for (x = x0; x <= x1; x++)
{
LCD_PutPixel(x, (y0 + (x -x0) * (y1 - y0) / (x1 - x0)), FillColor);
}
}
else if (x0 > x1)
{
for (x = x0; x >= x1; x--)
{
LCD_PutPixel(x, (y0 + (x0 -x) * (y1 - y0) / (x0 - x1)), FillColor);
}
}
}
else
{
if (x0 < x1)
{
for (x = x0; x <= x1; x++)
{
LCD_PutPixel(x, (y0 - (x -x0) * (y0 - y1) / (x1 - x0)), FillColor);
}
}
else if (x0 > x1)
{
for (x = x0; x >= x1; x--)
{
LCD_PutPixel(x, (y0 - (x0 -x) * (y0 - y1) / (x0 - x1)), FillColor);
}
}
}
}
}
(3) 绘制扇形函数:
由于只能使用定点数,且也没有math库函数(需要使用三角函数),这给绘制扇形函数的实现增加了麻烦。
首先解决三角函数问题:最简单的方法,将0~90度的正弦值做成一个表格,以每度递增,如果想要更高的精度,可以以0.1度递增。根据三角函数公式可以求得各个象限的角度的三角函数值。如果编译器不支持浮点数,则可将表格中的三角函数值同时放大一个合适的倍数后取整,然后再在计算的时候缩小相应的倍数即可。
再就是扇形的绘制和填充了,这里我采用分割法来实现,如图所示:
任何一个扇形都可以被分割为图中所示的1、2、3三个区域(当其中的一个半径边与x轴或y轴重合时可以分割为2个区域),以前面画点画线为基础,加以简单的公式即可将一个完整的扇形区域绘制出来。算法就这么简单,但实现起来要考虑各个象限的取值不同以及实际在LCD上绘制时其坐标系与正常的坐标系是关于x轴对称的,所以在实现函数的时候要特别的细心,考虑周全。
其他就是润色的工作了。