| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4157 人关注过本帖, 2 人收藏
标题:[原创]TC下高彩色直接写屏技术
取消只看楼主 加入收藏
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏(2)
 问题点数:0 回复次数:6 
[原创]TC下高彩色直接写屏技术

TC下高彩色直接写屏技术

本文纯属抛砖引玉之作,如果各路高手对此文有什么不同或者更加准确的看法,请畅所欲言。

bbs.bc-cn.net

本文章基于高彩色640X480模式。

个人极力推荐‘晕倒死’下的C语言编辑器:WIN-TC 1.91

个人极力反对大家把自己的硬盘格成NTFS格式!

鄙视微软!

又:由于各个显卡可能存在不兼容,而我又不知道SVGA标准,所以很有可能会相当多的网友不能正常运行程序,抱歉~

终于,在一个夜黑风高的夜晚,我终于找到了一个不用图形驱动程序(BGI)就可进入640x480x65536的方法(花了不少精力呢~~还是值得的T_T):

void setmode(int vmode)

{

asm mov ax,0x4f02

asm mov bx,vmode

asm int 0x10

}

vmode值的说明:

0x00480x0049都是640x480x65536模式

0x004a则是800x600x65536模式

0x0003则是80x25x16文本模式

其实还有1024x768x65536模式的,但是由于要显示的像素实在太多了,所以也就没必要列出来了。

所谓高彩色就是计算机用2个字节来描述一个像素的颜色。由于一个字节有8位,可以表示256个数,所以两个字节就一共可以表示256*256=65536种颜色。同理,如果用3个字节或者3个字节以上来描述一个像素的颜色那就是真彩色。24位真彩色能显示的颜色数已经大大超过了人的眼睛所能分辨的能力。而且由于用3个像素才能表示一个点,所以在显示方面显得很慢,占用的VRAM也比较多。因此在很多对颜色要求不是太过分的场合,我推荐大家采用高彩色就可以了。(而且我也没能找到转到真彩色模式的方法,如果有那位网友找到了请和我联系,oldmanpushcart@hotmail.com 或者上bbs.bc-cn.net vlinux飘飘 也可,小弟先谢了)

又所谓直接写屏幕技术,其实这个也没什么技术可言,直接写就是直接写咯。但是我们要搞清楚几点:

1. 往那里写?

2. 写什么?

3. 怎么写?

总结起来也无非就是3WWhere,What,hoW)。

1. 战斗在0xa0000000处打响

由于系统统一编址时,EGAVGAVRAM开始段地址分配为0xA000,所以VRAM开始单元地址为0xa000:0x0000。好,知道了VRAM的开始地址我们也就知道该往那里写了,于是我们定义一个指向0xa0000000的远程指针,这样就可以从0xa0000000开始写数据了。

unsigned int far *VramPoint=(unsigned int far *)0xa0000000L;

这样,第一个问题往那里写就解决了。

2. 转换RGB表示高彩色

高彩色在内存中是用2个字节来表示一个像素的。那每个颜色的值是如何确定的呢?比如:谁知道红色在高彩色中是如何定义的呢的?这样就到了整个技术的难点了——用RGB表示颜色值。

说句实话,我也不清楚高彩色的颜色值是怎么定义的,但即使你知道我也不想听,因为记下65536那么多种颜色不是闹着完的。还好我想出了个比较easy的方法解决了这个问题。用RGB来表示颜色值。现在问题又来了——什么叫RGB呢?

RGB就是Red Green Blue即红绿蓝三种基本色的E文缩写。每一种颜色都有256种强度,不同强度的基本色相互搭配会产生不同的颜色效果。故RGB三种基本色的256种强度共计可以表现256*256*256=16777216种颜色,也就是我们说的16M色。

毫无疑问,这样强大的颜色系统肯定能击溃我们脆弱的眼睛。但,也许有细心的网友在看到这里的时候会有个很大的疑问——我打算用RGB来表示高彩色,可是RGB的颜色系统用的是3个字节来表示一个像素的颜色,而高彩色是用2个字节来表示的,多出的一个字节怎么办?

是啊,怎么办?没关系,我花了一个上午的时间终于找到了解决的方法——转换!

转换的原理很简单,因为高彩色只能显示出32种红色、蓝色和64种绿色,所以我就把多余的颜色砍掉了。问:“你怎么知道高彩色只能显示‘32种红色、蓝色和64种绿色’的?”对此你大可以不必去理解,我估计也没几个人想去听,我也忘记从那里做的笔记了,好像是上高中的时候上美术课老师无意中说的而我又恰好无意中把它记了下来下面我就来说些关键的——如何转换。

比如有三个RGB的值 r=128 g=31 b=165 我们要把他们转换成高彩色的值可以这样转:

r=128 对应的二进制 10000000

g=31 00011111

b=165 10100101

然后我们把rb的后面3位都砍掉,把g的后面2位也砍掉,这样我们得到:

10000 000111 10100

再把他们重新组合起来变成:10000000 11110100

最后再反序得到:11110100 10000000

这就是转换的高彩色的颜色值了。这个颜色接近于紫色。

当然,具体操作是用位运算来实现的,具体代码如下:

unsigned int setcolor64k(register unsigned char r,

register unsigned char g,

register unsigned char b)

{

unsigned int a;

unsigned char *p=&a;

r&=248;g&=252;b>>=3;

*(p+1)=r|(g>>5);g<<=3;

*p=g|b;

return a;

}

那也许有人会问,这样做有什么好处?我们直接用高彩色的值不快吗,干吗还要花精力去转换呢?下面我就来说说这样做的好处。

好处(1)省下了你去记65536种颜色的时间。你可以用WINDOWS自带的[画图]程序中的真彩色颜色表很容易的查找到真彩色每一种颜色所对应的颜色值(注意,[画图]中的RGU就是RGB

好处(2)你可以用它来在高彩色下模拟显示24位真彩色图像。这个功能不错吧~~因为真彩色是用RGB的强度值来表示的,所以可以把它们转换成高彩色。

当然啦,把真彩色转换成高彩色肯定是会丢失颜色的,但是人的眼睛是分辨不出来~~反正我是没分辨出来 \^o^/

另:其实我认真的观察了很久,发现用计算机显示24位真彩色和显示高彩色的时候真的找不到任何的分别,我很怀疑计算机在显示的时候是不是偷偷把真彩色暗地里转换成高彩色再输出,用人类的眼睛不能分辨这么多颜色的弱点来蒙骗我们??当然啦,这仅仅是一个菜鸟的无聊的观点而已 \^_^/

好了,现在我们解决了第2个大问题:写什么

3. 怎么写

由于高彩色是用2个字节表示一个颜色的,而unsigned int正好也是2个字节,所以我们可以用一个unsigned int变量来读写一个颜色。这也是我把setcolor64k()的返回值和指针类型设计成unsigned int型的缘故。

在高彩色640X480模式下,计算机把整个屏幕分为10个部分,其中前9个部分每个部分都能表示32768个点,第10个部分表示12288个点。所以有:9*32768+12288=640*480

总共307200个点组成。其中,每个部分的地址都是从0xa0000000重新开始的。由于上述原因,我们必须编写一个函数用它来换显示部分:

void changepage(register unsigned char page)

{

asm mov ax,0x4f05

asm mov bx,0

asm mov dx,page /*page是选择的部分*/

asm int 0x10

}

然后我们还要编写一个函数用来快速判断一个二维坐标的点在VRAM中是在第几部分的哪个位置!注意,如何快速判断我认为这个是最最难的地方,不管我尽多大努力,在速度上仍然是差强人意!所以这个问题我就先放这吧,如果有高手看到了请指点一二,以餮网友。

好了,到此,3个难点都解决了。也许你还有一些不理解,不要紧,我们马上结束理论上的东西,投入到实验当中去。

搜索更多相关主题的帖子: 彩色 技术 
2005-01-22 13:32
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏
得分:0 

下面是我编写的一个演示程序,作用是把整个屏幕的前9部分用一种颜色画满!

#include "stdio.h"

void setmode(int vmode)

{

asm mov ax,0x4f02

asm mov bx,vmode

asm int 0x10

}

void changepage(register unsigned char); /*换显示部分函数*/

unsigned int setcolor64k(register unsigned char, /*RGB颜色转换函数*/

register unsigned char,

register unsigned char);

void main()

{

/*定义一个unsigned int 的指针指向VRAM*/

unsigned int far *vp=(unsigned int far*)0xa0000000L;

register unsigned char page; /*当前显示的页面*/

register unsigned int i;

setmode(0x0049);

getch(); /*暂停一下,等待显示器切换显示模式完毕*/

for(page=0;page<=8;page++)

{

changepage(page);

vp=(unsigned int far*)0xa0000000L;/*更换显示部分后重新定位指针*/

for(i=0;i<=32767;i++)

{

*(vp)=setcolor64k(27,240,246);/*按照RGB颜色画点*/

vp++;

}

}

getch(); /*暂停一下,看看效果*/

setmode(0x0003);

}

unsigned int setcolor64k(register unsigned char r,

register unsigned char g,

register unsigned char b)

{

unsigned int a;

unsigned char *p=&a;

r&=248;g&=252;b>>=3;

*(p+1)=r|(g>>5);g<<=3;

*p=g|b;

return a;

}

void changepage(register unsigned char page)

{

asm mov ax,0x4f05

asm mov bx,0

asm mov dx,page /*page是选择的部分*/

asm int 0x10

}

恩恩~感觉怎么样?是不是感觉挺快的?但是还是可以看出很明显闪过的痕迹。其实我们还可以再让它快上0.5~1倍,如果你用汇编语言来重新改写循环、位运算部分(尤其是循环部分)甚至用汇编重新改写过整个程序,那速度会更加的疯狂~

小提示:像这些在循环几万到几百万次的程序中,反复使用的变量类型最好用寄存器变量register类型


淘宝杜琨
2005-01-22 13:34
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏
得分:0 

下面这个是我的第二个例子,用高彩色模拟真彩色显示的演示程序,看看大家看得出转换后在颜色上有什么区别吗?这个例子是我N月之前一个帖子(《在TC下显示24位真彩色图片》)中的例子,当时没有采用直接写屏幕技术,现在我们拿来改一改。(注:因为没能写出判断“一个二维坐标的点在VRAM中处于那一部分的那一地址”的函数,所以显示图片的时候只能显示出图片的一部分)

#include "stdio.h"

void setmode(int vmode)

{

asm mov ax,0x4f02;

asm mov bx,vmode;

asm int 0x10;

}

typedef struct /*ColorBGR像素类型*/

{

unsigned char b;

unsigned char g;

unsigned char r;

}ColorBGR;

unsigned int setcolor64k(register unsigned char r,

register unsigned char g,

register unsigned char b)

{

unsigned int a;

unsigned char *p=&a;

r&=248;g&=252;b>>=3;

*(p+1)=r|(g>>5);g<<=3;

*p=g|b;

return a;

}

void main()

{

char fname[30]; /*文件名*/

int width,height,i,j;

FILE *fp;

ColorBGR *buffer;

int far *vp=(int far*)0xa0000000L;

printf("Please input the 64K BMP filename: "); /*输入24位位图的文件名*/

gets(fname);

if((fp=fopen(fname,"rb"))==NULL) /*打开文件,并且判断文件是否存在*/

{

printf("Can't find file %s",fname);

getch();

exit(1);

}

setmode(73);

fseek(fp,18,SEEK_SET);

fread(&width,4,1,fp); /*图像宽度*/

fread(&height,4,1,fp); /*图像长度*/

buffer=(ColorBGR *)malloc(width*sizeof(ColorBGR));/*为一行所有的像素的颜色开创空间,用来保存同一个宽度上的每个点的RGB三种颜色值*/

fseek(fp,54,SEEK_SET); /*定位文件指针指向颜色存储区*/

for(j=height-1;j>=0;j--)

{

fread(buffer,width*sizeof(ColorBGR),1,fp); /*读取该行像素的所有点的颜色*/

if(width%4) fseek(fp,(4-width%4),SEEK_CUR); /*宽度修正*/

vp=(int far*)0xa0000000L;

vp+=j*640L;

for(i=0;i<width;i++)

{

*(vp)=setcolor64k(buffer[i].r,buffer[i].g,buffer[i].b); /*重设每个点的颜色*/

vp++;

}

}

free(buffer);

fclose(fp);

getch();

setmode(0x0003);

}

哦对了,忘记告诉大家,在编译的时候会发出警告:

“警告 指针转换后指向其它类型在 setcolor64k 函数中”

这个大家不用担心,这个是我特意设计的,不是不小心的错误~~

总结一下。写到这里,我有两个不明白想请教各路虾米两个问题:

1. 有谁知道转到真彩色的方法(用BGI图形驱动的也成)?是不是没有啊!!

2. 如何编写一个快速查找“二维坐标的点在VRAM中处于那一部分的那一地址”的函数?记住,只要要快速,哪怕是用汇编、中断都在所不惜!

另外,大家可以采用EMS内存技术再配合视频缓冲技术,这样可以写出基本无闪的全屏动画来了~~

好啦,至此,高彩色直接写屏部分算是写完啦,如果大家对我的方法或者观点有什么不明白或者是意见不管是菜鸟还是虾米都尽管提出来,偶还是个大菜鸟,还要向大虾们多多学习。

附:鄙人的机器是:

联想“同禧300

显卡是标准SVGA而且是集成在主板中的(4M显存)Inter(r) 82810 Graphics Controller

内存:192MB

CPU:赛’533….

呵呵好低的配置,让大家见笑了。 :p


淘宝杜琨
2005-01-22 13:34
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏
得分:0 
晕,你们有谁的显卡和我的一样? intel810

不知道我找到的那个中断是不是与你们的显卡兼容!

还有,三少爷,你的程序太抽象啦,以至于我根本就通不过编译~~请修改一下啦

淘宝杜琨
2005-01-28 18:49
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏
得分:0 
哦,因为每个人的显卡是不同的,不同的显卡的非标准SVGA中断调用方式当然不同啦!
我的显卡是intel810的,我并不期待每个人都能正常运行这个程序,呵呵,显卡不同嘛。

不过建议你去看看win-tc中的第三方BGI演示,里面有个svga64k.bgi,看看你能用得么?

dx是两个字节?恩我没系统学过汇编,不清楚,反正能用就行了,呵呵

淘宝杜琨
2005-02-04 13:31
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏
得分:0 
我只有书本上的资料,《微机接口技术》

淘宝杜琨
2005-02-04 19:48
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏
得分:0 
你可以用win-tc 1.9.1,而且一定要用win-tc系列的,别的还不行哩!

我劝你不用太为这个程序投入,因为很多显卡是不同的。
这就是目前“驱动程序满天飞”的原因。

我这个程序仅仅针对我的intel810主板集成显卡而写的。
当然这个程序也很可能很幸运的适用于你的显卡上,因为我舍友的显卡就能运行我这个程序!

如果,万一万一不幸你不能运行我的程序,那也不要着急。慢慢去学C,总有一天你也可以找到自己显卡的中断,写出你自己的显卡驱动程序的!

我相信你,相信任何有信心的人。

淘宝杜琨
2005-03-10 17:27
快速回复:[原创]TC下高彩色直接写屏技术
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.019802 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved