Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Animation 16位动画-入门_Animation_Assembly_Nasm_Machine Code - Fatal编程技术网

Animation 16位动画-入门

Animation 16位动画-入门,animation,assembly,nasm,machine-code,Animation,Assembly,Nasm,Machine Code,花了一段时间,但最终在16位图形中得到了平方1。 在这里,我清除屏幕并绘制单个像素: mov ax, 0a000h mov es, ax ; es - Extra Segment now points to the VGA location mov ax, 0013h int 10h xor al, al mov dx, 3c8h out dx, al inc dx mov al, 63 out dx, al out dx, al out dx, al mov ax, 0100

花了一段时间,但最终在16位图形中得到了平方1。 在这里,我清除屏幕并绘制单个像素:

mov ax, 0a000h
mov es, ax      ; es - Extra Segment now points to the VGA location

mov ax, 0013h
int 10h

xor al, al
mov dx, 3c8h
out dx, al

inc dx
mov al, 63
out dx, al
out dx, al
out dx, al

mov ax, 0100h
int 21h
mov ax, 4c00h
int 21h

; draw single pixel :)

mov ah, 0ch;
mov al, 03h     ; color
mov cx, 70      ; x co-ordinate
mov dx, 70      ; y co-ordinate
; mov bh,1      ; page #
int 10h 

times 510-($-$$) db 0   ; PadZeros:
dw 0xaa55       ; MagicNumber
第二步:如何让它移动

显然,这意味着交替擦拭屏幕,更新和绘制循环中的像素。当然,它会在屏幕上飞过,所以我猜你会访问内部时钟的毫秒,比较,然后在它大于某个常数时更新

刚刚开始组装。我确实知道如何使用标签来生成伪函数,所以假设我可能已经在示例中完成了

我从nasm编译为bin,然后在qemu中直接打开。注意我不使用链接器,因此不需要使用.text或任何其他.bss 只是尝试从原始二进制文件开始工作

如果有人对低级机器代码入门教程感兴趣,我还试图记录我在YouTube上学到的一切:

如果其他任何人也在尝试编写内核、他们自己的操作系统、编译器或了解汇编中16位游戏图形的更多信息,请随时加入KAOS项目并帮助创建一个100%视频记录的操作系统:


这是80x80正方形最原始的动画

它的工作原理如下:

  • 等待VGA的垂直回程开始空白期(光束返回到屏幕开始)
  • 将整个VRAM设置为零(“清除整个屏幕”)
  • 在“bx”位置绘制80x80正方形
  • 将bx调整+-1并保持在0..239范围内
  • 无限重复
  • 不确定是否可以像dosbox中的循环计数那样影响qemu的速度(以及VGA模拟的准确性)

    也许可以先在DOSBOX中尝试一下(只需将二进制文件重命名为“test.com”,下面的源代码也将作为com文件使用),以了解图形编程的陷阱

    然后在dosbox中,您可以使用Ctrl+F11/F12减去/添加机器周期(PC的速度),以查看在非常慢的PC上使用此粗略算法时会发生什么

    在fast PC上,在光束返回第一条线之前,屏幕被清除,因此正方形被绘制在光束的前面,所有东西看起来都是实心的

    但我的dosbox默认设置是慢速的~286/386 PC-like,当光束开始在监视器上绘制第一条线时,它仍将清除屏幕,因此它将绘制黑色空线。一旦代码开始绘制正方形,它将最终赶上光束,在第50行附近,因此正方形底部的30行是可见的

    如果你玩机器速度游戏,你可以看到更多的人工制品,比如正方形完全画在光束后面(用户看不见),甚至闪烁(当整个图形需要比单帧刷新更长的时间时(在60Hz监视器上1000/60=16.6ms)


    现在我明白了,然后
    int8
    计时器中断实际上是BIOS提供的,所以我可以重写这个例子,用这个计时来显示差异(VSYNC与计时器动画)…嗯…我非常不愿意,因为计时器动画很烂(我的意思是,即使是VSYNC动画也必须使用计时器来弥补跳过的帧,但这对于简单的例子来说太复杂了,但是基于计时器的动画天生就很糟糕)。我最多会给它10分钟,看看我是否能让它工作

    好的,
    INT 08h
    基于定时器的版本(不要看你是否也容易因闪烁的图像而癫痫发作):

    它有两个主要问题:

  • int 8
    默认情况下,计时器在55毫秒内滴答作响,而大多数屏幕又是60赫兹,因此在60赫兹上需要16.6毫秒的滴答声才能平滑,更不用说刷新率更高了。现在,正方形每3-4个显示帧移动+1个像素

  • 即使计时器是10毫秒,它仍然会疯狂地闪烁,因为屏幕+绘图方块在新位置的擦除与显示光束不同步

  • 1.故障可通过重新配置8253/8254坑解决

    2.可以通过先将图像绘制到屏幕外缓冲区,然后将最终图像复制到真实的VRAM(理想情况下采用VSYNC ed方式防止“撕裂”)来解决


    这两个例子都非常粗糙,基本上只是说明“清除屏幕+在新位置绘图”确实可以使内容具有动画效果,而且这还不足以达到基本的质量

    为了得到任何合理的结果,你需要使用更复杂的逻辑,但这在很大程度上取决于你在画什么、制作什么动画以及如何制作

    VGA的一种通用方法是使用屏幕外缓冲区,并在绘图完成时将其复制到VRAM(将机器周期浪费在64k字节的复制上..今天听起来可能很可笑,但在1990年这是一件大事)


    或者使用VGA控制寄存器设置一种非官方的“x模式”并以支持双/三缓冲方案的方式设置VGA内存布局,因此直接将新帧绘制到VRAM中,但绘制到隐藏部分,绘制完成后,切换VRAM的显示部分以显示新准备的内容。这有助于避免64k拷贝,但写入VRAM实际上相当缓慢,因此只有在像素透支很少的情况下才值得付出努力。当像素透支很多时,速度已经太慢了(不可能达到60FPS),并在普通RAM屏幕外绘制它,使它实际上更快,即使最后的64k拷贝到VRAM。

    如果我正确读取该源代码,它会将颜色索引0设置为全白色,然后等待一个键并退出(如果加载了一些DOS,它会退出)。在
    之后的代码;绘制单像素
    是不可访问的?(现在我明白了,它是引导扇区,所以
    int21h
    是无效的,不知何故不会崩溃它,只要返回,然后你通过BIOS绘制像素…我明白了)为什么你要通过BIOS绘制像素?:-o..只需像
    mov al,3
    mov es:[70*320+70],al
    那样将其写入内存。关于yo
        BITS    16
    
        MOV     ax,13h
        INT     10h             ; 320x200 256colour VGA mode
        MOV     ax,0a000h
        MOV     es,ax           ; video RAM segment
    
        XOR     bx,bx           ; square position = 0
        MOV     si,1            ; direction of movement
    
    AnimateLoop:
        CALL    waitforRetrace  ; destroys al, dx
        ; clear whole screen
        XOR     di,di
        XOR     eax,eax
        MOV     cx,320*200/4
        REP STOSD
        ; draw 80x80 pixels square with color 3
        MOV     eax,0x03030303
        MOV     di,bx
        MOV     dx,80           ; height
    drawSquareLoop:
        MOV     cx,80/4
        REP STOSD               ; draw 80 pixels (single line)
        ADD     di,320-80       ; next line address
        DEC     dx
        JNZ     drawSquareLoop
        ; move it left/right
        ADD     bx,si           ; move it first
        CMP     bx,240
        JB      AnimateLoop     ; 0..239 are OK
        ; too far on either side, reverse the movement
        NEG     si
        ADD     bx,si           ; fix position to valid range
        JMP     AnimateLoop
    
    waitforRetrace:
        MOV     dx,03dah
    waitforRetraceEnd:
        IN      al,dx
        AND     al,08h
        JNZ     waitforRetraceEnd
    waitforRetraceStart:
        IN      al,dx
        AND     al,08h
        JZ      waitforRetraceStart
        RET
    
        times 510-($-$$) db 0   ; PadZeros:
        dw 0xaa55       ; MagicNumber
    
        BITS    16
        MOV     ax,13h
        INT     10h
        XOR     ax,ax
        ; ds = 0 segment (dangerous, don't do this at home)
        MOV     ds,ax
        MOV     ax,0a000h
        MOV     es,ax           ; video RAM segment
    AnimateLoop:
        ; clear whole screen
        XOR     di,di
        XOR     eax,eax
        MOV     cx,320*200/4
        REP STOSD
        ; draw square with color 3
        MOV     eax,0x03030303
        ; fetch position from BIOS timer-tick value
        ; (ticking every 55ms by default)
        MOVZX   di,byte [0x046C]    ; di = 0..255 from [0:046C]
        MOV     dx,80           ; height
    drawSquareLoop:
        MOV     cx,80/4
        REP STOSD
        ADD     di,320-80       ; next line address
        DEC     dx
        JNZ     drawSquareLoop
        JMP     AnimateLoop
    
        times 510-($-$$) db 0   ; PadZeros:
        dw 0xaa55       ; MagicNumber