【问题标题】:Graphics mode in assembly 8086汇编 8086 中的图形模式
【发布时间】:2018-02-06 17:20:19
【问题描述】:

我有一个名为average 的变量,在我的DATASEG 中,它每次都会更改,因为用户每次都输入不同的输入。我想要做的是进入图形模式(VGA)然后在那里打印你的平均值是:然后我知道如何更改为这样的图形模式的平均值:

mov ax, 13h  
int 10h

如果平均值高于 75,我想在下面打印平均值后,你是一个好学生,继续努力,如果不是。别担心你会好起来的! 提前致谢。

【问题讨论】:

  • 是的,有可能。会容易吗?应该不会了。奇怪的是,现代系统甚至可能不再允许您进入 VGA 模式。您需要在网上查看并四处挖掘,看看有什么可用的。仅供参考,进入模式 13,我认为您没有可用的字体,需要自己编写。或者,只需将标准输出转换为文本模式并让它更容易完成。
  • 那么你的问题是什么?真的“有可能”吗?你猜怎么着,检查数千个现有的可执行文件,我很确定其中一些正在做非常相似的事情,或者更复杂,所以你为什么还要问。如果《DOOM》在 1993 年成为可能,那么显示“你是好学生”能有多难……你需要支持 13h 模式的平台,如果你坚持的话(很简单的模式,容易上手,但是 320x200 的分辨率非常低,而且其中的文字特别难看,请重新考虑使用一些 SVGA 模式,例如 1024x768(但在您学会处理 13h 之后))。 Emu8086 允许 13h gfx
  • 一个不错的resource overview VGA。
  • 谢谢你们。我真的不介意文本是否丑陋,因为它是一个项目,我只是想第一次尝试使用图形模式。
  • 究竟是什么你不知道该怎么做......使用1.VGA 320x200x256 mode? 2.在里面打印字符/文本? 3. 打印数值(在寄存器或内存中)?字体可以从 EGA/VGA BIOS 或者使用这个Convert floating-point numbers to decimal digits in GLSL?

标签: assembly graphics emu8086 vga


【解决方案1】:

我假设:PC VGA x86 MS DOS 平台

除非你想要低级别的 IO 访问,这在 DOSBOX ...

  1. 视频/文本模式

    所以要在视频和文本模式之间切换,您需要使用 VGA BIOS:

    mov ax,mode ; here select which mode you want
    int 16      ; this calls EGA/VGA/VESA BIOS
    

    video modes 很多,这里有两个非常重要的:

    mode | type  | segment | resolution         | align
    ----------------------------------------------------
    03   | text  | B800h   | 80x25 chars        | 2 Byte
    19   | video | A000h   | 320x200x256 colors | 1 Byte
    

    在视频模式 19 中,您可以通过访问段 A000h 的内存来打印/查看像素,其中偏移量的计算方式如下:

    offset = 320*y + x
    

    320x200 模式完全适合64 KByte 段,因此您无需切换页面。这使它成为简单 asm gfx 程序的理想选择 ....

    模式3是文本模式,其中每个字符都有2 BYTEs一个是颜色,另一个是扩展ASCII代码。再次打印/查看是通过在段 B800h 访问 WORD 来完成的,其中偏移量是:

    offset = (80*y + x) * 2
    

    不知道这两个字节在很久以前的顺序是什么,但您可以轻松测试在0B800:0000 处写入A 是否会在左上角呈现A0B800:0001。文本模式中的 IIRC 颜色只是调色板中的前 16 种颜色,颜色字节编码墨水纸的亮度和闪光。此文本模式也是您的 MS-DOS shell 工作的默认模式,因此您应该在程序退出之前将其设置回来。

    所以你的程序应该是这样的:

     start:
         mov ax,19 ; set video mode
         int 16      
    
     mainloop:
         ; here your stuff
    
     exit:
         mov ax,3
         int 16
         ret
    
  2. 打印字符串

    对于初学者,您可以结合文本和视频模式......就像我在这里做的那样:

    这是一个简单的游戏,其中菜单处于文本模式(打印很容易,只需将字符串复制到 VRAM 中),而 sprite 图形游戏处于 320x200x256c 视频模式。

    当您想在 gfx 模式下打印时,您首先需要在内存中有一些 字体。如果您查看 EGA/VGA BIOS 文档,您可以获得位于 EGA/VGA ROM 中的字体并直接使用它。我还创建了这个图像(IIRC 使用 Trident 9000 256/512KB VGA 字体),我将它用作 OpenGL 和其他东西的等宽字体(访问 VGA BIOS 是不可能或不想要)...

    这里GLSL example of using it for printing你可以把它移植到CPU/VGA/asm,但是在CPU上打印更简单,不需要像 GLSL 片段这样可怕的东西。

    所以您只需要从 ASCII 代码计算图像位置并将其像素复制到 VRAM 中。在 asm 中粗略的位图并不容易,更容易的是直接以二进制形式(作为db 的集合),因此您可以编写一些简单的 C++ (或其他)脚本来加载图像并将其转换为 asm 源...

    这是我多年前在 NASM 中编写的一些古老的 320x200x256 colors 打印库(直接使用 EGA/VGA 字体):

     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;GFX mode 13h print librrary ver:1.0
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;txti       init font adress
     ;char       cx=color,al=ASCII,scr:di<=al ;cl=ch => no background
     ;print      scr:di <= ds:si ,cx=color cl=ch => no background
     ;printl     scr:di text after call ,cx=color ...
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     txti:   pusha           ;init font adress
         push es
         mov ax,1130h    ; VGA BIOS - font info
         mov bh,3        ; font 8 x 8 pixels
         int 10h         ; ES:BP returns font address
         mov [cs:fonts],es   ;get font adr
         mov [cs:fonto],bp
         pop es
         popa
         ret
     fonts   dw 0        ; font address for printing ...
     fonto   dw 0
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     char:   pusha       ;cx=color,al=ASCII,scr:di<=al ;cl=ch => no background
         push    ds
         push    es
         push    word 0A000h
         pop es
         sub     ah,ah
         shl     ax,3
         mov     ds,[cs:fonts]
         mov     si,[cs:fonto]
         add     si,ax
         mov     dh,8
     .char0: mov     dl,8
         lodsb
         mov     ah,al
     .char1: mov     al,cl
         rcl     ah,1
         jc  .char2
         mov     al,ch
     .char2: cmp     cl,ch
         jz  .char3
         mov     [es:di],al
     .char3: inc     di
         dec     dl
         jnz     .char1
         add     di,320-8
         dec     dh
         jnz     .char0
         pop es
         pop     ds
         popa
         ret
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     print:  pusha       ;scr:di <= ds:si ,cx=color cl=ch => no background
     .l0:    lodsb
         or  al,al
         jz  .esc
         call    char
         add     di,8
         jmp     short .l0
     .esc:   popa
         ret
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     printl: mov [cs:.dat],si    ;scr:di text after call ,cx=color ...
         pop si
         push    ax
         push    di
         push    ds
         push    cs
         pop ds
     .l0:    lodsb
         or  al,al
         jz  .esc
         call    char
         add     di,8
         jmp     short .l0
     .esc:   pop ds
         pop di
         pop ax
         push    si
         add di,9*320
         mov si,[cs:.dat]
         ret
     .dat:   dw  0
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;;; end. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    

    所以要使用它,程序应该是这样的:

     start:
         call txti ; just once at program startup
    
         mov di,50+320*10
         mov cx,127
         call printl
         db  'SPEKTRA software & hardware',0
    
         mov di,50+320*30
         mov cx,127
         call printl
         db  'print test',0
    

    print 通过设置 ds,si 使用,因此它指向您的以空字符结尾的字符串。正如您所看到的,printl 不需要它,因为它使用直接位于 printl 调用之后的字符串,并且程序在它之后继续......这样你不需要指针设置指令或任何额外的标签......颜色是在cl,ch 中,一个是墨水,另一个是纸。如果cl==ch 则不会仅渲染墨水像素,如果您在文本后面有图像或 gfx 背景,则不会渲染任何纸张......颜色的值可能不可见我从我的一个游戏中获取了颜色,它设置了它自己的调色板,所以如果什么都看不到尝试设置不同的cl,ch,比如mov cx,0305h看看这个:

  3. 打印数字

    打印非负整数值是将数字除以基数 (10) 并将remainder + '0' 以相反的顺序打印为字符...

    hex 中更容易,因为每个数字对应于半字节&lt;0-15&gt;,因此对于 16 位,您可以通过 xlat 表或添加 '0''A' 将最高 4 位转换为 char如果值低于10 ...所以没有除法只是位移/掩码...打印字符并将值左移4位以处理下一个数字...

    btw 在 gfx 模式下通常更好且用户友好,而不是将值打印为数字,而是呈现进度条之类的东西,这更容易......折叠到单循环呈现 H 或 V 线.. . 喜欢REP STOSB :) ...

  4. VESA

    对于 320x200x8bpp 以上的 Super VGA 视频模式,我们需要添加数据的页面交叉,因为 VRAM 不再适合 64KByte 段。我强烈建议为此使用 VESA (VBE) api。我们的想法是让A000:0000 段映射到我们可以随时更改的 VRAM 的某个段。有关如何查看这些内容的更多信息:

    如果您的 gfx 卡没有适用于大多数卡的 VESA/VBE,则可以在 MS-DOS 下使用UniVBE 5.3 或更新的实用程序来添加它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    相关资源
    最近更新 更多