注册 登录
编程论坛 C图形专区

800X600X256 虚拟缓冲区送显示缓冲区的困惑

ba_wang_mao 发布于 2006-11-08 16:41, 1822 次点击

方法如下:为屏幕建立一个虚拟屏幕,即在内存中开辟一片空间,用于存放屏幕信息。若将欲送到屏幕上的内容先送到虚拟屏幕(以下简称虚屏)中,然后将虚屏内容复制到物理屏幕上,
  ┌──────┐ 写入┌────┐ 写入┌────┐
  │欲显示的信息├──> 虚拟屏幕 ├──> 物理屏幕│
  └──────┘ └────┘ └────┘

1、在320X200X256下,可通过下面两条指令
VDCBuf=new (unsigned char)(320*200);
(a).memset(VDCBuf,RED,320*200);
(b).for ( i = 0 ; i < 200 ; i++)
movedata(FP_SEG(&(VDCBuf[i*320])),FP_OFF(&(VDCBuf[i*320])),0xA000,i*320,320);
将整个屏幕初始化为红色,
2、请问由于在800X600X256下存在分页,如何将通过虚拟屏幕将物理屏幕初始化为红色

13 回复
#2
一笔苍穹2006-11-08 18:31
去下个VBE标准文档看看吧,要不GOOGLE一下吴进以前写的相关文章,了解换页的概念。
#3
ba_wang_mao2006-11-08 19:53
谢谢一笔苍穹,我先查一查吴进相关的文章。
#4
一笔苍穹2006-11-09 10:24

恩,我当时也是靠吴进网站里的那几篇文章引发的兴趣入的门,可惜他的站点早就关闭了。不过网上应该还是能搜到。

#5
ba_wang_mao2006-11-09 17:03

以下是我从网上好不容易google的,
#include<conio.h>
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include <dos.h>
#include <stdlib.h>
#define VBE320X200X256 0X13
#define VBE640X480X256 0X101
#define VBE800X600X256 0X103
#define VBE1024X768X256 0X105
class VIEW //显示类
{
char *video,_video_; //虚拟屏幕内存指针
unsigned short g_cur_vbe_page; //引用neo变量
public:
VIEW(); //本类构造函数
~VIEW(); //本类析构函数
void InitGraph(void); //初始化显示模式
void CloseGraph(void); //关闭图形模式
void set_vbe_page(int page); //引用neo函数
void BitBlt(); //将虚拟屏幕的内容写至物理屏幕上
void PutPixel(int x,int y,int color); //指定颜色画点
void HLine(int x,int y,int color); //画横线
};

VIEW::VIEW()
{
GuiInitGraph(); //初始化图形显式模式
_video_=(char *)malloc(800*600*sizeof(char)); //为虚拟屏幕分配内存
video = _video_;
}

VIEW::~VIEW() //本类析构函数,自动执行
{
free(video); //释放虚拟屏幕所用内存
GuiCloseGraph(); //初始化屏幕为文本状态
}

/////////////////////////////////////////////////////////////////////////////////////////////////
//显存换页函数 引用neo函数
/////////////////////////////////////////////////////////////////////////////////////////////////
void VIEW:: set_vbe_page(int page)
{
if (g_cur_vbe_page != page)
{
_BX = 0;
_DX = g_cur_vbe_page = page;
_AX = 0x4F05;
__int__(0x10);
}
}

/////////////////////////////////////////////////////////////////////////////////////////////////
//初始化屏幕为800X600X256
/////////////////////////////////////////////////////////////////////////////////////////////////
void VIEW::GuiInitGraph(void)
{
_AX = 0x4F02;
_BX = VBE800X600X256;
__int__(0x10);
if(_AH != 0)
{
puts("Can't Initialize the graphics mode!");
exit(1);
}
}

/////////////////////////////////////////////////////////////////////////////////////////////////
//关闭图形模式函数
/////////////////////////////////////////////////////////////////////////////////////////////////
void VIEW::GuiCloseGraph(void)
{
_AX = 0x4F02;
_BX = 0x03;
__int__(0x10);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
//按指定颜色画点到虚拟屏幕
/////////////////////////////////////////////////////////////////////////////////////////////////
void VIEW::PutPixel(int x, int y,int color)
{
if(x<=799 &&y<=599)
{
video=_video_+y*800+x; //移动虚拟屏幕指针
*video=color=c; //写入颜色代码并改变当前颜色
}
video=_video_; //恢复虚拟屏幕指针
}

/////////////////////////////////////////////////////////////////////////////////////////////////
//虚拟屏幕800X600送物理屏幕函数
/////////////////////////////////////////////////////////////////////////////////////////////////
void VIEW::BitBlt() //屏幕刷新函数
{
unsigned char i;
unsigned short *VIDEO=(unsigned short *)(0xA000<<4); //显存指针

video=_video; //恢复虚拟屏幕指针
for(i=0;i<14;i++)
{
set_vbe_page(i); //选择显存页面
memcpy(VIDEO,video,65536); //从虚拟屏幕拷贝64k数据到显存
video+=32768; //虚拟屏幕指针后移
}
set_vbe_page(14); //选择最后一页
memcpy(VIDEO,video,42496); //写入最后一页数据
video=_video; //恢复虚拟屏幕指针
}


void main()
{
VIEW vga; //创建控制指针

for (int i=0;i<800;i++)
for (int j=0;j<600;j++)
vga.PutPixel(i,j,WHITE);//从虚屏用白色点填充
vga.BitBlt(); //送到物理屏幕
getch();
getch();
}

一笔苍穹,上面的程序怎么无法实现800X600X256的屏幕上满屏显示白色呢?

#6
一笔苍穹2006-11-09 17:31
呵呵,里面还有NEO的痕迹。
_video_=(char *)malloc(800*600*sizeof(char));这句在TC\BC下是申请不到的,你也不检查一下就拿着指针用了。
#7
ba_wang_mao2006-11-10 09:01
一笔苍穹:
1、 件扩展名为*.CPP时,可以采用
_video_= new ( char)[800*600]; // 为虚拟屏幕分配内存
if (_video_f==NULL) // 内存分配失败
{
exit(1);
}
那么在扩展名为*.C时,该如何分配呢?我试过如果使用
_video_=(char *)malloc(800*600*sizeof(char));
不可靠,该如何办呢?
2、如何将虚拟屏幕_video_写到物理屏幕呢?
  如果每次往物理屏幕送1行=800个像素,采用movedata()函数,有可能进行换页,我不知道该如何处理。
  如果每次往物理屏幕送10行=8000个像素,采用movedata()函数,又该如何处理。
#8
一笔苍穹2006-11-10 10:44
你的什么编译器啊?
#9
ba_wang_mao2006-11-10 11:37

TC++3.0 for dos/BC3.1++ for dos

、如何将虚拟屏幕_video_写到物理屏幕呢?
  如果每次往物理屏幕送1行=800个像素,采用movedata()函数,有可能进行换页,我不知道该如何处理。
for (int i=0;i<600;i++)
movedata(source_seg,source_off,dest_seg,dest_off,800);
但是换页时该如何处理呢?我看到过《RockCarry工作室》的陈凯发表过虚拟缓冲区送显示缓冲区相关的文章。

#10
一笔苍穹2006-11-10 12:18
如果是TC++/BC++的话,你的代码:
_video_= new ( char)[800*600]; // 为虚拟屏幕分配内存
if (_video_f==NULL) // 内存分配失败
{
exit(1);
}
同样是不可靠的,一个基本的事实,DOS在实模式下每调用一次new或malloc只能申请到最多64KB的空间,你用TC++/BC++在普通情况下是无法一次性申请到800X600合400多KB的空间的,你也许会想到将这468KB的空间分开申请,那我还要告诉你一个失望的消息:DOS下一般情况下你能使用的自由空间只有640KB,你的程序本身就要占个几十KB,一个虚拟屏幕就要400多KB,加一块就是500多KB,DOS一般还要加载一些常驻程序像鼠标的驱动光驱驱动什么的,哪怕是它什么都不加载把这640K全给你,你也只剩下100K左右的空间了,省着点用吧——做图形程序的人都知道100KB是多么的微不足道。对了,记得让程序在大模式或紧凑模式下编译,不然你还无福享用这全部的640KB空间。现在你能知道比尔·盖茨在DOS刚诞生时说的那句名言:“640K对于任何用户都已经足够了…”是多么可笑和滑稽了吧?
好了,无奈归无奈,但解决方案还是要给一些的:
上策:别用TC/BC了,最好是连DOS都别碰了,LINUX或WINDOWS吧,脱离苦海,逃出阿鼻狱,阿弥陀佛……
中策:别用TC/BC了,Microsoft C也别碰了,DJGPP或WatcomC吧,保护模式,无内存限制,善哉善哉……
下策:还是用TC/BC,使用扩展扩充内存,可以访问16M内存,去查查XMS/EMS的资料吧,要不就直接用NEO中的头文件NEMS.H和XMS.H,里面有需要的基本函数,接口说明参考NEO的使用文档。等你了解完了这些后,你可以做出你上面要的东西,但却发现又淊入了一个泥潭。

[此贴子已经被作者于2006-11-10 12:21:29编辑过]

#11
ba_wang_mao2006-11-10 14:58
一笔苍穹:
1、我必须要在DOS下用TC++编程,由于要画实时曲线,因此希望将画的中间过程全部(以前画的线全部清除,当前时刻重新画线)在虚拟屏上做,最后显示屏上显示的是最终结果。
  看来,只能用XMS存储虚拟屏幕内容了。XMS方面的编程我参照你的NEO程序已经完全调试成功(汉字库HZK16就是调入XMS内存中)但是,如果将虚拟屏内容送到物理屏幕
我摸不着边际,请求一笔苍穹帮忙,  
  如果每次往物理屏幕送1行=800个像素,采用movedata()函数,中间进行换页,该如何处理?
for (int i=0;i<600;i++)
movedata(source_seg,source_off,dest_seg,dest_off,800);
 2、如何显示一个红色的底色白色的字呢(红底白字),图形模式有前景色及背景色的概念吗?
#12
一笔苍穹2006-11-10 15:44
第一行有800个像素,显存中的一页一般为64K,在8位色深模式下,即可存储0xffff(65535)个像素,然后做一个很简单的数学运算:扫描线的像素偏移除以64K,整数部分就是这一行所在的页码了,假如你要拷贝第一行扫描线,它位于第就是800 / 64K,它在第0页,如果你要拷贝的是第400行,就是800*400/65536=4,那就是要换到第四号页了。至于换完页后第400行的最末一个像素在4#显存页中对应哪个地址呢(即偏移量)?你可以用800*400%65536算得。
不过你要是用XMS的话,movedata()有可能被优化掉,你边做边看吧。
#13
ba_wang_mao2006-11-10 16:16
太感谢一笔苍穹了。
不知你的GUI设计的怎么样了,我觉得要想在DOS下设计出《WINDOWS经典界面》开始菜单上的“白色”都比较困难,还有窗口上的标题条上的“过渡色”,不知如何设计,主要是对设色板无概念。
#14
一笔苍穹2006-11-10 16:51

现在没时间做这些东西了,NEO的维护也几近停滞,只能说争取今年能再发布一个正式版吧,GUI那块可能还是空缺,所以要让你失望了。
要在256色做外观比较漂亮的GUI是极有挑战力的,在高、真彩下做就好弄些。在256色模式下要考虑的东西较多,归结下来其它还是调色板的问题,要做一个覆盖面齐全的调色板不是件容易事,为了显示其它各种图片,还要有比较好的抖动函数,NEO库里的那个还不行,总之加油吧。

1