double buffering with vsync
authorEleni Maria Stea <estea@igalia.com>
Tue, 5 Jan 2021 18:51:22 +0000 (20:51 +0200)
committerEleni Maria Stea <estea@igalia.com>
Tue, 5 Jan 2021 18:51:22 +0000 (20:51 +0200)
bb.asm

diff --git a/bb.asm b/bb.asm
index a3f6011..4eb536e 100644 (file)
--- a/bb.asm
+++ b/bb.asm
@@ -8,6 +8,20 @@
 ; we have to tell assembler that code is 16bit mode
        bits 16
 
+; macros
+%macro SETPAL 4        ; 4 = num arguments of macro (index rgb)
+       mov dx, 3c8h    ; index register
+       mov al, %1
+       out dx, al
+       inc dx
+       mov al, %2 >> 2
+       out dx, al
+       mov al, %3 >> 2
+       out dx, al
+       mov al, %4 >> 2 ; shift to give the value from 0 - 255
+       out dx, al
+%endmacro
+
 start:
        mov sp, 7c00h
 
@@ -41,11 +55,11 @@ start:
 ; bios helpers, 13h = disk io
        mov ax, 0
        mov ds, ax
-       mov ah, 02h                     ; call 2: read sectors into memory
-       mov al, 1                               ; number of sectors to read
-       mov ch, 0                               ; low 8 bits of cylinder number
-       mov cl, 2                               ; sector number that starts from 1
-       mov dh, 0                               ; head number
+       mov ah, 02h                             ; call 2: read sectors into memory
+       mov al, 3                                       ; number of sectors to read
+       mov ch, 0                                       ; low 8 bits of cylinder number
+       mov cl, 2                                       ; sector number that starts from 1
+       mov dh, 0                                       ; head number
        mov dl, [saved_drive_num]       ; 8bits
        mov bx, sector_2
        int 13h
@@ -132,21 +146,25 @@ sector_2:
        test al, 3fh    ; test with 3fh to keep the lowest 6 bits of al
        jnz .pal_loop
 
+; setup lovebug palette
+       SETPAL 64, 0, 255, 0    ; chr(64) = @
+       SETPAL 65, 0, 0, 0              ; A
+       SETPAL 66, 50, 50, 50   ; B
+       SETPAL 67, 57, 4, 4             ; C
+       SETPAL 68, 108, 9, 9    ; D
+       SETPAL 69, 164, 4, 4    ; E
+
 ; disable all interrupts (for bios to not read the keyboard)
        cli
 
        ; ds on 0 because rand uses it for accesses to mem
        xor ax, ax
        mov ds, ax
-       mov ax, 0a000h
+       mov ax, backbuffer
+       shr ax, 4 ; to use it as segment! (shift right)
        mov es, ax
 main_loop:
-; wait for vblank
-       mov dx, 3dah
-       in al, dx
-       and al, 8               ; the 4th bit is 1 when we are in the vertical blanking period
-       jz main_loop
-
+; draw to back buffer
        xor bx, bx              ; mov bx, 0 to clear the register
 .static_loop:
        call rand
@@ -156,6 +174,34 @@ main_loop:
        cmp bx, 64000   ; num pixels
        jnz .static_loop
 
+       ; draw lovebug
+       mov di, 32000
+       mov si, lovebug
+       call blit32
+
+; wait for vblank
+.vsync:
+       mov dx, 3dah
+       in al, dx
+       and al, 8               ; the 4th bit is 1 when we are in the vertical blanking period
+       jnz     .vsync
+
+; copy backbuffer to video memory
+       push es
+       push ds
+       mov ax, es
+       mov ds, ax                      ; ds points to backbuffer now (was in es)
+       xor si, si
+       mov ax, 0a000h
+       mov es, ax
+       xor di, di                      ; write in es:di
+       mov ecx, 16000          ; 16000 double words (dwords) = 64000 bytes
+       rep movsd
+       pop ds
+       pop es
+
+       inc word [num_frames]
+
        in al, 64h              ; 60h = keyb data port, 64h = keyb status port
        and al, 1               ; 1 = OUTBUF_FULL = the keyb controller out buf is full
        jz main_loop    ; no key pressed, loop back
@@ -164,9 +210,85 @@ main_loop:
 ; re-enable all interrupts
        sti
 
+; text mode
+       mov ax, 3               ; text mode
+       int 10h
+; use bios to print
+; Int 10/AH=0Eh
+       mov si, str_frames  
+       call print_str
+       mov ax, [num_frames]
+       call print_num
+       mov si, str_newline
+       call print_str
 .inf_loop:
        jmp .inf_loop
 
+; reads from ds:si writes to es:di (bug top left corner)
+; knows how many pixels on screen and how many in the lovebug
+blit32:
+       mov cx, 1024    ; 32 x 32 lovebug
+.loop:
+       mov al, [ds:si]
+       cmp al, 64
+       jz .skip_pixel
+       mov [es:di], al
+.skip_pixel:
+       inc si
+       inc di
+
+       dec cx                          ; dec the num_pixels we want to write 
+       jz      .end                    ; all pixels have been written
+       test cx, 1fh            ; keep 5 least significant bits, 3 most significant bits 0
+       jnz .loop                       ; when this is 0 we are in a multiple of 32
+       add di, 320 - 32        ; screen width - bug width
+       jmp .loop
+.end:
+       ret
+
+print_str:
+       ;Int 10/AH=0Eh
+       mov al, [si]
+       test al, al
+       jz .end
+       mov ah, 0eh
+       xor bx, bx
+       int 10h
+       inc si
+       jmp print_str
+.end:
+       ret
+
+print_num:
+       ; converts digits to ascii - print
+       push word 0
+       test ax, ax
+       jnz .conv_loop
+       push word '0'
+       jmp .conv_end
+.conv_loop:
+       test ax, ax
+       jz .conv_end
+       xor dx, dx
+       mov cx, 10
+       div cx  ; ax contains cx / 10
+       add dl, '0'
+       push dx
+       jmp .conv_loop
+.conv_end:
+       mov bp, sp
+       mov ax, [ss:bp]
+       test ax, ax
+       jz .print_end
+       mov ah, 0eh
+       xor bx, bx
+       int 10h
+       add sp, 2
+       jmp .conv_end
+.print_end:
+       add sp, 2
+       ret
+
 ; random number generator
 ; by nuclear
 rand:
@@ -180,3 +302,51 @@ rand:
 
 randmul dd 1103515245
 randval dd 0ace1h
+
+num_frames dw 0
+str_frames db 'frames: ', 0
+str_newline db 13, 10, 0       ; crlf carriage return line feed newline
+
+; db to write pixels transparent 255
+; @: transparent
+; A: black
+; B: gray
+; C: dark red
+; D: medium red
+; E: red
+lovebug:
+       db '@@@@BAAAB@@@@@BAAB@@@@@BAAAB@@@@'
+       db '@@@@@@@@AAAB@BAAAAB@BAAA@@@@@@@@'
+       db '@@@@@@@@@@@AAAAAAAAAA@@@@@@@@@@@'
+       db '@@@@@@@@@@@@AAAAAAAA@@@@@@@@@@@@'
+       db '@@@@@@@@@@@@AAAAAAAA@@@@@@@@@@@@'
+       db '@@@@@@@@@@@@BAAAAAAB@@@@@@@@@@@@'
+       db '@@@@@@@@@@@@@AAACAA@@@@@@@@@@@@@'
+       db '@@@@@@@@@@CDDEECDEEDDC@@@@@@@@@@'
+       db '@@@@@@@CDDEEEEEDCEEEEEDDC@@@@@@@'
+       db '@@@@@CDEEEEDCDECDEDCDEEEEDC@@@@@'
+       db '@@@@CDDCDEECACEDCECACEEDCDDC@@@@'
+       db '@@@CDECACEEDCDECDEDCDEECACEDC@@@'
+       db '@@@DEEDCDEEEEEEDCEEEEEEDCDEED@@@'
+       db '@@CEEEEEEEEEEEDCDDEEEEEEEEEEEC@@'
+       db '@@DEDCDEEEDCDECACCEDCDEEEDCDED@@'
+       db '@@EECACEEECACEDCDDECACEEECACEE@@'
+       db '@CEEDCDEEEDCDEEDCEEDCDEEEDCDEEC@'
+       db '@DEEEEEEEEEEEEDCCDEEEEEEEEEEEED@'
+       db 'CEEEEEEDCDEEEDCBACDEEEDCDEEEEEEC'
+       db 'CEDCDEECACEEDCAABACDEECACEEDCDEC'
+       db 'DECACEEDCDEDCAABAAACDEDCDEECACED'
+       db 'DEDCDEEEEEDCAAAABAAACDEEEEEDCDED'
+       db 'CEEEEEEEEECAAAABAAAAACEEEEEEEEEC'
+       db 'CEEEEEEEEDAAAAAABAAAAADEEEEEEEEC'
+       db '@DEDCDEEDCAAAAABAAAAAACDEEDCDED@'
+       db '@DECACEDCAAAAAAABAAAAAACDECACED@'
+       db '@DEDCDDCAAAAAAABAAAAAAAACDDCDED@'
+       db '@CEEEECAAAAAAAAABAAAAAAAACEEEEC@'
+       db '@@EEED@AAAAAAAABAAAAAAAAA@DEEE@@'
+       db '@@EEDC@@AAAAAAAABAAAAAAA@@CDEE@@'
+       db '@@DEC@@@@@AAAAABAAAAAA@@@@@CED@@'
+       db '@@@C@@@@@@@@AAAABAAA@@@@@@@@C@@@'
+
+       align   16      ; if the address is not a multiple of 16 add some 0 to become one (because we'll use backbuffer as a segment)
+backbuffer: