org 0x0000 ; Adresse de début .COM

jmp start
%include "affichageTexte.asm"

start:
;On initialise Data Segment et Extra Segment à Code Segment
	call initialise_segments

	mov si, hello; met l'adresse de la chaîne à afficher dans le registre SI
	call affiche_chaine
ecran:
	mov ax, 0x4F00 ; demande infos sur le pilote VESA VBE
	mov di, VESASignature
	int 10h
	cmp ax, 0x4F ; Si AL <> 0x4F, on n'a pas de VESA, donc fin. Si AH <> O, erreur, donc fin.
	jne fin
	mov si, OEMStringPtr ; pointeur vers le nom de l'OEM stocké offset:segment
	lodsw; on charge l'adresse d'offset dans ax
	mov bx, ax ; BX contient l'adresse d'offset
	lodsw ; on charge l'adresse de segment dans ax
	mov si, bx ; SI pointe sur le nom de l'OEM
	push ds ; on sauvegarde DS
		mov ds, ax ; ds contient l'adresse de segment du nom de l'OEM
		call affiche_chaine
	pop ds ; on restaure DS

	mov cx , 18
lignes_vides:
	mov si, retour_chariot
	call affiche_chaine
	loop lignes_vides

	mov si, VideoModePtr ; pointeur vers la liste des modes supportés
	lodsw ; on charge l'adresse d'offset dans ax
	mov cx, ax ; cx contient l'adresse d'offset
	lodsw ; on charge l'adresse de segment dans ax
	mov si, cx ; si pointe sur le premier mode supporté
	mov dx, ax ; dx contient l'adresse de segment
lit_mode_suivant:
	push ds
		mov ds, dx ; ds contient l'adresse de segment de la liste des modes
		lodsw ;charge dans ax le mode
	pop ds
	cmp ax, 0xFFFF ; Fin de la liste
	je arret_modes
	mov cx, ax
	mov ax, 0x4F01 ; demande infos sur le mode VESA
	mov di, ModeAttributes
	int 0x10
	cmp ax, 0x4F ; Si AL <> 0x4F, la fonction n'est pas supportée, on se contentera du VGA. Si AH <> O, erreur, pareil.
	jne lit_mode_suivant
	test word [ModeAttributes], 0xF
	jz lit_mode_suivant
;On ecrit les modes
	mov di, hello ; on écrit dans hello
	mov ax, cx
	push cx
		mov ch, 3
		mov bl, 16
		call nombre_vers_chaine
		mov al, ':'
		stosb
		mov ch, 4
		mov bl, 10
		mov ax, [XResolution]
		call nombre_vers_chaine
		mov ax, ('*' << 8) + ' '
		stosw
		mov al, ' '
		stosb
		mov ax, [YResolution]
		call nombre_vers_chaine
		mov ax, ' '
		stosb
		mov ch, 2
		mov al, [BitsPerPixel]
		call nombre_vers_chaine
		mov al, ' '
		stosb
		mov ax, ';' ; on met 2 caractères d'un coup après la chaîne : un '\n' et le zéro terminal.
		stosw ; les caractères sont dépilés, c'est à dire qu'il faut placer le premier dans la zone basse
	pop cx
    push si ;sauve si sur la pile
		mov si, hello
		call affiche_chaine
    pop si ; on récupère si
	push dx
		mov ax, [XResolution]
		shr ax, 5
		push ax
			mov ax, [YResolution]
			shr ax, 3
			push ax
				mov al, [BitsPerPixel]
				xor ah, ah
				shr ax, 3
			pop bx
			mul bx
		pop bx
		mul bx
	pop dx
	cmp ax, [maxResol]
	jb lit_mode_suivant
	mov [maxResol], ax
	mov [mode_souhaite], cx
    jmp lit_mode_suivant
arret_modes:
	mov cx, [mode_souhaite] ; On s'enquiert du mode souhaité
    mov ax, 0x4F01 ; demande infos sur le mode VESA
	mov di, ModeAttributes
    int 0x10
	mov di, hello ; on écrit dans hello
	mov ax, cx
	push cx
		mov ch, 3
		mov bl, 16
		call nombre_vers_chaine
		mov al, ':'
		stosb
		mov ch, 4
		mov bl, 10
		mov ax, [XResolution]
		call nombre_vers_chaine
		mov ax, ('*' << 8) + ' '
		stosw
		mov al, ' '
		stosb
		mov ax, [YResolution]
		call nombre_vers_chaine
		mov ax, ' '
		stosb
		mov ch, 2
		mov al, [BitsPerPixel]
		call nombre_vers_chaine
		mov ax, 13 ; on met 2 caractères d'un coup après la chaîne : un '\n' et le zéro terminal.
		stosw ; les caractères sont dépilés, c'est à dire qu'il faut placer le premier dans la zone basse
	pop cx
    mov si, hello
    call affiche_chaine

    mov ax, [WinASegment]
    or ax, ax ; on teste l'adresse du segment de la fenêtre. Si elle est nulle, on passe en mode 0x13
    jnz adresse_OK
adresse_mode_13h:
    mov word [mode_souhaite], 0x0013 ; infos du mode 0x13, le mode VGA
    mov word [WinASegment], 0xA000
    mov word [YResolution], 200
    mov word [XResolution], 320
;    mov word [largeur_memoire], 320
adresse_OK:
	mov di, hello ; met l'adresse de la chaîne à lire dans le registre SI
	call lit_chaine ; On attend l'utilisateur pour nettoyer l'écran

	mov ax, 0x4F02
	mov bx, [mode_souhaite]
	int 0x10 ; Changement de mode vidéo
	call nettoyage_ecran
	mov ax, 10 ; Coordonnée Y
	mov bx, 10 ; Coordonnée X
	;	mov dx, 0x04; Couleur
	call affiche_point	
	mov bx, 160 ; Coordonnée X
	mov ax, 100 ; Coordonnée Y
;	mov dx, 0x04; Couleur
	call affiche_point
	mov bx, 319 ; Coordonnée X
	mov ax, 199 ; Coordonnée Y
;	mov dx, 0x03; Couleur
	call affiche_point
	mov bx, 639 ; Coordonnée X
	mov ax, 399 ; Coordonnée Y
;	mov dx, 0x03; Couleur
	call affiche_point
	mov bx, 639 ; Coordonnée X
	mov ax, 479 ; Coordonnée Y
;	mov dx, 0x03; Couleur
	call affiche_point
	mov bx, 799 ; Coordonnée X
	mov ax, 599 ; Coordonnée Y
;	mov dx, 0x03; Couleur
	call affiche_point
	mov bx, 1279 ; Coordonnée X
	mov ax, 1023 ; Coordonnée Y
;	mov dx, 0x03; Couleur
	call affiche_point
	jmp fin
	push 100
	push 10
	push 100
	push 20
	mov dx, 0x03; Couleur
	call affiche_ligne
	add sp, 8
	push 102
	push 20
	push 102
	push 10
	mov dx, 0x05; Couleur
	call affiche_ligne
	add sp, 8
	push 114
	push 10
	push 104
    push 10
    mov dx, 0x06; Couleur
    call affiche_ligne
    add sp, 8
    push 104
    push 20
    push 114
    push 20
    mov dx, 0x07; Couleur
    call affiche_ligne
    add sp, 8
    push 126
    push 20
    push 124
    push 10
    mov dx, 0x08; Couleur
    call affiche_ligne
    add sp, 4
    push 116
    push 18
    mov dx, 0x09; Couleur
    call affiche_ligne
    add sp, 4
    push 124
    push 30
    mov dx, 0x0A; Couleur
    call affiche_ligne
    add sp, 4
    push 116
    push 22
    mov dx, 0x0B; Couleur
    call affiche_ligne
    add sp, 4
    push 132
    push 10
    mov dx, 0x0C; Couleur
    call affiche_ligne
    add sp, 4
    push 136
    push 16
    mov dx, 0x0D; Couleur
    call affiche_ligne
    add sp, 4
    push 136
    push 24
    mov dx, 0x0E; Couleur
    call affiche_ligne
    add sp, 4
    push 132
    push 30
    mov dx, 0x0F; Couleur
    call affiche_ligne
    add sp, 8
    push 10
    push 10
    push 310
    push 190
    mov dx, 0x02; Couleur
    call affiche_ligne
    add sp, 8
;    push 511
;    push 614
;    push 1000
;    push 614
;    mov dx, 0x03; Couleur
;    call affiche_ligne
;    add sp, 8
;    mov di, hello; met l'adresse de la chaîne à lire dans le registre SI
;    call lit_chaine ; On attend la volonté de l'utilisateur
;    mov ax, 0x4F02 ; Retour au mode texte
;    mov bx, 0x0003; 80 * 25, mode texte
;    int 0x10

initialise_disque: ; Initialise un disque
    mov ax, 0
    mov dl, 0           ; Lecteur = 0 (= A)
    int 0x13
    jc initialise_disque ; En cas d'erreur, on recommence

lire_disque:
    mov ax, 0x2000      ; ES:BX = 2000:0000
    mov es, ax
    xor bx, bx
    mov ah, 2           ; charge les données en ES:BX
    mov al, 6           ; charge jusqu'au secteur 6
    xor ch, ch          ; premier cylindre
    mov cl, 1           ; premier secteur
    xor dh, dh          ; première tête de lecture
    int 0x13            ; Lit
    jc lire_disque      ; En cas d'erreur, on recommence

initialise_HD: ; Initialise le disque dur
    mov ax, 0
    mov dl, 0x80 ; Lecteur = 0x80 (=C)
    int 0x13
    jc initialise_HD         ; En cas d'erreur, on recommence

ecrit_disque:
    mov ax, 0x2000      ; ES:BX = 2000:0000
    mov es, ax
    xor bx, bx
    mov ah, 3           ; Ecrit à partir de ES:BX
    mov al, 6           ; Ecrit jusqu'au secteur 6
    xor ch, ch          ; premier cylindre
    mov cl, 1           ; premier secteur
    xor dh, dh          ; première tête de lecture
    int 0x13            ; Ecrit
    jc ecrit_disque     ; En cas d'erreur, on recommence

fin:
    jmp $
;    ret

lit_chaine:
    push ax
    push cx
    push dx
    mov ah, 0x03
    int 0x10; appel de l'interruption BIOS qui donne la position du curseur, stockée dans dx
    mov cx, 1
attend_clavier:
    mov ah, 0x01;on teste le buffer clavier
    int 0x16
    jz attend_clavier
    ;al contient le code ASCII du caractère
    xor ah, ah; on lit le buffer clavier
    int 0x16
    stosb
    cmp al, 13
    je fin_attend_clavier
    ;al contient le code ASCII du caractère
    mov ah, 0x0A;on affiche le caractère courant cx fois
    int 0x10
    inc dl; on passe à la colonne suivante pour la position du curseur
    mov ah, 0x02;on positionne le curseur
    int 0x10
    jmp attend_clavier
fin_attend_clavier:
    inc dh; on passe à la ligne suivante pour la position du curseur
    xor dl, dl
    mov ah, 0x02;on positionne le curseur
    int 0x10
    mov byte [di], 0;on met le caractère terminal dans si
    pop dx
    pop cx
    pop ax
    ret
;fin de lit_chaine

;fonction affiche_point : on est déjà dans un mode graphique
;BX : Coordonnée X du point
;AX : Coordonnée Y du point
;dL : Couleur du point
affiche_point:
    push bx ; On sauve les registres qu'on va manipuler
		push cx
			push es
				push di
					push dx
						push ax
							mov cx, word [BytesPerScanLine]
							mul	cx
							mov di, ax
							push dx
								mov ax, bx
								xor ch, ch
								mov cl, [BitsPerPixel]
								shr cx, 3
								mul cx
								add di, ax
							pop dx
						.change_fenetre:
							mov ax, 0x4F05
							xor bh, bh
							xor bl, bl
							int 0x10 ; Changement de fenêtre
						bloc_OK:
							mov es, [WinASegment] ; On va dans la mémoire vidéo
							mov ax, 0xFFFF ; On fixe la couleur du pixel
							stosw ; Et on l'écrit dans la mémoire vidéo
							stosw
						pop ax ; On restaure les registres manipulés
					pop dx
				pop di
			pop es
		pop cx
	pop bx
	ret
;fin de affiche_point

;fonction affiche_ligne : on est déjà dans un mode graphique
; DL contient la couleur
affiche_ligne:
    jmp depart_affiche_ligne
Y2: dw 0
X2: dw 0
Y1: dw 0
X1: dw 0
deltaX: dw 0
deltaY: dw 0
incX: dw 0
incY: dw 0
e: dw 0
couleur: db 0
depart_affiche_ligne:
    push si
    push ax
    push bx
    push cx
    push dx
    push di
    push es
    mov ax, sp
    mov si, ax
    add si, 16 ; SI pointe sur Y2
    mov di, Y2
    mov ax, ds
    mov es, ax
    mov ax, ss
    mov ds, ax
    mov cx, 4
    rep movsw
    mov ax, es
    mov ds, ax
    mov [couleur], dl
    mov ax, [X2]
    mov bx, [X1]
    sub ax, bx
    mov [deltaX], ax
    mov cx, [Y2]
    mov bx, [Y1]
    sub cx, bx
    mov [deltaY], cx
    or ax, ax ; test deltaX
    jnz test_deltaX_positif
    or cx, cx ; test deltaY
    jnz test_deltaY_deltaX_nul
fin_affiche_ligne:
    mov dl, [couleur]
    mov ax, [X2]
    mov bx, [Y2]
    call affiche_point
    mov ax, [X1]
    mov bx, [Y1]
    call affiche_point
    pop es
    pop di
    pop dx
    pop cx
    pop bx
    pop ax
    pop si
    ret

deltaX_positif:
    or cx, cx
    jnz test_deltaY_deltaX_positif
    ;vecteur horizontal vers la droite
    mov cx, [deltaX]
    mov dx, 1
    mov word [incX], 1
    mov word [incY], 0
    jmp ligne_H_V

test_deltaY_deltaX_nul:
    mov word [incY], 1
    mov word [incX], 0
    cmp cx, 0
    jns ligne_H_V
    neg cx
    mov word [incY], -1
ligne_H_V:
    mov ax, [X1]
    mov bx, [Y1]
    mov dl, [couleur]
boucle_H_V:
    loop avance_H_V
    jmp fin_affiche_ligne

avance_H_V:
    add ax, [incX]
    add bx, [incY]
    call affiche_point
    jmp boucle_H_V

test_deltaX_positif:
    cmp ax, 0
    jns deltaX_positif
    or cx, cx
    jnz test_deltaY_deltaX_negatif
    ;vecteur horizontal vers la gauche
    mov cx, [deltaX]
    neg cx
    mov dx, -1
    mov word [incX], -1
    mov word [incY], 0
    jmp ligne_H_V

charge_registres:
    shl cx, 1
    shl ax, 1
    mov [deltaY], cx
    mov [deltaX], ax
    mov ax, [X1]
    mov bx, [Y1]
    ret

charge_e_deltaX_et_cmp_X2:
    mov [e], ax
    call charge_registres
    mov cx, [X2]
    ret

charge_e_deltaY_et_cmp_Y2:
    mov [e], cx
    call charge_registres
    mov cx, [Y2]
    ret

affiche_et_charge_eY:
    mov dl, [couleur]
    call affiche_point
    add bx, [incY]
    mov dx, [e]
    ret

affiche_et_charge_eX:
    mov dl, [couleur]
    call affiche_point
    add ax, [incX]
    mov dx, [e]
    ret

octants1_et_4:
    call charge_e_deltaX_et_cmp_X2
depart_boucle1:
    call affiche_et_charge_eX
    cmp ax, cx
    je fin_affiche_ligne
    sub dx, [deltaY]
    cmp dx, 0
    jns X_pret1
    add bx, [incY]
    add dx, [deltaX]
X_pret1:
    mov [e], dx
    jmp depart_boucle1

deltaY_positif_deltaX_negatif:
    neg ax
deltaY_positif_deltaX_positif:
    mov word [incY], 1
    ;deltaY > 0, deltaX > 0
    cmp ax, cx
    jae octants1_et_4
    neg ax
    call charge_e_deltaY_et_cmp_Y2
depart_boucle2_et_3:
    call affiche_et_charge_eY
    cmp bx, cx
    je fin_affiche_ligne
    add dx, [deltaX]
    cmp dx, 0
    jns X_pret2_et_3
    add ax, [incX]
    add dx, [deltaY]
X_pret2_et_3:
    mov [e], dx
    jmp depart_boucle2_et_3

octant5:
    call charge_e_deltaX_et_cmp_X2
depart_boucle5:
    call affiche_et_charge_eX
    cmp ax, cx
    je fin_affiche_ligne
    sub dx, [deltaY]
    cmp dx, 0
    js X_pret5
    add bx, [incY]
    add dx, [deltaX]
X_pret5:
    mov [e], dx
    jmp depart_boucle5

octant8:
    neg cx
    call charge_e_deltaX_et_cmp_X2
depart_boucle8:
    call affiche_et_charge_eX
    cmp ax, cx
    je fin_affiche_ligne
    add dx, [deltaY]
    cmp dx, 0
    jns X_pret8
    add bx, [incY]
    add dx, [deltaX]
X_pret8:
    mov [e], dx
    jmp depart_boucle8

test_deltaY_deltaX_positif:
    mov word [incX], 1
    cmp cx, 0
    jns deltaY_positif_deltaX_positif
    ;deltaY < 0, deltaX > 0
    mov word [incY], -1
    neg cx
    cmp ax, cx
    jae octant8
    neg cx
    jmp octants6_et_7

test_deltaY_deltaX_negatif:
    mov word [incX], -1
    cmp cx, 0
    jns deltaY_positif_deltaX_negatif
    ;deltaY < 0, deltaX < 0
    mov word [incY], -1
    cmp ax, cx
    jbe octant5
    neg ax
octants6_et_7:
    call charge_e_deltaY_et_cmp_Y2
depart_boucle6_et_7:
    call affiche_et_charge_eY
    cmp bx, cx
    je fin_affiche_ligne
    add dx, [deltaX]
    cmp dx, 0
    js X_pret6_et_7
    add ax, [incX]
    add dx, [deltaY]
X_pret6_et_7:
    mov [e], dx
    jmp depart_boucle6_et_7
;AFFICHE_LIGNE ENDP

nettoyage_ecran:
    push di
    push es
    push ax
    push bx
    push cx
    push dx
    mov es, [WinASegment]; On lit l'adresse de départ de la mémoire vidéo

    mov cx, [YResolution]
    mov ax, [XResolution]
    mul cx	; Nombre de points total
    mov ax, dx
	mov cl, [BitsPerPixel]
	shr cl, 3
	mul	cl
	mov cx, ax
    xor dx, dx
    xor bh, bh
	xor bl, bl
boucle_fenetres:
    push cx
		mov ax, 0x4F05
		int 0x10 ; Changement de fenêtre
		mov cx, 0x8000 ; Nombre de mots dans un morceau d'écran
		xor di, di
	.point:	
		mov ax, [couleur_defaut]
		stosw
		mov ax, [couleur_defaut+2]
		stosw
		loop .point
		inc dx
    pop cx
    loop boucle_fenetres
.depile:
    xor dx, dx
    mov [bloc_courant], dl
    mov ax, 0x4F05
    int 0x10 ; Changement de fenêtre
    pop dx
    pop cx
    pop bx
    pop ax
    pop es
    pop di
    ret
;Fin nettoyage_ecran

;Initialisation des segments
initialise_segments:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ax, 0x8000
    cli
    mov ss, ax
    mov sp, 0xF000
    sti
	ret
;Fin initialisation segments

mode_souhaite: dw 0x0013
maxResol: dw 0
couleur_defaut: db 0x0F, 0x0F, 0x0F, 0xFF; B, G, R, A
largeur_memoire: dw 320
bloc_courant: db 0
disquettes: db ' lecteur(s) de disquette installé(s).', 13, 0
pas: db 'Pas de ', 0
coprocesseur: db 'Coprocesseur arithmétique.', 13, 0
memoire_dispo: db ' ko.', 13, 0
au_demarrage: db ' au démarrage.', 13, 0
DMA: db 'DMA.', 13, 0
RS232: db ' port(s) RS232 disponible(s).', 13, 0
manette: db 'Manette de jeu.', 13, 0
modem_interne: db 'Modem interne.', 13, 0
imprimantes: db ' imprimante(s) connectée(s).', 13, 0
heure: db '00 h 00 min 00 s', 13, 0
retour_chariot: db 13, 0
nombre_de_cylindres: db ' cylindres.', 13, 0
nombre_de_tetes: db ' tetes.', 13, 0
nombre_de_secteurs: db ' secteurs par piste.', 13, 0
pas_33h: db 'Pas d`interruption 0x33.', 13, 0
;Informations du pilote VESA
VESASignature: times 4 db 0; /* 'VESA' 4 byte signature */
VESAVersion: dw 0; /* VBE version number */
OEMStringPtr: dd 0; /* Pointer to OEM string */
Capabilities: dd 0; /* Capabilities of video card */
VideoModePtr: dd 0; /* Pointer to supported modes */
TotalMemory: dw 0; /* Number of 64kb memory blocks */
reserved: times 236 db 0; /* Pad to 256 byte block size */
;Informations d'un mode vidéo
ModeAttributes: dw 0; /* Mode attributes */
WinAAttributes: db 0; /* Window A attributes */
WinBAttributes: db 0; /* Window B attributes */
WinGranularity: dw 0; /* Window granularity in k */
WinSize: dw 0; /* Window size in k */
WinASegment: dw 0; /* Window A segment */
WinBSegment: dw 0; /* Window B segment */
WinFuncPtr: dd 0; /* Pointer to window function */
BytesPerScanLine: dw 0; /* Bytes per scanline */
XResolution: dw 0; /* Horizontal resolution */
YResolution: dw 0; /* Vertical resolution */
XCharSize: db 0; /* Character cell width */
YCharSize: db 0; /* Character cell height */
NumberOfPlanes: db 0; /* Number of memory planes */
BitsPerPixel: db 0; /* Bits per pixel */
NumberOfBanks: db 0; /* Number of CGA style banks */
MemoryModel: db 0; /* Memory model type */
BankSize: db 0; /* Size of CGA style banks */
NumberOfImagePages: db 0; /* Number of images pages */
res1: db 0; /* Reserved */
RedMaskSize: db 0; /* Size of direct color red mask */
RedFieldPosition: db 0; /* Bit posn of lsb of red mask */
GreenMaskSize: db 0; /* Size of direct color green mask */
GreenFieldPosition: db 0; /* Bit posn of lsb of green mask */
BlueMaskSize: db 0; /* Size of direct color blue mask */
BlueFieldPosition: db 0; /* Bit posn of lsb of blue mask */
RsvdMaskSize: db 0; /* Size of direct color res mask */
RsvdFieldPosition: db 0; /* Bit posn of lsb of res mask */
DirectColorModeInfo: db 0; /* Direct color mode attributes */
res2: times 216 db 0; /* Pad to 256 byte block size */
hello: db 'Bonjour papi. Je cherche une ligne de plus de quatre vingts caractères. Ce doit être relativement facile à trouver, non ?', 13, 0
times 4096-($-$$) db 0
