vga lines WIP

This commit is contained in:
Frater 2026-02-19 00:00:10 +01:00
commit d2fb28b29c
3 changed files with 974 additions and 411 deletions

View file

@ -60,7 +60,7 @@ section .text
%include "./common/debug_txt.asm" %include "./common/debug_txt.asm"
; GUI ; GUI
; %include "./gui/lib-api.asm" %include "./gui/lib-api.asm"
; --- Données texte --- ; --- Données texte ---
str_quit db "Quitter", 0 str_quit db "Quitter", 0
@ -106,9 +106,11 @@ entrycode:
call mouse_init call mouse_init
GFX MOUSE_SHOW GFX MOUSE_SHOW
call main_testing
.loops: .loops:
call main_loop hlt
jmp .loops ;jmp .loops
; --- Callbacks (Fonctions appelées par le moteur) --- ; --- Callbacks (Fonctions appelées par le moteur) ---
on_click_quit: on_click_quit:
@ -119,44 +121,99 @@ on_click_quit:
on_click_hello: on_click_hello:
ret ret
main_loop:
push bp
mov bp, sp main_testing:
GFX LINE,10,10,10,67, 15
ret
%define .oldval word [bp-2] %define .oldval word [bp-2]
%define .my_slider word [bp-4] %define .my_slider word [bp-4]
%define .value word [bp-6] %define .value word [bp-6]
main_loop:
push bp
mov bp, sp
sub sp, 6 sub sp, 6
push cs push cs
pop ds pop ds
GFX TXT_MODE, GFX_TXT_WHITE DEBUG 1
GFX GOTOXY, 10,50 ISADBG ISA_LEFT, 1
GFX WRITE, cs, str_hello
; Init du système GUI ; Init du système GUI
; call gui_init_system call gui_init_system
DEBUG 2
ISADBG ISA_LEFT, 2
; --- CRÉATION DYNAMIQUE DES BOUTONS ---
; Créer Bouton 1 "QUITTER"
GUI OBJ_CREATE, OBJ_TYPE_BUTTON_ROUNDED, 10, 10, 80, 16
GUI OBJ_SET_TEXT, ax, cs, str_quit
; Créer Bouton 2 "HELLO"
GUI OBJ_CREATE, OBJ_TYPE_BUTTON_ROUNDED, 100, 50, 80, 16
GUI OBJ_SET_TEXT, ax, cs, str_hello
; Créer 3 checkbox "option"
GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50, 100, 15
GUI OBJ_SET_TEXT, ax, cs, str_option1
GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50+16, 100, 15
GUI OBJ_SET_TEXT, ax, cs, str_option2
GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50+16*2, 100, 15
GUI OBJ_SET_TEXT, ax, cs, str_option3
DEBUG 3
ISADBG ISA_LEFT, 3
; Créer Slider (Drag)
GUI OBJ_CREATE, OBJ_TYPE_SLIDER, 10, 100, 150, 12
GUI OBJ_SET_MODE, ax, SLIDER_HORIZONTAL
GUI OBJ_SLIDER_SET_ATTR, ax, 10, 140, 10, 15
GUI OBJ_CREATE, OBJ_TYPE_SLIDER, 400, 10, 16, 150
mov .my_slider, ax
GUI OBJ_SET_MODE, .my_slider, SLIDER_VERTICAL
GUI OBJ_SLIDER_SET_ATTR, .my_slider, 0, 31, 0, 12
mov .oldval, 0x1256
mov .value, 0xFADE
DEBUG 4
ISADBG ISA_LEFT, 4
.loop: .loop:
; call gui_process_all call gui_process_all
GUI OBJ_GET_VAL, .my_slider
mov .value, ax
; mov dh, 1 cmp ax,.oldval
; mov dl, 10 je .loop
; call scr_gotoxy
; ; debug
; mov ax, SEG_BDA_CUSTOM mov .oldval, ax
; mov fs, ax GFX RECTANGLE_FILL,0,148,50,166, PATTERN_WHITE
; mov ax, word [fs:PTR_MOUSE + mouse.x] GFX GOTOXY, 8, 150
; call scr_puthex16
; mov ax, .value
; mov al, ' ' call print_word_hex
; call scr_putc ; end debug
;
; mov ax, word [fs:PTR_MOUSE + mouse.y] ; change palette...
; call scr_puthex16 ;and ax, 0x00FF
;mov bh, 0x00
;mov bl, al
;mov ah, 0x0b
;mov al, 0x00
;int 0x10
mov dx, CRTC_COLOR_DATA
and ax, 0x001F
out dx, ax
nop
jmp .loop jmp .loop
leave leave
ret ret

View file

@ -72,10 +72,11 @@ endstruc
struc gfx struc gfx
.cur_x resw 1 ; x,y en pixel .cur_x resw 1 ; x,y en pixel
.cur_y resw 1 .cur_y resw 1
.cur_mode resw 1 ; mode text
.cur_offset resw 1 ; offset calculé pour le prochain caractère .cur_offset resw 1 ; offset calculé pour le prochain caractère
.cur_line_ofs resw 1 ; "interligne" +2000h ou -2000h .cur_line_ofs resw 1 ; "interligne" +2000h ou -2000h
.cur_shift resb 1 ; x&7 (0..7) .cur_shift resb 1 ; x&7 (0..7)
.cur_mode resb 1 ;
endstruc endstruc
; ----------------------------------------------------------------------------------- ; -----------------------------------------------------------------------------------

View file

@ -32,14 +32,18 @@
; ;
; bit : descr ; bit : descr
; 0..3 : text color : 0=black .. 15=white ; 0..3 : text color : 0=black .. 15=white
; 4 : transparent : 1=apply background attribut ; 4..7 : background color
; 5..7 : free ; 8..D : unused
; 8..F : background color (si bit 4 = 1) ; E : text transparent
; F : background transparent
; ;
%define GFX_TXT_WHITE_TRANSPARENT 000001111b %define GFX_TXT_WHITE_TRANSPARENT 0x0F
%define GFX_TXT_BLACK_TRANSPARENT 000000000b %define GFX_TXT_BLACK_TRANSPARENT 0x00
%define GFX_TXT_WHITE 111110000b %define GFX_TXT_WHITE 0xF0
%define GFX_TXT_BLACK 100001111b %define GFX_TXT_BLACK 0x0F
%define GFX_TXT_TRANSPARENT_BKG 0x8000
%define GFX_TXT_TRANSPARENT_TEXT 0x4000
%macro GFX 1-* %macro GFX 1-*
; %1 est l'index de la fonction ; %1 est l'index de la fonction
@ -97,10 +101,10 @@ graph_driver:
dw vga_set_writemode ; mode texte dw vga_set_writemode ; mode texte
dw vga_putc ; dessin d'un caractère dw vga_putc ; dessin d'un caractère
dw vga_write ; dessin d'une chaine de caractère dw vga_write ; dessin d'une chaine de caractère
dw vga_none ; dessin d'une ligne (Bresenham) avec décision horizontale/verticale dw vga_line ; dessin d'une ligne (Bresenham) avec décision horizontale/verticale
dw vga_none ; dessin d'un rectangle dw vga_draw_rect ; dessin d'un rectangle
dw vga_none ; dessin d'un rectangle plein dw vga_none ; dessin d'un rectangle plein
dw vga_none ; dessin d'un rectangle arrondi dw vga_draw_rounded_frame ; dessin d'un rectangle arrondi
dw vga_mouse_hide ; cache la souris dw vga_mouse_hide ; cache la souris
dw vga_mouse_show ; montre la souris dw vga_mouse_show ; montre la souris
dw vga_mouse_cursor_move ; déplacement du curseur dw vga_mouse_cursor_move ; déplacement du curseur
@ -323,7 +327,7 @@ vga_set_charpos:
%undef .y %undef .y
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; cga_putc_unalign (car) ; vga_putc_unalign (car)
; - x non aligné (x&7 != 0) ; - x non aligné (x&7 != 0)
; - écrit sur 2 bytes (di et di+1) dans chaque banque ; - écrit sur 2 bytes (di et di+1) dans chaque banque
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
@ -333,113 +337,138 @@ vga_set_charpos:
vga_putc: vga_putc:
push bp push bp
mov bp, sp mov bp, sp
; --- Définition des variables locales --- sub sp, 4 ; .cpt [bp-2], .glyph_row [bp-4]
%define .cpt word [bp-2] %define .cpt word [bp-2]
sub sp, 2 ; 1 word variable locale %define .glyph_row word [bp-4]
pusha pusha
push gs ; VRAM segment
push fs push fs
push es push es
call vga_mouse_hide ; Protection souris call vga_mouse_hide ; Protection souris
; --- CONFIGURATION VGA ---
mov dx, EGAVGA_CONTROLLER mov dx, EGAVGA_CONTROLLER
; Forcer le mode de remplacement (écrase la VRAM avec la donnée CPU) mov ax, 0x0205 ; Mode 2
mov ax, 0x0205 ; Index 5 (Mode) : Mode 2 out dx, ax
mov ax, 0x0003 ; Function REPLACE
out dx, ax
mov dx, VGA_SEQUENCER
mov ax, 0x0F02 ; Tous les plans
out dx, ax out dx, ax
; Opération logique : REPLACE (0) mov ax, SEG_VIDEO
; (On pourrait mettre 0x1003 pour faire du OR matériel si besoin) mov gs, ax
mov ax, 0x0003 ; Index 3 (Data Rotate) = REPLACE mov ax, SEG_BDA_CUSTOM
out dx, ax mov fs, ax
push cs
; Configuration VGA : Activer l'écriture sur les 4 plans pour le texte pop ds
mov dx, VGA_SEQUENCER ; Sequencer
mov ax, 0x0F02 ; Index 2 (Map Mask) = 0x0F (tous les plans)
out dx, ax
mov bx, SEG_VIDEO
mov es, bx
mov bx, SEG_BDA_CUSTOM
mov fs, bx
mov ax, .car mov ax, .car
call get_glyph_offset call get_glyph_offset ; cs:si = offset font
; Base offset VRAM pour la scanline Y
mov di, [fs:PTR_GFX + gfx.cur_offset] mov di, [fs:PTR_GFX + gfx.cur_offset]
mov cl, [fs:PTR_GFX + gfx.cur_shift] mov cl, [fs:PTR_GFX + gfx.cur_shift]
mov ch, [fs:PTR_GFX + gfx.cur_mode]
mov bx, GFX_OFFSET
; On définit la couleur de texte (Ici simplifiée : bit 0 du mode) ; --- RÉCUPÉRATION DES COULEURS ---
; Si bit 0 = 1, on écrit en couleur 15 (blanc), sinon couleur 0 (noir) mov ax, [fs:PTR_GFX + gfx.cur_mode]
mov ax, mov bl, al ; BL = Couleur texte (low nibble)
test bl, 00000001b and bl, 0x0F
jz .color_ok mov bh, al ; BH = Couleur fond (high nibble)
mov bh, 0x0F ; Couleur Blanche (tous les plans à 1) shr bh, 4
.color_ok:
mov .cpt, 8 mov .cpt, 8
mov dx, EGAVGA_CONTROLLER mov dx, EGAVGA_CONTROLLER
.row_loop: .row_loop:
lodsb ; AL = octet du glyphe lodsb ; AL = octet glyphe
xor ah, ah
mov .glyph_row, ax ; Image 16 bits du glyphe non décalé
; Gestion du décalage horizontal (X non aligné sur 8) ; --- PASSE 1 : DESSIN DU FOND (SI OPAQUE) ---
xor ah, ah ; AX = 00:Glyphe mov ax, [fs:PTR_GFX + gfx.cur_mode]
shr ax, cl ; AH:AL = Glyphe décalé sur 16 bits test ax, GFX_TXT_TRANSPARENT_BKG
jnz .skip_bkg
; --- DESSIN DE L'OCTET 1 (DI) --- mov ax, .glyph_row
push ax not al ; Inverser le glyphe pour le fond
mov ah, al ; AH = partie du glyphe pour cet octet ror ax, cl ; Aligner le fond sur les octets VRAM
mov al, 0x08 ; Index 8 : Bit Mask
out dx, ax ; On définit quels pixels seront modifiés
mov al, [es:di] ; LATCH LOAD : Aspire les 4 plans dans le GPU ; Octet 1 (DI)
mov [es:di], bh ; WRITE : Applique la couleur BH à travers le masque push ax ; Sauver masque décalé (AH:AL)
mov ah, al ; Masque pour octet 1
mov al, 0x08 ; Bit Mask register
out dx, ax
mov al, [gs:di] ; LATCH LOAD (Charger le fond actuel)
mov [gs:di], bh ; WRITE Fond (BH)
pop ax pop ax
; --- DESSIN DE L'OCTET 2 (DI+1) --- ; Octet 2 (DI+1)
test cl, cl ; Y a-t-il un décalage ? test cl, cl
jz .next_line ; Non, on saute l'octet suivant jz .skip_bkg
; AH contient déjà le masque pour l'octet 2
mov al, 0x08 mov al, 0x08
; AH contient déjà le reste du glyphe décalé out dx, ax
out dx, ax ; Nouveau Bit Mask pour l'octet adjacent mov al, [gs:di+1] ; LATCH LOAD Octet suivant
mov [gs:di+1], bh ; WRITE Fond (BH)
.skip_bkg:
mov al, [es:di+1] ; LATCH LOAD ; --- PASSE 2 : DESSIN DU TEXTE ---
mov [es:di+1], bh ; WRITE mov ax, [fs:PTR_GFX + gfx.cur_mode]
test ax, GFX_TXT_TRANSPARENT_TEXT
jnz .next_line
mov ax, .glyph_row
ror ax, cl ; Aligner le texte sur les octets VRAM
; Octet 1 (DI)
push ax
mov ah, al
mov al, 0x08
out dx, ax
mov al, [gs:di] ; LATCH LOAD
mov [gs:di], bl ; WRITE Texte (BL)
pop ax
; Octet 2 (DI+1)
test cl, cl
jz .next_line
mov al, 0x08
; AH contient le glyphe décalé pour l'octet 2
out dx, ax
mov al, [gs:di+1] ; LATCH LOAD
mov [gs:di+1], bl
.next_line: .next_line:
add di, 80 ; Ligne suivante (640 pixels = 80 octets) add di, 80 ; Ligne suivante
dec .cpt dec .cpt
jnz .row_loop jnz .row_loop
; --- NETTOYAGE (TRÈS IMPORTANT pour la souris) --- ; --- NETTOYAGE ---
mov dx, 0x3CE mov dx, EGAVGA_CONTROLLER
mov ax, 0x0005 ; Revenir en Write Mode 0 mov ax, 0x0005 ; Write Mode 0
out dx, ax out dx, ax
mov ax, 0xFF08 ; Bit Mask par défaut mov ax, 0xFF08 ; Bit Mask = FF
out dx, ax out dx, ax
; Avancer le curseur ; Mise à jour position
add word [fs:PTR_GFX + gfx.cur_x], 8 add word [fs:PTR_GFX + gfx.cur_x], 8
; Recalculer l'offset pour le prochain caractère (gère le changement d'octet)
mov cx, [fs:PTR_GFX + gfx.cur_x] mov cx, [fs:PTR_GFX + gfx.cur_x]
mov dx, [fs:PTR_GFX + gfx.cur_y] mov dx, [fs:PTR_GFX + gfx.cur_y]
call vga_calc_addr call vga_calc_addr
mov [fs:PTR_GFX + gfx.cur_offset], di mov [fs:PTR_GFX + gfx.cur_offset], di
; Note: calc_addr doit mettre le résultat dans DI ou BX selon ton usage
call vga_mouse_show call vga_mouse_show
pop es pop es
pop fs pop fs
pop gs
popa popa
leave leave
ret ret
%undef .car ; clean defs
%undef .cpt %undef .cpt
%undef .glyph_row
; ;
; write string from [DS:SI] to screen ; write string from [DS:SI] to screen
@ -475,6 +504,486 @@ vga_write:
%undef .txt_seg %undef .txt_seg
%undef .txt_ofs %undef .txt_ofs
; ------------------------------------------------------------
; vga_line (x1, y1, x2, y2, color)
; ------------------------------------------------------------
%define .x1 word [bp+4]
%define .y1 word [bp+6]
%define .x2 word [bp+8]
%define .y2 word [bp+10]
%define .color byte [bp+12]
vga_line:
push bp
mov bp, sp
pusha
call vga_mouse_hide
mov ax, .x1
mov bx, .x2
mov cx, .y1
mov dx, .y2
; Cas 1 : Ligne Verticale (x1 == x2)
cmp ax, bx
je .call_vertical
; Cas 2 : Ligne Horizontale (y1 == y2)
cmp cx, dx
je .call_horizontal
; Cas 3 : Ligne diagonale quelconque (Bresenham)
.bresenham:
; ... Algorithme classique utilisant vga_putpixel ...
.call_vertical:
push word .color
push dx ; y2
push cx ; y1
push ax ; x1
call vga_line_vertical
add sp, 8
jmp .done
.call_horizontal:
push word .color
push bx ; x2
push ax ; x1
push cx ; y1
; call vga_line_horizontal
add sp, 8
; jmp .done
.done:
call vga_mouse_show
popa
leave
ret
; clean defs
%undef .x1
%undef .y1
%undef .x2
%undef .y2
%undef .color
; ------------------------------------------------------------
; vga_line_bresenham (x1, y1, x2, y2, color)
; ------------------------------------------------------------
%define .x1 word [bp+4]
%define .y1 word [bp+6]
%define .x2 word [bp+8]
%define .y2 word [bp+10]
%define .color word [bp+12]
vga_line_bresenham:
push bp
mov bp, sp
sub sp, 12 ; Variables locales : dx, dy, sx, sy, err, e2
%define _dx word [bp-2]
%define _dy word [bp-4]
%define _sx word [bp-6]
%define _sy word [bp-8]
%define _err word [bp-10]
%define _e2 word [bp-12]
pusha
push es
; --- Calculs préliminaires Bresenham ---
; dx = abs(x2-x1), sx = x1<x2 ? 1 : -1
mov ax, .x2
sub ax, .x1
mov _sx, 1
jns .dx_ok
neg ax
mov _sx, -1
.dx_ok:
mov _dx, ax
; dy = -abs(y2-y1), sy = y1<y2 ? 1 : -1
mov ax, .y2
sub ax, .y1
mov _sy, 1
jns .dy_ok
neg ax
mov _sy, -1
.dy_ok:
neg ax ; dy doit être négatif
mov _dy, ax
; err = dx + dy
mov ax, _dx
add ax, _dy
mov _err, ax
; --- CONFIGURATION VGA MODE 2 ---
mov dx, EGAVGA_CONTROLLER
mov ax, 0x0205 ; Write Mode 2
out dx, ax
mov ax, 0x0003 ; Function Replace
out dx, ax
mov ax, SEG_VIDEO
mov es, ax
mov cx, .x1 ; Courant X
mov dx, .y1 ; Courant Y
.plot_loop:
; Calculer l'adresse et le Bit Mask pour le pixel courant
push dx
push cx
call vga_calc_addr ; DI = offset VRAM, CL = bit shift (0-7)
; Configurer le Bit Mask (Index 8)
mov ah, 0x80
shr ah, cl ; AH = Masque du pixel
mov al, 0x08
mov dx, EGAVGA_CONTROLLER
out dx, ax
; Écriture Mode 2 (Latches + Couleur)
mov al, [es:di] ; LOAD LATCHES
mov ax, .color
mov [es:di], al ; WRITE Couleur (VGA Mode 2 utilise AL comme couleur)
pop cx
pop dx
; Vérifier si on a atteint la destination
cmp cx, .x2
jne .continue
cmp dx, .y2
je .exit_loop
.continue:
; e2 = 2 * err
mov ax, _err
shl ax, 1
mov _e2, ax
; if e2 >= dy: err += dy; x1 += sx
mov bx, _dy
cmp ax, bx
jl .skip_x
add _err, bx
add cx, _sx
.skip_x:
; if e2 <= dx: err += dx; y1 += sy
mov bx, _dx
cmp _e2, bx
jg .plot_loop
add _err, bx
add dx, _sy
jmp .plot_loop
.exit_loop:
; --- NETTOYAGE VGA ---
mov dx, EGAVGA_CONTROLLER
mov ax, 0x0005 ; Reset Mode 0
out dx, ax
mov ax, 0xFF08 ; Reset Bit Mask
out dx, ax
pop es
popa
leave
ret
; clean defs
%undef .x1
%undef .y1
%undef .x2
%undef .y2
%undef .color
; vga_line_horizontal (y, x1, x2, color)
%define .y word [bp+4]
%define .x1 word [bp+6]
%define .x2 word [bp+8]
%define .color word [bp+10]
vga_line_horizontal:
push bp
mov bp, sp
pusha
push es
; Trier x1 et x2
mov ax, .x1
mov bx, .x2
cmp ax, bx
jbe .skip_swap
xchg ax, bx
.skip_swap:
; AX = x-start, BX = x-end
; Configurer VGA Mode 0 avec Bit Mask
mov dx, EGAVGA_CONTROLLER
mov ax, 0x0005 ; Write Mode 0
out dx, ax
mov ax, 0x0003 ; Function Replace
out dx, ax
; Activer Set/Reset pour la couleur
mov ax, 0x0F01 ; Enable Set/Reset
out dx, ax
mov al, 0x00 ; Index 0: Set/Reset Color
mov ah, byte .color
out dx, ax
mov dx, .y
mov cx, ax ; CX = x1 pour calc_addr
call vga_calc_addr ; DI = offset, CL = shift (non utilisé ici)
mov ax, SEG_VIDEO
mov es, ax
; Boucle simple pixel par pixel (optimisation octet par octet possible ici)
.pixel_loop:
push bx
push cx
; Utilisation du Bit Mask pour le pixel individuel (plus simple que le mode planaire manuel)
mov bx, cx
and bx, 7 ; x % 8
mov ah, 0x80
shr ah, cl ; Bit mask pour le pixel
mov al, 0x08 ; Index 8
mov dx, EGAVGA_CONTROLLER
out dx, ax
mov al, [es:di] ; Load latches
mov [es:di], al ; Write (la couleur est dans Set/Reset)
pop cx
pop bx
inc cx
test cx, 7
jnz .no_inc_di
inc di
.no_inc_di:
cmp cx, bx
jbe .pixel_loop
; Nettoyage Set/Reset
mov dx, EGAVGA_CONTROLLER
mov ax, 0x0001
out dx, ax
pop es
popa
leave
ret
; clean defs
%undef .y
%undef .x1
%undef .x2
%undef .color
; vga_line_vertical (x, y1, y2, color)
%define .x word [bp+4]
%define .y1 word [bp+6]
%define .y2 word [bp+8]
%define .color word [bp+10]
; vga_line_vertical (x, y1, y2, color)
vga_line_vertical:
push bp
mov bp, sp
pusha
; --- Trier Y ---
mov ax, .y1
mov bx, .y2
cmp ax, bx
jbe .y_ok
xchg ax, bx
.y_ok:
; AX = Y-start, BX = Y-end
; --- Calculer le nombre de pixels (Hauteur) ---
mov cx, bx
sub cx, ax
inc cx ; CX = Nombre de lignes à tracer
; --- Calculer l'adresse initiale ---
push cx ; Sauver la hauteur
mov dx, ax ; DX = Y-start
mov cx, .x ; CX = X
call vga_calc_addr ; DI = offset VRAM, CL = bit shift
pop cx ; Restaurer la hauteur dans CX
; --- Configurer le GPU (Mode 2) ---
mov dx, EGAVGA_CONTROLLER
mov ax, 0x0205 ; Write Mode 2
out dx, ax
mov ah, 0x80 ; Bit Mask : 1 pixel
shr ah, cl ; Aligner sur le X
mov al, 0x08 ; Index 8
out dx, ax
mov ax, SEG_VIDEO
mov es, ax
mov al, byte .color ; AL = Couleur pour le Mode 2
.v_loop:
mov ah, [es:di] ; LATCH LOAD
mov [es:di], al ; WRITE COLOR
add di, 80 ; Scanline suivante
loop .v_loop ; Répéter CX fois
; --- Reset ---
mov dx, EGAVGA_CONTROLLER
mov ax, 0x0005 ; Mode 0
out dx, ax
mov ax, 0xFF08 ; Reset Mask
out dx, ax
popa
leave
ret
; clean defs
%undef .x
%undef .y1
%undef .y2
%undef .color
; ------------------------------------------------------------
; vga_draw_rect
; Dessine un rectangle vide (contour)
; Entrée : x1, y1, x2, y2, color
; ------------------------------------------------------------
; Arguments
%define .x1 word [bp+4]
%define .y1 word [bp+6]
%define .x2 word [bp+8]
%define .y2 word [bp+10]
%define .color word [bp+12] ; word pour l'alignement pile (mais on utilise byte)
vga_draw_rect:
push bp
mov bp, sp
pusha
; 1. Ordonner X (x1 < x2)
mov ax, .x1
mov bx, .x2
cmp ax, bx
jle .x_ok
xchg ax, bx
mov .x1, ax
mov .x2, bx
.x_ok:
; 2. Ordonner Y (y1 < y2)
mov ax, .y1
mov bx, .y2
cmp ax, bx
jle .y_ok
xchg ax, bx
mov .y1, ax
mov .y2, bx
.y_ok:
call vga_mouse_hide
; 3. Dessiner les 4 lignes
; Pour éviter les pixels en double dans les coins, on peut ajuster légèrement,
; mais pour un driver simple, tracer les 4 lignes brutes est acceptable.
GFX LINE, .x1, .y1, .x2, .y1, .color
GFX LINE, .x1, .y2, .x2, .y2, .color
GFX LINE, .x1, .y1, .x1, .y2, .color
GFX LINE, .x2, .y1, .x2, .y2, .color
call vga_mouse_show
popa
leave
ret
; clean defs
%undef .x1
%undef .y1
%undef .x2
%undef .y2
%undef .color
; ------------------------------------------------------------
; cga_draw_rounded_frame
; dessiner un cadre arrondi
; Entrée : AX=x1, BX=y1, CX=x2, DX=y2
; ------------------------------------------------------------
%define .x1 word [bp+4]
%define .y1 word [bp+6]
%define .x2 word [bp+8]
%define .y2 word [bp+10]
%define .color word [bp+12]
; Variable locale pour l'index du motif (y % 8)
%define .coord1 word [bp-2]
%define .coord2 word [bp-4]
vga_draw_rounded_frame:
push bp
mov bp, sp
sub sp, 4 ; Reserve espace pour .coord1 et .coord2
pusha
call vga_mouse_hide
; Lignes horizontales (raccourcies de 2px pour laisser place à l'arrondi)
mov ax, .x1
add ax, 2
mov .coord1, ax
mov bx, .x2
sub bx, 2
mov .coord2, bx
GFX LINE, .coord1, .y1, .coord2, .y1, .color
GFX LINE, .coord1, .y2, .coord2, .y2, .color
; Lignes verticales (raccourcies de 1px en haut et en bas)
mov cx, .y1
add cx, 2
mov .coord1, cx
mov dx, .y2
sub dx, 2
mov .coord2, dx
GFX LINE, .x1, .coord1, .x1, .coord2, .color
GFX LINE, .x2, .coord1, .x2, .coord2, .color
; Ajout des pixels de transition pour adoucir les coins (chanfrein)
mov ax, .x1
inc ax ; x1 + 1
mov bx, .y1
inc bx ; y1 + 1
GFX PUTPIXEL, ax, bx, .color ; Coin haut-gauche
mov ax, .x1
inc ax
mov bx, .y2
dec bx ; y2 - 1
GFX PUTPIXEL, ax, bx, .color ; Coin bas-gauche
mov ax, .x2
dec ax ; x2 - 1
mov bx, .y1
inc bx ; y1 + 1
GFX PUTPIXEL, ax, bx, .color ; Coin haut-droite
mov ax, .x2
dec ax
mov bx, .y2
dec bx ; y2 - 1
GFX PUTPIXEL, ax, bx, .color ; Coin bas-droite
call vga_mouse_show
popa
leave
ret
%undef .x1
%undef .y1
%undef .x2
%undef .y2
%undef .color
; Entrée: AX = X (0-639), BX = Y (0-479), CL = Couleur (0-15) ; Entrée: AX = X (0-639), BX = Y (0-479), CL = Couleur (0-15)
%define .x word [bp+4] %define .x word [bp+4]
@ -484,52 +993,48 @@ vga_putpixel:
push bp push bp
mov bp, sp mov bp, sp
pusha pusha
push es
mov bx, .y ; 1. Calcul de l'offset (Y * 80 + X / 8) sans IMUL
mov ax, .x mov ax, .y
mov cl, .color mov di, ax ; DI = Y
; Calcul de l'offset (Y * 80 + X/8) shl di, 6 ; DI = Y * 64
shl ax, 4 ; AX = Y * 16
add di, ax ; DI = Y * 80
imul di, bx, 80 ; DI = Y * 80 mov cx, .x ; CX = X
mov bx, ax ; Sauvegarde X mov bx, cx ; Sauvegarde X pour le masque
shr ax, 3 ; AX = X / 8 shr cx, 3 ; CX = X / 8
add di, ax ; DI = Offset final add di, cx ; DI = Offset final
; Calcul du masque de bit (7 - (X % 8)) ; 2. Configuration du contrôleur graphique (Mode d'écriture 2)
mov dx, EGAVGA_CONTROLLER
mov ax, 0205h ; Index 5 : Mode d'écriture 2
out dx, ax ; Ce mode permet d'envoyer la couleur via AL directement
; 3. Calcul du Bit Mask (7 - (X % 8))
and bx, 7 ; BX = X % 8 and bx, 7 ; BX = X % 8
mov ah, 80h ; Bit 7 à 1 mov ah, 80h ; Bit 7 à 1
shr ah, cl ; Décale pour pointer le bon pixel (cl = bx ici) mov cl, bl ; Utilise le reste pour décaler
; Note: en pratique on utilise souvent une table de pré-calcul pour shr ah, bl shr ah, cl ; AH = Masque du pixel
mov al, 08h ; Index 8 : Bit Mask
; Programmation du Graphics Controller
mov dx, EGAVGA_CONTROLLER
; Sélection du Bit Mask (Index 8)
mov al, 08h
out dx, ax ; AH contient le masque calculé out dx, ax ; AH contient le masque calculé
; Sélection du Set/Reset (Couleur, Index 0) ; 4. Écriture du pixel
mov ax, 0000h
mov al, 00h
mov ah, cl ; Couleur
out dx, ax
; Enable Set/Reset (On active les 4 plans, Index 1)
mov ax, 0F01h
out dx, ax
; 4. Écriture (Nécessite une lecture préalable pour charger les Latches)
mov ax, SEG_VIDEO mov ax, SEG_VIDEO
mov es, ax mov es, ax
mov al, [es:di] ; Lecture bidon pour charger les verrous (latches)
mov [es:di], al ; L'écriture applique la couleur via le matériel
; Reset des registres pour ne pas casser le reste du dessin mov al, [es:di] ; LATCH LOAD : Indispensable pour préserver les autres plans
mov ax, 0FF08h mov al, .color ; AL = Index de couleur (0-15)
mov [es:di], al ; WRITE : Le GPU applique AL là où le Bit Mask est à 1
; 5. Nettoyage minimal (Reset Mode 0)
mov ax, 0005h ; Index 5 : Mode d'écriture 0
out dx, ax out dx, ax
mov ax, 0001h mov ax, 0FF08h ; Index 8 : Reset Bit Mask
out dx, ax out dx, ax
pop es
popa popa
leave leave
ret ret