Tryb graficzny

Program rysujący na ekranie figury geometryczne na podstawie danych umieszczonych w pliku wejściowym o nazwie podawanej przy wywołaniu.
Figury powinny być rysowane w trybach VGA: 320×200-256kol i 640×480-16kol w jednym z czterech kolorów: biały, czerwony, zielony lub niebieski (B,C,Z lub N). Ekran jest traktowany jako pierwsza ćwiartka układu współrzędnych. Początek układu współrzędnych znajduje się w lewym dolnym rogu ekranu.
Dodatkowo w trybie 320×200 figury są wypełniane
Pierwsza linia pliku zawiera tryb ekranu: 320 lub 640
320 – oznacza tryb 320×200
640 – oznacza tryb 640×480

Kolejne linie określają poszczególne figury do wyświetlenia na ekranie. Każda taka linia zawiera na początku literę określającą kolor figury, a następnie ciąg par współrzędnych wierzchołków figury.
Przykład pliku wejściowego: (rysuje czerwony kwadrat i niebieski trójkąt w trybie 320×200):

320
C 0,0 50,0 50,50 0,50
N 100,80 150,110 200,40

Przykład wywołania Programu:
program3 dane.wej

; by Pawel Konieczny
; ver 1.0
.186
;................. Segment danych .................
dane1 segment
p0          dw  ?
q0          dw  ?
p1          dw  ?
q1          dw  ?
f_in            db  10 dup (?),'0'
uchwyt          dw  ?
bufor          db  1000 dup ('$')
errorx        db  'Za duza wspolrzedna X$'
errory            db  'Za duza wspolrzedna Y$'
error1        db  'Brak parametru$'
error2        db  'Nie znaleziono pliku$'
error4        db  'Nie mozna zamknac pliku$'
gran_linii    dw  ?
gran_ekran    dw  ?
WspX        dw  ?
WspY        dw  ?
kop_di        dw  ?
x          dw  ?
y          dw  ?
w1        dw  ?
w2        dw  ?
a          dw  ?
b          dw  ?
dex          dw  ?
dey          dw  ?
adx          dw  ?
ady          dw  ?
ix          dw  ?
iy          dw  ?
du          dw  ?
dr         dw  ?
pp          dw  ?
cp          dw  ?
kolor          db  ?
dane1 ends
;..................................................

;................. Segment kodu ...................
code1 segment
ASSUME cs:code1, ds:dane1, ss:stos1
start:
mov ax,seg dane1
mov ds,ax

call CzyParam
call CzytPar
next:
call OtwPlik
call CzytPlik
call Wcz_rozdz

mov di,5           ; tu sie zaczyna pierwszy kolor
call Wcz_kolor
inc di
inc di
jmp startuj
start3:
mov di,[kop_di]
call Wcz_kolor
inc di
inc di
startuj:
call Czytaj       ; pierwsza wspolrzedna (dwie liczby), ustawia 'di' na pierwszy znak po ostatniej liczbie
mov ax,[a]
mov [p0],ax
mov [w1],ax
mov ax,[b]
mov [q0],ax
mov [w2],ax

inc di            ; przeskocz spacje
call CzyKoniec    ; sprawdz, czy doszlismy do konca linii

start2:
call Czytaj       ; druga wspolrzedna
mov ax,[a]
mov [p1],ax
mov ax,[b]
mov [q1],ax

call Rysuj_linie

inc di
call CzyKoniec

mov ax,[p1]
mov [p0],ax
mov ax,[q1]
mov [q0],ax
jmp start2

pob_pierw:
mov ax,[w1]
mov [p0],ax
mov ax,[w2]
mov [q0],ax
call Rysuj_linie

mov di,-1
mov ax,[WspX]
dec ax
mov [gran_linii],ax         ; gran_linii = WspX - 1
xor bx,bx
jmp szuk_pier
do_nowej_linii:
mov di,[gran_linii]
mov cx,[WspX]
add [gran_linii],cx
xor bx,bx
mov cx,[gran_ekran]
cmp [gran_linii],cx
ja start3                  ; gdy dojdziemy do konca, wczytuj nastepna figure
szuk_pier:
inc di
cmp di,[gran_linii]
jae do_nowej_linii
mov al,byte ptr es:[di]
cmp al,[kolor]
jne szuk_pier
mov bx,di              ; znacznik pierwszego wystapienia
szuk_drug:               ; znaleziono pierwszy punkt
inc di
cmp di,[gran_linii]      ; drugi punkt musi byc w tej samej linii ...
ja [do_nowej_linii]     ; ... gdy go nie ma, skaczemy do nowej linii
mov al,byte ptr es:[di]
cmp al,[kolor]
je czy_nie_sa_obok     ; znaleziono drugi punkt, ale sprawdzamy, czy nie sa obok siebie
jmp szuk_drug

czy_nie_sa_obok:
inc bx
cmp bx,di
je szuk_drug
;    dec bx

cmp [WspX],320
je wypelnij_low
call ZamkPlik
call Koniec

wypelnij_low:
mov al,[kolor]
mov byte ptr es:[bx],al
inc bx
cmp bx,di
jne wypelnij_low
jmp do_nowej_linii
;jmp szuk_pier

CzyParam PROC               ; sprawdzenie czy sa parametry
mov bx,80h           ; sprawdzamy czy istnieje ...
mov cl,byte ptr es:[bx]       ; ... jakikolwiek parametr
cmp cl,0             ; jesli nie ma zadnego parametru, to ...
je Komunikat1        ; ... wypisz blad
ret
CzyParam ENDP

CzytPar PROC               ; czytanie pierwszego parametru
inc bx               ; parametry zaczynaja sie od 82h
mov dl,byte ptr es:[bx]       ; wczytujemy znak do dl
cmp dl,0dh
je next
mov f_in[di],dl      ; a nastepnie do bufora, ktory bedzie nazwa pliku
inc di
jmp CzytPar
ret
CzytPar ENDP

CzyKoniec PROC                ; ------------------ Sprawdz, czy doszlismy do konca linii ------------------------------
mov dl,[bufor+di]
mov [kop_di],di
inc [kop_di]
inc [kop_di]
cmp dl,0dh
je pob_pierw
ret
CzyKoniec ENDP
; wejscie : 'di' - miejsce w pliku
; wyjscie : skok do 'pob_pierw', gdy napotkano na koniec pliku

Wcz_rozdz PROC                ; ------------------------- Wczytanie rozdzielczosci ------------------------------------
low_res:              ; -- czy 320 x 200 --
mov dl,[bufor]
cmp dl,'3'
jne high_res
mov dl,[bufor+1]
cmp dl,'2'
jne Koniec
mov dl,[bufor+2]
cmp dl,'0'
jne Koniec
mov dl,[bufor+3]
cmp dl,13            ; sprawdzamy, czy jest znak konca linii ...
jne Koniec           ; ... gdy nie, wychodzimy (znaczy to, ze jest jeszcze jakas cyfra)
mov [WspX],320
mov [WspY],200
mov [gran_ekran],63999
call InitLow
ret

high_res:              ; -- czy 640 x 480 --
mov dl,[bufor]
cmp dl,'6'
jne Koniec
mov dl,[bufor+1]
cmp dl,'4'
jne Koniec
mov dl,[bufor+2]
cmp dl,'0'
jne Koniec
mov dl,[bufor+3]
cmp dl,13            ; sprawdzamy, czy jest znak konca linii ...
jne Koniec           ; ... gdy nie, wychodzimy
mov [WspX],640
mov [WspY],480
mov [gran_ekran],307199
call InitHigh
ret
Wcz_rozdz ENDP

Wcz_kolor PROC                ; ----------------------------- Wczytanie koloru ----------------------------------------
mov dl,[bufor+di]
cmp dl,'B'
je bialy               ;  kolor bialy
cmp dl,'C'
je czerwony           ;  kolor czerwony
cmp dl,'Z'
je zielony           ;  kolor zielony
cmp dl,'N'
je niebieski           ;  kolor niebieski

jmp Koniec           ; gdy kolor jest niezdefiniowany, wychodzimy

bialy:
mov [kolor],15
ret

czerwony:
mov [kolor],4
ret

zielony:
mov [kolor],2
ret

niebieski:
mov [kolor],1
ret
Wcz_kolor ENDP

Czytaj PROC                   ; --------- Wczytanie liczb obok przecinka i umieszczenie ich do zmiennych a,b ----------
xor cx,cx
; --------- wczytanie pierwszego punktu do 'cx' ----------
first_p:            ; zmienna 'p'
mov al,[bufor+di]

sub al,30h
xor ah,ah         ; zamien ascii na cyfre
add cx,ax         ; dodaj cyfre do sumy
mov ax,cx         ; przenies sume do 'ax'

inc di            ; sprawdz nastepny znak
mov dl,[bufor+di]     ; ...........
cmp dl,','        ; jesli jest przecinkiem ...
je podstaw        ; ... to zakoncz wczytywanie

mov bx,ax         ; ... w przeciwnym wypadku pomnoz przez 10 poprzednia liczbe
shl ax,3            ; ax = ax * 8
shl bx,1            ; bx = bx * 2 = ax * 2
add ax,bx         ; ax = ax + bx = ax * 10

mov cx,ax
jmp first_p

podstaw:
cmp ax,[WspX]
jae Komunikatx
mov a,ax
inc di
xor cx,cx

; --------- wczytanie drugiego punktu do 'cx' ----------
second_p:            ; zmienna 'q'
mov al,[bufor+di]

sub al,30h
xor ah,ah         ; zamien ascii na cyfre
add cx,ax         ; dodaj cyfre do sumy
mov ax,cx         ; przenies sume do 'ax'

inc di            ; sprawdz nastepny znak
mov dl,[bufor+di]     ; ...........
cmp dl,' '        ; jesli jest spacja
je podstaw2        ; to zakoncz wczytywanie

mov bx,ax         ; w przeciwnym wypadku pomnoz przez 10 poprzednia liczbe
shl ax,3            ; 2^3 +
shl bx,1            ; + 2^1
add ax,bx

mov cx,ax
jmp second_p

podstaw2:
cmp ax,[WspY]
jae Komunikaty
mov [b],ax
ret
Czytaj ENDP

InitLow PROC                  ; -------------------------- Inicjalizacja trybu 320 x 200 x 256 ------------------------
mov ax,0013h
int 10h
mov ax,0A000h
mov es,ax         ; es = 0A000h
ret
InitLow ENDP

InitHigh PROC                 ; -------------------------- Inicjalizacja trybu 640 x 480 x 16 -------------------------
mov ax,0012h
int 10h
mov ax,0a000h
mov es,ax         ; es = 0A000h
ret
InitHigh ENDP

RysujPunkt PROC
cmp [WspX],320
je PunktLow
cmp [WspX],640
je PunktHigh
ret
RysujPunkt ENDP

PunktLow:                 ; ------------------------ Rysowanie punktu o wps. x,y ----------------------------------
mov ax,[y]
neg ax
add ax,199        ; ax = 199 - ax
mov bx,ax         ; bx = ax
shl ax,8            ; ax = ax*256
shl bx,6            ; bx = bx*64 = ax*64
add ax,bx         ; ax = ax*256 + ax*64 = ax*320 = wiersz*320
add ax,[x]            ; ax = wiersz*320 + kolumna = 320y+x
mov di,ax
mov al,[kolor]
mov byte ptr es:[di],al
ret

PunktHigh:               ; ------------------------ Rysowanie punktu o wps. x,y ----------------------------------
push cx
mov ax,[x]
mov bx,[y]
neg bx
add bx,479
mov dx,bx
shl bx,6
shl dx,4
add bx,dx         ; bx = y * 80
mov dx,ax
shr dx,3          ; dx = x / 8
add bx,dx         ; bx = wyliczony adres
mov cl,7
and cl,al         ; cl = n (numer bitu w wyznaczonym bajcie w bx)
mov al,80h
shr al,cl         ; al = maska
mov dx,3CFh
out dx,al               ; wpisujemy do rejestru Bit Mask

mov al,2
mov dx,3C4h
out dx,al               ; select map mask register

mov al,0Fh
mov dx,3C5h
out dx,al               ; enable all planes

mov al,es:[bx]          ; czytanie z pamieci
mov es:[bx],byte ptr 0  ; czyszczenie kolorow
mov al,[kolor]
out dx,al               ; ustawianie nowego koloru
mov es:[bx],byte ptr 0FFh ; zapisywanie do pamieci

pop cx
ret

OtwPlik PROC                  ; ----------------------------- Otwieranie pliku ----------------------------------------
mov ax,3d00h       ; otwieramy plik do odczytu
lea dx,[f_in]
int 21h
jc Komunikat2
mov [uchwyt],ax
ret
OtwPlik ENDP

CzytPlik PROC                 ; ------------------------- Czytanie z pliku do bufora ----------------------------------
mov ax,3f00h
mov bx,[uchwyt]
mov cx,500         ; czytamy..
lea dx,[bufor]       ; do bufora
int 21h
ret
CzytPlik ENDP

Rysuj_linie PROC              ; ----------------- Rysowanie linii o koncach (p0, q0), (p1, q1) ------------------------
push di
mov ax,[p1]
sub ax,p0
mov [dex],ax      ; dex = p1-p0
mov ax,[q1]
sub ax,[q0]
mov [dey],ax      ; dey = q1-q0
cmp [dex],0       ; ---- sprawdzanie dex
jge dalej
mov ax,[dex]    ; gdy dex < 0
neg ax
mov [adx],ax    ; adx = |dex|
jmp spr_y
dalej:          ; gdy dex >= 0
mov ax,[dex]
mov [adx],ax      ; adx = |dex|
spr_y:
cmp [dey],0       ; ---- sprawdzanie dey
jge dalej2
mov ax,[dey]   ; gdy dey < 0
neg ax
mov [ady],ax   ; ady = |dey|
jmp nie_spr
dalej2:          ; gdy dey >= 0
mov ax,[dey]
mov [ady],ax      ; ady = |dey|
nie_spr:
mov ax,[p0]
mov [x],ax          ; x = p0
mov ax,[q0]
mov [y],ax          ; y = q0
mov [cp],0          ; cp = 0
cmp [dex],0       ; ----- pierwszy if -------
jle dalej3
mov [ix],1     ; if dex > 0 then ix = 1
jmp if_2     ; wyskocz z petli
dalej3:
mov [ix],-1    ; if dex <= 0 then ix = -1
mov [cp],-1    ;                  cp = -1
if_2:          ; ------ drugi if --------
cmp [dey],0
jle dalej4
mov [iy],1     ; if dey > 0 then iy = 1
jmp if_3     ; wyskocz z petli
dalej4:
mov [iy],-1    ; if dey <= 0 then iy = -1
if_3:          ; ------ trzeci if -------
mov ax,[adx]
cmp ax,[ady]
jl end_else
mov ax,[ady]   ; -------  gdy adx >= ady  ---------
add ax,ax    ;  ax = 2*ady
mov [dr],ax    ; dr = 2*ady
mov ax,[adx]
add ax,ax    ;  ax = 2*adx
mov bx,[dr]    ;  bx = dr
sub bx,ax    ;  bx = dr - 2*adx
mov [du],bx    ; du = dr - 2*adx
mov ax,[dr]
sub ax,[adx]   ;  ax = dr - adx
mov [pp],ax    ; pp = dr - adx
mov ax,[adx]
inc ax
mov cx,ax
petla_for1:
call RysujPunkt
mov ax,[x]
add ax,[ix]
mov [x],ax    ; x = x + ix
mov ax,[pp]
cmp ax,[cp]   ; cp nie jest -1
jle if_el
mov ax,[y]         ; if pp > cp
add ax,[iy]
mov [y],ax   ; y = y + iy
mov ax,[pp]
add ax,[du]
mov [pp],ax  ; pp = pp + du
loop petla_for1
pop di
ret
if_el:            ; if pp <= cp
mov ax,[pp]
add ax,[dr]
mov [pp],ax  ; pp = pp + dr
loop petla_for1
pop di
ret
end_else:       ; -------  gdy adx < ady  ---------
mov ax,[adx]
add ax,ax
mov [dr],ax    ; dr = 2*adx
mov ax,[ady]
add ax,ax    ;  ax = 2*ady
mov bx,[dr]    ;  bx = dr
sub bx,ax    ;  bx = dr - 2*ady
mov [du],bx    ; du = dr - 2*ady
mov ax,[dr]
sub ax,[ady]   ;  ax = dr - ady
mov [pp],ax    ; pp = dr - ady
mov ax,ady
inc ax
mov cx,ax
petla_for2:
call RysujPunkt
mov ax,[y]
add ax,[iy]
mov [y],ax    ; y = y + iy
mov ax,[pp]
cmp ax,[cp]
jle if_else
mov ax,[x]         ; if pp > cp
add ax,[ix]
mov [x],ax   ; x = x + ix
mov ax,[pp]
add ax,[du]
mov [pp],ax  ; pp = pp + du
loop petla_for2
pop di
ret
if_else:          ; if pp <= cp
mov ax,[pp]
add ax,[dr]
mov [pp],ax  ; pp = pp + dr
loop petla_for2
pop di
ret
Rysuj_linie ENDP

ZamkPlik PROC                 ; ------------------------------- Zamykanie pliku ---------------------------------------
mov ax,3e00h
mov bx,[uchwyt]
int 21h
jc Komunikat4
ret
ZamkPlik ENDP

Komunikat1:
lea dx,[error1]
mov ah,9h
int 21h
call Koniec

Komunikat2:
lea dx,[error2]
mov ah,9h
int 21h
call Koniec

Komunikat4:
lea dx,[error4]
mov ah,9h
int 21h
call Koniec

Komunikatx:
mov ax,0003h
int 10h
lea dx,[errorx]         ; mov dx,offset error
mov ah,9h
int 21h
call Koniec

Komunikaty:
mov ax,0003h
int 10h
lea dx,[errory]         ; mov dx,offset error
mov ah,9h
int 21h
call Koniec

Koniec PROC                   ; ------------------------------ Procedury koncowe --------------------------------------
; ---------- Czekanie na klawisz -------------

mov ax,0
int 16h

; ---------- Powrot do tr. tekstowego -------------

mov ax,0003h
int 10h

; ---------- Wyjscie do systemu -------------

mov ax,4c00h
int 21h
ret
Koniec ENDP

code1 ends
;..................................................

;................ Segment stosu ...................
stos1 segment stack
dw 1000 dup(?)
stos1 ends
;..................................................

END start

Dodaj komentarz