/* * Implémentation en C de l'algorithme de tracé de ligne de Bresenham * pour EGA et VGA. Fonctionne en modes 0xE, 0xF, 0x10, et 0x12. * * Compilé avec Borland C++ 4.02 * Testé par Jim Mischel 11/21/94 * * Par Michael Abrash. */ #include /* contient la macro MK_FP */ #define EVGA_SCREEN_WIDTH_IN_BYTES 80 /* offset mémoire du début d'une rangée au début de la prochaine */ #define EVGA_SCREEN_SEGMENT 0xA000 /* segment de la mémoire vidéo */ #define GC_INDEX 0x3CE /* port du registre Index GC */ #define GC_DATA 0x3CF /* port du registre Data GC */ #define SET_RESET_INDEX 0 /* indexes des registres */ #define ENABLE_SET_RESET_INDEX 1 /* requis de */ #define BIT_MASK_INDEX 8 /* Graphics Controller */ /* * Affiche un point en (X0,Y0) dans la couleur pour laquelle * la carte EGA est configurée. Laisse le masque de bit positionné à la valeur * requise par le point. */ void EVGADot(X0, Y0) unsigned int X0; /* coordonnées d'affichage du point, avec */ unsigned int Y0; /* (0,0) comme coin supérieur gauche de l'écran */ { unsigned char far *PixelBytePtr; unsigned char PixelMask; /* Calcule l'offset dans le segment de l'écran de l'octet dans lequel le pixel réside */ PixelBytePtr = MK_FP(EVGA_SCREEN_SEGMENT, ( Y0 * EVGA_SCREEN_WIDTH_IN_BYTES ) + ( X0 / 8 )); /* Génère un masque avec un bit 1 à la position du pixel dans l'octet de l'écran */ PixelMask = 0x80 >> ( X0 & 0x07 ); /* Configure le registre Bit Mask du Graphics Controller pour permettre d'afficher seulement le bit correspondant au pixel devant être modifié */ outportb(GC_INDEX, BIT_MASK_INDEX); outportb(GC_DATA, PixelMask); /* Affiche le pixel. En raison de la fonctionnalité set/reset de EGA/VGA, la valeur écrite n'a pas d'importance. L'octet de l'écran subit un OR afin d'effectuer une lecture pour verrouiller la mémoire vidéo, puis d'effectuer une écriture pour la modifier. */ *PixelBytePtr |= 0xFE; } /* * Affiche une ligne dans l'octant 0 ou 3 ( |DeltaX| >= DeltaY ). */ void Octant0(X0, Y0, DeltaX, DeltaY, XDirection) unsigned int X0, Y0; /* coordonnées du début de la ligne */ unsigned int DeltaX, DeltaY; /* longueur de la ligne (les deux > 0) */ int XDirection; /* 1 si la ligne est affichée de gauche à droite, -1 si elle est affichée de droite à gauche */ { int DeltaYx2; int DeltaYx2MinusDeltaXx2; int ErrorTerm; /* Configure le terme d'erreur initial et les valeurs à l'intérieur de la boucle d'affichage */ DeltaYx2 = DeltaY * 2; DeltaYx2MinusDeltaXx2 = DeltaYx2 - (int) ( DeltaX * 2 ); ErrorTerm = DeltaYx2 - (int) DeltaX; /* Affiche la ligne */ EVGADot(X0, Y0); /* affiche le premier pixel */ while ( DeltaX-- ) { /* Vérifie s'il est temps d'avancer la coordonnée Y */ if ( ErrorTerm >= 0 ) { /* Avance la coordonnée Y & ajuste le terme d'erreur */ Y0++; ErrorTerm += DeltaYx2MinusDeltaXx2; } else { /* Ajoute au terme d'erreur */ ErrorTerm += DeltaYx2; } X0 += XDirection; /* avance la coordonnée X */ EVGADot(X0, Y0); /* Affiche un pixel */ } } /* * Affiche une ligne dans l'octant 1 ou 2 ( |DeltaX| < DeltaY ). */ void Octant1(X0, Y0, DeltaX, DeltaY, XDirection) unsigned int X0, Y0; /* coordonnées du début de la ligne */ unsigned int DeltaX, DeltaY; /* longueur de la ligne (les deux > 0) */ int XDirection; /* 1 si la ligne est affichée de gauche à droite, -1 si elle est affichée de droite à gauche */ { int DeltaXx2; int DeltaXx2MinusDeltaYx2; int ErrorTerm; /* Configure le terme d'erreur initial et les valeurs utilisées à l'intérieur de la boucle d'affichage */ DeltaXx2 = DeltaX * 2; DeltaXx2MinusDeltaYx2 = DeltaXx2 - (int) ( DeltaY * 2 ); ErrorTerm = DeltaXx2 - (int) DeltaY; EVGADot(X0, Y0); /* affiche le premier pixel */ while ( DeltaY-- ) { /* Vérifie s'il est temps d'avancer la coordonnée X */ if ( ErrorTerm >= 0 ) { /* Avance la coordonnée X & ajuste le terme d'erreur */ X0 += XDirection; ErrorTerm += DeltaXx2MinusDeltaYx2; } else { /* Ajoute au terme d'erreur */ ErrorTerm += DeltaXx2; } Y0++; /* avance la coordonnée Y */ EVGADot(X0, Y0); /* affiche un pixel */ } } /* * Affiche une ligne sur EGA ou VGA. */ void EVGALine(X0, Y0, X1, Y1, Color) int X0, Y0; /* coordonnées de l'extrémité d'une ligne */ int X1, Y1; /* coordonnées de l'autre extrémité d'une ligne */ char Color; /* couleur dans laquelle afficher la ligne */ { int DeltaX, DeltaY; int Temp; /* Paramètre la couleur de l'affichage */ /* Met la couleur de l'affichage dans le registre Set/Reset */ outportb(GC_INDEX, SET_RESET_INDEX); outportb(GC_DATA, Color); /* Force tous les plans dans la couleur Set/Reset */ outportb(GC_INDEX, ENABLE_SET_RESET_INDEX); outportb(GC_DATA, 0xF); /* Economise la moitié des cas d'affichage de ligne en permutant Y0 avec Y1 et X0 avec X1 si Y0 est supérieur à Y1. Au final, DeltaY est toujours > 0, seuls les cas des octants 0-3 nécessitent un traitement. */ if ( Y0 > Y1 ) { Temp = Y0; Y0 = Y1; Y1 = Temp; Temp = X0; X0 = X1; X1 = Temp; } /* Traite comme des cas distincts, les quatre octants dans lesquels Y1 est supérieur à Y0 */ DeltaX = X1 - X0; /* calcule la longueur de la ligne dans chaque coordonnée */ DeltaY = Y1 - Y0; if ( DeltaX > 0 ) { if ( DeltaX > DeltaY ) { Octant0(X0, Y0, DeltaX, DeltaY, 1); } else { Octant1(X0, Y0, DeltaX, DeltaY, 1); } } else { DeltaX = -DeltaX; /* valeur absolue de DeltaX */ if ( DeltaX > DeltaY ) { Octant0(X0, Y0, DeltaX, DeltaY, -1); } else { Octant1(X0, Y0, DeltaX, DeltaY, -1); } } /* Retourne l'état de EGA/VGA à normal */ outportb(GC_INDEX, ENABLE_SET_RESET_INDEX); outportb(GC_DATA, 0); outportb(GC_INDEX, BIT_MASK_INDEX); outportb(GC_DATA, 0xFF); }