TC下高彩色直接写屏技术
本文纯属抛砖引玉之作,如果各路高手对此文有什么不同或者更加准确的看法,请畅所欲言。
bbs.bc-cn.net
本文章基于高彩色640X480模式。
个人极力推荐‘晕倒死’下的C语言编辑器:WIN-TC 1.91
个人极力反对大家把自己的硬盘格成NTFS格式!
鄙视微软!
又:由于各个显卡可能存在不兼容,而我又不知道SVGA标准,所以很有可能会相当多的网友不能正常运行程序,抱歉~
终于,在一个夜黑风高的夜晚,我终于找到了一个不用图形驱动程序(BGI)就可进入640x480x65536的方法(花了不少精力呢~恩~还是值得的T_T):
void setmode(int vmode)
{
asm mov ax,0x
asm mov bx,vmode
asm int 0x10
}
vmode值的说明:
0x0048或0x0049都是640x480x65536模式
0x
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. 怎么写?
总结起来也无非就是3W(Where,What,hoW)。
1. 战斗在0xa0000000处打响
由于系统统一编址时,EGA,VGA的VRAM开始段地址分配为0xA000,所以VRAM开始单元地址为0xa000:0x0000。好,知道了VRAM的开始地址我们也就知道该往那里写了,于是我们定义一个指向0xa0000000的远程指针,这样就可以从0xa0000000开始写数据了。
unsigned int far *VramPoint=(unsigned int far *)0xa
这样,第一个问题 “往那里写” 就解决了。
2. 转换RGB表示高彩色
高彩色在内存中是用2个字节来表示一个像素的。那每个颜色的值是如何确定的呢?比如:谁知道红色在高彩色中是如何定义的呢的?这样就到了整个技术的难点了——用RGB表示颜色值。
说句实话,我也不清楚高彩色的颜色值是怎么定义的,但即使你知道我也不想听,因为记下65536那么多种颜色不是闹着完的。还好我想出了个比较easy的方法解决了这个问题。用RGB来表示颜色值。现在问题又来了——什么叫RGB呢?
RGB就是Red Green Blue即红绿蓝三种基本色的E文缩写。每一种颜色都有256种强度,不同强度的基本色相互搭配会产生不同的颜色效果。故RGB三种基本色的256种强度共计可以表现256*256*256=16777216种颜色,也就是我们说的
毫无疑问,这样强大的颜色系统肯定能击溃我们脆弱的眼睛。但,也许有细心的网友在看到这里的时候会有个很大的疑问——我打算用RGB来表示高彩色,可是RGB的颜色系统用的是3个字节来表示一个像素的颜色,而高彩色是用2个字节来表示的,多出的一个字节怎么办?
是啊,怎么办?没关系,我花了一个上午的时间终于找到了解决的方法——转换!
转换的原理很简单,因为高彩色只能显示出32种红色、蓝色和64种绿色,所以我就把多余的颜色砍掉了。问:“你怎么知道高彩色只能显示‘32种红色、蓝色和64种绿色’的?”对此你大可以不必去理解,我估计也没几个人想去听,我也忘记从那里做的笔记了,好像是上高中的时候上美术课老师无意中说的而我又恰好无意中把它记了下来…下面我就来说些关键的——如何转换。
比如有三个RGB的值 r=
r=128 对应的二进制 10000000
g=31 00011111
b=165 10100101
然后我们把r和b的后面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,0x
asm mov bx,0
asm mov dx,page /*page是选择的部分*/
asm int 0x10
}
然后我们还要编写一个函数用来快速判断一个二维坐标的点在VRAM中是在第几部分的哪个位置!注意,如何快速判断我认为这个是最最难的地方,不管我尽多大努力,在速度上仍然是差强人意!所以这个问题我就先放这吧,如果有高手看到了请指点一二,以餮网友。
好了,到此,3个难点都解决了。也许你还有一些不理解,不要紧,我们马上结束理论上的东西,投入到实验当中去。