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...