title graphics : all sort of graphic procedures extrn scan_code: byte, key_flag: byte, timer_flag: byte public init_vga, plot_pixel_xy_dbuffer, show_double_buffer, rtn_to_text_mode public set_palette_register, get_palette_register, pcx_load public update_color_register, keyboard_int, timer_tick, setup_int public draw_sprite, pcx_grap_bitmap, get_sprite_background, draw_background .model compact include macros.asm .code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; init_vga proc near ; purpose : initialize the graphic card to vga mode. ; input : none. ; output : none. ; method : put 13h(vga mode) into ax and interrupt video 10h. push ax mov ax, @data ; initialize data segment mov ds, ax mov ah, 0 ; initialize the mov al, 013h ; graphic card to int 10h ; vga mode. pop ax ret init_vga endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; plot_pixel_xy_dbuffer proc near ; purpose : draw a dot onto the double_buffer use x and y coordination. ; input : stack on entry : return address (top), color, y, x, double buffer ; address. ; output : none. ; method : times y by 320, then add x. Take the value and put into ; memory offset. then put the color into double buffer. push bp ; initialize... mov bp, sp ; put sp value to bp and save bp on the stack. push ax ; save registers push bx push cx push dx push si mov ax, @data ; initialize data segment mov ds, ax mov bx, word ptr[bp+6] ; put y into bx; mov ax, word ptr[bp+6] ; put another copy of y into ax; mov cl, 8 shl bx, cl ; shift bx 8 bits left mov cl, 6 shl ax, cl ; shift ax 6 bits left add ax, bx ; sum ax and bx into ax, than means ; y*256 + y*64 = y*320 add ax, word ptr [bp+8] ; add x to ax which contains y * 320 mov bx, word ptr [bp+10] ; move double buffer address into bx mov cx, word ptr [bp+4] ; move the color value into cx mov si, ax ; move the offset address to si ; so it can do indirect address mov word ptr [bx+si], cx ; finally, we put the color into ; double buffer in x and y coordination. pop si ; restore registers pop dx pop cx pop bx pop ax pop bp ; restore bp ret 8 ; return and pop the 4 parameter into space. plot_pixel_xy_dbuffer endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; show_double_buffer proc near ; purpose : put double_buffer stuff onto the screen ; input : stack entry: return address (top), buffer address ; output : none ; method : use a loop to put the contents in double_buffer to screen_buffer push bp ; initialize... mov bp, sp ; put sp value to bp and save bp on the stack. push ds ; save registers push es push cx push ax push si push di mov ax, @data ; initialize data segment mov ds, ax cld mov ax, 0a000h ; load screen_buffer segment mov es, ax mov di, 0 mov ax, @data mov ds, ax mov ax, word ptr [bp+4] ; load double_buffer segment mov si, ax mov cx, 32000d ; we want to mov 320*200 bytes or 320*200/2 words rep movsw ; do the movement. pop di ; restore registers pop si pop ax pop cx pop es pop dx pop bp ; restore bp ret 2 show_double_buffer endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rtn_to_text_mode proc near ; purpose : put the screen back to text mode ; input : none ; output : none ; method : put 3 into ax and interrupt video 10h push ax ; save register. mov ax, @data ; initialize data segment mov ds, ax mov ah, 0 ; initialize the mov al, 03h ; graphic card to int 10h ; text mode. pop ax ; return register. ret rtn_to_text_mode endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set_palette_register proc ;purpose : to set the one of palette_register color. ;input : stack entry : return address (top), index, blue, green, red. ;output : none. ;method : use the i/o port to set the palette register instead of calling ; interrupt. It is much faster. ; palette mask 3c6h ; read palette register 3c7h ; write palette register 3c8h ; palette data 3c9h push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers push dx mov ax, @data ; initialize data segment mov ds, ax mov dx, 3c6h mov al, 0ffh out dx, al ; tell the palette_mask a palette register ; will be updated. mov dx, 3c8h mov al, byte ptr [bp+4] out dx, al ; put the index into the writing palette ; register mov dx, 3c9h mov al, byte ptr [bp+10] out dx, al ; put the red into the data palette ; register mov al, byte ptr [bp+8] out dx, al ; put the green into the data palette ; register mov al, byte ptr [bp+6] out dx, al ; put the blue into the data palette ; register pop dx ; restore registers. pop ax pop bp ; restore bp ret 8 ; return and pop the 4 parameter into space. set_palette_register endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_palette_register proc ;purpose : to read the one of palette_register color. ;input : stack entry : return address (top), index, blue, green, red. ;output : stack contains value in the sequence of index (top), blue, ; green, red. ;method : use the i/o port to read the palette register instead of calling ; interrupt. It is much faster. ; palette mask 3c6h ; read palette register 3c7h ; write palette register 3c8h ; palette data 3c9h push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers push dx mov ax, @data ; initialize data segment mov ds, ax mov dx, 3c6h mov al, 0ffh out dx, al ; tell the palette_mask a palette register ; will be updated. mov dx, 3c7h mov al, byte ptr [bp+4] out dx, al ; put the index into the writing palette ; register mov dx, 3c9h mov al, byte ptr [bp+10] in al, dx ; put the red into the data palette ; register mov dx, 3c9h mov al, byte ptr [bp+8] in al, dx ; put the green into the data palette ; register mov dx, 3c9h mov al, byte ptr [bp+6] in al, dx ; put the blue into the data palette ; register pop dx ; restore registers. pop ax pop bp ; restore bp ret ; return to calling program. get_palette_register endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pcx_load proc ; purpose : to read and uncompress data in pcx file. ; input : stack entry: return address (top), filename's address, handle, ; file_buffer's address, data's address, counter, main_counter ; output : none ( the return parameters on the stack are all pointers. So we ; don't need to return them. ) ; method : First it open the file and move the read/ write pointers 128 bytes ; from the beginning. ; Second it read and uncompress the image. ; Third it update the color palette in pcx file to the palette ; register. push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers. push bx push cx push ds push es push dx mov ax, @data ; initialize ds mov ds, ax xor al, al mov ah, 3dh ; open an existing file function number mov dx, word ptr [bp+4] ; dx have the file address mov cl, 0 ; read_only attribute int 21h ; open the file mov word ptr [bp+6], ax ; save handle or error code. mov ah, 42h ; moves read pointer function mov bx, word ptr [bp+6] ; get handle xor cx, cx mov dx, 128d ; 128 bytes to move mov al, 0 ; move relative to beginning of file int 21h ; move file pointer pcx_load_big_while : mov ax, @data ; initialize ds mov ds, ax xor al, al mov ah, 3fh ; read file function mov bx, word ptr [bp+6] ; get handle mov cx, 1h ; read first byte mov dx, word ptr [bp+10] ; load the data address int 21h ; read file into buffer mov bx, word ptr [bp+10] cmp byte ptr [bx], 192d ; compare data to 192 jb next ; jump if less than 192 ;cmp byte ptr [bx], 255d ; compare data to 255 ;ja next ; jump if greater than 255 sub byte ptr [bx], 192d ; subtract 192 from data mov al, byte ptr [bx] ; put data-192 into counter mov byte ptr [bp+12], al xor al, al ; clean al mov ah, 3fh ; read file function mov bx, word ptr [bp+6] ; get handle mov cx, 1h ; read first byte mov dx, word ptr [bp+10] ; load the data address int 21h ; read file into buffer pcx_load_while : mov bx, word ptr [bp+10] ; put data in al so it can be accessed. mov al, byte ptr [bx] mov bx, word ptr [bp+8] ; put al(data) into file buffer. mov byte ptr [bx], al inc word ptr [bp+8] ; increase file buffer pointer inc word ptr [bp+14] ; increase main counter dec byte ptr [bp+12] ; decrease counter by one cmp byte ptr [bp+12], 0d ; until counter reach 0 ja pcx_load_while jmp pcx_load_end next : ; move data into file buffer mov bx, word ptr [bp+10] ; move data into al mov al, byte ptr [bx] mov bx, word ptr [bp+8] ; move file buffer pointer into bx. mov byte ptr [bx], al ; put data into file buffer inc word ptr [bp+8] ; move pointer inc word ptr [bp+14] ; increase main counter pcx_load_end : cmp word ptr [bp+14], 64000d ; if main counter haven't reach 320*200 then jb pcx_load_big_while ; go back to top and loop again. mov ah, 3eh ; close the file function number mov bx, word ptr [bp+6] ; get handle int 21h ; close the file jmp normal pcx_load_error : disp_str 'error!!! ' ; used to display a message and wait for a mov al, 0h ; keypress. mov ah, 01h int 21h normal : pop dx ; restore registers. pop es pop ds pop cx pop bx pop ax pop bp ; restore bp ret 12 ; return to calling program and kick 14 bytes ; in stack to space. pcx_load endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; update_color_register proc ;purpose : ;input : return address (top), filename's address, handle, 1 byte color ; variable's address, counter, ;output : ;method : push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers push bx push cx push dx mov ax, @data ; initialize ds mov ds, ax xor al, al mov ah, 3dh ; open an existing file function number mov dx, word ptr [bp+4] ; dx have the file address mov cl, 0 ; read_only attribute int 21h ; open the file mov word ptr [bp+6], ax ; save handle or error code. mov ah, 42h ; moves read pointer function mov bx, word ptr [bp+6] ; get handle mov cx, 1111111111111111b mov dx, 1111110100000000b ; 768 bytes to move mov al, 2d ; move relative to the end of file int 21h ; move file pointer mov word ptr [bp+10], 0d ; initialize counter register_part_while : xor al, al ; clean al mov ah, 3fh ; read file function mov bx, word ptr [bp+6] ; get handle mov cx, 1h ; read first three byte mov dx, word ptr [bp+8] ; load the data address int 21h ; read file into buffer xor ah, ah ; clean ah mov bx, word ptr [bp+8] ; get actual pointer mov al, byte ptr [bx] ; get red shr al, 1 shr al, 1 push ax xor al, al ; clean al mov ah, 3fh ; read file function mov bx, word ptr [bp+6] ; get handle mov cx, 1h ; read first three byte mov dx, word ptr [bp+8] ; load the data address int 21h ; read file into buffer xor ah, ah ; clean ah mov bx, word ptr [bp+8] ; get actual pointer mov al, byte ptr [bx] ; get green shr al, 1 shr al, 1 push ax xor al, al ; clean al mov ah, 3fh ; read file function mov bx, word ptr [bp+6] ; get handle mov cx, 1h ; read first three byte mov dx, word ptr [bp+8] ; load the data address int 21h ; read file into buffer xor ah, ah ; clean ah mov bx, word ptr [bp+8] ; get actual pointer mov al, byte ptr [bx] ; get blue shr al, 1 shr al, 1 push ax mov ax, word ptr [bp+10] ; get index push ax call set_palette_register inc word ptr [bp+10] ; increase counter cmp word ptr [bp+10], 256d jl register_part_while jmp update_normal update_error : disp_str 'error!!! ' ; used to display a message and wait for a mov al, 0h ; keypress. mov ah, 01h int 21h update_normal : pop dx ; restore registers. pop cx pop bx pop ax pop bp ; restore bp ret 8 ; return and pop the 4 parameter into space. update_color_register endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Keyboard_Int Proc ; keyboard interrupt routine ;save registers push ds push ax mov ax, seg scan_code ; set up ds mov ds, ax in al, 60h ; read scan code push ax ; save it in al, 61h ; control port value mov ah, al ; save in ah or al, 80h ; set bit for keyboard out 61h, al ; write back xchg ah, al ; get back control value out 61h, al ; resent control port pop ax mov ah, al ; save scan code in ah test al, 80h ; test for break code jne key_0 ; yes, clear flags, goto key_0 mov scan_code, al ; save in variable mov key_flag, 1 ; set key flag key_0 : mov al, 20h ; reset interrupt out 20h, al pop ax ; restore registers pop ds iret keyboard_int endp ; end keyboard routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; timer_tick proc push ds ; save registers push ax mov ax, seg timer_flag ; get segment of flag mov ds, ax ; put in ds mov timer_flag, 1 ; set flag pop ax ; restore ds pop ds iret timer_tick endp ; end timer routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; setup_int proc ; input: al= interrupt type ; di = address of buffer for old vector ; si = address of buffer containing new vector ; save old interrupt vector push es push bx push ax push di push si push dx push ds mov ah, 35h ; get vector int 21h ; es:bx = vector mov [di], bx ; save offset mov [di+2], es ; save segment ; set new vector mov dx, [si] ; has offset push ds ; save it mov ds, [si+2] ; ds has segment number mov ah, 25h ; set vector int 21h pop ds ; restore pop ds pop dx pop si pop di pop ax pop bx pop es ret setup_int endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pcx_grap_bitmap proc ; purpose: grabs a bitmap from a .pcx frame buffer ; input : stack entry : return address (top), file buffer address, ; grab_x, grab_y, sprite address, x_off, y_off, counter, counter2 ; output : none ( the return parameters on the stack are all pointers. So we ; don't need to return them. ) ; ; method : ? push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers push bx push cx push si push ds push es push dx mov ax, @data ; initialize data segment mov ds, ax mov ax, word ptr [bp+6] ; grab grab_x value mov cx, 25d mul cx ; multiply by 25 inc ax ; add 1 mov word ptr [bp+12], ax ; save to x_off mov ax, word ptr [bp+8] ; grab grab_y value mov cx, 25d mul cx ; multiply by 25 inc ax ; add 1 mov word ptr [bp+14], ax ; save to y_off mov cx, 320d mul cx ; y_off multiply by 320 mov word ptr [bp+14], ax ; save to y_off mov word ptr [bp+16], 0 ; initialize counter mov word ptr [bp+18], 0 ; initialize counter2 grab_outer_loop : grab_inner_loop : mov bx, word ptr [bp+12] ; put y_off + x_off + counter2 add bx, word ptr [bp+14] ; into bx add bx, word ptr [bp+18] mov si, word ptr [bp+4] ; move the appropriate pixel mov dl, byte ptr [si+bx] ; to dl xor dh, dh push dx mov ax, word ptr [bp+16] ; get counter mov cx, 24d mul cx ; multiply by 24 add ax, word ptr [bp+18] ; then add counter2 mov bx, ax ; copy value to bx mov si, word ptr [bp+10] ; store sprite address in si pop dx mov byte ptr es:[si+bx], dl ; put dl into sprite address inc word ptr [bp+18] ; increment counter cmp word ptr [bp+18], 24d ; compare counter with 24 jl grab_inner_loop ; jump back if less add word ptr [bp+14], 320d ; add 320 to y_off mov word ptr [bp+18], 0 ; initialize counter inc word ptr [bp+16] ; increment counter2 cmp word ptr [bp+16], 24d ; compare counter2 with 24 jl grab_outer_loop ; jump back if less pop dx ; restore registers. pop es pop ds pop si pop cx pop bx pop ax pop bp ; restore bp ret 16 ; return and pop the 9 parameter into space. pcx_grap_bitmap endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; draw_sprite proc ; purpose : a drawing of a sprite ; input : stack entry : return address (top), x, y, sprite address, counter, ; counter2, double buffer, offset, work_offset ; output : none ; method : ? push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers push bx push cx push si push ds push es push dx mov ax, @data ; initialize data segment mov ds, ax mov word ptr [bp+10], 0 ; initialize counter mov word ptr [bp+12], 0 ; initialize counter2 mov word ptr[bp+18], 0 ; initialize work_offset mov bx, word ptr[bp+6] ; put y into bx; mov ax, word ptr[bp+6] ; put another copy of y into ax; mov cl, 8 shl bx, cl ; shift bx 8 bits left mov cl, 6 shl ax, cl ; shift ax 6 bits left add ax, bx ; sum ax and bx into ax, than means ; y*256 + y*64 = y*320 add ax, word ptr [bp+4] ; add x to ax which contains y * 320 mov word ptr [bp+16], ax ; save to offset. draw_out_loop: draw_inner_loop: mov bx, word ptr[bp+12] ; mov x into bx add bx, word ptr[bp+18] ; work_offset + x mov si, word ptr[bp+8] ; mov sprite into si mov dl, byte ptr es:[si+bx] ; get the color of that pixel. cmp dl, 0 jz draw_zero mov bx, word ptr [bp+12] ; put x into bx add bx, word ptr [bp+16] ; add offset mov si, word ptr [bp+14] ; load double buffer mov byte ptr[si+bx], dl ; put color of that pixel into double_buffer draw_zero : inc word ptr [bp+12] ; increase x cmp word ptr [bp+12], 24d ; compare with 24 jl draw_inner_loop ; jump if smaller add word ptr [bp+16], 320d ; add 320 to offset add word ptr [bp+18], 24d ; add 24 to work_offset mov word ptr [bp+12], 0d ; initialize x inc word ptr[bp+10] ; increase y cmp word ptr [bp+10], 24d ; compare with 24 jl draw_out_loop ; jump if smaller pop dx ; restore registers. pop es pop ds pop si pop cx pop bx pop ax pop bp ; restore bp ret 16 ; return and pop the 9 parameter into space. draw_sprite endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_sprite_background proc ; purpose : get sprite background. ; input : stack entry : return address (top), x, y, sprite address, counter, ; counter2, double buffer, offset, work_offset ; output : none ; method : ? push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers push bx push cx push si push ds push es push dx mov ax, @data ; initialize data segment mov ds, ax mov word ptr [bp+10], 0 ; initialize counter mov word ptr [bp+12], 0 ; initialize counter2 mov word ptr[bp+18], 0 ; initialize work_offset mov bx, word ptr[bp+6] ; put y into bx; mov ax, word ptr[bp+6] ; put another copy of y into ax; mov cl, 8 shl bx, cl ; shift bx 8 bits left mov cl, 6 shl ax, cl ; shift ax 6 bits left add ax, bx ; sum ax and bx into ax, than means ; y*256 + y*64 = y*320 add ax, word ptr [bp+4] ; add x to ax which contains y * 320 mov word ptr [bp+16], ax ; save to offset. get_out_loop: get_inner_loop: mov bx, word ptr [bp+12] ; put x into bx add bx, word ptr [bp+16] ; add offset mov si, word ptr [bp+14] ; load double buffer mov dl, byte ptr[si+bx] ; get color of that pixel from double_buffer mov bx, word ptr[bp+12] ; mov x into bx add bx, word ptr[bp+18] ; work_offset + x mov si, word ptr[bp+8] ; mov sprite into si mov byte ptr es:[si+bx], dl ; get the color of that pixel. inc word ptr [bp+12] ; increase x cmp word ptr [bp+12], 24d ; compare with 24 jl get_inner_loop ; jump if smaller add word ptr [bp+16], 320d ; add 320 to offset add word ptr [bp+18], 24d ; add 24 to work_offset mov word ptr [bp+12], 0d ; initialize x inc word ptr[bp+10] ; increase y cmp word ptr [bp+10], 24d ; compare with 24 jl get_out_loop ; jump if smaller pop dx ; restore registers. pop es pop ds pop si pop cx pop bx pop ax pop bp ; restore bp ret 16 ; return and pop the 9 parameter into space. get_sprite_background endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; draw_background proc ; purpose : a drawing of a sprite ; input : stack entry : return address (top), x, y, sprite address, counter, ; counter2, double buffer, offset, work_offset ; output : none ; method : ? push bp ; initialize... mov bp, sp ; put sp value to bp and save bp ; on the stack. push ax ; save registers push bx push cx push si push ds push es push dx mov ax, @data ; initialize data segment mov ds, ax mov word ptr [bp+10], 0 ; initialize counter mov word ptr [bp+12], 0 ; initialize counter2 mov word ptr[bp+18], 0 ; initialize work_offset mov bx, word ptr[bp+6] ; put y into bx; mov ax, word ptr[bp+6] ; put another copy of y into ax; mov cl, 8 shl bx, cl ; shift bx 8 bits left mov cl, 6 shl ax, cl ; shift ax 6 bits left add ax, bx ; sum ax and bx into ax, than means ; y*256 + y*64 = y*320 add ax, word ptr [bp+4] ; add x to ax which contains y * 320 mov word ptr [bp+16], ax ; save to offset. drawb_out_loop: drawb_inner_loop: mov bx, word ptr[bp+12] ; mov x into bx add bx, word ptr[bp+18] ; work_offset + x mov si, word ptr[bp+8] ; mov sprite into si mov dl, byte ptr es:[si+bx] ; get the color of that pixel. mov bx, word ptr [bp+12] ; put x into bx add bx, word ptr [bp+16] ; add offset mov si, word ptr [bp+14] ; load double buffer mov byte ptr[si+bx], dl ; put color of that pixel into double_buffer inc word ptr [bp+12] ; increase x cmp word ptr [bp+12], 24d ; compare with 24 jl drawb_inner_loop ; jump if smaller add word ptr [bp+16], 320d ; add 320 to offset add word ptr [bp+18], 24d ; add 24 to work_offset mov word ptr [bp+12], 0d ; initialize x inc word ptr[bp+10] ; increase y cmp word ptr [bp+10], 24d ; compare with 24 jl drawb_out_loop ; jump if smaller pop dx ; restore registers. pop es pop ds pop si pop cx pop bx pop ax pop bp ; restore bp ret 16 ; return and pop the 9 parameter into space. draw_background endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end