Amiga Demomaking Tutorial par Alain


Table des matières

Chapitre 1: Introduction
Chapitre 2: La couche d'abstraction graphique
Chapitre 3: La couche d'abstraction sonore
Chapitre 4: Les bitmaps
Chapitre 5: Scrolls texts
Chapitre 6: RotoZoom
Chapitre 7: Tunnel
Chapitre 8: Bump Mapping

Chapitre 1: Introduction

Ce tutorial, sans aucune prétention, a pour but de vous apprendre a programmer quelques effets graphiques bien connus de tous les demomakers. N'étant pas moi même un "vrai" demomaker, les effets que je vous présente ont été en partie repris d'un vieux tutorial sous MS/DOS intitulé "The Art Of Demomaking" d'Alex Champandard, que vous pouvez trouver ici. Les autres effets sont, soit de mon invention, soit récupéré par-ci par-la, un peu partout sur le net.

Plateforme
Ce tutorial a ceci de particulier qu'il est destiné a 2 plateformes: AmigaOS et Windows. Le but premier pour moi était de programmer l'Amiga, mais il faut bien dire que c'est bien pratique de programmer sur son laptop ou n'importe ou. J'ai donc developpé une couche d'abstraction au niveau graphique et au niveau musical. De cette façon seules ces deux parties changent en fonction de la plateforme, mais le reste, le plus important, les effets utilisent exactement le même code ( à part lors d'optimisations en ASM ).

Language et environnement
Le language utilisé pour ce tutorial est le C++. Rien de bien compliqué, il faut juste que vous connaissiez les notions d'héritages, de classes, et de méthodes virtuelles. Au niveau Amiga, j'ai utilisé pour la compilation StormC3 du CD developper 2.1. Je conseille donc d'avoir ou d'acheter ce CD bien pratique pour suivre ce tutorial. La version windows a été developpée sur VisualC++6 et utilise DirectX. Pour compiler les exemples sous DirectX, il vous faut downloader le kit de développement DirectX8 disponible par exemple ici [137MB, quand même]

Etant donné que ce tutorial est principalement orienté Amiga, je serais assez bref concernant les particularités de Windows. Et dans la même idée, nous allons faire a l'occasion des optimisations de routines en ASM 68k mais jamais en ASM Intel (pouaa! :)) (de toute façon en général les PC sont assez puissant et ne requiert peu/pas d'optimisations)

Les sources fournies disposent des fichiers de projets Storm(*.¶) et Visual (.dsp et .dsw). Pour identifier chaque compilateur/systéme j'ai utilisé les #define _WINDOWS et _AMIGAOS. deux autres #define sont définis: _CYBERGRAPHX qui, si vous ne le mettez pas, vous permet quand même de compiler si vous ne disposez pas des includes CyberGraphx et _FPS qui ajoute ou enlève les routines de calcul de FPS qui ralentissent légérement la démo.

Chapitre 2: La couche d'abstraction graphique

La couche d'abstraction a pour but de lancer un écran 320x200 en 256 couleurs en double buffer, et ce quelque soit la machine. Elle s'occupe aussi d'ouvrir une fenétre et d'attendre que la touche ESC( windows) ou le bouton gauche de la souris(Amiga) soit pressé pour fermer le programme.

pourquoi seulement 320x200?
Ben simplement pasque sur un amiga 68k pour avoir une vitesse suffisante, on peux pas beaucoup aller plus haut. d'autre part, ceci est un tutorial qui peut être appliqué à beaucoup de plateforme, et 320x200 c'est disponible quasiment partout.

Double buffer? c'est quoi ça?
C'est une technique datant de très très longtemps ( genre Commodore64 ) pour avoir un affichage sans saccade a l'écran. Le principe est très simple: on a une image affichée a l'écran et une image en mémoire. L'image en mémoire est la prochaine image a afficher. C'est donc sur celle çi que l'ont va dessiner. Quand on a fini de dessiner, on échange les 2 images, l'image que l'ont vient de dessiner devient l'image a l'écran, et l'autre devient la prochaine image dans laquelle on peut dessiner. L'échange des images se fait juste quand le faisceau à électron de l'écran revient a sa position de départ (VBL) de cette manière aucun déchirement de l'image n'est perceptible, et l'animation est smooth.

La classe CGfxSupport
La classe CGfxSupport est la classe qui implémente le graphisme. Les méthodes qu'elle propose sont les suivantes:

int InitDisplay
() = 0;
void SetResolution(int nWidth, int nHeight, int nBBPlane) = 0;
void SetPalette(PALETTEENTRY *pPalette) = 0;
void DemoMessageBox(char *strMessage);
virtual void OnInit() = 0;
virtual void OnEnd() = 0;
virtual void OnDisplayFrame(BYTE *pBitmapBuffer) = 0;


InitDisplay
C'est la méthode principale de cette classe. C'est cette méthode qui change la résolution de l'écran et lance la démo. Elle ne rend la main que lorsque l'utilisateur presse le bouton de la souris (ou ESC sous Windows).
Elle appelle la méthode OnInit juste avant de se lancer dans la boucle principale, puis pour chaque frame(image) elle appelle OnDisplayFrame, puis avant de rendre la main, elle appelle OnEnd. Ces 3 méthodes doivent être surchargées dans votre démo pour initialiser vos effets, les désinitialiser et aussi afficher les effets.

SetResolution
Cette méthode est là pour choisir la résolution de l'écran souhaitée. On passe la hauteur, la largeur, et le nombre de Bitplane voulus ( 8=256 couleurs,..., 32= TRUE COLOR). Dans notre implémentation toute autre résolution que le 320x200x8 n'est pas supporté, mais cette méthode pourra être utile le jour ou on décidera d'améliorer notre code et de supporter d'autres résolutions.

SetPalette
Bon ben la pas de mystéres, c'est la méthode qui permet de changer la palette courante de l'écran. Le type PALETTEENTRY est défini comme ça:

struct PALETTEENTRY
{
BYTE peRed;
BYTE peGreen;
BYTE peBlue;
};

DemoMessageBox
Cette méthode permet d'afficher un petit message box sur l'écran de windows/workbench avec le message de son choix. Typiquement je l'utilise a la fin de la démo pour afficher le nombre de FPS.

OnInit
Cette fonction est appellée au tout début de la démo pour permettre d'initialiser les effets.

OnEnd
Cette fonction est appellée à la fin de la démo pour permettre de désinitialiser les effets ou de stopper la musique par exemple.

OnDisplayFrame
Cette fonction est appellée à chaque image. un pointeur sur l'image est passé, l'image doit être dessinée dans le buffer, puis lorsque la fonction retourne, le mécanisme de double-buffering est appelé de manière a afficher l'image.

Implémentation pour Amiga

Implémentation pour Windows
Bon je vais faire assez court la dessus, pasque c'est pas un tutorial windows ici.
Alors, l'implémentation pour Windows se situe dans le fichier WindowsGfxSupport.cpp et utilise DirectDraw7(ou plus). En gros, d'abord dans la méthode CreateDemoWindow on crée une fenetre avec un accélerateur (moyen propre de Windows pour recuperer la touche ESC), puis on l'affiche.
Ensuite on passe a la méthode InitDirectDraw qui initialise Direct draw, puis change le mode graphique, puis instancie les buffers pour le double-buffering.
Ensuite on part dans la méthode MsgLoop qui est la boucle principale. Elle recupére les messages Windows pour savoir si on doit quitter, affiche chaques images et met en oeuvre le mécanisme du double buffer.

Les effets
Bien, maintenant que la partie chiante est faite, on va penser un peu aux effets de la mort qu'on pourrais faire dans cette démo. Mais avant de faire un sinusrotozoom en gouraud shading qui arrache, on va définir une classe de base pour nos effets, la classe CBaseEffect (ouais, je sais je regorge d'imagination pour les noms)

La classe CBaseEffect
La classe CBaseEffect propose un set de methode commun pour tous les effets. Elle dispose en plus de quelques "bonus" comme le calcul des FPS(Images par seconde) de l'effet.

Voici ses méthodes:

CBaseEffect(int width = 320,int height = 200);
virtual ~CBaseEffect();
virtual void Update(BYTE *pBitmap);

void GetPalette(PALETTEENTRY *pPalette, int nOffset=0, int nLength=256);
void SetPosition(int x, int y);
void SetSize(int w,int h);
void ResetTime();
long GetTime();
float GetFPS();

Constructeur
Le constructeur peut reçevoir en argument optionnels la taille de l'effet. Par défaut l'effet prend l'écran complet. Cette taille peut être changée plus tard en utilisant SetSize.

Destructeur
Le destructeur, voila rien a dire de plus :)


Update
Cette méthode écrit dans le buffer passé en paramétre (pBitmap) la prochaine image de l'effet.


GetPalette
Cette méthode permet de récuperer la palette de l'effet pour, par exemple, la passer a CGfxSupport pour changer la palette de l'écran. Les arguments optionnels permettent de récuperer qu'une partie de la palette (si par exemple un effet n'utilise que les 3 couleurs 126,127,128, on appelera GetPalette( pPalette,126,3), de cette manière on peut utiliser les autres couleurs pour un autre effet au même moment).


SetPosition
La position de l'effet.


SetSize
La taille de l'effet.


ResetTime
Cette méthode met a zéro le timer qui calcule les FPS et le temps de GetTime.


GetTime
Fournis le temps écoulé en millisecondes depuis le dernier ResetTime ou la construction de l'objet( si ResetTime n'a jamais été appelé ). Si le define _FPS n'a pas été défini a la compilation, la valeur retournée n'est pas valide.


GetFPS
Retourne le nombre d'images/secondes (FPS) de l'effet.
Si le define _FPS n'a pas été défini a la compilation, la valeur retournée n'est pas valide.

Oh mon Dieu, c'est pleins d'étoiles!
Je me suis dit qu'on pouvais pas se quitter comme ça pour ce chapitre la. En effet rien de plus frustrant que de programmer pleins de trucs et ensuite d'avoir un écran noir! Alors bon on va programmer un petit effet de starfield pour tester tout ça.
Alors pour l'effet CStars c'est assez simple: on va dériver une classe de CBaseEffect, puis faire l'implémentation des méthodes suivantes:

CStars(int width = 320, int height = 200, int nNumberStar = 256);
virtual ~CStars();
virtual void Update(BYTE *pBitmap);
void GetPalette(PALETTEENTRY *pPalette);


Constructeur
Dans le constructeur, on va allouer une tableau de structure TStar de la grandeur nNumberStar et générer des étoiles au hasard dans l'espace de width * height
.

struct TStar
{
float x, y; // position
unsigned char plane; // plan
};


La structure TStar a 3 champs. X et Y définissent la position de l'étoile, et plane défini le plan de l'étoile (au 1er plan les étoiles vont vites et sont brillantes, au dernier plan (le 3éme) les étoiles sont lentes et brillent moins).

Destructeur
Le destructeur libére la mémoire des étoiles.


Update
Ici on dessine les étoiles, la procédure est la suivante:

- On appelle la classe de base (pour le timing, par exemple, et pour allouer les variables).

- Pour chaques étoiles:
{
-- on bouge l'etoile a droite, la vitesse dependant du plan de l'etoile..
-- si elle est sortie on la remet a 0 et on genere sa position verticale au hasard
-- on dessine l'etoile avec une couleur dependant du plan
}

GetPalette
On met toutes les couleurs a noir, sauf la 248(gris foncé), 249(gris clair) et 250(blanc).


Conclusion
Ben voila.. Aprés un chapitre on dispose d'un framework qui permet de programmer des effets sous Amiga AGA, Amiga CGX et Windows, on a un moyen de calculer les FPS des effets, on a une classe de base pour les effets, et on a un joli starfield qui épate les voisins. Pas mal pour un début!
Dans le prochain chapitre, on va parler musique. On verra en effet comment jouer un fichier MOD sur PC et sur Amiga.. d'ici la amusez vous bien!

Les Fichiers à downloader

- Les sources complétes du chapitre 1 [lha] [zip]
- L'executable Amiga
- L'executable Windows






Chapitre 3: La couche d'abstraction sonore
Chapitre 4: Les bitmaps
Chapitre 5: Scrolls texts
Chapitre 6: RotoZoom
Chapitre 7: Tunnel
Chapitre 8: Bump Mapping