ChewBaccA ! présente : LE ROTOZOOM !!!!!!
Bon, c la premiere fois que j'ecris une doc, donc
j'espere que ce sera pas de la doc de merde, et que vous arriverez a comprendre.
Je tiens a preciser que je suis pas une grosse bete de code (quoique...
:0 ), et que donc il est possible que ce texte contienne quelques imperfections
ou imprecisions (peut etre des termes de maths que j'emploie pas correctement
ou ce genre de connerie ), et donc si vous etes vous meme une grosse bete,
evitez le comportement genre : "woarf il est con lui, c trop de la merde
sa doc", a la place, vous m'envoyez un chtit mail et je corrige l'erreur
(mais en fait, si vous etes une grosse bete, je vois pas l'interet de lire
cette doc...). Vala vala, a part ca bin je suis pas responsable de tout
ce qui peut vous arriver en lisant ce texte et patati et patata...
Donc allons-y maintenant que les choses sont fixees.
1) le rotozoom oui, mais qu'est-ce que c'est ????
Je pense que c'est une question qu'on est en droit de se poser quand on veut coder un rotozoom. On peut dire que le rotozoom est un effet graphique qui comme son nom l'indique, consiste a effectuer sur une texture une rotation + un zoom. Si vous voulez avoir une idée concrete de ce que ca donne avant de le coder, prenez une feuille de papier et approchez la de vos yeux en la faisant tourner, en gros c ca :).
2) plus loin dans le rotozoom : comment ca marche ????
(euh, désolé pour les titres des différentes parties
de la doc, comme je l'ai dit, c la premiere fois que j'ecris ca )
Le principe du rotozoom consiste a mapper une ligne
oblique de la texture a rotozoomer horizontalement sur l'ecran, comme le
montre le schema ci-dessous :
Comme on le voit, le fait de mapper horizontalement
une ligne oblique donne l'impression de rotation...
Le probleme est donc de definir cette ligne et de
l'afficher a l'ecran, et de faire ca jusqu'a ce que l'ecran soit tout rempli...
On doit definir la ligne a afficher en fonction de deux facteurs :
- l'angle de la rotation
- le coefficient de zoom
Pour definir cette ligne, j'utilise un vecteur que
je balade dans la texture pour determiner quels pixels de la texture je
dois afficher a l'ecran.
Ainsi, pour passer d'un pixel a un autre dans la
texture, on se balade selon notre petit vecteur, ce qui definit la ligne
oblique dont j'ai parle plus haut.On note que si le vecteur de deplacement
a une norme inferieure a 1 pixel, le fait de se deplacer ne modifiera pas
le pixel sur lequel on se trouve, ce qui nous fait afficher deux fois le
meme pixel : c'est un zoom !!! :)
On voit que la direction et le sens du vecteur dependent
de l'angle, et que sa norme est modifiee par le coefficient de zoom. Plus
le vecteur est petit, plus le zoom est fort, et plus il est grand, plus
on a l'impression de s'éloigner de l'image. D'ou un petit calcul
pour trouver les coordonnées du vecteur :
xx = cos(alpha)*scale;
yy = sin(alpha)*scale;
(le vecteur a pour coordonnées xx et yy (je precise au cas ou...),
alpha est l'angle de la rotation, scale le coefficient de zoom)
Maintenant qu'on a notre vecteur, voila comment l'utiliser (pasque c'est bien joli d'avoir un vecteur, mais bon...) pour afficher une ligne.
(note : c du code de base pour expliquer le principe, il va sans dire que ca a besoin d'optimisation...)
variables : x et y -> coordonnees a l'ecran
u et v -> coordonnees a l'interieur de la texture
xx et yy -> coordonnees du vecteur
for(x=0;x<320;x++) {
u = u + xx;
v = v + yy;
// on se deplace dans la texture selon le vecteur
putpixel(x,y,texture[u][v]); // on affiche le point actuel
de la texture a l'ecran
}
Voila, donc je pense que c'est le plus dur a comprendre
(n'est-ce pas froggy :) ), si vous comprenez pas, hesitez pas a me contacter.
Sinon, faut aussi faire gaffe a ce que le point (u;v) soit bien dans la
texture, donc on fait un ptit modulo sur u et v pour eviter qu'ils sortent
(un autre moyen etant d'utiliser des octets pour u et v, et une texture
256*256, de facon a economiser ce modulo ).
Bon, une fois qu'on a affiche notre ligne horizontale,
on est bien content, mais il en faut d'autres pour remplir l'ecran...
Le truc a faire, c'est de trouver quel pixel de
la texture correspond au premier pixel de la prochaine ligne a afficher.
Un autre petit schema pour etayer mes propos incoherents :
Comme le montre l'image, pour trouver le premier
point de la ligne suivante, il faut repartir au debut de la ligne qu'on
vient d'afficher (dont on prendra soin de sauver les coordonnees), et se
deplacer selon un vecteur perpendiculaire a celui qu'on utilise pour tracer
les lignes, soit le vecteur de coordonnees (-yy;xx).
Bin voila, c'est tout... Pour les flemmards (ou
ceux ki ont pas tout compris), voila un petit code d'exemple (du bon source
a ripper quoi :) ) :
avant, une chtite description des variables :
xx et yy : ce sont les coordonnees du vecteur balade
u et v : ce sont les coordonnees du pixel courant dans la texture
_u et _v : coordonnees du premier pixel de la ligne courante (pour
pouvoir changer de ligne a la fin)
x et y : coordonnees du pixel courant a l'ecran
texture : tableau contenant la texture (je note texture[x][y] le pixel
de coordonnees (x;y) dans la texture, mais c'est juste pour simplifier
l'ecriture, d'ailleurs il est plus simple d'avoir un tableau de 64000 octets
pour stocker la texture (mais c juste mon avis perso...) )
putpixel(x,y,c) : fonction qui affiche un pixel de couleur c aux coordonnees (x;y) a l'ecran
... initialisation de tous les machins ki peuvent servir ...
... on modifie l'angle et/ou le coefficient de zoom
xx = cos(alpha)*scale;
yy = sin(alpha)*scale;
// on calcule le vecteur balade
for(y=0;y<200;y++) { // pour toutes
les lignes horizontales de l'ecran
_u = u;
_v = v;
// on sauve les coordonnees du premier pixel de la ligne a afficher
for(x=0;x<320;x++) {
// affichage d'une ligne horizontale
u = u + xx;
v = v + yy;
// on se balade dans la texture
putpixel(x, y, texture[u][v]); // on
affiche le point actuel de la texture a l'ecran
}
u = _u - yy;
// on se place sur le premier pixel de la prochaine ligne a afficher
v = _v + xx;
// en se deplacant selon un vecteur perpendiculaire au vecteur utilise
pour tracer les lignes
}
... pis maintenant on peut boucler ...
Voila, en fait c'est super simple un rotozoom une fois qu'on a pige le principe, et vous pouvez voir que le code est tres court aussi...
3) tous les petits trucs sur le rotozoom que j'ai pas voulu dire avant...
* j'ai appris a faire un rotozoom
avec la doc de Rixed dans le reporter, malheureusement (comme pas mal de
docs de Rixed je trouve) elle n'est pas d'une clarté incroyable,
donc en fait c'estune réedition... c'était juste pour dire
que bon, c'est quand meme Rixed qui m'a mache le boulot :)
* ya une petite variante interessante a faire sur
un rotozoom, c modifier le coefficient de zoom a chaque nouvelle ligne
horizontale (ca revient grosso modo a changer la place de 2 lignes de code
pour les placer dans la boucle principale) : ca fait une petite deformation
de texture marrante
* utiliser des nombres a virgule fixe !!!! c'est
vrai, les float c lent et c chiant... pour les fixes, il suffit de multiplier
toutes les coordonnees utilisees par 256 (donc un decalage vers la gauche
de 8 bits) pour avoir une meilleur precision, et de les diviser par 256
au moment ou on les utilise pour l'affichage a l'ecran
* pour l'optimisation, on peut aussi precalculer
les tables de sin/cos
* cette methode d'utiliser un vecteur pour se balader
dans une texture sert pas que dans le rotozoom, on peut faire ca aussi
pour beaucoup d'autres deformations
* si vous voulez juste faire un zoom, il suffit
d'utiliser un vecteur (scale;0) pour le trace de chaque ligne (et a ce
compte la bien sur, on a pas besoin d'ajouter le 0 a chaque fois :) )
* etant donne que la boucle principale contient
que des additions, je suis quasiment sur que l'utilisation des complexes
pour coder cet effet est un peu un moyen de ralentir le code :)
4) dernieres petites choses...
Si vous avez lu cette doc et que vous avez rien compris,
vous pouvez me demander des explications, soit en me mailant : chewie@wanadoo.fr
soit sur irc, sur les channels #demofr ou #codefr (#pixelfr aussi des fois,
mais c'est plutot le genre de truc que je prefere pas dire :) ). Si au
contraire vous avez lu cette doc et que vous vous etes decouvert une passion
pour le rotozoom, envoyez moi un petit mot, ca fait toujours plaisir et
ca m'encouragera a faire d'autres docs...