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
	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 al, [BitsPerPixel]
	shr al, 3
	mov byte [octetsParPixel], al
    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 byte [octetsParPixel], 1
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, 30 ; Coordonnée Y
	mov bx, 121 ; Coordonnée X
	call affiche_point	
	mov ax, 10 ; Coordonnée Y
	mov bx, 10 ; Coordonnée X
	call affiche_point	
	mov bx, 160 ; Coordonnée X
	mov ax, 100 ; Coordonnée Y
	call affiche_point
	mov bx, 319 ; Coordonnée X
	mov ax, 199 ; Coordonnée Y
	call affiche_point
	mov bx, 639 ; Coordonnée X
	mov ax, 399 ; Coordonnée Y
	call affiche_point
	mov bx, 639 ; Coordonnée X
	mov ax, 479 ; Coordonnée Y
	call affiche_point
	mov bx, 799 ; Coordonnée X
	mov ax, 599 ; Coordonnée Y
	call affiche_point
	mov bx, 1279 ; Coordonnée X
	mov ax, 1023 ; Coordonnée Y
	call affiche_point
	push 16
	push 0
	push 26
    push 0
    call affiche_ligne
    add sp, 8
	push 12
	push 0
	push 12
	push 10
	call affiche_ligne
	add sp, 8
	push 14
	push 10
	push 14
	push 0
	call affiche_ligne
    add sp, 8
    push 16
    push 10
    push 26
    push 10
    call affiche_ligne
	add sp, 8
    push 120;test octant6
    push 30
    push 110
    push 10
    call affiche_ligne
    add sp, 4
    push 100;test octant5
    push 20
    call affiche_ligne
    add sp, 4
    push 110;test octant3
    push 50
    call affiche_ligne
    add sp, 4
    push 100; test octant 4
    push 40
    call affiche_ligne
    add sp, 4
    push 130;test octant 7 
    push 10
    call affiche_ligne
    add sp, 4
    push 140; test octant 8
    push 20
    call affiche_ligne
    add sp, 4
    push 140; test octant 1
    push 40
    call affiche_ligne
	add sp, 4
	push 130; test octant 2
	push 50
	call affiche_ligne
    add sp, 8
    push 10
    push 10
    push 310
    push 190
    call affiche_ligne
    add sp, 8
	mov cx, 27
	mov bx, 8*27
	mov ax, 50
afficheAlphabet:
	dec cx
	call affiche_caractere
	inc cx
	sub bx, 8
	loop afficheAlphabet
fin:
    jmp $

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
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, byte [octetsParPixel]
				mul cx
				add di, ax
			pop dx
		.change_fenetre:
			mov ax, 0x4F05
			xor bh, bh
			xor bl, bl
			int 0x10 ; Changement de fenêtre
			mov es, [WinASegment] ; On va dans la mémoire vidéo
			mov bx, couleurPoint
		.couleur:
			inc bx
			mov al, byte [bx]
			stosb
			loop .couleur
		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
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
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 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 bx, [X2]
	mov ax, [Y2]
	call affiche_point
;	mov bx, [X1]
;	mov ax, [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 word [incX], 1
	mov word [incY], 0
	jmp ligne_H_V

test_deltaY_deltaX_nul:
;cx contient deltaY
	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 bx, [X1]
	mov ax, [Y1]
avance_H_V:
	call affiche_point
	add bx, [incX]
	add ax, [incY]
	loop avance_H_V
	jmp fin_affiche_ligne
	
test_deltaX_positif:
	cmp ax, 0
	jns deltaX_positif
	or cx, cx ; CX contient DeltaY
	jnz test_deltaY_deltaX_negatif
	;vecteur horizontal vers la gauche
	mov cx, [deltaX]
	neg cx
	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 bx, [X1]
    mov ax, [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:
    call affiche_point
    add ax, [incY]
    mov dx, [e]
    ret

affiche_et_charge_eX:
    call affiche_point
    add bx, [incX]
    mov dx, [e]
    ret

octants1_et_4:
    call charge_e_deltaX_et_cmp_X2
depart_boucle1:
    call affiche_et_charge_eX
    cmp bx, cx
    je fin_affiche_ligne
    sub dx, [deltaY]
    cmp dx, 0
    jns X_pret1
    add ax, [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 ax, cx
    je fin_affiche_ligne
    add dx, [deltaX]
    cmp dx, 0
    jns X_pret2_et_3
    add bx, [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 bx, cx
    je fin_affiche_ligne
    sub dx, [deltaY]
    cmp dx, 0
    js X_pret5
    add ax, [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 bx, cx
    je fin_affiche_ligne
    add dx, [deltaY]
    cmp dx, 0
    jns X_pret8
    add ax, [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 ; cx contient deltaY
	jns deltaY_positif_deltaX_negatif
	;deltaY < 0, deltaX < 0
	mov word [incY], -1
	cmp ax, cx ; ax contient deltaX
	jbe octant5
	neg ax
octants6_et_7:
	call charge_e_deltaY_et_cmp_Y2
depart_boucle6_et_7:
	call affiche_et_charge_eY
	cmp ax, cx
    je fin_affiche_ligne
    add dx, [deltaX]
    cmp dx, 0
    js X_pret6_et_7
    add bx, [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, [octetsParPixel]
	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, [WinSize]
		shl cx, 9 ;Passage de ko en mots.
		xor di, di
	.point:
		push cx
		push bx
			mov cl, [octetsParPixel]
			xor ch, ch
			mov bx, couleur_defaut
		.couleur:
			inc bx
			mov al, byte [bx]
			stosb
			loop .couleur
		pop bx
		pop cx
		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

affiche_caractere:
	push bx
	push dx
	push si
	push cx
	push ax
	push ax
	mov ax, cx
	mov cx, 6
	mul cx
	mov si, Alphabet; adresse de la lettre
	add si, ax; si contient l'adresse de la lettre
.colonne:
	pop ax
	push cx
	mov dl, 0b10000000
	mov cx, 8; On affiche 8 colonnes
.ligne:
	push ax
	mov al, [si]; On charge l'octet à afficher
	test al, dl
	jz .suite
	pop ax
	call affiche_point
	push ax
.suite:
	shr dl, 1
	inc bx
	pop ax
	loop .ligne
	pop cx
	inc ax; passage à la ligne suivante
	sub bx, 8
	push ax
	inc si
	loop .colonne
	pop ax
	pop ax
	pop cx
	pop si
	pop dx
	pop bx
	ret
;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 0x00, 0x1F, 0x1F, 0x1F; ARGB
couleurPoint: db 0x00, 0xFF, 0x00, 0x00; ARGB
octetsParPixel: db 4
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', signature de 4 octets
VESAVersion: dw 0; numéro de version de VBE
OEMStringPtr: dd 0; Pointeur vers le nom de l'OEM
Capabilities: dd 0; Possibilités de la carte graphique
VideoModePtr: dd 0; Pointeur vers les modes accessibles
TotalMemory: dw 0; Nombre de blocs mémoire de 64ko
reserved: times 236 db 0; Complément à 256 octets, taille du bloc
;Informations d'un mode vidéo
ModeAttributes: dw 0; Attributs du mode
WinAAttributes: db 0; Attibuts de la fenêtre A
WinBAttributes: db 0; Attibuts de la fenêtre B
WinGranularity: dw 0; Granularité de la fenêtre en ko
WinSize: dw 0; Taille de la fenêtre en ko
WinASegment: dw 0; Segment de la fenêtre A
WinBSegment: dw 0; Segment de la fenêtre B
WinFuncPtr: dd 0; Pointeur vers la fonction "de fenêtrage"
BytesPerScanLine: dw 0; Octets par "scanline"
XResolution: dw 0; Résolution horizontale
YResolution: dw 0; Résolution vertical
XCharSize: db 0; Largeur d'un caractère
YCharSize: db 0; Hauteur d'un caractère
NumberOfPlanes: db 0; Nombre de plans mémoire
BitsPerPixel: db 0; Bits par pixel
NumberOfBanks: db 0; Nombre de banques de style CGA
MemoryModel: db 0; Type de modèle mémoire
BankSize: db 0; Taille des banques de style CGA
NumberOfImagePages: db 0; Nombre de pages image
res1: db 0; Reservé
RedMaskSize: db 0; Taille du masque rouge en couleur directe
RedFieldPosition: db 0; Position du bit faible du masque rouge
GreenMaskSize: db 0; Taille du masque vert en couleur directe
GreenFieldPosition: db 0; Position du bit faible du masque vert
BlueMaskSize: db 0; Taille du masque bleu en couleur directe
BlueFieldPosition: db 0; Position du bit faible du masque bleu
RsvdMaskSize: db 0; Taille du masque réservé en couleur directe
RsvdFieldPosition: db 0;  Position du bit faible du masque réservé
DirectColorModeInfo: db 0; Attributs du mode de couleur directe
res2: times 216 db 0; Complément à 256 octets, taille du bloc
%include "alphabet.asm"
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
