|
PRÉSENTATION :
Utilisation de la propriété ScanLine en assembleur
NOTES :
Petite démo pour montrer le principe d'utilisation de TBitMap.ScanLine.
Une fois n'est pas coutume, pour palier au fait que les aperçus ne sont que des images fixes... Voici la version
compilée du programme : source0069.exe.zip [200Ko]
Ce programme montre aussi un exemple simple de thread auxiliaire afin de rendre fluide une animation
sans avoir recours à DoubleBuffered qui ralenti énormément les animations.
L'utilisation de GetTickCount permet d'avoir une vitesse d'animation à peu près constante suivant les PC.
CODE :
Unit Unit2;
//
// Sujet : Démo de l'utilisation de ScanLine pour le dessin rapide
// d'un BitMap. Le dessin est réalisé en assembleur afin
// d'en agmenter aussi la vitesse.
// C'est aussi un petit exemple de thread de dessin.
//
// Par Nono40 : http://nono40.developpez.com http://nono40.fr.st
// mailTo:nono40@fr.st
//
// Le 11/11/2003
//
// Cette Unité contient le Thread de dessin
//
Interface
Uses
Windows,Classes,Graphics;
Type
// Définition d'un classe personnalisée simple de thread
TMonThread = Class(TThread)
Private
{ Déclarations privées }
BitMap:TBitMap;
Protected
Procedure Execute; override;
Procedure MAJForm;
End;
Const
// Nombre de points-1
MaxPoints=19999;
// Taille du dessin en pixels
Taille =600;
// Constante de centrage des points dans l'image. Les points
// sont calculés dans un repère centré au milieu de l'image
// Centrage est l'offset en octets du point milieu du bitmap
// par rapport au coin bas gauche.
Centrage =((Taille Div 2)*Taille+Taille Div 2)*4;
Implementation
Uses Unit1,Math,SysUtils;
Var
// Ces trois tableaux contiennent les couleurs et positions
// des points. En l'indexage d'un tableau d'élément de 4 octets
// étant plus facile en assembleur, c'est pour cela que la
// structure est choisie sur trois tableaux séparés et non
// sur un tableau d'enregistrements.
LesPointsC:Array[0..MaxPoints]Of TColor;
LesPointsX:Array[0..MaxPoints]Of Single;
LesPointsY:Array[0..MaxPoints]Of Single;
// Cette variable va contenir le point en cours. C'est à dire
// celui qui est le plus "loin".
LePoint :Integer;
// Tableau contenant la liste précalculée des couleurs des points.
LesCouleurs:Array[0..128*6-1]Of TColor;
// Variables de mémorisation du type d'animation en cours
TypeAnim :Integer;
PasAnim :Integer;
Procedure TMonThread.Execute;
Var
i,j :Integer; // Indexs de travail...
x :Integer; // Position X du point en cours de dessin
y :Integer; // Position Y du point en cours de dessin
Vide :Single; // Variable temporaire
Pas :Single; // Pas de zoom exponentiel
Tick :DWord; // Chronomatrage pour la vitesse de dessin
PtrBmp :Pointer; // Pointeur vers le début du bitmap
Delta :Integer; // Nombre d'octets entre deux lignes de ScanLine[]
Fin :Integer; // Variable contenant la fin du tableau
IndexCouleur :Integer; // Index dans le tableau des couleurs
// Incrémentation du pas d'animation et
// choix de l'animation suivante.
Procedure TestAnimSuivante(Maxi:Integer);
Begin
Inc(PasAnim);
If PasAnim>Maxi Then
Begin
PasAnim:=0;
Inc(TypeAnim);
If TypeAnim>8 Then TypeAnim:=1;
End;
End;
Begin
// Création du bitmap de travail avec les propriétés voulues
// Le format pf32bit permet d'accéder aux pixels comme un
// tableau d'entiers.
BitMap:=TBitMap.Create;
BitMap.Width := Taille;
BitMap.Height := Taille;
BitMap.PixelFormat := pf32Bit;
BitMap.Canvas.Brush.Color := clBlack;
BitMap.Canvas.Brush.Style := bsSolid;
// Préremplissage du tableau des couleurs
For i:=0 To 127 Do LesCouleurs[ i]:=$FE0000+(i*2)Shl 8;
For i:=0 To 127 Do LesCouleurs[128+i]:=$FEFE00-(i*2)Shl 16;
For i:=0 To 127 Do LesCouleurs[256+i]:=$00FE00+(i*2);
For i:=0 To 127 Do LesCouleurs[384+i]:=$00FEFE-(i*2)Shl 8;
For i:=0 To 127 Do LesCouleurs[512+i]:=$0000FE+(i*2)Shl 16;
For i:=0 To 127 Do LesCouleurs[640+i]:=$FE00FE-(i*2);
// Effacement des points
For i:=0 To MaxPoints Do
Begin
LesPointsC[i] := clBlack;
LesPointsX[i] := 0;
LesPointsY[i] := 0;
End;
LePoint :=0;
// Le premier point en mémoire d'un bitmap est le premier
// point de la dernière ligne.
PtrBmp :=BitMap.ScanLine[Taille-1];
// Calcul de la distance en octets entre deux lignes
// et du sens de cette différence, ceci s'ffranchit
// des alignement et du sens "Haut-Bas"/"Bas-haut" du bitmap
Delta :=Integer(BitMap.ScanLine[Taille-2])-Integer(PtrBmp);
// Pas de zoom pour la simulation d'avance des points
Pas := Power(9,1/(Maxpoints+1));
// Memo pour synchro sur le nombre de Tick
Tick := 0;
// Mémoire pour CMOV ( ne peut pas faire sur une valeur immédiate )
Fin := MaxPoints;
// Couleur en cours en bas du tableau
IndexCouleur := 0;
// Sélection de la première animation
TypeAnim := 7;
PasAnim := 0;
While Not Terminated Do
Begin
If (GetTickCount-Tick)>=20 Then // Une image tous les 20ms soit 50 Images/Seconde
Begin
// Mémorisation de l'heure de départ
Tick:=GetTickCount;
// Calcul de 100 nouveaux points
// La liste des points étant FIFO, les points les plus
// vieux sont donc remplacés
For j:=1 To 5 Do
Begin
// Ajout d'un groupe de points
For i:=1 To 20 Do
Begin
// Point suivant
Inc(LePoint);
If LePoint>MaxPoints Then LePoint:=0;
// Couleur du point
LesPointsC[LePoint] := LesCouleurs[IndexCouleur];
// Sélection du calcul en fonction du type d'animation en cours
Case TypeAnim Of
1 :Begin // Cercle de plus en plus rapide
Vide :=(PasAnim*0.00200)*Pi*PasAnim/(MaxPoints+1);
LesPointsX[LePoint] := Cos(Vide)*50;
LesPointsY[LePoint] := Sin(Vide)*50;
TestAnimSuivante(20000);
End;
2 :Begin // Cercle de moins en moins rapide
Vide := Sqr(20000-PasAnim)*0.00200*Pi/(MaxPoints+1);
LesPointsX[LePoint] := Cos(Vide)*50;
LesPointsY[LePoint] := Sin(Vide)*50;
TestAnimSuivante(20000);
End;
3 :Begin // Bande ondulée
LesPointsX[LePoint] := Cos(256*Pi*PasAnim/(MaxPoints+1))*50;
LesPointsY[LePoint] := Sin( 4*Pi*PasAnim/(MaxPoints+1))*50;
TestAnimSuivante(50000);
End;
4 :Begin // Ressort
Vide := PasAnim+2000*Sin(PasAnim);
LesPointsX[LePoint] := Cos( 6*Pi*Vide/(MaxPoints+1))*50;
LesPointsY[LePoint] := Sin( 6*Pi*Vide/(MaxPoints+1))*50;
TestAnimSuivante(60000);
End;
5 :Begin // Carré
Vide :=Sin(20*Pi*PasAnim/(MaxPoints+1))*50;
Case PasAnim And 3 Of
0: Begin
LesPointsX[LePoint] := 50;
LesPointsY[LePoint] := Vide;
End;
1: Begin
LesPointsX[LePoint] := -Vide;
LesPointsY[LePoint] := -50;
End;
2: Begin
LesPointsX[LePoint] := -50;
LesPointsY[LePoint] := -Vide;
End;
3: Begin
LesPointsX[LePoint] := Vide;
LesPointsY[LePoint] := 50;
End;
End;
TestAnimSuivante(50000);
End;
6 :Begin // Coeur
Case PasAnim Mod 200 Of
0..49 : Begin
Vide := (PasAnim Mod 200)+0;
LesPointsX[LePoint] :=-Cos( Pi*Vide/40 )*25+25;
LesPointsY[LePoint] := Sin( Pi*Vide/40 )*25+25;
End;
50..99 : Begin
Vide := (PasAnim Mod 200)-50;
LesPointsX[LePoint] := Cos( Pi*Vide/40 )*25-25;
LesPointsY[LePoint] := Sin( Pi*Vide/40 )*25+25;
End;
100..149: Begin
Vide := (PasAnim Mod 200)-90;
LesPointsX[LePoint] := Vide*50/57 -52;
LesPointsY[LePoint] :=-Vide*75/57 +20.5;
End;
150..199: Begin
Vide := (PasAnim Mod 200)-140;
LesPointsX[LePoint] :=-Vide*50/57 +52;
LesPointsY[LePoint] :=-Vide*75/57 +20.5;
End;
End;
TestAnimSuivante(40000);
End;
7 :Begin // Sinusoide sur cylindre et rotatif
Vide := Sin(Pi*PasAnim/500)+PasAnim/2000;
LesPointsX[LePoint] := Cos( 0.4*Pi*Vide )*50;
LesPointsY[LePoint] := Sin( 0.4*Pi*Vide )*50;
TestAnimSuivante(40000);
End;
8 :Begin // Spirale
Vide :=240*Pi*PasAnim/(MaxPoints+1);
LesPointsX[LePoint] := Cos(Vide)*10+40*Cos(Vide/40);
LesPointsY[LePoint] := Sin(Vide)*10+40*Sin(Vide/40);
TestAnimSuivante(40000);
End;
Else
TypeAnim:=1;
End;
End;
// Couleur suivante à la fin du groupe de points
Inc(IndexCouleur);
If IndexCouleur>High(LesCouleurs) Then IndexCouleur:=0;
End;
// Effacement du bitmap
Bitmap.Canvas.FillRect(BitMap.Canvas.ClipRect);
// Dessin des points dans le bitmap
Asm
PUSH EDI
PUSH EBX
PUSH ESI
MOV EDX,LePoint // On commence par le point du fond
MOV EDI,PtrBmp // Pointeur vers le BitMap
MOV EBX,Delta // Décalage d'une ligne à l'autre
FLD Pas // Lecture du pas multiplicatif
FLD1 // Le coeff commence à 1
@@Boucle:
FLD DWord Ptr LesPointsY[EDX*4]
FMUL ST(0),ST(1) // Calcul de Y*Coeff
FISTP Y
MOV EAX,Y // Chargement de Y
CMP EAX,-(Taille/2) // Tests de débordement
JL @@HorsBmp
CMP EAX, (Taille/2)-4
JG @@HorsBmp
FLD DWord Ptr LesPointsX[EDX*4]
FMUL ST(0),ST(1) // Calcul de X*Coeff
FISTP X
CMP X,-(Taille/2) // Tests de débordement
JL @@HorsBmp
CMP X, (Taille/2)-4
JG @@HorsBmp
ADD EAX,Taille/2 // Centrage Y
IMUL EAX,EBX // Offset de la ligne ( coordonnée "Y" )
LEA ESI,[EDI+EAX] // ESI va pointer sur le début de la ligne
MOV EAX,X // Lecture de la coordonnée "X"
// Lecture de la couleur du point
MOV ECX,DWord ptr LesPointsC[EDX*4]
// Ecriture du point sous forme
// de 12 pixels
MOV DWord Ptr [ESI+EAX*4+ 4+Taille*2],ECX // **
MOV DWord Ptr [ESI+EAX*4+ 8+Taille*2],ECX
ADD ESI,EBX // Ligne suivante
MOV DWord Ptr [ESI+EAX*4+ 0+Taille*2],ECX // ****
MOV DWord Ptr [ESI+EAX*4+ 4+Taille*2],ECX
MOV DWord Ptr [ESI+EAX*4+ 8+Taille*2],ECX
MOV DWord Ptr [ESI+EAX*4+12+Taille*2],ECX
ADD ESI,EBX // Ligne suivante
MOV DWord Ptr [ESI+EAX*4+ 0+Taille*2],ECX // ****
MOV DWord Ptr [ESI+EAX*4+ 4+Taille*2],ECX
MOV DWord Ptr [ESI+EAX*4+ 8+Taille*2],ECX
MOV DWord Ptr [ESI+EAX*4+12+Taille*2],ECX
ADD ESI,EBX // Ligne suivante
MOV DWord Ptr [ESI+EAX*4+ 4+Taille*2],ECX // **
MOV DWord Ptr [ESI+EAX*4+ 8+Taille*2],ECX
@@HorsBMP:
FMUL ST(0),ST(1) // Coeff:=Coeff*Pas
DEC EDX // Point suivant
CMOVS EDX,Fin // Retour en fin de tableau
CMP EDX,LePoint // Test de fin de boucle
JNE @@Boucle
FSTP Vide // Dépilage de Coeff en fin de boucle
FSTP Vide // Dépilage de Pas en fin de boucle
POP ESI
POP EBX
POP EDI
End;
// Mise à jour de la fiche
Synchronize(MAJForm);
End;
End;
BitMap.Free;
End;
Procedure TMonThread.MAJForm;
Begin
// La mise à jour est un simple Draw sur l'image.
Form1.Image1.Canvas.Draw(0,0,BitMap);
End;
end.
|
| |