org 100h call initscreen xor eax, eax xor ebx, ebx here: push eax push ebx mov ecx, ebx xor ecx, eax call putpixel pop ebx pop eax inc eax cmp eax, 480 jl here xor eax, eax inc ebx cmp ebx, 640 jl here mainloop: call checkforkey jne mainloop call restorescreen mov ax, 4c00h int 21h initscreen: mov bx, cs mov ds, bx mov es, bx mov ax, 4f00h mov di, 60000 int 10h cmp word [60000], 'VE' jne no_vesa cmp word [60002], 'SA' jne no_vesa mov ax, 4f01h mov di, 60000 mov cx, 112h int 10h and byte [60000], 00000001b jz no_112 and byte [60000], 01000000b jnz no_112_window xor eax, eax mov ax, [60004] shl eax, 10 mov [WinGran], eax ;granularity in bytes xor eax, eax mov ax, [60006] shl eax, 10 mov [WinSize], eax ;window size in bytes mov [BankEnd], eax ;end byte+1 of current bank = window size xor edx, edx div dword [WinGran] ;divide winsize by wingran dec ax mov [GUIWSMO], ax ;Granularity Units In Window Size Minus One mov ax, [60008] mov [WinSeg], ax ;segment of window mov ax, 4f03h int 10h mov [OldMode], bx ;get current screen mode mov ax, 4f02h mov bx, 112h int 10h cmp ax, 004fh ;change screen mode jne no_112_init ;if couldnt change, dislpay error and exit mov ax, [WinSeg] mov es, ax ret no_vesa: mov dx, no_vesa_msg jmp errormsg no_112: mov dx, no_112_msg jmp errormsg no_112_window: mov dx, no_112_window_msg jmp errormsg no_112_init: mov dx, no_112_init_msg jmp errormsg errormsg: mov ax, 900h int 21h mov ax, 4c01h int 21h restorescreen: mov ax, 4f02h mov bx, [OldMode] int 10h ret putpixel: ;eax =y, ebx =x, ecx =RBG0 mov edx, 640 ;edx destroyed mul edx add eax, ebx shl eax, 2 ;eax = (y*640+x)*4 cmp eax, [BankStart] jl ppcbl ;if below current window, change window to lowest that holds it (in case granularity is less than size). this should minimize bank switching when plotting lines and such. cmp eax, [BankEnd] jge ppcbh ;else if above current window, change window to highest that holds it. ppcbb: sub eax, [BankStart] ;convert from absolute position to position within window mov di, ax mov [es:di], ecx ;plot there. ret ppcbl: push eax ;must destroy eax to divide, so save first cuz calling routine needs it again xor edx, edx div dword [WinGran] ;find highest window that contains it by dividing sub ax, [GUIWSMO] ;find lowest window from that jnc ppcblnc xor ax, ax ;if below zero, make zero ppcblnc: mov bx, ax ;save ax to bx mul dword [WinGran] mov [BankStart], eax ;bankstart = bank * granularity add eax, [WinSize] mov [BankEnd], eax ;bankend = bankstart + size mov ax, 4f05h ;ax = change bank mov dx, bx ;dx = bx = bank to change xor bx, bx ;bx = 0 int 10h ;change the bank pop eax ;restore absolute pos to eax jmp ppcbb ppcbh: push eax xor edx, edx div dword [WinGran] add ax, [GUIWSMO] mov bx, ax mul dword [WinGran] mov [BankStart], eax add eax, [WinSize] mov [BankEnd], eax mov ax, 4f05h mov dx, bx xor bx, bx int 10h pop eax jmp ppcbb checkforkey: mov ah, 11h int 16h jnz keyhit ;if not keyhit then ret with z clear xor ax, ax jmp cfkend keyhit: mov ah, 10h ;retrieve key hit int 16h ; ah=bios, al=ascii cfkend: cmp al, 27 ret ;ret with z is set if esc hit. no_vesa_msg db 'ERROR: VESA is not present. (Get UniVBE or a decent graphics card.)', 13, 10, '$' no_112_msg db 'ERROR: VESA Mode 112h (640x480x16.8Mc) is not supported in hardware.', 10, 13, '$' no_112_window_msg db 'ERROR: VESA Mode 112h (640x480x16.8Mc) does not support 16-bit access.', 10, 13, '$' no_112_init_msg db 'ERROR: Could not initialize VESA mode 112h (640x480x16.8Mc) for some odd reason.', 10, 13, '$' align 4 BankStart dd 0 section .bss align 4 WinGran resd 1 WinSize resd 1 GUIWSMO resw 2 BankEnd resd 1 WinSeg resw 1 OldMode resw 1