IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez Discussion :

[SOURCE] [SDL] Comment programmer une rotation


Sujet :

Contribuez

  1. #1
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut [SOURCE] [SDL] Comment programmer une rotation
    Si vous ne voulez pas utiliser les fonctions proposées pour la bibliothèque SDL pour effectuer une rotation (http://jeux.developpez.com/faq/sdl/?...ransformations)
    mais que vous voulez programmer vous même votre propre rotation.


    Si vous voulez voir comment réaliser une telle opération sous SDL, voici un code permettant de le faire :

    Prototype (la surface de destination est automatiquement allouée et fait la même taille que la surface d'origine, donc n'oubliais pas le SDL_FreeSurface) :
    SDL_Surface* SDL_RotationCentral(SDL_Surface* origine, float angle)

    Je souligne que les calculs sont effectués par le CPU, donc il n'y a aucune optimisation de la carte graphique.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
     
    /*permet de déterminer la valeur d'un pixel au position x,y*/
    Uint32 inline SDL_LirePixel(SDL_Surface* surface, int x, int y)
    {
      int bpp = surface->format->BytesPerPixel;
     
      Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
     
      switch(bpp)
      {
                 case 1:
                      return *p;
                 case 2:
                      return *(Uint16 *)p;
                 case 3:
                     if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
                         return p[0] << 16 | p[1] << 8 | p[2];
                     else
                         return p[0] | p[1] << 8 | p[2] << 16;
                 case 4:
     
     
                      return *(Uint32 *)p;
                 default:
                      return 0;
      } 
     
    }
     
     
    /*permet d'écrire un pixel au position x,y*/
    void inline SDL_EcrirePixel(SDL_Surface* surface, int x, int y, Uint32 pixel)
    {
        int bpp = surface->format->BytesPerPixel; 
        Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; 
     
     
        switch(bpp) { 
        case 1: 
            *p = pixel; 
            break; 
     
        case 2: 
            *(Uint16 *)p = pixel; 
            break; 
     
        case 3: 
            if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { 
                p[0] = (pixel >> 16) & 0xff; 
                p[1] = (pixel >> 8) & 0xff; 
                p[2] = pixel & 0xff; 
            } else { 
                p[0] = pixel & 0xff; 
                p[1] = (pixel >> 8) & 0xff; 
                p[2] = (pixel >> 16) & 0xff; 
            } 
            break; 
     
        case 4: 
     
            *(Uint32 *)p = pixel; 
            break; 
        }  
     
    }
     
    /*effectue une rotation centrale d'angle en degré, alloue automatiquement la mémoire*/
    SDL_Surface* SDL_RotationCentral(SDL_Surface* origine, float angle)
    {
     SDL_Surface* destination;
     int i;
     int j;
     Uint32 couleur;
     int mx, my;
     float d;
     int bx, by;
     float angle_radian;
     
    /* détermine la valeur en radian de l'angle*/
     angle_radian = -angle * M_PI / 180.0;
     
    /* 
     * alloue la mémoire à l'espace de destination, attention, 
     * la surface est de même taille
     */
     destination = SDL_CreateRGBSurface(SDL_HWSURFACE, origine->w, origine->h, origine->format->BitsPerPixel,
    			origine->format->Rmask, origine->format->Gmask, origine->format->Bmask, origine->format->Amask);
     
     /*on vérifie que la mémoire a été allouée*/
     if(destination==NULL)
      return NULL;
     
    /* pour simplifier les notations*/
     mx = origine->w/2;
     my = origine->h/2;
     
     for(j=0;j<origine->h;j++)
      for(i=0;i<origine->w;i++)
      {
    /* on détermine la valeur de pixel qui correspond le mieux pour la position
     * i,j de la surface de destination */
     
    /* on détermine la meilleure position sur la surface d'origine en appliquant
     * une matrice de rotation inverse
     */
       bx = (int) (cos(angle_radian) * (i-mx) + sin(angle_radian) * (j-my)) + mx;
       by = (int) (-sin(angle_radian) * (i-mx) + cos(angle_radian) * (j-my)) + my;
       /* on vérifie que l'on ne sort pas des bords*/
       if (bx>=0 && bx< origine->w && by>=0 && by< origine->h)
       {
         couleur = SDL_LirePixel(origine, bx, by);
         SDL_EcrirePixel(destination, i, j, couleur);
       }
      }
     
    return destination;
    }
    Si vous avez des suggestions, n'hésitez pas !


    [Edit] il faut noter que l'on parcourt la surface de destination et non la surface d'origine pour forcer chaque pixel de destination a avoir une couleur à peu près correct (à peu près comme une rotation en informatique est dans la plupart des cas non bijective). Alors que si l'on parcourait les pixels de la surface d'origine, déterminait les positions de sa position, il pourrait y avoir des trous noirs dans la surface de destination.

    [Edit] Voici la version qui ne déborde pas sur les bords et qui ajuste la taille de la surface de destination :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
     
    /*effectue une rotation centrale, alloue automatiquement la mémoire*/
    SDL_Surface* SDL_RotationCentralN(SDL_Surface* origine, float angle)
    {
     SDL_Surface* destination;
     int i;
     int j;
     Uint32 couleur;
     int mx, my, mxdest, mydest;
     int bx, by;
     float angle_radian;
     float tcos;
     float tsin;
     double largeurdest;
     double hauteurdest;
     
    /* détermine la valeur en radian de l'angle*/
     angle_radian = -angle * M_PI / 180.0;
     
    /*pour éviter pleins d'appel, on stocke les valeurs*/
     tcos = cos(angle_radian);
     tsin = sin(angle_radian);
     
    /*calcul de la taille de l'image de destination*/
     largeurdest=   ceil(origine->w * fabs(tcos) + origine->h * fabs(tsin)),
     hauteurdest=   ceil( origine->w * fabs(tsin) + origine->h * fabs(tcos)),
     
     
    /* 
     * alloue la mémoire à l'espace de destination, attention, 
     * la surface est de même taille
     */
     destination = SDL_CreateRGBSurface(SDL_HWSURFACE, largeurdest, hauteurdest, origine->format->BitsPerPixel,
    			origine->format->Rmask, origine->format->Gmask, origine->format->Bmask, origine->format->Amask);
     
     /*on vérifie que la mémoire a été allouée*/
     if(destination==NULL)
      return NULL;
     
     /*calcul du centre des images*/
     mxdest = destination->w/2.;
     mydest = destination->h/2.;
     mx = origine->w/2.;
     my = origine->h/2.;
     
     for(j=0;j<destination->h;j++)
      for(i=0;i<destination->w;i++)
      {
    /* on détermine la valeur de pixel qui correspond le mieux pour la position
     * i,j de la surface de destination */
     
    /* on détermine la meilleure position sur la surface d'origine en appliquant
     * une matrice de rotation inverse
     */
     
       bx = (ceil (tcos * (i-mxdest) + tsin * (j-mydest) + mx));
       by = (ceil (-tsin * (i-mxdest) + tcos * (j-mydest) + my));
       /* on vérifie que l'on ne sort pas des bords*/
       if (bx>=0 && bx< origine->w && by>=0 && by< origine->h)
       {
         couleur = SDL_LirePixel(origine, bx, by);
         SDL_EcrirePixel(destination, i, j, couleur);
       }
     }
     
    return destination;
    }
    Je ne répondrai à aucune question technique en privé

  2. #2
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Très intéressants, cela me rappelle mes cours d'algébre (d'isomorphisme...), mais j'ai 3 remarques :

    1) Quels sont les performances par rapport à l'utilisation de rotozoomSurface ?

    2) Pourquoi faire une décomposition pour 3 bytes et pas 2 ou 4 ? Cela me semble particulier, non ?

    3) Pourquoi garder la même taille ? Si on fait 4 fois des rotations de 90 degrés, on ne perd pas les bords ?

    Jc

  3. #3
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Citation Envoyé par fearyourself
    Très intéressants, cela me rappelle mes cours d'algébre (d'isomorphisme...), mais j'ai 3 remarques :

    1) Quels sont les performances par rapport à l'utilisation de rotozoomSurface ?
    Je n'ai pas testé, mais apparement, la fonction rotozoom a acceleré par la carte graphique, il faudrait réaliser des tests (jvais le faire)

    2) Pourquoi faire une décomposition pour 3 bytes et pas 2 ou 4 ? Cela me semble particulier, non ?
    Si tu parles de LirePixel et EcrirePixel, ce sont les fonctions que l'on peut recuperer à droite à gauche, et je ne sais pas en quoi l'endianness du système change qqch.

    3) Pourquoi garder la même taille ? Si on fait 4 fois des rotations de 90 degrés, on ne perd pas les bords ?
    Effectivement, on perd les bords, mais j'avais la flemme de faire le calcul, je vais essayer de le faire. De plus, classiquement, on coupe les bords comme ça (on peut le constater avec des logiciels de traitement d'image)
    Je ne répondrai à aucune question technique en privé

  4. #4
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Alors j'ai testé les différences de performances sur mon ordi entre la bibliothèque gfx (qui est acceleré par la carte graphique) et la fonction que j'ai proposé.

    100 rotations d'une image de 800*600 :
    - gxf : 10 sec
    - ma fonction : 1 min...
    Néanmoins, cela reste interessant de voir le code d'une rotation et ça évite d'ajouter une bibliothèque en plus (enfin, si elle est performante... )

    Sinon, je ferais une autre version qui ne rogne pas les bords, j'avais réalisé les calculs pour cela l'an dernier, mais ils sont sur un serveur qui est en arrêt jusqu'au 20 25, et n'ayant pas envie de perdre du temps là dessus, je ferai la mise à jour dans ces eaux là.
    Je ne répondrai à aucune question technique en privé

  5. #5
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    J'ai apparement retrouvé de tête les calculs, mais ce n'est pas vraiment optimisé (par exemple pour les calculs de la taille de la surface de destination).

    J'ai donc ajouté au code une autre fonction qui créait une surface de destination plus grande et qui ne déborde pas.
    Je ne répondrai à aucune question technique en privé

  6. #6
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    Je me suis un peu essayé à l'optimisation. Pour le côté pédagogique et lisible ça ne va plus être ça mais ça tourne mieux.

    Je n'en ai pas besoin chez moi alors je ne l'ai pas mis mais utiliser "SDL_LockSurface" peut-être nécessaire pour accéder directement aux pixels.

    J'ai commencé par modifier la fonction pour prendre la surface de destination en entrée afin de ne pas la créer à chaque frame et j'ai aussi supprimé les calculs de taille maximale. Dans une optique jeu/temps réel couper l'image n'est pas un problème (pour du dessin ça pourrait être différent) car on ne cumule pas les rotations (ce qui aurait comme défaut de cumuler les approximations et de vite corrompre l'image). Typiquement on incrémente l'angle et on refait la rotation à partir de l'original à chaque frame (de toute façon on a rien à y gagner pour les performances).
    Par contre il faudrait (mais là j'ai eu la flemme pour ce soir) permettre de placer l'image après la rotation à des coordonnées données (ce devrait être simple, juste un décalage à mettre). De plus, dans l'optique de placer un sprite à un endroit de l'écran, il faudrait ne boucler que sur la zone (limitée) de l'écran qu'occupe le sprite ce qui limitera beaucoup les calculs.

    Bref sur une image qui trainait en 800x600 j'ai obtenu # 20 fps.

    Les fonction d'accès aux pixels semblaient un bon angle d'attaque donc je m'en suis passé. Mon image étant en 8 bits j'ai fait avec (mais cela m'oblige a avoir le même format de pixels entre source et destination... ce qui semble de toute façon souhaitable pour les performances). Je suppose qu'en 32 bits cela irait aussi vite avec un processeur 32 bits, à moins que la bande passante mémoire ne suive pas. Cela m'a surtout permis d'utiliser un pointeur sur les pixels de destination pour passer d'un pixel à un autre avec une simple incrémentation du pointeur. Résultat 28 fps.

    Comme entre deux pixels on incrémente juste i et/ou j on peut incrémenter les coordonnées dans l'image d'origine d'une valeur fixe ce qui suprime beaucoup d'opérations sur les flottants, à commencer par les multiplications. 36fps.

    Pour voir j'ai passé les boucles à "for(j=destination->h; j>0; --j)" ce qui m'a donnée environ 0.5fps. Pas terrible mais bon.

    Ultime détail, l'ajout de "-O3 -march=athlon64" aux options de compilation pour optimiser au maximum et là... presque 70fps ! Ce qui me fait penser qu'il faudrait que je retente avec les fonctions d'accès aux pixels qui n'étaient peut-être pas en inline à l'origine, et elles n'étaient peut-être donc pas si coûteuses que ça.

    Pour faire mieux il faudrait passer à des calculs sur des entiers. En remplaçant les conversions flottants vers entiers (pour se faire une idée du coût de la conversion) par une mise à 0 je passe de 70 à 115 fps
    Sinon commencer pour chaque ligne directement à un pixel qui tombe dans l'image d'origine mais ça risque de casser les boucles.

    Je pense qu'un petit bout d'assembleur pas bien compliqué pour les boucles elles mêmes pourrait bien aider (en tout cas si l'asm sert c'est là ou nul part). Je serait curieux de voir combien on y gagnerait.


    Sinon c'est vrai qu'il faudrait un rien pour en faire un rotozoom. Là il est un peut tard mais ce serait plus classe et pas plus lent.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
    void SDL_RotationCentralN(SDL_Surface* origine, SDL_Surface* destination, float angle_radian) {
       Uint8* p;                 // pointeur sur le pixel à remplir
       int i;
       int j;
       int midx, midy;           // coordonees du milieu de l'ecran
       int intx, inty;           // valeurs entieres pour atteindre le pixel lui-même
       float x, y;               // valeurs de travail
       float ligne_x, ligne_y;   // valeurs au debut des lignes
       float dxi, dyi, dxj, dyj; // increments des x et y suivant i et j (compteurs des x et y)
       float tcos;
       float tsin;
     
       /*pour éviter pleins d'appel, on stocke les valeurs*/
       tcos = cos(angle_radian);
       tsin = sin(angle_radian);
     
       /* pour simplifier les notations*/
       midx = origine->w/2;
       midy = origine->h/2;
     
       p = (Uint8*)destination->pixels;
       ligne_x = -tcos * midx - tsin * midy + midx;
       ligne_y =  tsin * midx - tcos * midy + midy;
       dxi =  tcos;
       dxj =  tsin;
       dyi = -tsin;
       dyj =  tcos;
     
       /* on détermine la valeur de pixel qui correspond le mieux pour la position
       * i,j de la surface de destination */
     
       /* on détermine la meilleure position sur la surface d'origine en appliquant
        * une matrice de rotation inverse
        */
       for(j=destination->h; j>0; --j) {
          x = ligne_x;
          y = ligne_y;
          for(i=destination->w; i>0; --i) {
             intx = (int) x;
             inty = (int) y;
     
             /* on vérifie que l'on ne sort pas des bords*/
             if (intx>=0 && intx < origine->w && inty>=0 && inty < origine->h)
                // On va cherche la couleur du pixel
                *p = * ((Uint8*)origine->pixels + inty * origine->pitch + intx);
     
             ++p;     // pixel suivant
             x += dxi;
             y += dyi;
          }
          ligne_x += dxj;
          ligne_y += dyj;
       }
    }

  7. #7
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Sympa comme boulot bien que j'ai un doute sur la portabilité... Ta ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    *p = * ((Uint8*)origine->pixels + inty * origine->pitch + intx);
    ne fonctionnera qu'avec du 8 bits, il faudrait arranger cela pour que cela fonctionne avec du 16, 24 ou 32 bits...

    La question que je dois poser est : pourquoi le faire ?

    Encore une fois, je ne pense pas que les pages sources ont une nécessité d'être les codes les plus performants...

    Par contre, ce n'est pas pour autant que je trouve que l'on devrait laisser tomber ton code. Il présente une bonne base pour un code performant mais aussi lisible.

    Jc

  8. #8
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    j'ai aussi supprimé les calculs de taille maximale
    En fait, ce calcul peut se faire en une ligne sans passer par des boucles, c'est juste une histoire de maximum avec un cos et un sin sur les bords de l'origine.

    Par exemple pour la taille en largeur, tu prends le maximum en abscisse - la valeur absolue du minimum en abscisse de la rotation des angles...

    Je sais pas si c'est clair mais ça ne demande presque aucun calcul et surtout pas des boucles comme j'avais fait (mais j'avais la flemme de faire autrement sur le coup)
    Je ne répondrai à aucune question technique en privé

  9. #9
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    Citation Envoyé par millie
    (mais j'avais la flemme de faire autrement sur le coup)
    Bienvenue au club C'est vrai que c'est pas super compliqué (je pensais uniquement aux perf alors j'ai dynamité tout ce qui était sur mon chemin sans trop réfléchir) mais j'ai un peu peur de la création de la surface correspondante en terme de performances. D'expérience je sais que "new" et "delete" sont lents, mais si SDL_CreateRGBSurface n'est pas trop coûteux ça pourrait être pratique.

    Citation Envoyé par fearyourself
    Par contre, ce n'est pas pour autant que je trouve que l'on devrait laisser tomber ton code. Il présente une bonne base pour un code performant mais aussi lisible.
    Un bon exemple d'optimisation avec ses étapes pourrait être intéressant. Avec la base SDL pour faire une rotation indépendante du frame rate ça dépannerait certains aussi. Et une homothétie (si je me rappelle bien du terme) pour obtenir le fameux mode 7
    OpenGL a beau rendre tout ça obsolète ça ne me lasse pas.

    Citation Envoyé par fearyourself
    ne fonctionnera qu'avec du 8 bits, il faudrait arranger cela pour que cela fonctionne avec du 16, 24 ou 32 bits...
    Tout à fait d'accord. Ce n'est pas vraiment un problème de portabilité (ça marche sur un Mac ou n'importe quoi) mais plutôt des surfaces que l'on utilise. Si on veut des couleurs à foison il faut changer "Uint8" et "Uint32" mais faire un code qui peut tout faire a un coût et je pense que dans ce cas le particulariser pour les surfaces que l'on utilise (on mixe généralement assez peu 3 formats de couleurs différents) me semble viable.

    Si j'ai le temps ce soir je retente avec les fonctions d'accès au pixels mais avec toutes les optimisations du compilateur pour voir ce que ça coûte vraiment. Et j'ai une idée de fonction pour limiter le coût en gardant de meilleures perf... enfin je crois.

    J'ai aussi du code en court pour supprimer les conversions flottants/entiers mais il ne marche pas encore. Je soupçonne une boulette sur les pointeurs (je dois trop faire de java en ce moment ). Je crois que je vais bientôt apprendre à utiliser gdb

  10. #10
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Avons-nous donc une version finale pour cette source ?

    Jc

  11. #11
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    C'est juste une source qu'une personne peut reprendre en partie.

    Ca dépend en fait un peu de l'utilisation que la personne souhaite faire.
    Je ne répondrai à aucune question technique en privé

  12. #12
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par millie
    C'est juste une source qu'une personne peut reprendre en partie.

    Ca dépend en fait un peu de l'utilisation que la personne souhaite faire.
    Oui mais avec les remarques qui ont été faites, où se trouve la version finale ?

    Jc

  13. #13
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    Oui mais avec les remarques qui ont été faites, où se trouve la version finale ?
    Dans ce forum d'ici la fin du week-end ?
    J'ai essayé mais j'ai pas fait mieux en terme de perfs. Faut croire que je m'y suis mal pris ou que les processeurs actuels mangent des flottants pour le petit dej' (cette dernière explication me plait plus ).

    Alors je vais juste mettre un peu au propre avec une base SDL autour pour que ce soit plus facile à tester. Et un max de commentaires, promis.

  14. #14
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par Sivrît
    Dans ce forum d'ici la fin du week-end ?
    J'ai essayé mais j'ai pas fait mieux en terme de perfs. Faut croire que je m'y suis mal pris ou que les processeurs actuels mangent des flottants pour le petit dej' (cette dernière explication me plait plus ).

    Alors je vais juste mettre un peu au propre avec une base SDL autour pour que ce soit plus facile à tester. Et un max de commentaires, promis.
    Non, cela ne presse pas mais je vais sûrement mettre tous les sources en place la semaine prochaine donc je vérifie que j'ai les dernières versions de chaque source

    Jc

  15. #15
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    D'accord, je fais ma version qui alloue la mémoire mais qui calcule la taille de manière rapide dans l'heure. A tout de suite
    Je ne répondrai à aucune question technique en privé

  16. #16
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Ayé, j'ai mis à jour la version qui calcule la taille de la surface de destination pour qu'il n'y ait pas de dépassement. Je ne fais plus de boucle pour calculer mais j'utilise une simple formule.
    Je ne répondrai à aucune question technique en privé

  17. #17
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par millie
    Ayé, j'ai mis à jour la version qui calcule la taille de la surface de destination pour qu'il n'y ait pas de dépassement. Je ne fais plus de boucle pour calculer mais j'utilise une simple formule.
    Ca marche,
    Jc

  18. #18
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    J'ai ajouté un main et la boucle SDL. Aussi ajouté le zoom, c'était décidément trivial.

    C'est en bonne voie mais j'y retourne encore ce soir (j'éditerai ce post). Pas mal de commentaires à faire (les perfs ont parfois des comportements étranges) mais pas le temps avant ce soir.

    Note : le code pour limiter les fps était une idée en passant mais c'est en fait délicat à mettre en place alors il risque de sauter.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
     
    #include <stdlib.h>
    #include <math.h>
    #include "SDL/SDL.h"
     
    /* Ligne de compilation (je suis sous linux).
     * gcc -O3 -march=athlon64 roto.cpp -pthread `sdl-config --cflags --libs` -lGL -lGLU
     *
     * `sdl-config --cflags --libs` donne -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT -L/usr/lib -lSDL
     *
     * Spécifier l'architecture fait perdre en portabilité mais le gain de vitesse est énorme.
     * Toutes les optimisations du code devraient être faites avec le max d'optimisation du compilateur (-O3)
     * pour que les tests soient représentatifs.
     */
     
    #define PATH_IMAGE "Fond24.bmp"        /* chemin de l'image (bitmap) à faire tourner */
    #define FPS_DISP_RATE 2000             /* Temps en ms entre deux affichages des fps */
    #define VITESSE_ANGULAIRE M_PI / 10.0f /* Vitesse angulaire en radians par seconde*/
     
    /* Etat des touches du clavier. true pour enfoncée. */
    bool etatClavier[512];
     
    /* Fonction de copie de pixels pour ne pas trop dépendre du format de l'image */
    void inline SDL_CopyPixel(SDL_Surface* src, int x, int y, SDL_Surface* dest, int i, int j) {
    	int bpp = src->format->BytesPerPixel;
    	Uint8 *srcPixel = (Uint8 *)src->pixels + y * src->pitch + x * bpp;
    	Uint8 *destPixel = (Uint8 *)dest->pixels + j * dest->pitch + i * bpp;
     
    	switch(bpp) { 
    		case 1: 
    			*destPixel = *srcPixel; 
    			break; 
     
    		case 2: 
    			*(Uint16 *)destPixel = *(Uint16 *)srcPixel; 
    			break; 
     
    		case 3:
    			/* L'opération sur 24 bits est lente */
    			destPixel[0] = srcPixel[0];
    			destPixel[1] = srcPixel[1];
    			destPixel[2] = srcPixel[2];
    			break; 
     
    		case 4: 
    			*(Uint32 *)destPixel = *(Uint32 *)srcPixel; 
    			break; 
    	}  
    }
     
    /* Effectue une rotation centrale plus un changement d'échelle, alloue automatiquement la mémoire.
     * Le zoom est "gratuit". Prendre un rapport de 1 pour retrouver la rotation.
     * Les formules mathématiques sont ici appliqués "naïvement". Ce n'est pas l'idéal pour les performances
     * mais c'est simple et lisible. C'est un passage conseillé pour vérifier que la logique est bonne.
     * Si après en optimisant ça ne marche plus on saura pourquoi.
     */
    SDL_Surface* SDL_RotoZoom(SDL_Surface* origine, float angle_radian, float rapport) {
    	SDL_Surface* destination;     /* Surface de destination, allouée ici et retournée */
    	int mx, my, mxdest, mydest;   /* Coordonnées des centres des surfaces */
    	int i, j;                     /* Coordonnées de travail lors du parcourt de la surface de destination */
    	int bx, by;                   /* Coordonnées de travail, correspondent à i et j dans l'image d'origine */
    	float tcos, tsin;             /* cos et sin de angle_radian */
    	int largeurdest, hauteurdest; /* Dimentions de la surface de destination */
     
    	/*pour éviter pleins d'appels, on stocke les valeurs*/
    	tcos = cos(angle_radian);
    	tsin = sin(angle_radian);
     
    	/*calcul de la taille de l'image de destination*/
    	largeurdest= (int) ceil( (origine->w * fabs(tcos) + origine->h * fabs(tsin)) * rapport );
    	hauteurdest= (int) ceil( (origine->w * fabs(tsin) + origine->h * fabs(tcos)) * rapport );
     
    	/* 
    	* alloue la mémoire à l'espace de destination
    	*/
    	destination = SDL_CreateRGBSurface(SDL_HWSURFACE, largeurdest, hauteurdest, origine->format->BitsPerPixel,
    			origine->format->Rmask, origine->format->Gmask, origine->format->Bmask, origine->format->Amask);
     
    	/*on vérifie que la mémoire a été allouée*/
    	if(destination==NULL)
    		return NULL;
     
    	/*calcul des centres des images*/
    	mxdest = (int) destination->w/2;
    	mydest = (int) destination->h/2;
    	mx = (int) origine->w/2;
    	my = (int) origine->h/2;
     
    	/* Coeur de l'algo
    	 * On parcourt la surface de destination pour la remplir
    	 */
    	for(j=0; j<destination->h; j++)
    		for(i=0; i<destination->w; i++) {
    			/*
    			 * on détermine la valeur de pixel qui correspond le mieux pour la position
    			 * i,j de la surface de destination 
    			 *
    			 * on détermine la meilleure position sur la surface d'origine en appliquant
    			 * une matrice de rotation inverse
    			 */
    			bx = mx + (int)( ( tcos*(i-mxdest) + tsin*(j-mydest)) / rapport );
    			by = my + (int)( (-tsin*(i-mxdest) + tcos*(j-mydest)) / rapport );
    			/* on vérifie que l'on ne sort pas des bords */
    			if (bx>=0 && bx< origine->w && by>=0 && by< origine->h)
    				SDL_CopyPixel(origine, bx, by, destination, i, j);
    		}
     
    	return destination;
    }
     
    /* Le même en optimisé.
     * Les calculs peuvent être grandement simplifiés car d'une boucle à l'autre bx et by augmentent d'une valeur fixe. 
     * C'est l'optimisation la plus simple. Très intéressante car on ne perd rien en fonctionalité.
     */
    SDL_Surface* SDL_RotoZoom_Opt(SDL_Surface* origine, float angle_radian, float rapport) {
    	SDL_Surface* destination;     /* Surface de destination, allouée ici et retournée */
    	int mx, my, mxdest, mydest;   /* Coordonnées des centres des surfaces */
    	int i, j;                     /* Coordonnées de travail lors du parcourt de la surface de destination */
    	int bx, by;                   /* Coordonnées de travail, correspondent à i et j dans l'image d'origine */
    	float x, y;                   /* valeurs de travail (bx et by avant arrondit) */
    	float ligne_x, ligne_y;       /* valeurs au debut des lignes (retour de i à 0) */
    	float dxi, dyi, dxj, dyj;     /* increments des x et y suivant i et j (compteurs des x et y) */
    	float tcos, tsin;             /* cos et sin de angle_radian */
    	int largeurdest, hauteurdest; /* Dimentions de la surface de destination */
     
    	/*pour éviter pleins d'appel, on stocke les valeurs*/
    	tcos = cos(angle_radian);
    	tsin = sin(angle_radian);
     
    	/*calcul de la taille de l'image de destination*/
    	largeurdest= (int) ceil( (origine->w * fabs(tcos) + origine->h * fabs(tsin)) * rapport );
    	hauteurdest= (int) ceil( (origine->w * fabs(tsin) + origine->h * fabs(tcos)) * rapport );
     
    	/* 
    	* alloue la mémoire à l'espace de destination, attention, 
    	* la surface est de même taille
    	*/
    	destination = SDL_CreateRGBSurface(SDL_HWSURFACE, largeurdest, hauteurdest, origine->format->BitsPerPixel,
    			origine->format->Rmask, origine->format->Gmask, origine->format->Bmask, origine->format->Amask);
     
    	/*on vérifie que la mémoire a été allouée*/
    	if(destination==NULL)
    		return NULL;
     
    	/* calcul des centres des images */
    	mxdest = (int) destination->w/2;
    	mydest = (int) destination->h/2;
    	mx = (int) origine->w/2;
    	my = (int) origine->h/2;
     
    	/* Initialisation et calculs des incréments */
    	ligne_x = mx + (-tcos * mxdest - tsin * mydest) / rapport;
    	ligne_y = my + ( tsin * mxdest - tcos * mydest) / rapport;
    	dxi =  tcos / rapport;
    	dxj =  tsin / rapport;
    	dyi = -tsin / rapport;
    	dyj =  tcos / rapport;
     
    	/* Coeur de l'algo
    	 * On parcourt la surface de destination pour la remplir
    	 */
    	for(j=0;j<destination->h;j++){
    		x = ligne_x; 
    		y = ligne_y;
    		for(i=0;i<destination->w;i++) {
    			bx = (int) x;
    			by = (int) y;
    			/* on vérifie que l'on ne sort pas des bords*/
    			if (bx>=0 && bx< origine->w && by>=0 && by< origine->h)
    				SDL_CopyPixel(origine, bx, by, destination, i, j);
     
    			/* On incrémente les coordonnées dans l'image d'origine */
    			x += dxi;
       			y += dyi;
    		}
    		/* incrément pour le changement de ligne */
    		ligne_x += dxj;
    		ligne_y += dyj;
    	}
     
    	return destination;
    }
     
    /* Gestion des évènements SDL.
     * On se contente de tenir à jour le tableau des touches appuyées même si c'est peu utile ici.
     * On ferme sur un SDL_QUIT (arrive en cas de fermeture de la fenêtre par ex).
     */
    void GestionEvenements(void) {
    	SDL_Event e;
     
    	while (SDL_PollEvent(&e)) {
    		switch (e.type) {
    			case SDL_KEYUP:
    				etatClavier[e.key.keysym.sym]=false;
    				break;
     
    			case SDL_KEYDOWN:
    				etatClavier[e.key.keysym.sym]=true;
    				break;
     
    			case SDL_QUIT:
    				/* Dans l'absolu il faudrait libérer nos surfaces */
    				SDL_Quit();
    				exit(EXIT_SUCCESS);
     
    			default:
    				break;
    		}
    	}
    }
     
     
    int main(int argc, char* argv[])
    {
    	unsigned int currentFrm;
    	unsigned int lastFrm;
     
    	unsigned int lastFpsDisplay; /* instant du dernier affichage des fps */
     
    	float tempsEcoule = 0.0f;    /* temps écoulé depuis la dernière image, en secondes */ 
    	float fpsCounter = 0;        /* compteur des images affichées depuis le dernier calcul de fps */ 
    	float angle = 0.0f;          /* angle courrant pour la rotation (en radians) */ 
     
     
    	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)<0) {
    		exit(EXIT_FAILURE);
    	}
     
    	SDL_Surface* fenetre = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | /*SDL_FULLSCREEN |*/ SDL_DOUBLEBUF);
    	if (fenetre==NULL) {
    		SDL_Quit();
    		exit(EXIT_FAILURE);
    	}
     
    	/* Initialisation du clavier */
    	for(int i=0; i<512; i++)
    		etatClavier[i]=false;
     
    	/* Lecture de l'image que l'on va torturer */
    	SDL_Surface* imageOriginale = SDL_LoadBMP(PATH_IMAGE);
    	if (imageOriginale==NULL) {
    		SDL_Quit();
    		exit(EXIT_FAILURE);
    	}
     
    	/* Boucle principale */
    	currentFrm = SDL_GetTicks();
    	lastFrm = currentFrm;
    	lastFpsDisplay = currentFrm;
    	while (1) {
    		/* gestion du temps */
    		lastFrm = currentFrm;
    		currentFrm = SDL_GetTicks();
    		tempsEcoule = (currentFrm-lastFrm)/1000.0f;
     
    		/* Affichage du frame rate sur la console */
    		if(currentFrm-lastFpsDisplay>FPS_DISP_RATE) {
    			printf("%f\n", fpsCounter*1000.0f/(currentFrm-lastFpsDisplay));
    			lastFpsDisplay = currentFrm;
    			fpsCounter = 0;
    		}
     
    		GestionEvenements();
    		if(etatClavier[SDLK_ESCAPE]) {
    			/* On quitte sur "échap", avec un évènement SDL_QUIT lancé à la main
    			 * pour arriver au même point d'arrêt qu'avec la fermeture de la fenêtre par exemple.
    			 */
    			SDL_Event ev;
    			ev.type = SDL_QUIT;
    			SDL_PushEvent(&ev);
    		}
     
    		angle += VITESSE_ANGULAIRE * tempsEcoule;
    		if(angle>2*M_PI)
    			angle-=2*M_PI;
     
    		/* Effacer l'écran. Utiliser une couleur particulière permet de voir ce qui a été affiché et ce qui est vide */
    		SDL_FillRect(fenetre, NULL, 0x000f0fff);
     
    		SDL_Surface* surfRot = SDL_RotoZoom_Opt(imageOriginale, angle, 1.8);
    		SDL_BlitSurface(surfRot, NULL, fenetre, NULL);
    		SDL_FreeSurface(surfRot); /* Très très très important si on ne veut pas manger toute sa ram et plus en 2 minutes */
     
    		fpsCounter++;
    		SDL_Flip(fenetre);
    	}
     
    	/* Jamais atteint */
    	return EXIT_SUCCESS;
    }
    Edit: maj du code

  19. #19
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Aussi ajouté le zoom, c'était décidément trivial.
    Le zoom n'est pas si trivial que ça. Car il faut passer par la bijection inverse pour calculer les bonnes couleurs.

    En plus, pour déterminer la meilleur couleur, comme on travaille avec des coordonnées entières, il peut y avoir des recouvrements avec d'autres pixels (comme avec la rotation), ici, on prend simplement la partie entière, mais on pourrait calculer une meilleur couleur qui correspond au recouvrement.
    Par exemple si ça tombe 20% sur le pixel Nord Est, 10% sur le pixel Nord Ouest, 40% sur le Sud est et 30% sur le pixel Sud ouest, il serait peut être mieux de calcul la somme du rapport des couleurs de chaque pixel...


    Comme quoi, ce n'est pas si trivial que ça !
    Je ne répondrai à aucune question technique en privé

  20. #20
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    Citation Envoyé par millie
    Le zoom n'est pas si trivial que ça. Car il faut passer par la bijection inverse pour calculer les bonnes couleurs.
    Si on veut de la qualité avec interpolation/moyennage/tramage c'est de suite moins trivial et surtout en temps réel et en software. Je pense que la version basique ne mange pas de pain et est satisfaisante dans bien des cas. Après tout c'est avec ça qu'on a fait mario kart et toute la 3d (du moins pour les jeux) avant l'accélération matérielle.
    Mais c'est vrai que mon image de test avec ses traits blancs et fins sur fond noir ne rend pas du tout avec un rapport de 0,5.


    La rotation est vraiment lente sur 24bpp. Je dirais que ce mode est à fuir. 8bpp c'est bien mais comme on crée une nouvelle surface on perd la palette donc image toute noire (j'ai pas trouvé comment copier la palette proprement et rapidement, si qqn a une idée ça serait bien pratique).

    Inliner l'accès aux pixels à la main en supprimant le switch (donc bpp fixé) apporte un petit quelque-chose en 24bpp. En 8bpp c'est beaucoup plus sensible. Par contre parourir la surface avec un pointeur est moins intéressant (mais en 8bpp ça peut aider). En plus en 24bpp il y a un octet de bourrage en fin de ligne qui complique tout (m'aura fallut du temps pour le trouver celui-là). Bref, sauf 24bpp, se fixer sur un format de couleur apporte un bon plus.

    Je suis retourné sur la suppression des flottants. En 24bpp c'est 48fps qui passent à 52. Bof. Mais en 8bpp ça donne 84 au lieu de 74 (du 13% donc !). Comme quoi tout dépend du goulot d'étranglement. Je me demande si sur un pentium (ou plus vieux même) ça serait plus intéressant. Pas vital mais pas inintéressant alors je colle le code ici. C'est brut mais ça marche.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    SDL_Surface* SDL_RotoZoom_Opt(SDL_Surface* origine, float angle_radian, float rapport) {
    	SDL_Surface* destination;     /* Surface de destination, allouée ici et retournée */
    	int mx, my, mxdest, mydest;   /* Coordonnées des centres des surfaces */
    	int i, j;                     /* Coordonnées de travail lors du parcourt de la surface de destination */
    	unsigned int bx, by;                   /* Coordonnées de travail, correspondent à i et j dans l'image d'origine */
    	int x, y;                   /* valeurs de travail (bx et by avant arrondit */
    	int ligne_x, ligne_y;       /* valeurs au debut des lignes (retour de i à 0) */
    	int dxi, dyi, dxj, dyj;     /* increments des x et y suivant i et j (compteurs des x et y) */
    	float tcos, tsin;             /* cos et sin de angle_radian */
    	int largeurdest, hauteurdest; /* Dimentions de la surface de destination */
     
    	/*pour éviter pleins d'appel, on stocke les valeurs*/
    	tcos = cos(angle_radian);
    	tsin = sin(angle_radian);
     
    	/*calcul de la taille de l'image de destination*/
    	largeurdest= (int) ceil( (origine->w * fabs(tcos) + origine->h * fabs(tsin)) * rapport );
    	hauteurdest= (int) ceil( (origine->w * fabs(tsin) + origine->h * fabs(tcos)) * rapport );
     
    	/* 
    	* alloue la mémoire à l'espace de destination, attention, 
    	* la surface est de même taille
    	*/
    	destination = SDL_CreateRGBSurface(SDL_HWSURFACE, largeurdest, hauteurdest, origine->format->BitsPerPixel,
    			origine->format->Rmask, origine->format->Gmask, origine->format->Bmask, origine->format->Amask);
     
    	/*on vérifie que la mémoire a été allouée*/
    	if(destination==NULL)
    		return NULL;
     
    	/* calcul des centres des images */
    	mxdest = (int) destination->w/2;
    	mydest = (int) destination->h/2;
    	mx = (int) origine->w/2;
    	my = (int) origine->h/2;
     
    	/* Initialisation et calculs des incréments */
    	ligne_x = mx*65536 + (-tcos * mxdest - tsin * mydest) / rapport * 65536.0;
    	ligne_y = my*65536 + ( tsin * mxdest - tcos * mydest) / rapport * 65536.0;
    	dxi =  tcos / rapport * 65536.0;
    	dxj =  tsin / rapport * 65536.0;
    	dyi = -tsin / rapport * 65536.0;
    	dyj =  tcos / rapport * 65536.0;
     
    	/* Coeur de l'algo
    	 * On parcourt la surface de destination pour la remplir
    	 */
    	for(j=0;j<destination->h;j++){
    		x = ligne_x; 
    		y = ligne_y;
    		for(i=0;i<destination->w;i++) {
    			bx = ((unsigned int) x) >> 16;
    			by = ((unsigned int) y) >> 16;
    			/* on vérifie que l'on ne sort pas des bords*/
    			if (bx>=0 && bx< origine->w && by>=0 && by< origine->h)
    				SDL_CopyPixel(origine, bx, by, destination, i, j);
     
    			/* On incrémente les coordonnées dans l'image d'origine */
    			x += dxi;
       			y += dyi;
    		}
    		/* incrément pour le changement de ligne */
    		ligne_x += dxj;
    		ligne_y += dyj;
    	}
     
    	return destination;
    }
    Après la seule piste que je vois conciste à ne plus passer sur les pixels sans antécédant. Suivant l'angle il peut y en avoir beaucoup. C'est plus coton, plus compliqué et ça me fait encore un segfault (ça doit être l'heure) alors je crois que c'est facultatif... surtout que ça risque d'être plus lent.

    J'avais collé on petit bout de code pour limiter la vitesse d'affichage mais SDL_Delay n'est pas assez fin, et sans c'est moins utile. Et même là avoir le fps que l'on attent n'est pas évident (en clair mon code ne marche pas tout à fait ).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    while(FPS_LIMIT>0 && SDL_GetTicks()-lastFrm<1000/FPS_LIMIT)
    	{} //SDL_Delay(10);
    Voilà. S'il n'y avait pas ce problème de palette il y aurait moyen de faire une version spéciale 8bits avec entiers turbo-illisibles. Faudrait aussi voir le 32bits (quitte à ne pas se servir de la transparance) mais je crois qu'un simple bitmap ne peut pas. Mais ça peut peut-être en rester là.

    Dernières remarques :
    - Les rotations soft c'est bien mais si on en veut beaucoup c'est du précalculé dans les étapes d'animation des sprites (avec les gigas de ram de maintenant on peut y aller) ou openGL/D3D car même les machines actuelles ont leurs limites... Enfin 60 images sur une rotation en 800*600 sans assembleur c'est déjà pas trop mal.
    - Pour tester la vitesse de rendu mieux vaut figer l'angle... mais pas sur 0 pour éviter que le compilo optimise trop de choses. Bref prudence.
    - Faire les tests plusieurs fois car il peut y avoir des variations sensibles et durables d'une éxécution à l'autre (ce qui donne des résultats curieux).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 03/05/2006, 15h33
  2. Comment programmer une mise à jour ?
    Par qnop dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 4
    Dernier message: 15/03/2006, 16h33
  3. Comment faire une rotation de metafile (l'angle de 90° me suffit) ?
    Par Tardiff Jean-François dans le forum Langage
    Réponses: 4
    Dernier message: 28/01/2005, 08h58
  4. comment programmer une progressbar
    Par Choucas dans le forum Paradox
    Réponses: 3
    Dernier message: 13/11/2002, 11h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo