DOS GRAF TUT


Tryb graficzny w jezyku assembler
Autor: Bogdan Drozdowski, bogdandr (at) op.pl



Na poczatek uprzedzam: jesli myslicie o wysokich rozdzielczosciach, to sie
zawiedziecie, gdyz ten kurs nie bedzie takich omawial. Jesli naprawde
wolicie wysokie rozdzielczosci, to poszukajcie w Internecie opisu standardu
VESA lub DirectX API.


A my, zamiast bawic sie w te wszystkie skomplikowane sprawy, zajmiemy sie
tzw. trybem 13h. Ten tryb oferuje rozdzielczosc 320x200 w 256 kolorach
(co widac tez w Liscie Przerwan Ralfa Brown'a - RBIL).

Ale najwazniejsza jego cecha jest to, ze 320x200 = 64000 < 64kB, tj caly
ekran miesci sie w jednym segmencie, co znacznie ulatwia prace.


Ekran w trybie graficznym miesci sie w segmencie 0A000h oraz:

0A000:0000 - pierwszy piksel (bajt, 256 mozliwosci)
0A000:0001 - drugi piksel
0A000:0002 - trzeci piksel
...


Do zmiany trybu graficznego uzywa sie przerwania 10h, funkcji 0 (opis wyjety
z Listy przerwan Ralfa Browna):

==================================
INT 10 - VIDEO - SET VIDEO MODE
AH = 00h
AL = desired video mode (see #00010)
Return: AL = video mode flag (Phoenix, AMI BIOS)
20h mode > 7
30h modes 0-5 and 7
3Fh mode 6
AL = CRT controller mode byte (Phoenix 386 BIOS v1.10)
Desc: specify the display mode for the currently active display
adapter
==================================

Jak widac, zmiana trybu graficznego na omawiany tryb 13h nie jest
trudniejsza niz:

mov ax, 13h
int 10h

Powrot do tradycyjnego trybu tekstowego 80x25 wyglada tak:

mov ax, 3
int 10h


Pytanie brzmi: jak cokolwiek narysowac?
Nic prostszego! Po prostu pod adres:

wiersz*320 + kolumna

zapisujemy odpwiedni bajt, np. tak (skladnia TASM):

==================================
mov ax, 0a000h
mov es, ax
xor di,di
mov byte ptr es:[di],15 ; NASM: mov byte [es:di],15
==================================


No ale 1 piksel to za malo na nasze ambicje, prawda?
Sprobujmy narysowac pozioma linie (NASM):


==================================
; nasm -O999 -o liniapoz.com -f bin liniapoz.asm

org 100h

mov ax, 13h
int 10h ; uruchom tryb graficzny 13h

mov ax, 0a000h
mov es, ax
xor di, di

mov al, 15
mov cx, 10

rep stosb ; przenies 10 bajtow wartosci 15 pod es:di
; = 0a000:0000

xor ah, ah
int 16h

mov ax, 3
int 10h ; powrot do trybu tekstowego

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

To chyba nie bylo zbyt trudne, prawda? No to sprobujmy cos trudniejszego:
linia pionowa.

Cala "filozofia" polega na tym, aby po narysowaniu piksela przejsc o 1 wiersz
nizej (czyli o 320 bajtow dalej). Piszmy wiec (NASM):


==================================
; nasm -O999 -o liniapio.com -f bin liniapio.asm

org 100h

mov ax, 13h
int 10h

mov ax, 0a000h
mov es, ax
xor di, di

mov al, 15
mov cx, 100

rysuj:
mov [es:di], al
add di, 320
loop rysuj

xor ah, ah
int 16h

mov ax, 3
int 10h

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


Na razie bylo latwo: rysowac zaczynalismy w lewym gorny rogu, wiec DI byl
rowny 0. A co, jesli chcemy wyswietlac piksele gdzies indziej?

Coz, sa 2 mozliwosci:

1. W czasie pisania programu (czyli przed kompilacja) znasz dokladna
pozycje, gdzie bedziesz rysowac.

W takim przypadku kompilator policzy DI za ciebie, wystarczy wpisac
cos takigo:
mov di, wiersz*320 + kolumna

wstawajac w miejsce slow "wiersz" i "kolumna" znane przez siebie wartosci.


2. Pozycja, gdzie bedziesz rysowac jest zmianna i zalezy np. od tego, co
wpisze uzytkownik.
Tutaj jest gorzej. Trzeba wpisac do programu instrukcje, ktore przemnoza
wiersz przez 320 i dodadza kolumne. Nalezy za wszelka cene unikac
niewiarygonie wolnej instrukcji (I)MUL! Ten problem rozwiazemy tak
(wiersz i kolumna to 2 zmienne po 16 bitow):

mov ax, [wiersz]
mov bx, [wiersz] ; 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, [kolumna] ; AX = wiersz*320 + kolumna

mov di,ax


Ostatni przykad: rysowanie okregu (no, w kazdym razie czegos co mialo byc
okregiem a ma ksztalt bardziej przypominajacy elipse...). Program ten
wykorzystuje koprocesor do policzenia sinusow i kosinusow dla katow od
0 do 360 stopni, przerobinych na radiany. Komentarze obok instrukcji FPU
oznaczaja stan stosu, od st(0) z lewej.

==================================
; nasm -O999 -o kolo.com -f bin kolo.asm

org 100h

mov ax, 13h
int 10h

mov ax, 0a000h
mov es, ax

mov cx, 360

finit
fldpi
fild word [sto80]

fdivp st1, st0 ; pi/180

finit
fld1
fild word [r] ; r, 1, pi/180
fldz ; kat=0, r, 1, pi/180

mov al, 15

rysuj:
fld st0 ; kat, kat, r, 1, pi/180

fmul st3 ; kat w radianach
mov di, 100*320 + 160 ; srodek ekranu

fsin ; sin(kat), kat, r, 1, pi/180
fmul st2 ; sin(kat)*r, kat, r, 1, pi/180

fistp word [wys] ; kat, r, 1, pi/180

fld st0 ; kat, kat, r, 1, pi/180
fcos ; cos(kat), kat, r, 1, pi/180
fmul st2 ; r*cos(kat), kat, r, 1, pi/180

fistp word [szer] ; kat, r, 1, pi/180

add di, [szer] ; dodajemy odleglosc pozioma

mov dx, [wys]
mov bx, dx
shl dx, 8
shl bx, 6
add dx, bx ; dx = wys*320

sub di, dx ; odejmujemy odleglosc pionowa

mov [es:di], al

fadd st0, st2 ; kat += 1

dec cx
jnz rysuj

; -------------------------

finit

xor ah, ah
int 16h

mov ax, 3
int 10h

mov ax, 4c00h
int 21h


r dw 50
szer dw 0
wys dw 0
sto80 dw 180
==================================


Podobnie, uzywajac FSIN i FCOS, mozna rysowac np. linie ukosne, ktore
pominalem w tym kursie.



Mam nadzieje, ze po lekturze tego odcinka kazdy bez problemow bedzie rysowal
w tym dosc prostym (zwlaszcza do nauki) trybie graficznym.

Milego eksperymentowania!


Wyszukiwarka

Podobne podstrony:
DOS DIOD TUT
GRAF TUT
DOS PWR TUT
DOS MYSZ TUT
GRAF TUT
DOS SPKR TUT
DOS CPU TUT
DOS BOOT TUT
DOS SYS TUT
DOS BIBL TUT
GRAF TUT
DOS TSR TUT
DOS BMP TUT
FUNFACE DOS OPIS
ART121 tut 2

więcej podobnych podstron