0Dh模式下的DOS EGA图形编程

Par*_*ppa 7 graphics dos retro-computing

我正在做一些有趣的复古编程.我想要创建的是使用EGA图形的DOS游戏,但我在网上找到一个很好的参考有点麻烦.每个谈论做DOS编程的人都假设程序员会使用模式13h,虽然有些页面提到了其他图形模式,但我还没有找到一个讨论正确使用的模式.

这就是我现在要努力的方法:

//------------------------------------------------------------------------------
//  DOS graphics test
//
//  Thanks to the following links:
//    http://gamebub.com/cpp_graphics.php
//
//  Written for Digital Mars C compiler to be compiled as a DOS 16 bit binary.
//------------------------------------------------------------------------------

#include <dos.h>
#include <stdio.h>

#define SCREEN_WIDTH  320;
#define SCREEN_HEIGHT 200;

unsigned char far *vram = (unsigned char far *)0xA0000000L;

//------------------------------------------------------------------------------
void set_video_mode(unsigned char mode)
{
    union REGS in, out;
    in.h.ah = 0;
    in.h.al = mode;
    int86(0x10, &in, &out);
}

//------------------------------------------------------------------------------
void plot_pixel(unsigned int x, unsigned int y, unsigned char color)
{
    // this is wrong because it's only 4 bpp not 8
    vram[y * 320 + x] = color;
    //vram[((y<<8)+(y<<6))+x] = color;
}

//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    // EGA 320 x 200 x 16
    set_video_mode(0x0d);

    for (unsigned char i = 0; i < 255; i++)
    {
        vram[i] = i;
    }

    //plot_pixel(10, 10, 1);

    getc(stdin);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果您将set_video_mode()更改为取代0x13而不是0x0d,则此示例代码效果很好,但就像我说我试图在这里获取EGA图形而不是VGA.:)我意识到为了做每像素四位,我要么要么假设plot_pixel同时写入两个像素,要么做一点点twiddling以确保我只写了四位我实际上想要.

我的问题是我没有看到我期望的输出 - 特别是没有颜色!一切似乎都是单色的,这根本不是我想要的.在这种图形模式下使用调色板是否有某种不同的程序比在13h?或者我以某种方式调用了与我想要的完全不同的图形模式?非常感谢指导.

我不认为我的编译器args是相关的,但以防万一:

..\dm\bin\dmc test.c -o test -mm
Run Code Online (Sandbox Code Playgroud)

t0m*_*13b 5

嗯..不知道这是否是一个值得回答的问题,如果我记得的话,您需要使用inport, inportb, outport,outportb到端口来控制 EGA 寄存器,这取自优秀的 FAQSYSW (大量材料集合,包括图形演示、数学,分形压缩),原始档案可以在这里这里找到:

3C0h:属性控制器:地址寄存器
位 0-4 要写入端口 3C0h 的数据寄存器的地址。
      5 如果设置屏幕输出已启用并且调色板无法修改,
         如果禁用清屏输出并且可以修改调色板。


端口3C0h 的特殊之处在于它既是地址寄存器又是数据写入寄存器。
内部触发器会记住它当前是否充当地址或
数据寄存器。对属性控制器的访问必须用 at 分隔
至少250ns。读端口 3dAh 会将触发器重置为地址模式。


3C0h 索引 0-Fh (W):属性:调色板
位 0 原蓝色
      1 原色绿色
      2原色红
      3 二次蓝
      4 二次绿
      5 次红

3C0h 索引 10h (W):属性:模式控制寄存器
位 0 如果设置则为图形模式,否则为字母数字模式。
      1 如果设置为单色模式,否则为彩色模式。
      2 个 9 位宽字符(如果设置)。
         字符 C0h-DFh 的第 9 位将与
         第 8 位。否则它将是背景颜色。
      3 如果设置属性位 7 闪烁,则为高强度。

3C0h 索引 11h (W):属性:过扫描颜色寄存器。
位 0-5 屏幕边框颜色。颜色在调色板寄存器中定义。
注意:EGA 要求高分辨率模式下过扫描颜色为 0。

3C0h 索引 12h (W):属性:色彩平面启用寄存器
位 0 位平面 0 如果设置则启用。
      1 位平面 1 如果设置则启用。
      2 位平面 2 如果设置则启用。
      3 位平面 3 如果设置则启用。
    4-5 视频状态复用器。仅供诊断使用。
         两个属性位出现在输入状态的位 4 和 5 上
         寄存器 1 (3dAh)。0:红/蓝,1:蓝(I)/绿,2:红(I)/绿(I)

3C0h 索引 13h (W):属性:水平 PEL 平移寄存器
位 0-3 指示向左移动显示的像素数
         值 9bit 文本模式 256 色模式 其他模式
           0 1 0 0
           1 2 不适用 1
           2 3 1 2
           3 4 不适用 3
           4 5 2 4
           5 6 不适用 5
           6 7 3 6
           7 8 不适用 7
           8 0 不适用

3C2h (R):输入状态#0 寄存器
位 4 由杂项输出选择的开关状态
         寄存器 3C2h 位 2-3。如果设置则切换为高电平。
      5 如果设置,功能连接器 (FEAT0) 的引脚 19 为高电平
      6 如果设置,功能连接器 (FEAT1) 的引脚 17 为高电平
      7 如果由于垂直回扫而发生设置IRQ 2。应该清除
         通过 IRQ 2 中断例程清除端口 3d4h 索引 11h 位 4。

3C2h (W):杂项输出寄存器
位 0 如果设置颜色仿真。基地址=3Dxh,否则为单声道仿真。根据
         地址=3Bxh。
      1 启用 CPU 对视频内存的访问(如果设置)
    2-3 时钟选择。0:14MHz,1:16MHz,2:外部
      4 禁用内部视频驱动程序(如果设置)
      5 当处于奇数/偶数模式时 选择高 64k 组(如果已设置)
      6 水平同步极性。如果设置则为负
      7 垂直同步极性。如果设置则为负
         位 6-7 表示显示屏上的行数:
           0:200行,2:350行
注意:硬件复位时设置为全零。

3C4h 索引 0 (W):定序器:复位
位 0 异步复位(如果清零)
      1 同步复位(如果清除)

3C4h 索引 1 (W):定序器:时钟模式
位 0 如果设置的字符时钟为 8 点宽,否则为 9 点。
      1 如果设置,CRTC 使用 2/5 的时钟周期,否则使用 4/5。
      2 如果设置每隔一个字符加载视频序列化器
         时钟周期,其他每个周期。
      3 如果设置点时钟为主时钟/2,否则与主时钟相同
          (参见 3C2h 位 2-3)。(像素加倍)。

3C4h 索引 2 (W):定序器:映射掩码寄存器
位 0 如果设置,则启用对平面 0 的写入
      1 如果设置,则启用对平面 1 的写入
      2 如果设置,则启用对平面 2 的写入
      3 如果设置,则启用对平面 3 的写入

3C4h 索引 3 (W):定序器:字符映射选择寄存器
位 0-1 如果字符的位 3,则选择 EGA 字符映射 (0..3)
         属性明确。
    2-3 如果字符的位 3,则选择 EGA 字符映射 (0..3)
         属性已设置。
注意:字符映射表的放置方式如下:
      地图 0 位于 0k,地图 1 位于 16k,地图 2 位于 32k,地图 3 位于 48k

3C4h 索引 4 (W):定序器:内存模式寄存器
位 0 设置是否处于字母数字模式,在图形模式下清除。
      1 设置适配器上的大小是否超过 64kbyte。
      2 如果设置,则启用奇/偶寻址模式。奇数/偶数模式放置所有奇数
         平面 1&3 中的字节,以及平面 0&2 中的所有偶数字节。

3CAh (W):图形 2 位置
bit 0-1 选择图形控制器应控制哪些位平面
         #2. 始终设置为 1。

3CCh (W):图形 1 位置
bit 0-1 选择图形控制器应控制哪些位平面
         #1. 始终设置为 0。

3CEh 索引 0 (W):图形:设置/重置寄存器
位 0 如果处于写入模式 0 并且 3CEh 索引 1 的位 0 设置为写入
         显示存储器会将字节的平面 0 中的所有位设置为此
         位,如果在映射掩码寄存器(3CEh
         索引 8)。
      1 平面 1 和 3CEh 索引 1 的位 1 相同。
      2 平面 2 和 3CEh 索引 1 的位 2 相同。
      3 平面 3 和 3CEh 索引 1 的位 3 相同。

3CEh 索引 1 (W):图形:启用设置/重置寄存器
位 0 如果置位,则在写入模式 0 下启用平面 ​​0 的设置/复位。
      1 飞机 1 相同。
      2 飞机 2 也同样。
      3 飞机 3 也是如此。

3CEh 索引 2 (W):图形:颜色比较寄存器
位 0-3 在读取模式 1 下,比较读取的字节地址处的每个像素
         如果此颜色和输出中的相应位设置为 1
         它们匹配,如果不匹配则为 0。颜色无关寄存器(3CEh 索引 7)
         可以从比较中排除位平面。

3CEh 索引 3 (W):图形:数据旋转
位 0-2 在写入数据之前旋转数据的位置数
         显示内存。仅在写入模式 0 下有效。
    3-4 在写入模式 2 下,该字段控制数据之间的关系
         从CPU写入,从先前读取锁存的数据和
         写入显示存储器的数据:
           0:CPU 数据未修改地写入
           1:CPU 数据与锁存数据进行“与”运算
           2:CPU 数据与锁存器数据进行或运算。
           3:CPU 数据与锁存数据进行异或运算。

3CEh 索引 4 (W):图形:读取地图选择寄存器
bit 0-1 读取模式 0 将读取的平面编号。

3CEh 索引 5 (W):图形:模式寄存器
bit 0-1 写入模式:控制来自 CPU 的数据之前如何转换
         正在写入显示内存:
           0:模式0作为读-修改-写操作。
              首先,读访问加载 EGA 的数据锁存器
              视频内存中寻址位置的值。然后写一个
              访问将提供目标地址和CPU数据
              字节。写入的数据由功能码中的修改
              数据循环寄存器(3CEh 索引 3)作为 CPU 的函数
              数据和锁存器,然后数据按指定的方式旋转
              相同的寄存器。
           1:模式 1 用于视频到视频传输。
              读访问将加载数据锁存器的内容
              视频内存的寻址字节。写访问将写入
              锁存器的内容到寻址字节。因此单个
              MOVSB指令可以复制源地址字节中的所有像素
              到目的地地址。
           2:模式 2 将颜色写入寻址字节中的所有像素
              视频内存。CPU数据的Bit 0写入平面0等
              等等。各个位可以通过启用或禁用
              位掩码寄存器(3CEh 索引 8)。
      2 如果设置,则强制所有输出进入高阻抗状态。
      3 阅读模式
           0:根据读取映射从 4 个位平面之一读取数据
              选择寄存器(3CEh 索引 4)。
           1:返回的数据是占用的8个像素之间的比较
              读取字节和颜色比较寄存器中的颜色(3CEh
              索引 2)。如果相应像素的颜色被设置一位
              与寄存器匹配。
      4 如果设置,则启用奇/偶模式(请参见 3C4h 索引 4 位 2)。
      5 如果设置,则使用偶数/奇数位对启用 CGA 样式 4 颜色像素。

3CEh 索引 6 (W):图形:杂项寄存器
位 0 如果设置则表示图形模式,否则表示字母数字模式。
      1 如果设置,则启用奇/偶模式。
    2-3 内存映射:
           0:使用A000h-BFFFh
           1:使用 A000h-AFFFh EGA 图形模式
           2:使用B000h-B7FFh单色模式
           3:使用 B800h-BFFFh CGA 模式

3CEh 索引 7 (W):图形:颜色 无关寄存器
位 0 如果清除,则在读取模式 1 下忽略位平面 0。
      1 如果清除,则忽略读取模式 1 中的位平面 1。
      2 如果清除,则忽略读取模式 1 中的位平面 2。
      3 如果清除,则忽略读取模式 1 中的位平面 3。

3CEh 索引 8 (W):图形:位掩码寄存器
位 0-7 如果设置每个位,则可以写入字节中的相应位
         显示内存。

3d4h 索引 0 (W):CRTC:水平总计寄存器
位 0-7 水平总字符时钟-2

3d4h 索引 1 (W):CRTC:水平显示结束寄存器
位 0-7 显示的字符时钟数 -1

3d4h 索引 2 (W):CRTC:开始水平消隐寄存器
bit 0-7 水平消隐开始的计数

3d4h 索引 3 (W):CRTC:结束水平消隐寄存器
位 0-4 当字符的最后 5 位完成时,水平消隐结束
         计数器等于该字段。
    5-6 水平显示后延迟显示开始的字符时钟数
         已达到总数。

3d4h 索引 4 (W):CRTC:开始水平回扫寄存器
位 0-7 当字符计数器达到此值时开始水平回扫
         价值。

3d4h 索引 5 (W):CRTC:结束水平回扫寄存器
位 0-4 当字符计数器的最后 5 位达到时,水平回扫结束
         等于这个值。
    5-6 水平显示后延迟显示开始的字符时钟数
         回溯。
      7 在奇/偶模式下提供平滑滚动。当设定显示开始时
         来自奇数字节。

3d4h 索引 6 (W):CRTC:垂直总计寄存器
位 0-7 垂直总计的低 8 位。位 8 位于 3d4h 索引 7 中
         位 0。

3d4h 索引 7 (W):CRTC:溢出寄存器
位 0 垂直总计的位 8(3d4h 索引 6)
      1 垂直显示结束位 8(3d4h 索引 12h)
      2 垂直回扫开始的位 8(3d4h 索引 10h)
      3 开始垂直消隐的第 8 位(3d4h 索引 15h)
      4 行比较寄存器的第 8 位(3d4h 索引 18h)

3d4h 索引 8 (W):CRTC:预设行扫描寄存器
位 0-4 我们在第一个字符行中向下滚动的行数。
         提供平滑的垂直滚动。

3d4h 索引 9 (W):CRTC:最大扫描行寄存器
位 0-4 字符行中的扫描线数 -1。在图形模式下这是
         该行在传递到之前显示的次数 (-1)
         下一行(0:正常,1:双倍,2:三倍...)。
         这与位 7 无关,除了在 CGA 模式下,这似乎
         要求该字段为 1 并且位 7 设置为工作。

3d4h 索引 0Ah (W):CRTC:光标起始寄存器
位 0-4 字符内光标的第一条扫描线。

3d4h 索引 0Bh (W): CRTC: 光标结束寄存器
位 0-4 字符内光标的最后一个扫描行
    5-6 字符时钟中光标数据的延迟。

3d4h 索引 0Ch (W):CRTC:起始地址高位寄存器
bit 0-7 显示缓冲区起始地址的高 8 位

3d4h 索引 0Dh (W):CRTC:起始地址低位寄存器
bit 0-7 显示缓冲区起始地址的低 8 位

3d4h 索引 0Eh (W): CRTC: 光标位置高位寄存器
bit 0-7 光标地址的高8位

3d4h 索引 0Fh (W): CRTC: 光标位置低位寄存器
bit 0-7 光标地址的低8位

3d4h 索引 10h (R): CRTC: 光笔高位寄存器
bit 0-7 光笔位置地址的高 8 位。

3d4h 索引 10h (W):CRTC:垂直回扫开始寄存器
bit 0-7 垂直回扫开始的低 8 位。垂直回扫开始于
         行计数器达到该值。位 8 位于 3d4h 索引 7 中
         位 2。

3d4h 索引 11h (R): CRTC: 光笔低位寄存器
bit 0-7 光笔位置地址的低 8 位。

3d4h 索引 11h (W):CRTC:垂直回扫结束寄存器
位 0-3 当行计数器的最后 4 位等于时,垂直回扫结束
         这个值。
      4 如果清除 清除挂起的垂直中断。
      5 垂直中断 (IRQ 2) 如果设置则禁用。通常可以留下
         已禁用,但某些系统(包括 PS/2)要求启用它。

3d4h 索引 12h (W):CRTC:垂直显示结束寄存器
bit 0-7 垂直显示结束的低 8 位。当该行出现时,显示结束
         计数器达到该值。位 8 位于 3d4h 索引 7 位 1 中。

3d4h 索引 13h (W):CRTC:偏移寄存器
bit 0-7 扫描线中的字节数 / K。其中 K 为 2 表示字节模式,4 表示
         字模式,8 表示双字模式。

3d4h 索引 14h (W):CRTC:下划线位置寄存器
位 0-4 字符单元内下划线的位置。

3d4h 索引 15h (W):CRTC:起始垂直空白寄存器
bit 0-7 垂直空白起始的低 8 位。垂直消隐开始于
         行计数器达到该值。位 8 位于 3d4h 索引 7 中
         位 3。

3d4h 索引 16h (W):CRTC:结束垂直空白寄存器
bit 0-4 当行计数器的低 5 位达到时,垂直消隐停止
         等于这个字段。

3d4h 索引 17h (W):CRTC:模式控制寄存器
位 0 如果清除,则使用 CGA 兼容内存寻址系统
         通过用字符行扫描计数器位 0 替换地址位 13,
         从而为偶数和奇数扫描线创建 2 个组。
      1 如果清除则使用 Hercules 兼容内存寻址系统
         用字符行扫描计数器位 1 替换地址位 14,
         从而创建了4家银行。
      2 如果设置,则仅每隔一行增加扫描行计数器。
      3 如果设置,则仅每隔一个字符增加内存地址计数器
         钟。
      4 如果设置,则禁用 EGA 输出驱动器。
      5 当处于字模式时,如果该位被设置为其他位置,则位 15 将循环至位 0
         位 13 循环到位 0。
      6 清除系统是否处于字模式。地址向上旋转 1 位
         将位 13 或 15 放入位 0。
      7 清除该位将重置显示系统,直到该位被设置为止
         再次。

3d4h 索引 18h (W):CRTC:行比较寄存器
bit 0-7 线路比较的低 8 位。当线路计数器达到此值时
         值,显示地址换行为0。提供分屏
         设施。位 8 位于 3d4h 索引 7 位 4 中。

3dAh (R):输入状态#1 寄存器
位 0 垂直或水平回扫有效(如果设置)
      1 光笔已触发(如果设置)
      2 光笔开关如果设置则打开
      3 正在进行垂直回扫(如果已设置)
    4-5 显示 6 种颜色输出中的两种,具体取决于 3C0h 索引 12h。
          属性:位 4-5:输出位 4 输出位 5
                   0 蓝红
                   1 I 蓝绿
                   2 我红我绿

3dAh (W):功能控制寄存器
位 0 输出到功能连接器的引脚 21。
      1 输出到功能连接器的引脚 20。


Fra*_*cis 4

模式 0x0d 是基于平面的,而 0x13 不是(没有像模式 X 那样的特殊配置)。您应该查看更多文档以了解如何在平面模式下工作。

  • 尝试http://www.phatcode.net/res/224/files/html/index.html。它对于 VGA 和 EGA 都非常有帮助,因为平面模式思想在 CGA、EGA 和 VGA 上是相同的。 (3认同)