实现画图API接口
定义一个画图操作的容器集合
很多时候程序需要移植,同样对一个UI来说,有时需要在很多平台上能运行,如在板上的程序,希望能在WINDOW上写一个模拟器,(为了方便,我的程序也在一个简单WINDOWS模拟器上执行);很多平台上也提供了不同的硬件来对画图进行加速或一些特效,但对于上层UI的代码我们希望和这些都是无关的,所以要定义一些接口,对于C语言来说,可以定义一个操作的struct集合容器,上层的UI操作只能通过这些操作来画图,接着上节的,如下定义一些基本的操作:
在一个头文件里(UI_Adapter.h) 作如下的定义:
/*画点*/
typedef void (*tagUI_SetPointPixel) (int x, int y, PIXELINDEX pixelValue);
/*获取一个点的颜色*/
typedef unsigned int (*tagUI_GetPointPixel) (int x, int y);
/*画线*/
typedef void (*tagUI_DrawHLine) (int x0, int y0, int x1);
typedef void (*tagUI_DrawVLine) (int x0, int y0, int y1);
/*画填充的矩形*/
typedef void (*tagUI_DrawFillRect) (int x0, int y0, int x1, int y1);
/*获取显存的分辨率宽高*/
typedef int (*tagUI_GetScreenX) ();
typedef int (*tagUI_GetScreenY) ();
typedef struct _GUI_DrawApi
{
tagUI_SetPointPixel pfSetPointPixel;
tagUI_GetPointPixel pfGetPointPixel;
tagUI_DrawHLine pfDrawHLine;
tagUI_DrawVLine pfDrawVLine;
tagUI_DrawFillRect pfDrawFillRect;
tagUI_GetScreenX pfGetScreenX;
tagUI_GetScreenY pfGetScreenY;
}UI_DriveDrawApi;
为了方便移值,在一个头文件(UI_Types.h)中有如下的定义:
typedef signed char I8;
typedef unsigned char U8; /* unsigned 8 bits. */
typedef signed short I16; /* signed 16 bits. */
typedef unsigned short U16; /* unsigned 16 bits. */
typedef signed int I32; /* signed 32 bits. */
typedef unsigned int U32; /* unsigned 32 bits. */ /*保险的应是 unsigned long*/
typedef signed int S32; /*保险的应是 signed long*/
typedef signed long long S64;
#ifdef linux
#define PIXELINDEX U16 /*每个像素位数*/
#endif
#ifdef WIN32
#define PIXELINDEX U32
#endif
有了上面的基本的操作API操口,那么对于LINUX FRAMEBUFFER的定义可以像下面这样的写:
首先定义一个全局的 UI_DriveDrawApi 对像,可以定义在一个c 文件里,定义一个方法来初始化这个对像,如下:
static UI_DriveDrawApi *_pDriverDrawApi;
void UI_DrawApiInit(UI_DriveDrawApi* pDriveDrawApi)
{
UI_LOCK();
_pDriverDrawApi = pDriveDrawApi;
UI_UNLOCK();
}
UI_DrawApiInit 方法是公开的,不同平台的应用程序需要定义一个 UI_DriveDrawApi的接口来初始化上面的静态变量_pDriverDrawApi.
在根据前一节的定义,可以这样定义linux framebuffer 的操作.
static UI_DriveDrawApi _DriverDrawApi = {
fb_SetPointPixel,
fb_GetPointPixel,
fb_DrawHLine,
fb_DrawVLine,
fb_DrawFillRect,
fb_GetScreenX,
fb_GetScreenY
};
有了上面这个,可以在应用程序里的一个合适的地方,操作UI画图前,调用前面UI的初始化过程:UI_DrawApiInit,
像下面这样:
UI_DrawApiInit(&_DriverDrawApi);
上面接口里的 tagUI_GetScreenX 和 tagUI_GetScreenY 方法对于 linux framebuffer 来说就是获取fb_var_screeninfo 里的 xres_virtual 和 yres_virtual.
为上层操作定义方法
对于后面的UI实现来说,通过上面的接口,可以操作显存了,这了方便再定义如下的转换方法:
#include "UI_Adapter.h"
/*对应底层的画图API*/
static UI_DriveDrawApi *_pDriverDrawApi;
void UI_DrawApiInit(UI_DriveDrawApi* pDriveDrawApi)
{
UI_LOCK();
_pDriverDrawApi = pDriveDrawApi;
UI_UNLOCK();
}
int UI_GetScreenX()
{
return _pDriverDrawApi->pfGetScreenX();
}
int UI_GetScreenY()
{
return _pDriverDrawApi->pfGetScreenY();
}
void UI_SetPointPixel(int x, int y, int pixelValue)
{
_pDriverDrawApi->pfSetPointPixel(x, y, pixelValue);
}
unsigned int UI_GetPointPixel(int x, int y)
{
return (unsigned int)_pDriverDrawApi->pfGetPointPixel(x, y);
}
void UI_HLine(int x0, int y0, int x1)
{
_pDriverDrawApi->pfDrawHLine(x0, y0, x1);
}
void UI_VLine(int x0, int y0, int y1)
{
_pDriverDrawApi->pfDrawVLine(x0, y0, y1);
}
void UI_FillRect(int x0, int y0, int x1, int y1)
{
_pDriverDrawApi->pfDrawFillRect(x0, y0, x1, y1);
}
void UI_DrawRect(int x0, int y0, int x1, int y1)
{
UI_HLine(x0, y0, x1);
UI_HLine(x0, y1, x1);
UI_VLine(x0, y0, y1);
UI_VLine(x1, y0, y1);
}
UI_LOCK() 与 UI_UNLOCK() 这是一个加锁的操作,在不同的平台需要不同的实现,如常用的互拆锁。
有上面的操作API后,UI画图就用上面的定义来操作画图。