免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3651 | 回复: 0
打印 上一主题 下一主题

UCGUI的模拟器UCGUISim详解 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-09-30 15:41 |只看该作者 |倒序浏览

问题的由来-----模拟器完成了什么
在官方发布的UCGUI的源码包当中,附有很多的示例,源码与示例都打包成一个VC工程,在这个工程中我们可以编译和运行UCGUI的示例,进行UCGUI的图形编程,非常方便,这个工程结构下:
?? Application-------UCGUI应用程序目录。
?? Config-------------UCGUI配制文件目录。
?? GUI----------------UCGUI源码文件。
?? Simulation--------模拟器库文件、模拟器头文件目录,主要有GUISim.lib这个提供模拟器的库文件。
?? System-------------应用程序的接口调用主文件,即调用用户的MainTask函数的main函数。
在这个官方提供的包中,我们进行UCGUI的图形编程时,大多都是将要写的程序源文件放加到Application目录中,其中应用程序中必不可少要提供的一个函数是MainTask(),好奇的朋友会发觉,我们程序并没创建窗口,为什么一运行就有窗口界面并有一个LCD显示屏显示出自己的UCGUI程序的运行效果出来,其实这些我们看不到的代码都是写在GUISim.lib这个库文件当中的,为了了解模拟器具体做了些什么,我通过反编译,还原了官方模拟器的源码,下面详细介绍模拟器的构成[以下均为官方模拟器采用的方法]。
GUISim.lib主要完成以下几件事,具体的模块划分将在文中后面描述:
1. 创建模拟器主窗口,这个窗体包括一些模拟器控制菜单,如打开LOG记录/打开调色板显示窗体/新建LCD模拟器窗体,以及暂停/继续模拟器。
2. 创建一个LCD模拟显示窗口并初始化其显示所需的各种数据结构,LCD窗口的大小由UCGUI中LCDConf.h中配制时指定(LCD_XSIZE/LCD_YSIZE),及其它的诸如每个象素占用多少位(LCD_BITSPERPIXEL),首先分配一块足够大的显存(4M)并初始化这块数据为0,每个象素占用不大于 8位时模拟显示屏幕需要用到8位图,还必须初始化要用到的调色板。
3. 提供操作LCD模拟显示屏幕的几个基本图形函数,UCGUI是一个设计层次非常清晰的图形系统,它将GUI的底层图形功能作为一层向上层提供最基本的图形功能,只有这一层才与具体的硬件相关,这一层包括基本的画点函数/矩形填充函数/调色板初始化函数/颜色索引与RGB的转换函数。
4. 提供上层的LOG记录接口的实现,主要完成UCGUI中调试信息的输出,是否输出调试信息可以由UCGUI中的一个开关设置。
5. 开启一个新的线程,在此线程中调用System\Main.c中的main()函数,此函数中再调用MainTask()函数,这个函数即为我们在模拟器中编程必须提供的一个函数,在单任务情形下UCGUI的程序均写在MainTask函数当中,供模拟器开启的线程调用。这里必须分清楚:主线程创建模拟器主窗口及LCD模拟窗口;UCGUI图形应用程序以新开的另外一个线程运行,这个线程结束时则UCGUI图形应用程序结束。
6. 从LCD模拟器窗口消息函数当中接收KEY消息及MOUSE消息,并通过UCGUI中的KEY及MOUSE接口传送到UCGUI内部以驱动UCGUI事件消息LOOP。
二、进一步入了解-----模拟器的基本实现原理
-----LCD模拟显示器的实现原理。
1. 上文中已经提到了UCGUI是一个设计层次分明的图形系统,具体的图形功能分为一层;再细化图形层,还可细分为两层:层一是最底层的直接实现基本的画点函数/矩形填充函数/调色板初始化函数/颜色索引与RGB的转换函数,这一层与直接的硬件及调色板相关,由模拟器中的LCDSIM.c文件实现;层二是位于上述层一之上,提供更多更强图形功能的函数,如位图[1位/2位/4位/8位/16位]显示函数/水平垂直画线函数/矩形填充函数/画点函数,这些功能在\LCDDriver\LCDWin.c中完成,这一层当中的画点函数均以宏的形式提供,具体实现由上述更低的上述层一即模拟器的图形驱动来实现。
在WIN环境下,实现这个模拟器比较简单,要做的就是将GUI的结果显示给用户看,即做出一个LCD模拟显示器,将GUI画图的结果呈现在上面,
GUI画图的结果在显存中,所以也就是将显存中的GUI画图数据用位图显示出来,处理这个位图显示时,可以分两种情况:第一种情况是单个象素点占8位及8位以下的情况,此时显示位图需要用到调色板(所以初始化时必须初始化调色板),每个象素点简化处理为占用一个字节(8位以下实际情况下并非如此,实际是几位就占几位),值表示的是该象素点在调色板中的颜色索引,此时将显存中的数据以8位位图来显示处理;第二种情况是单个象素点占用8位以上的情况,这种情况下,每个象素点简化处理为占用4个字节(实际情况占几位就是几位),其值表示的是实际的该点的RGB颜色值,此时将显存中的数据以32位位图来显示处理。
2. 在LCD窗口中,将GUI画图的结果以上述位图形式画到LCD窗体当中并隔一定时间刷新显示,虽然这样做不一定在速度上非常准确实时,但基本上可以满足要求了,只要我们设定一个重画定时器,定时检测在显示中数据是否发生变化,有变化则刷新一次LCD窗口中显示的内容,可以满足要求。
3. 在解决了模拟LCD显示的问题后,还有要弄清的问题是,要显示器的一屏象素的存放位置,也即画图时所读写象素的内存,其实只需开一块足够大的内存来存放一屏LCD的象素,读写象素均在此块内存中,我们可以称此块内存为显存。如LCD宽XSize,高YSize,显存起始地址为pFix,单个象素点占用8位或8位以下(此时一个象素占1字节),则象素点(x,y)的在显存中的地址即为 x y * YSize pFix;如果是单个象素点占8位以上(此时一个象素占四字节),则为(x y * YSize)*4 pFix。显存中象素是按行存放的,如果为了查看器(ucguiview)可以同样显示出独立运的模拟器程序的GUI画图结果,那么这个显存必须以内存映象文件的方式来实现多个进程之间内存共享访问支持。
4. 关于一个象素用多少位来表示的问题,其实这个问题与几位位图是一个意思:位图中,8位及8位以下的均会使用一个调色板,原因:用调色板[实际为一维组,表项个数由位图位数决定]可以以颜色索引来表示出一个象素点的RGB颜色,调色板中每一个表项存的是该表项索引对应的RGB颜色值,在位图存储时只须要将该位图对应的调色板数组存起来,那么存单个象素点时仅须要存其对应索引而不需要存4个字节的RGB颜色值,这样节约空间。位图中的数据为调色板中颜色的索引值,没有调色板是无法解析显示此位图的,所以8位及位以下位图对应的BMP文件会多出一个调色板内容;8位以上的位图,其位图数据即为RGB值或索引值(16位时),16位/24位/32位单象素分别占用2/3/4个字节,这里必须注意区别的是,我们这里所说的位图一个象素所占用情况分析,是指位图存储为文件时的占用情况,其中也并没有提到具体一个象素点中R/G/B分别占用多少位,特别对于16位的情况下,RGB占用情况一般分5/6/5或5/5/5,此时R/G/B中可以表示的最大值索引值为64,此时无法表示出0x0~0xff之间255种颜色,所以16位位图中的象素点数据还是直接的颜色索引值,并非直接RGB颜色值,但此时并不须要用调色板来辅助转化此索引值为RGB颜色值,而是通过一个转换算法,不过这样会对速度产生影响,没有使用调色板快,不采用调色板是因为需要太多调色板表项。
[注意:关于位图文件,这时就不多介绍了,介绍大家下载这篇文章看一下,"BMP档案结构及平滑缩放.doc",也可以自己通过WIN下面自带的画板来分析不同位数的位图,总之只要记住一点,要处理显示一个位图文件,必须知道位图文件大小及单个象素占用位数(即位图位数),然后显示时就是取得每个象素点的RGB值,这个RGB颜色值是根据调色板来取得或者由索引根据一定的转换算法取得或者象素点数据本身就表示RGB值]。
5. LCD_BITSPERPIXEL是UCGUI中定义的一个象素用多少位来表示的宏定义,则可以表示的颜色总数为1L
以上六点是LCD模拟显示器中用到的几点核心要点,要理解LCD模拟显示器,就必然先理解以上几点。
-----实现模拟LCD的内存布局。
[1]、首先是创建一个名为“emWinLCDMap”的大小为0x00400000(4M)的可读可写及其它所有权限的内存映象文件,如果已存在则是打开该内存映象文件,设其分配所得初始地址为pSMemFix,类型字节。
[2]、pSMemFix 0x20开始,分别存放XSize、YSize、VXSize、VYSize、FixedPalette、BPP、NumColors(分别为LCD水平宽度/竖直高度、LCD虚拟屏水平及竖直大小、调色板模式、单个象素点倍数、可用颜色总数),其计28个字节,这里存入这些信息是为ucguiview查看器使用的,所有的对于查看器要使用的信息均可以在这里存放。
[3]、pSMemFix 0x100开始,用于存放位图结构信息40(0x28)个字节及1000个字节(256*4)的调色板(最多可用表项为256项)信息,即如下结构:
typedef struct tagBITMAPINFO { // bmi
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
[4]、pSMemFix 0x1000开始,用作LCD的显存,存放LCD屏幕的象素点,大小总计为4M。
-----实现LCD功能的几个基本函数。
[1]、LCDSIM_SetPixelIndex--------画点.
///////////////////////////////////////////////////////////////////////
//
// 函数名 : LCDSIM_SetPixelIndex
// 功能描述 : 最基本的画点函数...
// 参数 : int x[点x坐标]
// 参数 : int y[点y坐标]
// 参数 : int Index[颜色索引值]
// 返回值 : void
//
///////////////////////////////////////////////////////////////////////
void LCDSIM_SetPixelIndex(int x, int y, int Index)
{
static int preIndex = 0, preLUT = 0, curLUT = 0, curColor = 0;
int pixPos = 0;
char* lptemp = 0;
if(paaPixel == 0) return;
if(BPP  XSize) x1 = XSize - 1;
if(y1 > YSize) y1 = YSize - 1;
if(x0  8){
step = 4;
color = Convert_Index16IntoIndex32(Index);
}
else{
color = Index;
}
comlum = (x1 - x0);
lptemp = (char*)paaPixel BytesPerLine * y0 x0 * step;
//矩形宽度是否为整行...
#ifdef FASTTING
if(comlum == XSize){
comlum = comlum*(y1-y0);
_asm{
mov eax, color
mov ecx, comlum
mov edi, lptemp
}
if(step == 1) __asm rep stosb
else __asm rep stosd
return;
}
#endif
// 2005-8-27 14:35:38 使用串传送指令提高速度...
for(line = y0; line  8){
//直接在显示内存中取,其值即为该点RGB值.
Color = *((int*)paaPixel y * BytesPerLine x * 4);
}
else if(BPP
int getColor = 0;
if(BPP == 0) return getColor;
else if(BPP > 8){
getColor = Convert_Index16IntoIndex32(Index);
}
else if(BPP
break;
}
return convertColor;
*/
}
在这个函数中,具体的转换的功能是由GUI\ConvertColor目录下的几个文件中提供的,具体参看UCGUI源码。
[7]、LCDSIM_SetLUTEntry------设置调色板信息。
void LCDSIM_SetLUTEntry(U8 Pos, LCD_COLor color)
{
char* lptemp = 0;
if(BPP == 0) return;
color=FilterColor(color,LCDSIM_aLCDColorBlack[0],LCDSIM_aLCDColorWhite[0]);
lptemp = (char*)pBitmapInfo 0x28 Pos * 4;
*(char*)lptemp = (color & 0xff0000) >> 16;
*(char*)lptemp = (color & 0xff00) >> 8;
*(char*)lptemp = color & 0xff;
ModifyCnt ;
LUT_ModifyCnt ;
if(pFix != 0){
lptemp = (char*)pFix 0x3c;
*lptemp = ModifyCnt;
lptemp = (char*)pFix 0x40;
*((int*)lptemp) = LUT_ModifyCnt;
}
}
?? [LUT_ModifyCnt]----记录调色信息的更改次数。
?? [pBitmapInfo]---------位图信息起始地址。
?? [FilterColor]-----------此函数负责将指定颜色值转换为在背景色与前景色之间的值。转换的方法是(colorWhite & 0xff - colorBlack &0xff) * (color & 0xff) / 0xff; colorWhite为前景色,colorBlack为背景色,取相应的R/G/B位,用前景色减去背景色之值再乘以color的对应R/G/B的值,所得值再除以255得商即为调整后颜色值,这样做目的是将指定颜色值调整为前景色与背景色之间。
-----模拟器的输入模拟在UCGUI当中有专门的接收输入的接口,有MOUSE、KEY、TOUCH的,分别为GUI_MOUSE_StoreState、GUI_StoreKeyMsg、GUI_TOUCH_StoreState这三个函数,三UCGUI中关于这些消息的处理都比较简易,并没有什么队列,都是接收一个处理一个,这对于简单的嵌入式应用来说已经足够,可以减少内存占用,但有可能造成消息的丢失,MOUSE及KEY消息均来自于LCD窗口的窗口消息处理函数中。
[MOUSE]
[1]、LCDSIM_SetMouseState--------传送MOUSE及TOUCH(触摸屏)消息到UCGUI。
void NotifyMouseState(LCD_tMouseState mouseState)
{
if(mouseState.KeyStat == 0){
GUI_TOUCH_StoreState(-1, -1);
}
else{
GUI_TOUCH_StoreState(mouseState.x, mouseState.y);
}
GUI_MOUSE_StoreState((const GUI_PID_STATE*)&mouseState);
}
MOUSE消息处理中,包括WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_LBUTTONUP这三种,NotifyMouseState的功能就是内存消息至ucgui.
[2]、LCDSIM_GetMouseState--------获取MOUSE消息。
[KEY]
[1]、HandleKeyEvents-------------传送KEY消息到UCGUI。
void HandleKeyEvents(UINT message, WPARAM wParam)
{
int key = 0, keyCount = 0;
switch(message){
case WM_KEYDOWN:
key = VirtKey2Key(wParam);
if(key == 0) key = Keydown2ASCII(wParam);
keyCount = 1;
break;
case WM_KEYUP:
key = VirtKey2Key(wParam);
keyCount = 0;
break;
}
if(key != 0) GUI_StoreKeyMsg(key, keyCount);
}
?? [VirtKey2Key]----主要处理一些特殊键,如SHIFT、DELTE、BACKSPACE、INSERT、CRTL、ENTER、方向键等。
?? [Keydown2ASCII]--将键盘虚拟码转换为ASCII码,大小写区别的,在键盘处理当中,如上所说的特殊键是有特别用途的,UCGUI中已重定义这些特殊键所对应的KEY值,可以在GUI.h当中查找GUI_KEY_UP来找到这些特殊键在UCGUI中的KEY值。在传送键盘消息时,这里只在WM_KEYDOWN时处理普通键,WM_KEYUP中并未处理,WM_KEYUP只处理了特殊键。其它人可以根据自己人须求要改写这个传送键盘消息到UCGUI的函数。
HandleKeyEvents在LCD的窗口消息函数中,当LCD窗口有键盘消息时,即传送至UCGUI内部,以驱动UCGUI的键盘处理。
三、拔去见日-----UCGUISim模拟器的模块划分。
在上面介如了模拟器的基本原理,差不多将核心的东西都说出来了,这时简要的说明一下模拟器的几个构成模块。
?? emWin.c----------创建UCGUISim模器主窗口及LCD显示窗口,处理KEY、MOUSE消息传送,开启、暂停UCGUI程序,输出LOG等。
?? LCDSIM.c--------实现模拟LCD显示屏。
?? Branding.c--------显示版权。
?? GUI_X_SIM.c---实现UCGUI的临界代码锁及实际的LOG输出及延时功能。
具体可以能见源码,这里就不就代码作详细解说了。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/29191/showart_393140.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP