阿贝的例程学校 第1部分:mode 13h

原创 2002年03月27日 08:51:00
 

[声明]我对阿贝的例程学校(Abe’s Demoschool)和阿贝的智囊(Abe’s bag of tricks)的翻译得到了原作者的同意。任何人如果想使用阿贝的例程学校(Abe’s Demoschool)和阿贝的智囊(Abe’s bag of tricks)做学习交流之外的事情,请与原作者联系:Albert.Veli@systemdesign.af.se<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

Abe's Demoschool Part 1 : mode 13h

阿贝的例程学校 1部分:mode 13h

 

欢迎来到例程学校的第一部分内容。在例程学校中,我将带你领略各种各样的图形特效,包括palette rotation(滚动调色板)、plasma、火焰、sprites(精灵)、3D图形、阴影、卷屏、mode-Xsoundblaster等等所有可以展示的效果。例程学校中的大部分内容都是基于mode 13h或称MCGA-mode。这就立刻引出了第一个问题:

 

[什么是mode 13h]

好吧,答案很简单:mode 13hPC机的一种图形模式,大部分游戏和图形演示都基于mode 13h完成。mode 13h的分辨率是水平方向320个像素,垂直方向200个像素。这使得屏幕上一共出现320×200=64000个像素。屏幕上的每个像素可以有256种不同的颜色(当然一个像素一次只能具有一种颜色)。你肯定知道,一个byte8bit)可以取256种不同的值。这意味着mode 13h中的每一个像素都可以用一个byte来表示,而事实也正是如此。

如上所述,mode 13h拥有320×200=64000个像素即64000bytesMode 13hscreen-memory从地址A000:0000h开始,到A000:FFFFh结束。这总共有65535bytes,从而使屏幕底部还包含了4个不可见的行。

要往屏幕上写一个像素,须先把段寄存器ES设为A0000h,再计算出该像素的偏移量放入DI,然后向ES:DI写入一个colorbyte(即表示颜色的byte)。偏移量用下式计算:

偏移量 = 320 × y + x

其中xx坐标值,yy坐标值。坐标(0,0)位于屏幕的左上角,坐标(319,319)位于屏幕的右下角。下面列出了各个坐标及其相应的偏移量:

       (0,0)       (1,0)       (2,0)       (3,0)                         (319,0)

0     0            1              2            3                           319        ------x-----à

1     320        321        322        323                       639        (319,1)

2     640        641        642        643                       959        (319,2)

.      .             .              .             .                            .

.      .             .              .             .                            .

.      .             .              .             .                            .

199  63680       63681       63682       63683                      63999

       (0,199)       (1,199)       (2,199)       (3,199)                         (319,199)

y

 

mode 13h属于一种线性存储模型(linear memory model),即byte一个接一个的顺序排列。

要在坐标(3,2)处用颜色1(缺省值是蓝色)写入一个像素,你应该向A000:(320×2+3)=A000:643处写入值1。试试吧,一定行。

下面是用C写的一个未优化的例子:

void putpixel(int x,int y,char color)

{

 int offs;

 offs=320*y + x;           //使用公式计算偏移量

 asm     mov     ax,0a000h //你不能把一个值直接放到ES

 asm     mov     es,ax      //把屏幕地址放入ES

 asm     mov     di,offs    //把计算出来的偏移量放入DI

 asm     mov     al,color   //colorbyte放入AL

 asm     mov     [es:di],al //最后将像素写入屏幕

}

在向屏幕写像素之前,你必须已经处于MCGA-mode 13h模式。可以用下面的方法切换到这个mode 13h

    mov     ax,13h  ;把模式代号放入AX

    int     10h      ;使用videointerrupt 10h进入改模式

可以用下面的方法切换回我们常用的textmode 3

    mov     ax,3    ;mode 3DOS的标准80×25 16色文本模式

    int     10h     ;进入textmode 3

你可以用C编写一个切换屏幕模式的函数:

void setmode(int mode)

{

  asm     mov     ax,mode

  asm     int     10h

}

这样,你就可以在main程序开头用setmode(0x0013);切换到mode 13h,再用setmode(3);切换回文本模式。

要优化putpixel函数,你可以将很慢的乘法替换为位运算和加法。你肯定也知道,向左移1位等同于乘以2,向左移2位等同于乘以4,等等。所使用的技巧是,将320分为几个以2为底的幂之和。320(256+64)y×320(y左移8)+(y左移6)。可以参看使用inline-assembler的优化过的putpixel实现之C代码。

一个像素具有什么颜色取决于两个因素:你向屏幕写入的颜色值(0255)以及该值在调色板中所代表的颜色。调色板共有256个入口(0255)。调色板中的每一种颜色由3byte表示,分别代表红、绿、蓝三种颜色。每一个byte值都在063之间。值的大小表示了颜色的强度:0表示没有强度,63表示最大强度。这样就有了643次方种可能的颜色。

[常见的颜色]

      绿             颜色

    ______________________________

    0       0       0       BLACK

    63      0       0       RED

    20      0       0       DARK RED暗红

    0       63      0       GREEN绿

    0       0       63      BLUE

    63      63      0       YELLOW

    63      32      0       ORANGE

    63      0       63      PURPLE

    0       63      63      CYAN

    63      63      63      WHITE

    32      32      32      GRAY

    10      10      10      DARKGRAY暗灰

MCGA-mode 13h总是以相同的调色板开始(即0表示黑,1表示蓝,等等)。但要自己改变调色板是很容易的。通过向3c8h8c9h端口写入适当信息,我们就可以改变调色板。这并没有看上去那么难。你只要向3c8h端口写入你希望改变的起始颜色的索引值,再向3c9h端口写入红、绿、蓝的值就可以了。向3c9h写入了这三个colorbyte后,索引会自动递增。

如果调色板被存放在一个数组pal3×256bytes长),我们假设0代表黑,1代表蓝,2代表灰,那么pal将会像这样开始:0,0,00,0,6332,32,32;……

下面是一个C函数,它根据数组pal的值来设置调色板:

void setpal(char*pal)

{

 int i;

 outp(0x3C8,0);         //从颜色值0开始

 for(i=0;i<256*3;i++)

 outp(0x3C9,pal[i]);    //将调色板数据送到3c9h端口

}

控制调色板最常用的方法就是在特定的程序里使用数组pal,而把调色板的信息存到磁盘的一个文件中。这个调色板文件很容易辨认,因为它的大小总是3×256=768bytes。在程序中你只需要从此磁盘加载调色板文件并将信息放入数组,再用上面讲到的setpal函数设置调色板。

在汇编语言中,你可以使用一个非常快的指令rep outsb来设置调色板。rep outsb 指令从DS:SIbyte传到DX值指示的端口,传送的byte数目由CX的值指定。每传一个byteSI就增加1

下面是设置整个调色板的汇编程序:

mov     dx,03c8h      ;将端口号放到DX

    xor     al,al          ;AX清零

    out     dx,al          ;0传到3c8h端口

    lds     si,pal         ;DS:SI指向pal

    mov     cx,3*256       ;将要传送的byte数目存放在CX

    inc     dx              ;DX = 3c9h

    rep     outsb          ;pal3c9h端口传送768bytes

一种常见的图形效果就是不断的循环改变数组pal并调用setpal(pal)以形成颜色的循环变化。你可以在其它图形特效里使用这种技术来制造静态plasma效果。首先设置数组pal,使其包含一些好看颜色之间平滑的循环变化;然后使用sin或者cos函数在屏幕上画出优美的图案;最后不断的滚动调色板,使其不停的循环即可。

画出的图案并不必须是plasma picture,你可以画任意图案上去,看看当调色板滚动的时候会产生什么效果。要使数组pal循环滚动,先将第一个颜色(即前三个byte)保存起来,然后将数组中所有的颜色值向前移动一个位置(即3byte),最后再将尾部空出来的位置设为刚才保存的颜色。

滚动调色板的C代吗如下:

(实际上就是每次将调色板中第一个颜色滚动到最末尾的位置)

void rotpal(char*pal,int first, int last)

{

  char r,g,b;

  int i;

  r=pal[first*3 + 0];    //将第一个颜色的三个值分别赋给r,g,b

  g=pal[first*3 + 1];

  b=pal[first*3 + 2];

  for(i=first*3;i<(last+1)*3;i++) //将所有颜色向前移动一个位置

    pal[i]=pal[i+3];

 pal[last*3+0]=r;       //将最末尾设置为保存的原第一个颜色

 pal[last*3+1]=g;

 pal[last*3+2]=b;

 wtsync();      //等待电子束扫完当前帧

 setpal(pal);   //根据滚动过的pal设置调色板

}

你并不一定非要将第一个和最末个颜色作为函数参数。但这样做的确有些好处。在例程中,我使用了一个拥有多于256种颜色的输组,每次滚动整个调色板时,都没有改变值为0的颜色,我只设置前256个颜色。我不让值为0的颜色参与滚动是因为,我不希望让背景颜色也改变。你可以让其也参加滚动试一试,这样就能明白我的意思了。

在每次改变调色板之前总应该调用wtsync函数,以避免因为与电子束不同步而产生的所谓“雪花”效果。wtsync等待垂直回溯,即电子束扫完一帧后跳回初始位置以便开始扫下一帧的时刻。

也许你会说本次的例程只能算是半个plasma特效——好吧,在例程学校以后的部分里,我会给你演示真正的plasma特效。

就到此为止,去看看例程的C源代码吧。

[例程在http://www.mds.mdh.se/f%C3%B6reningar/small/abe/abedemo1.zip下载。]

2016年阿里校招笔试题(JAVA研发岗)

一、单项选择题 1. A、B、C三个同学头上分别有三个数字a、b、c,他们看不到自己头上的数字,但可以看到其他两人的。比如B同学能看到a、c,但看不到b。已知1,并且各不相等。A、B、C三个人以此进...
  • xiaoquantouer
  • xiaoquantouer
  • 2016年09月17日 15:46
  • 4808

周志华 《机器学习》之 第七章(贝叶斯分类器)概念总结

贝叶斯分类器是利用概率的知识完成数据的分类任务,在机器学习中使用贝叶斯决策论实施决策的基本方法也是在概率的框架下进行的,它是考虑如何基于这些概率和误判损失来选择最优的类别标记。 贝叶斯决策论 ...
  • lixianjun913
  • lixianjun913
  • 2016年08月19日 14:18
  • 1206

ACMCLUB HDU ACM D题 朋友圈 并查集

问题 D : 朋友圈 时间限制:1 秒 内存限制:32 兆 特殊判题: 否 提交:57 解决: 15 题目描述 小明所在的学校有N个学生,形成M个俱乐部。每个俱乐部里的学生有着...
  • IAccepted
  • IAccepted
  • 2014年03月08日 22:02
  • 2310

long mode 模式下的中断服务例程

转自:点击打开链接 在 long mode 下,gate 是 16 字节的,并取消了对 task gate 的支持。即 IDT 的 entry 是 16 字节的,所以:gate = IDTR...
  • ProgrammingRing
  • ProgrammingRing
  • 2012年04月04日 13:48
  • 677

POSIX 线程详解,第1部分

内容 线程是有趣的 线程是快捷的 线程是可移植的 第一个线程 理解 thread1.c 无父,无子 同步漫游 理解 thread2.c 参考资料 简介: POS...
  • user_920
  • user_920
  • 2012年10月19日 14:02
  • 9518

王爽《汇编语言》实验13——编写、应用中断例程

(1)编写并安装int 7CH中断例程,功能为显示一个用0结尾的字符串。 (2)编写并安装int 7CH中断例程,功能为完成loop指令的功能。 (3)补全程序,分别在屏幕的2、4、6、8行显示4句英...
  • mp4spig
  • mp4spig
  • 2016年08月13日 16:22
  • 744

CC1310空中升级笔记02 CC26xx_CC13xx_BLE_OAD_例程梳理

在笔记1中,TI员工提到了CC26系列已经有实现的OAD的例程。本文大部分资料参考了《CC2640 Over-the-Air Download User’s Guide.pdf》,就先从这个文档下手,...
  • iotisan
  • iotisan
  • 2016年12月04日 16:14
  • 2308

Programming the microsoft windows driver mode 第1版中英PDF_chm 第2版英文PDF

  • 2015年11月24日 10:03
  • 23.91MB
  • 下载

例程(13)-用PCA输出高速脉冲

  • 2011年08月12日 17:35
  • 13KB
  • 下载

瑞萨MCU单片机资料 R5F100LEA RL78G13视频例程

  • 2015年05月31日 17:52
  • 159KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:阿贝的例程学校 第1部分:mode 13h
举报原因:
原因补充:

(最多只允许输入30个字)