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