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

GLUT Discussion :

Pression de 2 touches clavier


Sujet :

GLUT

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut Pression de 2 touches clavier
    Bonjour,

    Je souhaiterais savoir comment gérer avec glut la pression simultanée de 2 touches clavier (par exemple gauche et haut).

    Merci d'avance.

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 8
    Par défaut .
    Je propose cette solution :

    bool keys[256];

    // Fonction callback appelée lorsqu'une touche est pressée (key contient le code de cette touche)
    processSpecialKeysPressing(int key,int x,int y)
    {
    switch(key)
    {
    case GLUT_KEY_UP:keys[0]=true;break;
    case GLUT_KEY_RIGHT:keys[1]=true;break;
    // etc...
    }
    }

    processSpecialKeysReleasing(int key,int x,int y)
    {
    switch(key)
    {
    case GLUT_KEY_UP:keys[0]=false;break;
    case GLUT_KEY_RIGHT:keys[1]=false;break;
    // etc...
    }
    }

    int main(int argc,char** argv)
    {
    for(int i=0;i<256;i++)keys[i]=false;
    glutInit(argc,argv);
    glutSpecialUpFunc(processSpecialKeysPressing);
    glutSpecialDownFunc(processSpecialKeysReleasing);
    glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
    // ...
    }

    Ce qui permet de mettre a jour constamment un tableau de booléens indiquant si telle ou telle touche est pressée.
    Plus tard dans le code tu pourras en tirer parti de la sorte :

    if(keys[0] and keys[1])
    {
    // les touches haut et droites sont pressées.
    }

    N'oublie pas de définir des constantes symboliques plus parlante que 0 et 1 pour indiquer l'index dans le tableau de booléen de tel ou tel état.

    #define UP 0x00
    #define RIGHT 0x01

    etc...

    keys[UP] etc...

    Et n'oublie pas de placer cette cette ligne :
    glutSetKeyRepeat(GLUT_KEY_REPEAT_ON);
    avant de quitter ton programme

    Voilà, bonne chance

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut
    Oh, merci beaucoup pour ta réponse ! C'est super, je vais tester ça ...

    J'ai quelques petites questions :

    Pourquoi tu utilises des valeurs en hexa genre 0x01 ?
    A quoi sert glutSetKeyRepeat(GLUT_KEY_REPEAT_ON); ?

    Merci encore.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 8
    Par défaut .
    Pourquoi tu utilises des valeurs en hexa genre 0x01 ?
    Comme ça ! Pourquoi, t'aimes pas l'hexa ?

    A quoi sert glutSetKeyRepeat(GLUT_KEY_REPEAT_ON);
    A réautoriser l'API de l'OS de destination (soit X11, soit Windows) à notifier plusieurs fois en continu l'évènement "une touche du clavier a été pressée".
    Dans un logiciel comme le Bloc Notes de windows, lorsque tu appuis sur une touche, un message est envoyé à l'application qui le traite en affichant un caractère par exemple.
    Si tu maintiens ton doigt sur cette touche, il se passe environ une seconde de "vide" vis a vis des évènements claviers, puis soudain plusieurs messages sont envoyés a la suite jusqu'a ce que tu relàches la touche, provoquant l'affichage rapide de plusieurs caractères identiques.
    Ce comportement n'est pas souhaitable dans une application OpenGL, sauf si tu réalises un logiciel de traitement de texte en 3D mais bon, l'intérêt est limité
    Donc on commence par demander a glut au début de notre prog d'arrêter cette répétition des messages intempestives, et a la fin on réautorise ce comportement. (C'est important car sinon ton programme modifiera le mode de gestion des évènements claviers de TOUT ton ordi ! Pour revenir a la normale il faudra rebooter... (ou exécuté un programme qui contient un équivalent de glutSetKeyRepeat(GLUT_KEY_REPEAT_ON); )).

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut
    Oh oh ok ! Merci encore pour tes explications. Pour ce qui est de l'hexa, j'aurais pensé que mettre un entier aurait été identique ...

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut
    Bonjour, suite à ton aide pour la gestion du clavier, qui marche très bien, j'ai une petite question d'utilisation. En effet, je fait un if(keys[3]) {} par exemple, mais je le fais dans la fonction de call-back pour l´affichage dans la fenêtre.

    Or cette fonction n'est appellée qu'à chaque fois qu'on demande une réactualisation d'image. Je me suis donc dit qu'il fallait que je réactualise en boucle ma scène. C'est extra fluide en mettant un glutPostRedisplay(); après le glutSwapBuffers();.

    Cependant, mon processeur est utilisé à 100%, c'est assez logique. Je suppose que, dans les jeux, l'image est elle aussi réactualisée en permanence, mais je ne crois pas que les jeux prennent 100% du CPU. Je pense mettre un simple Sleep() avant le glutPostRedisplay(); et je voulais savoir si c'était la meilleur manière où s'il y a mieux.

    Merci encore pour ton aide.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 8
    Par défaut .
    Pour ce qui est de l'hexa, j'aurais pensé que mettre un entier aurait été identique ...
    Ca l'est. C'est juste pour aligné proprement la déclaration de constantes connues a la compilation.

    Or cette fonction n'est appellée qu'à chaque fois qu'on demande une réactualisation d'image. Je me suis donc dit qu'il fallait que je réactualise en boucle ma scène. C'est extra fluide en mettant un glutPostRedisplay(); après le glutSwapBuffers();.
    Oui, les jeux sont faits avec des langages réputés rapide a l'exécution car ils doivent en permanence redessiner le "monde" à l'écran, c'est ce que l'on appelle FPS (frames per second), plus le nombre de fps est grand, plus l'animation est fluide.
    Tu dois mettre tout le code de dessin d'OpenGL dans ta fonction glutDisplayFunc, donc éventuellement des tas de tests pour savoir quoi dessiner a chaque moment du jeu... (C'est trés brouillon, le but d'un moteur de jeu est de faciliter cet aspect notamment, en demandant a chaque entité du jeu d'exécuter son propre code d'affichage par exemple, enfin là c'est un autre sujet...).
    Cette fonction doit se terminer par un glutSwapBuffers (si tu est en GLUT_DOUBLE evidemment).
    Il est inutile de mettre un glutPostRedisplay a la suite.
    Cette fonction a pour but de forcer l'exécution du code de ta fonction display, mais en le faisant plus proprement (sinon tu pourrais l'appeler telle quelle dans le code).
    Le glutPostRedisplay doit être placé a la fin de ta boucle principale, cad a la fin de glutIdleFunc
    A ce propos je te conseille d'abandonner glut qui est une API vieillissante est limité, au profit d'une implémentation OpenSource de glut (FreeGlut, OpenGlut, etc...) mise a jour plus souvent, rétrocompatible avec glut et offrant de nouvelles fonctions intéressantes (comme le controle de la boucle principal, la possibilité de sortir proprement de glut, etc...)

    Cependant, mon processeur est utilisé à 100%, c'est assez logique. Je suppose que, dans les jeux, l'image est elle aussi réactualisée en permanence, mais je ne crois pas que les jeux prennent 100% du CPU. Je pense mettre un simple Sleep() avant le glutPostRedisplay(); et je voulais savoir si c'était la meilleur manière où s'il y a mieux.
    Alors là ça dépend... les jeux de dernières générations sur des PC de dernières générations ne prennent pas tout le CPU mais pas loin...
    Ca dépend de ce que tu veux faire toi, faire mumuse avec un cube ?
    Faire un jeu en 2D ? Faire un jeu en 3D avec un gameplay orienté 2D ? Faire ton propre moteur 3D ?
    Chacun de ses objectifs prend plus ou moins de CPU, étant donné un PC pas trop pourri.
    La meilleure solution pour gérer le framerate consiste a faire un sleep (enfin encore que, sleep prend un argument exprimé en secondes alors tu vas pas allez loin, vise plutôt du côté de nanosleep, toujours dans time.h).
    Mais l'argument du sleep ne doit surtout pas être une constante, sinon le jeu ira a vitesse normale sur ton PC (car tu règleras a ta convenance) et ira pas assez vite sur un vieux PC, et trop vite sur un super PC.
    Il faut calculer cet argument en fonction du temps que met le programme a effectuer un tour de boucle principal de ton jeu.
    Conseil : utilise glutGet(GLUT_ELAPSED_TIME);

    A+

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut
    Intéressant ! J'en apprend pas mal la.

    En fait, il me faut faire en tant que projet "étudiant" une balade dans un batiment 3D, un doom like en gros.

    J'ai compris (ou je crois avoir compris) que l'idleFunc fonctionne uniquement si le PC ne rame pas ...

    Pour ce qui est de faire des Sleep, je ne sais pas trop comment faire, mais pour l'instant, j'ai juste fait ça pour obtenir les fps et réactualiser l'image uniquement si le CPU n'a pas de mal :

    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
     
    // fonction de call-back qui tourne en tache de fond
    // lorsqu'il n'y a pas d'autre tache à executer
    GLvoid window_idle()
    {
    	// les calculs de position, les déplacements
    	// sont effectués, mais on met à jour uniquement
    	// lorsqu'on passe dans cette boucle, c'est à dire quand
    	// on a de la puissance pour effectuer le rendering de l'image
    	frame++;
    	temps = glutGet(GLUT_ELAPSED_TIME);
    	if (temps - tempsold > 1000)
    	{
    		fps = (frame*1000.0)/(temps-tempsold);
    		printf("FPS : %f et temps mis par 1000 boucles : %d\n",fps,temps-tempsold);
    		//Sleep((temps-tempsold)/50); // paramètre en millisecondes
    	 	tempsold = temps;		
    		frame = 0;
    	}
    	glutPostRedisplay(); // on est en tache de fond, donc ça ne rame pas on peut réactualiser
    }

  9. #9
    Membre averti
    Inscrit en
    Mars 2005
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 40
    Par défaut
    AH moi suite a ce post j'ai une question vraiment bete,
    j'ai meme honte de la poser, mais il le faut :

    pour la fonction keyboard habituelle, on l'active avec
    glutKeyboardFunc(keyboard);

    mais pour tes fonctions spéciale :
    processSpecialKeysReleasing(int key,int x,int y)
    et
    processSpecialKeysPressing(int key,int x,int y)

    on les actives comment?????

    ah ces debutants en openGL franchement ils ont de ces Questions.....

    merci de me repondre quand ca me soulagerai.....

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut
    pour la fonction keyboard habituelle, on l'active avec
    glutKeyboardFunc(keyboard);

    mais pour tes fonctions spéciale :
    processSpecialKeysReleasing(int key,int x,int y)
    et
    processSpecialKeysPressing(int key,int x,int y)
    En fait, les 2 fonctions sont glutSpecialFunc(&tafonctionquivabien) et glutSpecialUpFunc(&tafonctionquivabien)

    Au moins j'aurais pu repondre a une question .

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 8
    Par défaut .
    En fait, il me faut faire en tant que projet "étudiant" une balade dans un batiment 3D, un doom like en gros.
    Huh ? Quel niveau d'étude, quelle école ... ?

    J'ai compris (ou je crois avoir compris) que l'idleFunc fonctionne uniquement si le PC ne rame pas ...
    L'idle func est une fonction exécutée en continue, quand l'application n'est pas occupé a géré les évènements ou le réaffichage, c'est une sorte de boucle principale si tu veux. Mais ne t'inquiètes pas, ça n'existe plus depuis longtemps les PCs qui n'auraient même pas le temps de gérer une dizaine d'appels a l'idleFunc par seconde, et heureusement !

    Ta boucle principale doit contenir le code du moteur (le calcul des nouvelles positions des objets, etc...) puis un glutPostRedisplay, et enfin une fonction destinée a ralentir les PCs trop puissants.
    Si par exemple tu as choisi une vitesse de 50 FPS, ce qui signifie que idéalement le PC doit mettre 20 miliseconde a effectuer un tour de ta boucle principale (une exécution du code contenu dans idleFunc), et que ce dernier ne met que 15 milisecondes, il faut lui dire d'attendre 5 milisecondes, temps pendant lequel il pourra se consacrer aux autres processus.
    Le calcul de cette fonction de gestion de l'attente est assez simple
    Pour l'affichage des FPS dans la console par exemple, il faut placer cette fonction dans la boucle principale également, voici le code que j'utilise :

    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
     
    void gmlApplication::displayFPS()const
    {
      static uInt32 currentTime=0;
      static uInt32 timeBase=0;
      static uInt16 frame=0;
      static char s[30];
      frame++;
      currentTime=getElapsedTime();
      if(currentTime-timeBase>1000)
      {
        std::sprintf(s,"FPS:%4.2f",frame*1000.0/(currentTime-timeBase));
        timeBase=currentTime;
        frame=0;
        std::cout<<s<<std::endl;
      }
    }
    La fonction getElapsedTime me renvoie le nombre de ms écoulées depuis le lancement du programme (elle est équivalente a glutGet(GLUT_ELAPSED_TIME); )

    Voilà, A++

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut
    Pour les études, je suis en licence informatique, en région parsiennne.

    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
     
    GLvoid window_idle()
    {
    	// les calculs de position, les déplacements
    	// sont effectués, mais on met à jour uniquement
    	// lorsqu'on passe dans cette boucle, c'est à dire quand
    	// on a de la puissance pour effectuer le rendering de l'image
    	frame++;
    	temps = glutGet(GLUT_ELAPSED_TIME);
    	if (temps - tempsold > 1000)
    	{
    		fps = (frame*1000.0)/(temps-tempsold);
     
            printf("FPS : %f et Temps mis par 1 boucle : %f et pause :%f\n",fps,((float)(temps-tempsold)/1000),20-((float)(temps-tempsold))/1000);
     
            // temps mis par 1000 boucles : temps-tempsold
    		// temps mis par une boucle : (temps-tempsold)/1000
     
    		// si on choisi une vitesse de 50 FPS, soit 20 ms pour une boucle (une image)
    		// si le temps mis par une boucle est de 15ms par
    		// exemple, on va faire une pause de 5 ms
    		Sleep((int)(20-((float)(temps-tempsold))/1000)); // paramètre en millisecondes
     
     
    		//Sleep((temps-tempsold)/50); 
    	 	tempsold = temps;		
    		frame = 0;
    	}
    	glutPostRedisplay(); // on est en tache de fond, donc ça ne rame pas, on peut réactualiser
    }
    Voici en gros les affichages que j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FPS : 57 et Temps mis par 1 boucle : 1.016 et pause : 18.98
    Ca parrait correct. Le problème, c'est que mon microprocesseur est toujours utilisé à fond :S

  13. #13
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 93
    Par défaut
    J'ai trouvé, il fallait faire le sleep en dehors du if, en effet, au lieu de faire une pause avant chaque réactualisation d'image, je ne le faisais que toutes les 1000 images ...

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

Discussions similaires

  1. [CS3] Double pression touche clavier key.isDown, course du sprite
    Par funkyshaolin dans le forum Flash
    Réponses: 0
    Dernier message: 04/01/2011, 13h52
  2. Réponses: 3
    Dernier message: 03/06/2006, 16h59
  3. [VBA]Faire une pause jusqu'à pression d'1 touche clavier
    Par mainecoon dans le forum Général VBA
    Réponses: 23
    Dernier message: 22/01/2006, 18h08
  4. Simuler un e pression sur une touche du clavier
    Par Furius dans le forum VBScript
    Réponses: 13
    Dernier message: 11/12/2005, 17h53
  5. envoie de touche clavier
    Par psfox2001 dans le forum DirectX
    Réponses: 1
    Dernier message: 13/03/2003, 21h56

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