[原创]如何编写自己的图形开发包 — 第二章 给你一个画点函数,你就能描绘整个世界! - 2.2
此文出至[url]www.[/url] 作者:孙靖[bold]第二章 给你一个画点函数,你就能描绘整个世界! [/bold]
[bold]2.2 完善我们的画点函数[/bold]
就我们上小节提到的几个问题,其实可以帮助我们从现在开始建立比较宏观的概念在架构层面来考虑事情。虽然目前我们做的例子很简单,但他也充分展现了我们应该以何种方式和思维来安排设计我们的程序。(我并不是架构发面的高手,我很想自己有质的提高可我也在努力中)
由于要考虑我们的Dot()函数能自行排除输入坐标无效的功能,我们必须再返回到第一章的内容,对我们前面的代码稍做改动。
1. 我们要纪录下当前分辨率,以便在需要的时候使用他们
2. 增添必要的图形包初始化,和结束函数使其在架构上趋向完整
代码:查看Chap02-2
INT16 COLS, ROWS; /* 记录当前图形模式分辨率 */
INT16 OldSMode; /* 纪录原始模式 */
Void InitSVGA(); /* 图形初始化 */
void InitSVGA()
{
OldSMode = GetSVGAMode();
}
Void ExitSVGA(); /* 回到原来模式 */
Void ExitSVGA()
{
SetSVGAMode(OldSMode);
}
OK,有了以上改动,我们再来初步改造我们的Dot()函数,使其更能贴近实用。
代码:查看Chap02-2
void Dot(INT16 x, INT16 y, UINT8 color); /* 画点函数 */
void Dot(INT16 x, INT16 y, UINT8 color)
{
if (x > -1 && x < COLS && y > -1 && y < ROWS)
VideoBuffer[y* COLS +x] = color;
}
写到这里,我们的Dot()函数初步改造完毕。您可以将2.1中的Chap02-main2中写一个在定义范围之外的坐标,你肯定可以发现点画乱了。而你再实验一下以上的Chap02-2-main1发现他完美无缺,不会超出我们分辨率范围也不会导致画屏幕。呵呵,小小的成就感犹然而生。
代码:查看Chap02-2-main1
#include "GrTry.c"
int main()
{
INT16 i;
InitSVGA(); /* 图形初始化开始 */
SetSVGAMode(TRY320X200X256); /* 实现图形模式 */
for (i = 0; i < 256; i++) /* 调用Dot函数画点 */
Dot(i, i, i);
getch();
ExitSVGA(); /* 恢复原始的模式 */
}
效果如图2.3:
图2.3 修改后的画点函数效果
接下来我们要做一点更具挑战性的实验。我们不是还不确定我们在其他高一点的分辨率下我们的函数是否会奏效?下面我们就来尝试一下,我们就先试验640X480 - 256色(8位色深)模式。
代码:查看Chap02-2-main2
#include "GrTry.c"
int main()
{
INT16 i;
InitSVGA(); /* 图形初始化开始 */
SetSVGAMode(TRY640X480X256); /* 实现图形模式 */
for (i = 0; i < 256; i++) /* 调用Dot函数画点 */
Dot(i, i, i);
getch();
ExitSVGA(); /* 恢复原始的模式 */
}
效果如图2.4:
图2.4 高分辨率效果
这下惨了吧,出错了。按我们程序的代码,程序应该打印一条256个像素的斜线,也就是说上图中右边两段按道理应该接在最左边线段之下成一条直线的。
原来我们的机器在显示构造上是分页的。(具体我也说不大清楚,因为的确对硬件了解不深刻,我只是在玩嵌入式的128X64的普通液晶的时候也发现他是采用同样的分页机理,大家先熟悉这个名词就是了)什么意思呢?就是说,我们在对VideoBuffer写数据的时候还要考虑当前坐标在哪个页上,还要设置页面才能保证显示的正确。那么,通常情况下我们显卡都是默认为64K为一页。当然,也许你会遇见其他的显卡,所以你最好根据VBE3.0的标准去检测一下你的显卡到底是按多大显存分页的,以便您能实现自己预想的操作。而本文就默认按64K为一页来实现。
换页函数也很简单,说白了还是一个设置。
代码:查看Chap02-2\main3
void SelectPage(register UINT8 page); /* 换页函数 */
void SelectPage(register UINT8 page)
{
_BX = 0;
_DX = page;
_AX = 0x4f05;
__int__(0x10);
}
void Dot(INT16 x, INT16 y, UINT8 color); /* 画点函数 */
void Dot(INT16 x, INT16 y, UINT8 color)
{
UINT32 PageAll1, PageAll2;
UINT8 PageIndex;
if (x > -1 && x < COLS && y > -1 && y < ROWS)
{
PageAll1 = PageAll2 = (UINT32)y*(UINT32)COLS+(UINT32)x;
PageIndex = PageAll1 >> 16;
SelectPage(PageIndex); /* 计算并设置页面 */
VideoBuffer[PageAll2] = color;
}
}
代码:查看Chap02-2\main3-main1
#include "GrTry.c"
int main()
{
INT16 i;
InitSVGA(); /* 图形初始化开始 */
SetSVGAMode(TRY640X480X256); /* 实现图形模式 */
for (i = 0; i < 256; i++) /* 调用Dot函数画点 */
Dot(i, i, i);
getch();
ExitSVGA(); /* 恢复原始的模式 */
}
效果如图2.5:
图2.5 增加换页函数后高分辨率效果
哈哈,再多试试,我保证这回你的画点函数绝对可以正常的为你工作。所以在这大家要特别记住换页这一步骤。这步曾经困扰了我多久啊,由于不明白概念不知道硬件有这样的一个工作机理很多人可能就这步就给拦下啦。当然现代显卡还有显存为线性模式的,要你的是那些特殊显卡那就要你自己慢慢去摸索啦。
实验到这里,我们可以真的得意一下啦。因为你确实已经提供了一个相对比较完善的画点函数啦。当然,也许你会注意到Dot()总的换页函数很多时候是在重复工作,我们应该适当改进他,已减少不必要的开销。
代码:此段代码不特别演示,在Chap03以后(包括Chap03)都将是这个被优化了的Dot()函数
void Dot(INT16 x, INT16 y, UINT8 color); /* 画点函数,优化换页部分 */
void Dot(INT16 x, INT16 y, UINT8 color)
{
static UINT8 OldPage = 0;
UINT32 PageAll1, PageAll2;
UINT8 NewPage;
if (x > -1 && x < COLS && y > -1 && y < ROWS)
{
PageAll1 = PageAll2 = (UINT32)y*(UINT32)COLS+(UINT32)x;
NewPage = PageAll1 >> 16;
if (NewPage != OldPage)
{
OldPage = NewPage;
SelectPage(NewPage);
}
VideoBuffer[PageAll2] = color;
}
}
至此,第二章结束,各位可以反复的去实验本章提到的实例。介绍到这里,可以说我们图形包底层的很多知识已经具备,接下来我们要来看看,有了这样一个基础性的成果我们能做点什么?让我们来做点高级一点的高层建筑。
资料代码下载:
[[italic] 本帖最后由 jig 于 2008-1-22 09:19 编辑 [/italic]]
Chap02-2.rar
(19.45 KB)