您的位置:首页 > 编程语言

如何利用TC进行图形编程

2011-03-28 13:32 246 查看
/*叶子闲居 http://lxleaves.126.com 转载请保留此处*/

时常在一些论坛上看见有些人贴出如何利用TC进行图形编程,或者有些人询问如何进行GUI编程。无意发现国内这方面的资料委实很少,所以就没掂量掂量自己就贸然写了这篇文字,还望诸多高手海涵。


对于基本的图形函数,TC为我们提供的图形库是在远远不能满足需要,所以为了能够完善的显示出精彩的图形效果,我们需要利用VESA标准,具体中断调用为
int
10h(AX=4f??h)。考虑到256色比较容易处理(其实其它也差不多,只是256色的图形文件比较节省空间,而且显示出来的效果足以满足需要,所
以就…)显示模式为1024*768*256,以下是C语言显示图形方式的子函数:

void init256(char flag){

if(flag==1){ /*如果传入的参数为1,则置1024*768*256模式*/

_AX=0x4f02;

_BX=0x105;

geninterrupt(0x10);

}else{ /*如果参数为0,则返回文本模式*/

_AX=3;

geninterrupt(0x10);

}

}


TC提供比较方便的中断调用方法,_AX表示AX寄存器,如果其中的数据为4f02h,表示置VESA模式,_BX保存的是模式
号,geninterrupt(0x10)表示调用10h中断,这是个显示中断,VESA利用它的4f??h为作为SuperVGA的中断入口。(需要包
含头文件dos.h)




现在给大家灌输分页的概念,如果你已经对分页已经耳熟能详就跳过这段。我们要知道在pc系统中对显存是没法进行直接操作的,必须映射到内存的一段,但是因
为内存的限制,只能为显存提供一个段用于其映射的空间,也就是每次只能访问64K的显存,所以如果显示分辨率比较低,而且色彩比较小,这64K的空间勉强
覆盖整个屏幕所需要的显存,但是对于1024*768*256的显示方式,就需要1024*768=786432字节的空间,也就是需要12*64K的空
间才够,但是内存有限,所以必须采用换页机制,也就是当需要改变显存内容时将需要改变的地方映射到内存上,再进行操作,以至于可以访问整个显存。




因此,如何分页以及在何处分页是个重要的环节。因为调用中断进行分页会有相对较大的时间延迟,如果频繁地调用分页中断势必影响屏幕的显示速度,一个合理的
算法与每次调用中断会有天壤之别。比较简单的算法是首先用一个寄存量存取一个当前页的索引号,然后在每个画点处分析是否需要换页,即比较显存位置是否已经
映射到内存上,如果已经映射,则直接写显存(内存映射),如果没有映射,则调用换页中断,如此可以大大提高画图速度。由于具体的换页算法不是本文讨论的重
点,而且这种算法已经可以满足需要,所以本文写点采用这种最简单的算法。

void selectpage(){

int newpage=ramoffset/65536;



if(newpage!=nowpage){

_AX=0x4f05;

_BX=0;

_DX=newpage;

geninterrupt(0x10);



nowpage=newpage;

}

}


其中ramoffset(显存偏移)和nowpage(当前页)为全局变量,因为selectpage为子函数,在调用之后一切变量都不再存
在,newpage(待换页)则不需要这样。该换页函数首先计算当前显存偏移所在的页newpage(65536是64K,一页的大小),然后比较是否与
当前页相同(nowpage),如果相同则返回,否则执行换页,并刷新当前页中储存的页号码。



画点采用直接写显存的方法,这种方法的优点是速度很快。

void putpixel(int x,int y){

if(x> 1023||x <0||y> 767||y <0)return;

if((COLOR&0xff00)==0x100)return;

ramoffset=(long)y*1024+x;

selectpage();

if(WRITE_MODE==0)*(vram+ramoffset)=COLOR&0x00ff;

else *(vram+ramoffset)^=COLOR&0x00ff;

}


首先比较x,y是否越界,如果越界则返回,不执行任何操作;如果COLOR(全局变量)的高8位等于
1((COLOR&0xff00)==0x100),表示该点为透明,同样返回;否则计算显存偏移地址,1024*768*256的偏移地址计算
方法为((long)y*1024+x)*1,因为256色为伪彩,只占有1字节,通过256个索引来访问调色板,接着调用换页函数,再检查写点模式
WRITE_MODE,如果为0,表示直接覆盖,则写点方法为*(vram+ramoffset)=COLOR&0x00ff,这里需要剔出高位
(其实不剔出也没有关系),如果WRITE_MODE为非0,则与原色彩进行异或操作(连续偶数次写点不会改变原来的色彩)。

下面跳过其它基于写点的绘图操作,因为一切都是算法问题,只要注意优先完成一个页的绘制,再进行换页,尽量少换页(指的是绘点时同一个页中优先绘制)。


TC中环境读取最基本的是bioskey函数,它可以用来判断是否有键盘中断的产生。bioskey(0)表示读取键盘缓冲区,并取出按键
值;bioskey(1)表示读取键盘缓冲区,但不取出按键值,可以用来判断缓冲区是否有值,功能等同于kbhit()函数;bioskey(2)表示读
取扩展按键的值,可以用来结合常规按键判断扩大按键功能,具体对应的值可以参考相关资料。

因为TC2.0本身没有支持鼠标的函数,所以必须自己调用系统中断来解决

int mouse_reset(void){

_AX=0;

geninterrupt(0x33);

if(_AX==0) return 0;

return 1;

}

如果成功返回0,否则返回1,另外还需要对鼠标范围进行设定

void mouse_area(void){

_AX=7; /* X */

_CX=0; /*min X*/

_DX=1023; /*max X*/

geninterrupt(0x33);

_AX=8; /* Y */

_CX=0; /*min Y*/

_DX=768; /*max Y*/

geninterrupt(0x33);

}

因为是1024*768所以X最大为1023,最小为0,Y最大为767,最小为0,下面是对鼠标状态的读取

void mouse_read(void){

_AX=3;

geninterrupt(0x33);

mousex=_CX;

mousey=_DX;

mousekey=_BX;

}

mousex(鼠标X值),mousey(鼠标Y值),mousekey(鼠标按键)均为全局函数

相关的鼠标函数为:



/*用于读取鼠标按键是否被按下,如果按下,则返回1,否则返回0*/

int mouse_hit(void){

mouse_read();

if(mousekey!=0)return 1;

return 0;

}

/*用于检测鼠标是否移动,方法是比较当前鼠标坐标是否与原来坐标等同*/

int mouse_move(void){

mouse_read();

if(mousex!=mousemovex){

mousemovex=mousex;

return 1;

}

if(mousey!=mousemovey){

mousemovey=mousey;

return 1;

}

return 0;

}

以下具体讲解GUI模式消息处理过程,首先完成窗口的初始化操作,包括绘制必要的元素,这些元素都是用结构体来储存数据,包括坐标,文字内容等,方便对其的访问。然后开始监听消息

while(1){

int message=listen(1);

switch(message){

case NONE:autorefresh();break;

case MOUSEHIT:yourmousefun();break;

case KEYBOARD:yourkbfun();break;

}

}

listen函数实现方法为:

int listen(unsigned char flag){

char ALL=1;

mousekey=0;

while(1){



/*绘制鼠标图像*/

mouse_pushbmp();



while(1){

if(mouse_hit()){

/*如果是鼠标击键,拿掉鼠标图像,并退出循环(向系统发送消息)*/

mouse_popbmp();

return MOUSEHIT;

}

/*如果没有键盘或鼠标动作则持续循环*/

if(!mouse_move()&&!kbhit())continue;



/*如果是键盘操作,拿掉鼠标图像,并退出循环(向系统发送消息)*/

if((kb.key=bioskey(1))!=0){

mouse_popbmp();

return KEYBOARD;

}



/*至此确定是鼠标移动操作,拿掉鼠标图像,跳出一级循环*/

mouse_popbmp();

/*如果传入的参数为ALL,表示监听一切,则在此返回,否则继续循环*/

if(flag==ALL)return MOUSEMOVE;

break;

}

}

}

/*待续,写好一点,先贴上来*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: