Programmazione della VGA
Tratteremo in questo tutorial un argomento tra i più interessanti nella programmazione. Non riuscirò certo a coprire
l'intero argomento, mi propongo solo di dare una infarinatura generale lasciando poi a voi il compito di approfondire l'argomento, in
rete si trovano molte informazioni sulla programmazione della scheda video.
Il modo grafico che considererò qui è il 13h, quello della VGA "Standard" che lavora a 320x200 con 256 colori.
La prima cosa che un programma assembly (ma anche in ogni altro linguaggio) deve fare è impostare la modalità; bene, questo
può essere fatto utilizzando l'int 10h tramite la funzione 00h. Quindi:
Set_VGA PROC
mov ax,0013h ;ah=00 al=13h (mod. 320x200x256)
int 10h
RET
Set_VGA ENDP
Una volta terminato il programma si deve reimpostare la modalità testo, anche questo può essere fatto tramite l'int 10h:
Set_TXT PROC
mov ax,0003h ;ah=00 al=03h (mod. testo 80x25)
int 10h
RET
Set_TXT ENDP
Ora che siamo riusciti ad impostare la modalità grafica voluta vediamo come si può mettere un Pixel sullo schermo. Anche
per questa operazione si può ricorrere all'int 10h (funzione 0Ch)
Put_Pixel PROC
mov ah,0Ch
mov al,Color ;colore del pixel
mov cx,X ;coordinata X
mov dx,Y ;coordinata Y
mov bx,1 ;numero di pagina (per le
;modalità con più pagine)
int 10h
RET
Put_Pixel ENDP
Un problema di questo modo di posizionare un pixel sul video è dato dalla lentezza veramente insopportabile in alcune applicazioni,
perciò invece di usare la funzione del BIOS (int 10h) possiamo accedere direttamente alla memoria video. Il segmento in cui questa
risiede è all'indirizzo A000, quindi il punto di coordinate 0,0 sarà allindirizzo A000:0000 quello di coordinate 319,199
a A000:FFFF. E il punto di coordinate 145,76?? Bene per trovare l'indirizzo di un generico punto x,y in memoria si può usare
la formula:
ind = x + ( Y · 320)
Chiaro?
OK ma cosa ci mettiamo all'indirizzo calcolato?? Bene a quell'indirizzo ci va l'indice del colore del pixel. Per capire bene questo
dobbiamo fare una parentesi sulla palette.
LA PALETTE
La palette è la tavolozza dei colori da usare per realizzare il nostro disegno. Si tratta di un array bidimensionale di 256
elementi ognuno dei quali contiene 3 valori che corrispono al livello di Rosso, Verde, Blu (R G B).
Palette
-------
| r|g|b |
0|__|_|__|
| r|g|b |
1|__|_|__|
| r|g|b |
2|__|_|__|
| | | |
Come voi saprete mescolando in modo opporutuno il Rosso, Verde e Blu possiamo ottenere tutti i colori che vogliamo. Le gradazioni di
R G e B vanno da 0 a 63. Per leggere il valore di R G e B di un colore dalla palette procedo nel modo seguente:
get_pal PROC
mov dx,3c7h ;porta in cui va indicato
;l'indice del colore
mov al,col ;col è l'indice del colore
;da leggere (0..255)
out dx,al
add dx,2 ;3c9h è la porta da cui si
;leggono i 3 valori
in al,dx
mov R,al
in al,dx
mov G,al
in al,dx
mov B,al ; in R, G e B ho i valori
RET
get_pal ENDP
La procedura inversa, quella per impostare i valori di R G e B nella palette è la seguente:
set_pal PROC
mov dx,3c8h ;porta in cui va indicato l'indice
;del colore da scrivere
;(NB è diverso dal precedente!!)
mov al,col
out dx,al ;scrivo sulla porta il colore
inc dx ;3c9 è la porta su cui scrivere
;i 3 valori R G B
mov al,R
out dx,al
mov al,G
out dx,al
mov al,B
out dx,al ;ora nella palette c'è il
;nuovo colore
RET
set_pal ENDP
Spero di aver chiarito cos'è e come funziona la palette.
Tornando al discorso della put_pixel che agisce direttamente in memoria si diceva che all'indirizzo calcolato dalla formula
si doveva scrivere l'indice del colore, beh ora è chiaro no? Metto l'indice che il colore ha nella palette.
Per concludere il discorso vi lascio un esempio che utilizza un po' tutte le funzioni viste. Si tratta di un pgm che simula l'effetto
neve che si vede sui televisori rotti o non sintonizzati.
;SNOW.ASM - By b0nu$, 1997
.286
SEG_A SEGMENT
ASSUME CS:SEG_A, DS:SEG_A
ORG 100H
SNOW PROC FAR
INIT: JMP START
rgb db 3 dup(?) ;Array che contiene i valori
;di R G B del
colore
num_rnd_val dw 12345 ;A caso
num_rnd_mul dw 9421 ;A caso
START:
mov ax,0013h
int 10h ;imposto modalità 320x200
xor ax,ax
loop_pal: mov rgb[0],al
mov rgb[1],al
mov rgb[2],al
CALL Set_Pal ;imposto la palette con tutte
;le tonalità
di grigio nel
;quale si ha R=G=B.
inc al
cmp al,0FFh
jne loop_pal
xor bx,bx ;x=0
Ciclo_x: xor dx,dx ;y=0 ;parto da 0,0
Ciclo_y: push dx ;questo ciclo posiziona a caso
;pixel sullo schermo
push dx
CALL Random
pop dx
CALL Put_Pixel
pop dx
inc dx
cmp dx,0C7h ;199
jne Ciclo_y
inc bx
cmp bx,013Fh ;319
jne Ciclo_x
mov ax,0003h
int 10h ;imposto modalità txt
RETN
SNOW ENDP
Put_Pixel PROC ;dx=y bx=x ah=col
push ax ;usa l'accesso diretto in
;memoria video
mov ax,0A000h
mov es,ax
push bx
mov dh,dl
xor dl,dl
shl bx,6
add dx,bx
pop bx
add bx,dx
mov di,bx
xor al,al
pop ax ;prelevo il colore
mov es:[di],ah
RET
Put_Pixel ENDP
Set_Pal PROC ;al=colore
mov dx,3c8h
mov al,[col]
out dx,al
inc dx
mov al,rgb[0] ;red
out dx,al
mov al,rgb[1] ;green
out dx,al
mov al,rgb[2] ;blue
out dx,al
RET
Set_Pal ENDP
Random PROC ;Genera un numero casuale con
;l'algoritmo di
D.Lehmer
mov ax,num_rnd_val
mul num_rnd_mul
inc ax
mov num_rnd_val,ax
RET
Random ENDP
SEG_A ENDS
END INIT
Naturalmente non pretendo certo di aver coperto l'intero l'argomento, prendetelo solo come un introduzione, un punto di partenza da
cui spiccare il salto verso la grafica avanzata. Qui spero solo di avervi fatto capire alcuni meccanismi che stanno alla base della
programmazione della scheda video VGA.
|