Affichage de l'ensemble de Mendelbrot
Page 1 sur 1
Affichage de l'ensemble de Mendelbrot
Ce programme est aussi un programme de gestion d’image. Ici nous allons afficher l’ensemble fractal de Mendelbrot. Les flèches et les symboles + et – permettront de naviguer et de jouer sur la taille de l’image affichée.
Ce programme est succinct et peut être grandement amélioré.
Il reprend la trame d’affichage d’une fenêtre comme nous l’avons déjà vu dans les programmes précédents.
Nous commençons par créer une image vide qui servira de support au dessin des points de l’ensemble. Dans la procedure CreationImageMem nous appelons les fonctions CreateCompatibleDC pour créer un contexte en mémoire puis la fonction CreateDIBSection qui va créer l’image.
Nous conservons l’adresse retournée dans le pointeur hBitmap.
Après la création de la fenêtre comme déjà vu, nous ajoutons dans la procédure de gestion des évenements, les instructions concernant le fonctionnement de chaque touche. Les calculs se font en virgule flottante en utilisant les registres de type xmm0 et xmm1.
Dans la partie paint, nous nous contentons de recopier l’image créée en mémoire dans le contexte écran pour assurer son affichage.
Il ne reste plus qu’à effectuer le calcul pour chaque point de l’image afin de déterminer leur couleur. Dans ce calcul, nous nous contentons de déterminer que 2 couleurs : rouge et noir. Le programme peut donc être amélioré pour afficher une gamme de couleurs plus large. Bon courage !!
Ce programme est succinct et peut être grandement amélioré.
Il reprend la trame d’affichage d’une fenêtre comme nous l’avons déjà vu dans les programmes précédents.
Nous commençons par créer une image vide qui servira de support au dessin des points de l’ensemble. Dans la procedure CreationImageMem nous appelons les fonctions CreateCompatibleDC pour créer un contexte en mémoire puis la fonction CreateDIBSection qui va créer l’image.
Nous conservons l’adresse retournée dans le pointeur hBitmap.
Après la création de la fenêtre comme déjà vu, nous ajoutons dans la procédure de gestion des évenements, les instructions concernant le fonctionnement de chaque touche. Les calculs se font en virgule flottante en utilisant les registres de type xmm0 et xmm1.
Dans la partie paint, nous nous contentons de recopier l’image créée en mémoire dans le contexte écran pour assurer son affichage.
Il ne reste plus qu’à effectuer le calcul pour chaque point de l’image afin de déterminer leur couleur. Dans ce calcul, nous nous contentons de déterminer que 2 couleurs : rouge et noir. Le programme peut donc être amélioré pour afficher une gamme de couleurs plus large. Bon courage !!
- Code:
;programme calcul et affichage ensemble de mendelbrot en 64 bits
;
;
;============================================================================
; CONSTANTES
;============================================================================
%include "../windowsinc64.inc"
ILGIMAGE equ 1000
IHTIMAGE equ 600
ITMAXI equ 50
;==============================================
; MACROS
;=============================================
;Macro conversion couleur en 0x00bbggrr
;parametre 1 couleur bleu
;parametre 2 couleur verte
;parametre 3 couleur rouge
%macro RGB 3
mov eax,%3*256*256
add eax,%2*256
add eax,%1
%endmacro
global Main
;extern MessageBoxA ; tous les noms des fonctions de l'API sont mis dans le fichier include ci dessus
extern afferreur,affmessageP,affconsoleP,afftoutregistreP,afftoutreg8a15P,affmemoireP
;=============================================================================
section .data
;=============================================================================
szTitreFen: db 'Ensemble de Mandelbrot', 0
szClasseFen db "Classe1",0
;instance de la classe des fenetres
wcexa: align 8
wcex:
istruc WNDCLASSEX
iend
LGWCEX equ $ - wcex
;instance message
msga: align 8
msg: istruc MSG
at MSG.fin, db "<<< "
iend
; instance contexte dessin
ipainta: align 8
ipaint istruc PAINTSTRUCT
iend
;BitmapInfo Structure
BitmapInfo istruc BITMAPINFO
iend
ILGBITMAPINFO equ $ - BitmapInfo
;valeurs de départ des calculs
x1 dq -2.1
x2 dq 2.1
y1 dq -1.2
y2 dq 1.2
nbpixelsx dq 1000.0 ; taille de l'image
nbpixelsy dq 600.0
zoom dq 200.0
zero dq 0.0
un dq 1.0
deux dq 2.0
quatre dq 4.0
dix dq 10.0
neuf dq 0.9
unun dq 1.1
pointun dq 0.1
;=============================================================================
section .bss
;=============================================================================
hCons resq 1
hInst resq 1
hMainWnd resq 1
hdc resq 1
hdcMem resq 1
hBitmap resq 1
BitmapBits resq 1
dx1 resq 1
;szZoneResult resb 80;
;szResult1 resb 100
;=============================================================================
section .text
;=============================================================================
Main:
sub rsp, 28h ; alignement pile et reserve paramètres
;recup du handle du programme
xor rcx,rcx
call GetModuleHandleA
mov r9,__LINE__
cmp eax,NULL
je .erreur
mov [hInst],rax
;il faut creer une image en mémoire vide
call creationImageMem
; préparation de la structure de classe des fenêtres
mov dword[wcex+WNDCLASSEX.cbSize], LGWCEX ;taille de la structure de la classe de la fenetre
mov dword[wcex+WNDCLASSEX.style],CS_HREDRAW | CS_VREDRAW ; style des fenetres
mov qword[wcex+WNDCLASSEX.lpfnWndProc], WndProc ; nom de la procedure qui va gerer les évenements de la fenetre
xor rax,rax
mov dword[wcex+WNDCLASSEX.cbClsExtra], eax ;raz de ces zones
mov dword[wcex+WNDCLASSEX.cbWndExtra], eax
mov qword rax, [hInst]
mov qword[wcex+WNDCLASSEX.hInstance], rax ;handle du parent
mov qword[wcex+WNDCLASSEX.hIcon], NULL
;chargement image curseur souris
mov rcx,NULL
mov rdx,IDC_ARROW
call LoadCursorA
mov r9,__LINE__ - 1
cmp eax,NULL
je .erreur
mov qword[wcex+WNDCLASSEX.hCursor], rax
mov qword[wcex+WNDCLASSEX.hbrBackground],COLOR_BACKGROUND
mov qword [wcex+WNDCLASSEX.lpszMenuName], NULL
mov qword [wcex+WNDCLASSEX.lpszClassName], szClasseFen
;creation de la classe de la fenetre (c'est obligatoire)
mov rcx,wcex
call RegisterClassExA
mov r9,__LINE__ - 1
cmp eax,NULL
je .erreur
;creation de la fenetre
add rsp,20h
;8 parametres donc pas d'alignement à respecter
push NULL ; pas de données complémentaires
push qword[hInst] ;handle de l'instance du programme
push NULL ;fenetre non identifiée
push NULL ; pas de fenetre parent
push 258h ; hauteur de la fenetre
push 320h ; largeur de la fenetre
push 0Ah ; position verticale de la fenetre
push 0Fh ;position horizontale de la fenetre
;
sub rsp,20h ; reservation de la place pour les 4 parametres suivants
mov rcx,NULL ; pas de style complémentaire
mov rdx,szClasseFen ; classe de la fenetre doit être identique à la classe crée par RegisterClassExA
mov r8,szTitreFen ; titre de la fenetre
mov r9,WS_OVERLAPPEDWINDOW ; fenetre standard avec menu système
;
call CreateWindowExA
add rsp,40h
mov r9,__LINE__ - 2
cmp eax,NULL
je .erreur
mov [hMainWnd],eax ; conserve le handle de la fenetre
mov rcx,[hMainWnd]
mov rdx,SW_SHOWDEFAULT ; affichage de la fenetre
call ShowWindow
; ici on ne teste pas le code erreur (voir la doc microsoft)
mov rcx,[hMainWnd]
call UpdateWindow ;genere le message WM_PAINT qui dessinera dans la fenêtre
mov r9,__LINE__ - 1
cmp eax,NULL
je .erreur
;
.boucle_commande:
mov rcx,msg
mov rdx,NULL
mov r8,0
mov r9,0
call GetMessageA ;récuperation des messages
cmp eax,0 ; fin de boucle l'utilisateur a fermé la fenetre
jz .fin_commande
mov rcx,msg
call TranslateMessage ; convertit les actions clavier en message (voir la doc)
mov rcx,msg
call DispatchMessageA ; envoie le message à la procédure de gestion de la fenetre
jmp .boucle_commande
.fin_commande:
mov rcx,0 ; code retour OK
jmp .fin
.erreur:
call afferreur
mov rcx,1 ; code retour erreur
.fin:
; code retour positionné avant
call ExitProcess
;===========================================================
;Procédure de gestion des évenements de la fenetre
;===========================================================
WndProc:
%define .hWnd [rbp+16] ; pour simplifier l'ecriture dans les instructions suivantes
%define .uMsg [rbp+24]
%define .wParam [rbp+32]
%define .lParam [rbp+40]
;recuperation des parametres handle de la fenetre, type du message, wparam, lparam
;copie des paramètres dans l'espace réservé
mov [rsp+8],rcx ; handle fenêtre
mov [rsp+16],rdx ; type de message
mov [rsp+24],r8 ; wparam
mov [rsp+32],r9 ; lparam
enter 0,0 ; eventuellement reserver de la place pour variables locales
;ici il faut sauver les registres rbx,rdi,rsi r12 à r15 s'ils sont utilisés
;attention si nombre impair il faut aligner la pile
sub rsp,20h ; reservation pour les autres appels
;traitement des messages
cmp rdx,WM_CREATE
jz .creation
cmp rdx,WM_PAINT ; dessin du contenu de la fenetre
jz .paint
cmp rdx,WM_DESTROY
jz .destroy
cmp rdx,WM_COMMAND ; traitement des evenements
jz .commande
cmp rdx,WM_CHAR ; traitement des touches clavier
jz .clavier
cmp rdx,WM_KEYDOWN ; traitement des touches clavier
jz .touches
jmp .retourdefaut
.creation:
;ici il faut creer une premiere image
call dessinimage
jmp .retourproc
.clavier: ; pour gerer éventuellement d'autres touches clavier
mov rax,r8 ;wParam parametre supplementaire de la commande
jmp .retourproc
.touches:
mov rax,r8 ;wParam parametre supplementaire de la commande
cmp rax,6bh ; touche + pour grossissement de la figure
jne .suitet
movsd xmm0,[x2] ;calcul de la distance sur l'axe des x
subsd xmm0,[x1]
mulsd xmm0,[neuf] ; on multiplie par 0,9
addsd xmm0,[x1] ; et on l'ajoute à l'origine pour
movsd [x2],xmm0 ; calculer la fin
movsd xmm0,[y2] ; on fait la même chose sur l'axe des y
subsd xmm0,[y1]
mulsd xmm0,[neuf]
addsd xmm0,[y1]
movsd [y2],xmm0
jmp .touchesfin
.suitet:
cmp rax,6dh ; touche - pour revenir en arrière
jne .suitet1
movsd xmm0,[x2] ; calcul de la distance sur l'axe des x
subsd xmm0,[x1]
mulsd xmm0,[unun] ; on multiplie par 1,1
addsd xmm0,[x1] ; ajout à l'origine
movsd [x2],xmm0 ; pour calculer la fin
movsd xmm0,[y2] ; et on fait la même chose sur l'axe des y
subsd xmm0,[y1]
mulsd xmm0,[unun]
addsd xmm0,[y1]
movsd [y2],xmm0
jmp .touchesfin
.suitet1:
cmp rax,25h ; touche flèche gauche pour deplacer la figure
jne .suitet2
movsd xmm0,[x2] ; calcul de la largeur de la figure
subsd xmm0,[x1]
divsd xmm0,[dix] ; calcul d'un dizième
movsd xmm1,[x1] ; soustraction de l'origine pour se deplacer à gauche
subsd xmm1,xmm0
movsd [x1],xmm1
movsd xmm1,[x2] ; puis soustraction de la fin de la figure
subsd xmm1,xmm0
movsd [x2],xmm1
jmp .touchesfin
.suitet2:
cmp rax,27h ; touche flèche droite pour deplacer la figure
jne .suitet3
movsd xmm0,[x2] ; calcul de la largeur de la figure
subsd xmm0,[x1]
divsd xmm0,[dix] ; calcul d'un dizième
movsd xmm1,[x1] ; ajout à l'origine pour deplacer la figure vers la droite
addsd xmm1,xmm0 ; d'un dixième
movsd [x1],xmm1 ; puis ajout à l'extrèmité
movsd xmm1,[x2]
addsd xmm1,xmm0
movsd [x2],xmm1
jmp .touchesfin
.suitet3:
cmp rax,26h ; touche flèche haut pour deplacer la figure
jne .suitet4
movsd xmm0,[y2]
subsd xmm0,[y1]
divsd xmm0,[dix]
movsd xmm1,[y1]
addsd xmm1,xmm0
movsd [y1],xmm1
movsd xmm1,[y2]
addsd xmm1,xmm0
movsd [y2],xmm1
jmp .touchesfin
.suitet4:
cmp rax,28h ; touche flèche bas pour deplacer la figure
jne .suitet5
movsd xmm0,[y2]
subsd xmm0,[y1]
divsd xmm0,[dix]
movsd xmm1,[y1]
subsd xmm1,xmm0
movsd [y1],xmm1
movsd xmm1,[y2]
subsd xmm1,xmm0
movsd [y2],xmm1
jmp .touchesfin
.suitet5:
jmp .retourproc
.touchesfin: ; dessin de la fenêtre pour afficher la nouvelle image
call dessinimage ; calcul de la nouvelle image
mov rcx,.hWnd
mov rdx,NULL
mov r8,FALSE
call InvalidateRect
jmp .retourproc
.paint:
; rcx doit contenir le handle de la fenetre depuis le début de la procédure
mov rdx, ipaint ; structure
call BeginPaint ; debut du dessin
mov [hdc], rax
;ici il faut copier l'image à afficher.
; recopie de l'image du contexte mémoire dans le contexte écran
add rsp,20h
sub rsp,8h
push SRCCOPY
push 0 ; position gauche origine
push 0 ; position haute origine
push qword[hdcMem] ; origine
push IHTIMAGE ; hauteur destination
sub rsp,20h
mov rcx,[hdc] ; destination
mov rdx, 0 ; position haut destination
mov r8,0 ; position gauche destination
mov r9,ILGIMAGE ; largeur destination
call BitBlt ;transfert de l'image à l'emplacement desiré
add rsp,30h ;5 parametres et un alignement
mov r9,__LINE__ - 1
cmp rax,NULL
je .erreur
mov rcx,[rbp+16] ;handle de la fenetre
mov rdx, ipaint ; structure
call EndPaint ; fin du dessin
jmp .retourproc
.commande:
mov rax,r8 ;wParam parametre supplementaire de la commande
and rax,0FFFFh
; cmp rax,IDM_EXIT ; menu quitter
; je .close
jmp .retourproc
.close:
; ici rcx doit encore contenir le handle de la fenetre
call DestroyWindow ; destruction de la fenetre
jmp .retourproc
.destroy:
xor rcx,rcx
call PostQuitMessage
jmp .retourproc
.erreur:
call afferreur
.retourdefaut: ; appel par defaut pour tous les autres messages
call DefWindowProcA
.retourproc:
add rsp,20h
;ici il faut restaurer les registres sauvegardés
;attention si nombre impair il faut aligner la pile
leave ; restaure
ret
;============================================================
;creation image en memoire
;============================================================
creationImageMem:
sub rsp,28h
xor rax,rax
mov rcx,NULL
call CreateCompatibleDC ;création d'un contexte en memoire
mov r9,__LINE__
cmp eax,NULL
je .erreur
mov [hdcMem], rax;
mov rcx,BitmapInfo
call initStrucInfo
xor rax,rax
add rsp,20h
push NULL
push NULL
sub rsp,20h
mov rcx,[hdcMem]
mov rdx,BitmapInfo
mov r8,DIB_RGB_COLORS
mov r9,BitmapBits
call CreateDIBSection ; creation d'une image en memoire qui va servir de support
add rsp,10h
mov r9,__LINE__
cmp eax,NULL
je .erreur
mov [hBitmap],rax
jmp .fin
.erreur:
call afferreur
mov rax,FALSE
.fin:
add rsp,28h
ret
;===============================================================================
;init de la structure BITMAPINF
;================================================================================
;rcx contient l'adresse de la structure
initStrucInfo:
mov dword[rcx+BITMAPINFO.biSize], ILGBITMAPINFO ;longueur de la structure
mov dword[rcx+BITMAPINFO.biWidth],ILGIMAGE ;largeur image en dword
mov dword[rcx+BITMAPINFO.biHeight],IHTIMAGE ; hauteur image en dword
mov word[rcx+BITMAPINFO.biPlanes ],1
mov word[rcx+BITMAPINFO.biBitCount ],32 ; codage sur 32 bits
ret
;===================================================
; dessin image
;===================================================
dessinimage:
sub rsp,28h
xor rax,rax
mov rcx,[hdcMem] ; selection de l'emplacement de l'image
mov rdx,[hBitmap] ; dans le contexte mémoire
call SelectObject
mov r9,__LINE__
cmp eax,NULL
je .erreur
call calcul1
jmp .fin
.erreur:
call afferreur
mov rax,FALSE
.fin:
add rsp,28h
ret
;===================================================
; calcul pour chaque pixel de l'image
;==================================================
calcul1:
sub rsp,28h
movsd xmm10,[x2]
subsd xmm10,[x1]
divsd xmm10,[nbpixelsx] ; calcul pas x
movsd [dx1],xmm10
movsd xmm12, [y2]
subsd xmm12,[y1]
divsd xmm12,[nbpixelsy] ; calcul pas y
mov rbx,0 ; position X du pixel
.boucle:
cvtsi2sd xmm13, rbx ; convertit entier en double
mulsd xmm13,xmm10
addsd xmm13,[x1]
mov r13,0 ; position Y du pixel
.boucle1:
cvtsi2sd xmm14, r13 ; convertit entier en double
mulsd xmm14,xmm12
addsd xmm14,[y1]
;suite calcul
movsd xmm5, [zero]
movsd xmm6, [zero]
mov r9,0
.boucleFaire: ; coeur du calcul
movsd xmm7,xmm5
mulsd xmm5,xmm5
movsd xmm0,xmm6
mulsd xmm0,xmm0
subsd xmm5,xmm0
addsd xmm5,xmm13
mulsd xmm6,[deux]
mulsd xmm6,xmm7
addsd xmm6,xmm14
inc r9
cmp r9,ITMAXI
jge .suite
movsd xmm0,xmm5
mulsd xmm0,xmm5
movsd xmm7,xmm6
mulsd xmm7,xmm6
addsd xmm0,xmm7
ucomisd xmm0,[quatre]
jb .boucleFaire
xor rdx,rdx
mov rax,r9
mov r9,255
mul r9
mov r9,ITMAXI
div r9
call dessinpixel
jmp .suite2
.suite:
;suite des boucles
RGB 0,0,0 ;noir
call dessinpixel ; mise à jour du pixel
.suite2:
inc r13
cmp r13,IHTIMAGE-1
jle .boucle1
inc rbx
cmp rbx,ILGIMAGE-1
jle .boucle
jmp .fin
.erreur:
call afferreur
mov rax,FALSE
.fin:
add rsp,28h
ret
;===========================================================
;dessin pixel
;===========================================================
;rax contient la couleur
;rbx la position en X
;r13 la position en Y
dessinpixel:
sub rsp,28h
mov rcx,[hdcMem] ; dans le contexte memoire
mov rdx,rbx
mov r8,r13
mov r9,rax ; code couleur
call SetPixel
mov r9,__LINE__
cmp eax,-1
je .erreur
jmp .fin
.erreur:
call afferreur
mov rax,FALSE
.fin:
add rsp,28h
ret
Sujets similaires
» Premier programme : affichage d'un message
» Affichage simple dans la console
» Affichage d'un registre dans la console.
» Affichage simple dans la console
» Affichage d'un registre dans la console.
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
|
|