fxscroll
Défileur de texte
Au tout début des temps, vers 1984, ce qui allait devenir la Scène internationale des démos prenait naissance. Cette dernière est née du monde du cracking, l'art de percer les protections des jeux et des logiciels, surtout sur le Commodore 64. À l'origine, quand un cracker accomplissait son art sur un jeu, il créait un "loader", c'est à dire un petit programme qui affichait des messages défilant annonçant les prochains cracks du groupe ou de l'individu. Progressivement, ces loaders sont devenu de plus en plus complexe, incluant plasma, Copper list, et surtout des défileur de textes (text scroller, ou scrolly). Finalement, quelques individus ont décidés de coder ces loaders simplement pour le plaisir, pour pousser la machine aux limites (donnant naissance aux guerres Amiga/C64). Bref, aujourd'hui nous allons voir un effet très ancien, sinon LE premier effet... le défileur de texte.
Afficher du texte en mode graphique
Il existe 2 types de scrolly: celui qui charge en mémoire l'image bitmap de la police de caractères, emmagasinant dans un tableau chaques caractères, et l'autre qui utilise la police présente dans le ROM du BIOS. La technique que je présente est la seconde. Pour accèder au jeu de caractère présent dans le BIOS, il faut comprendre comment est structurer chaque caractère. La carte VGA enmmagasine le jeu de caractères standard à l'adresse : F000:FA6E. Il nous faut donc déclarer un pointeur sur cet adresse, de la même façon qu'on déclarait un pointeur sur la mémoire vidéo. Chaque caractères est enregistré sous la forme d'un bitmap de 8x8:
Adresse mémoire: [F000:FA6E]
Pour trouver la position de chaque caractère, il suffit de prendre l'adresse de base et de multiplier son code ASCII par 8. Voici par exemple, l'organisation de la lettre A dans le BIOS:
Octet Bitmap
OCTET 0: 0 0 0 0 0 0 0 0
OCTET 1: 0 0 0 1 1 0 0 0
OCTET 2: 0 0 1 0 0 1 0 0
OCTET 3: 0 1 0 0 0 0 1 0
OCTET 4: 0 1 1 1 1 1 1 0
OCTET 5: 0 1 0 0 0 0 1 0
OCTET 6: 0 1 0 0 0 0 1 0
OCTET 7: 0 0 0 0 0 0 0 0
Pour copier un caractère, nous devons se pointer sur la première ligne, dessiner les 8 bit de la ligne, où les pixels 0-7 sont afficher ou non dépendemment si le bit est à 1 ou 0, et ce pour les 8 lignes. Une façon rapide pour déterminer si un pixel est à 1 ou 0 est de procéder par masquage de bit. Pour chaque rangée, on fait un ET logique pour vérifier si on affiche un pixel ou non. On débute par 1000 0000, donc 0x80 (80 hexadécimal). On déplacle le bit 1 en décalant vers la droite d'une position, et on compare la prochaine, ainsi de suite jusqu'a la dernière.
CONCLUSION
Il est possible avec cette méthode d'afficher le caractère dans son format ordinaire de 8x8, ou d'en changer l'échelle. Dans le programme exemple, je modifie la taille des caractères, mais je ne rempli pas les pixels de façon "solide"... je ne fais qu'afficher les points constituant les lettres, afin de créer un lettrage composé uniquement de points. Il bien entendu très facile de le modifier afin qu'il affiche des lettres solides, et d'en changer l'apparence. Par exemple, je modifie la couleur de chaque ligne en incrémentant la variable col.
fxscroll.cpp
//--------------------------------------------------------------------------//
// T E X T S C R O L L E R //
// //
// code: Shaun Dore(dores@videotron.ca) //
///--------------------------------------------------------------------------//
#include <mem.h> // memset, memcpy
#include <stdio.h> // fread, printf
#include <conio.h> // getch, kbhit
#include <string.h> // strlen
#define LARGEUR 40 // largeur de la police
#define HAUTEUR 40 // hauteur de la police
#define VITESSE 4 // vitesse de deplacement
char *screen = (char *) (0xA0000000L); // Adresse de la memoire video
char *police = (char *) (0xF000FA6EL); // Adresse en ROM de la police
char *buffer = new char[64000L]; // Ecran virtuel 320x200
// Message qui deroule sur l'ecran
unsigned char message[] = " L'ARTISTE DIGITAL PROGRAMMATION GRAPHIQUE 2D/3D/Assembleur HTTP://PAGES.INFINIT.NET/SHAUN/ TUTEURS, CODE SOURCE ET PLUS!... PRESENTE PAR KRASHLOG DORES@VIDEOTRON.CA ";
// Dessine un caractere
void dessinecar(int xpos, int ypos, int c, unsigned char coul)
{
char far *car = &police[(c & 255) * 8]; // Obtient l'adresse du caractere
unsigned char bit; // Utiliser pour masquer l'octet
for (int y=0; y<HAUTEUR; y+=HAUTEUR/8)
{
if (y + ypos < 200)
{
bit = 0x80;
for (int x=0; x<LARGEUR; x+=LARGEUR/8)
{
if ((x + xpos < 320) && (x + xpos > 0))
if (*car & bit) buffer[(y+ypos)*320+x+xpos] = coul;
bit >>= 1; // Si le bit est egal a 1, affiche le pixel
}
}
coul++; // Incremente la couleur
car++; // Prochain octet du bitmap
}
}
void texte(int y)
{
int x=320;
int longueur = -(strlen(message)) * LARGEUR;
while(!(kbhit()))
{
if (x < longueur ) x = 320;
x-=VITESSE;
for (int i=0; message[i]; i++) dessinecar(x+(i*LARGEUR),y,message[i],22);
while (inp(0x3da) & 8);
while (!(inp(0x3da) & 8));
memcpy(screen,buffer,64000L);
memset(buffer,0,64000L);
}
}
void main()
{
asm{mov ax,0x13; int 0x10} // Mode 13h 320x200x256 graphique
texte(100-HAUTEUR/2); // Texte defilant
asm{mov ax,0x03; int 0x10} // Mode 03h 80x25 texte
delete[] buffer; // Vide le buffer
}