| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2640 人关注过本帖
标题:[原创]如何编写自己的图形开发包 — 第二章 给你一个画点函数,你就能描绘整 ...
只看楼主 加入收藏
jig
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
帖 子:530
专家分:242
注 册:2005-12-27
结帖率:100%
收藏
 问题点数:0 回复次数:6 
[原创]如何编写自己的图形开发包 — 第二章 给你一个画点函数,你就能描绘整个世界! - 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)
搜索更多相关主题的帖子: 图形 函数 世界 编写 描绘 
2008-01-22 09:18
一笔苍穹
Rank: 1
等 级:新手上路
帖 子:640
专家分:0
注 册:2006-5-25
收藏
得分:0 
原帖由 [bold][underline]jig[/underline][/bold] 于 2008-1-22 09:18 发表 [url=http://bbs.bccn.net/redirect.php?goto=findpost&pid=1185505&ptid=198264][/url]
此文出至[url]www.[/url]   作者:孙靖

……原来我们的机器在显示构造上是分页的。(具体我也说不大清楚,因为的确对硬件了解不深刻,我只是在玩嵌入式的128X64的普通液晶的时候也发现他是采用同样的分页机理,大家先熟悉这个名词就是了) ...


在实模式下,CPU的寻扯能力只有1M,也就是不管你有多少物理内存,它仅仅只能使用最开始的那1M(我们管这1M内存叫常规内存)。而且这1M也不是从头到尾能顺顺当当的访问,还要通过所谓的段地址+偏移地址机制才能够访问完全,而一个段的段限是64KB这也是在TC下一个数组最大只能有65535个字节的原因,超过这个数编译器便报错——这些东西在微机原理课本和汇编语言课本里是有的,我就不展开来说了。而像1024X768这样的高分辨率,8位色深时整个屏幕在显存中会占到768KB那么大,16位色深下则翻一番达到1.5MB,32位更是达到了3MB。这也是一般图形操作系统对显存的最低要求是4M的原因,否则根本不能支持高分辨率了。那这样一来,16位实模式下岂不是不能对显存访问了,CPU的寻址能力才1M而已,段限则更只有64KB,刚刚说的显存都已经好几MB了,怎么办呢?VESA的VBE标准里就订制了两种寻址模式,一种是应用于16位实模式的,叫页面映射模式(也就是我们常说的换页),这个很像EMS扩充内存的概念,既然CPU只能访问1M,每个数据段只能是64KB,那我们就将1M之外更多的内存映射到1M之内的这块空间来嘛,一般就以64KB为单位,你换到第0页,我就将显存的最开始那64KB映射到内存的0xA000:0000(这个地址在常规的1M内存之内,被称为显存首址),你对这64KB常规内存的所有读写操作都可以通过映射机制转换到显存上最开始那64KB了;然后你换到第1页,就会把显存中64KB-128KB这一段映射到0xA000:0000来,你所有的内存操作又会被映射到显存相应的位置,第二页第三页这样一页页的换下去,最终可以实现访问所有的显存了。

综上所述,映射是种一对多关系的具体实现,它以一块固定大小的常规内存实现对更大内存的对应。打个简单的比方,如果让你运一堆一百吨的煤到工厂去,而你的小卡车每次都只能载重一吨,而且你只有一辆车,那怎么办呢?大不小我一次运一吨运上一百次就运完了嘛。这样你每运一次就相当于“映射”了一次,直到你运完。这样,你用一个一吨的小卡照样能“访问”所有的煤并进行“操作”^_^

再来说说VBE标准中的第二种显存寻址方式——线性寻址,这是对于保护模式而言的,保护模式下,内存对于程序员来说是平坦的,线性的,并且寻址能力达到了4GB!这样一来就不需要这么麻烦了,有个载重一千吨的交通工具,一百吨煤一次性运完就OK了。像allegro等DOS下可以使用的图形库,就支持这种寻址方式,又快又直接。不过使用这个模式的前提是你的编译器得是32位的,支持DPMI。比如DJGPP和OPEN WATCOM
2008-01-22 14:23
jig
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
帖 子:530
专家分:242
注 册:2005-12-27
收藏
得分:0 
什么时候整理了添进去

个人网站 -  http://.h001.
2008-01-23 11:26
lianzerong
Rank: 1
等 级:新手上路
帖 子:53
专家分:0
注 册:2007-7-23
收藏
得分:0 
谢谢两位BZ辛苦了 !!!
学习中!!!!!!
2008-04-01 17:14
lionkind117
Rank: 1
等 级:新手上路
帖 子:9
专家分:5
注 册:2008-4-2
收藏
得分:0 
[bo]以下是引用 [un]一笔苍穹[/un] 在 2008-1-22 14:23 的发言:[/bo]



在实模式下,CPU的寻扯能力只有1M,也就是不管你有多少物理内存,它仅仅只能使用最开始的那1M(我们管这1M内存叫常规内存)。而且这1M也不是从头到尾能顺顺当当的访问,还要通过所谓的段地址+偏移地址机制才能够访问完全,而一个 ...

微机原理、汇编
汇编强人、硬件强人我崇拜你。
2008-04-03 19:23
hxlich
Rank: 2
等 级:论坛游民
帖 子:26
专家分:45
注 册:2010-3-28
收藏
得分:0 
好东西,慢慢看
2010-03-28 22:18
快速回复:[原创]如何编写自己的图形开发包 — 第二章 给你一个画点函数,你就能 ...
数据加载中...
 
   



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

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