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

Découvrez OpenGL 1.1 en VB6/VBA

Image non disponible


précédentsommairesuivant

VIII. Mise à jour régulière de l'image : le frame rate

Pour l'instant, la fenêtre n'est mise à jour que lorsqu'il y en a besoin.
C'est-à-dire lorsque la fenêtre est masquée puis réaffichée, ou lorsqu'elle est redimensionnée…

Souvent nous souhaitons afficher l'image à une certaine fréquence, car elle est en mouvement, pour un jeu par exemple.

C'est ce que nous allons faire, en suivant deux méthodes.

VIII-A. La procédure de rappel « Idle »

Cette méthode consomme beaucoup de CPU, car la procédure de rappel est sans cesse appelée.

Préférez la méthode suivante avec un Timer.

Glut nous met à disposition une procédure de rappel « Idle ».
Cette fonction est appelée sans cesse par la boucle de freeGLUT lorsque l'application est libre, c'est-à-dire qu'aucun événement n'est en attente.

Ajoutez une procédure CallBackIdle.

Procédure de rappel attente
Sélectionnez
Public Sub CallBackIdle()
            
End Sub

Et définissez cette procédure dans freeGLUT avant l’appel à glutMainLoop.

Définition dans freeGLUT de la fonction d'attente
Sélectionnez
' Fonction d'attente
glutIdleFunc AddressOf CallBackIdle

On peut grâce à la fonction glutGet(GLUT_ELAPSED_TIME) lire le temps écoulé en millisecondes depuis l'initialisation de freeGLUT (fonction glutInit).
On va définir une variable qui sera le temps écoulé qui déterminera la prochaine mise à jour : gWaitTime.

En en-tête de module
Sélectionnez
' Temps à attendre pour le prochain affichage
Private gWaitTime As Long

Ce temps est initialisé dans la fonction InitScene :

Initialisation du temps d'attente
Sélectionnez
Public Sub InitScene()
' Initialisation du temps déclencheur de l'affichage
gWaitTime = glutGet(GLUT_ELAPSED_TIME)
End Sub

Et enfin dans la fonction d'attente CallBackIdle, on vérifie si on a atteint ce temps.
Si c'est le cas, on déclenche un affichage avec glutPostRedisplay et on décale le temps d'attente.

Attente avant affichage
Sélectionnez
Public Sub CallBackIdle()
    Dim lTimer As Long
    ' Temps présent
    lTimer = glutGet(GLUT_ELAPSED_TIME)
    ' Si temps présent >= au temps attendu
    If lTimer >= gWaitTime Then
        ' Rafraichir l'affichage
        glutPostRedisplay
        ' n affichages par seconde
        gWaitTime = lTimer + (1000 / 50)
    End If
End Sub

1000 / 50 correspond à une attente de 1000/50 = 20 millisecondes.
On obtient alors un affichage de 50 images par seconde.

VIII-B. La procédure de rappel « Timer »

Glut nous met à disposition une procédure de rappel « Timer ».
Cette fonction est appelée après un temps écoulé en millisecondes.

Ajoutez une procédure CallBackTimer.

Procédure de rappel attente
Sélectionnez
' Fonction d'attente
Public Sub CallBackTimer(ByVal value As Long)
            
End Sub

Et définissez cette procédure dans freeGLUT avant l’appel à glutMainLoop.

Définition dans freeGLUT de la fonction d'attente
Sélectionnez
' Fonction d'attente
glutTimerFunc 1000 / 50, AddressOf CallBackTimer, 0

1000 / 50 correspond à une attente de 1000/50 = 20 millisecondes.
On obtient alors un affichage de 50 images par seconde.

Et enfin dans la fonction d'attente CallBackTimer, on relance un Timer et on déclenche un affichage avec glutPostRedisplay.

Attente avant affichage
Sélectionnez
' Fonction d'attente
Public Sub CallBackTimer(ByVal value As Long)
' Rappel de la fonction d'attente
glutTimerFunc 1000 / 50, AddressOf CallBackTimer, 0
' Rafraichir l'affichage si une fenêtre openGL est active
If glutGetWindow <> 0 Then glutPostRedisplay
End Sub

Pensez à bien vérifier qu’une fenêtre OpenGL est active avant d’exécuter glutPostRedisplay sinon l’application risque de planter à la fermeture de la fenêtre, le Timer pouvant se déclencher après destruction de la fenêtre.

VIII-C. Affichage du frame rate

Pour s'assurer que le frame rate correspond à ce qu'on attend, et pour éventuellement tester les performances de notre programme, nous allons afficher le frame rate réel dans la barre de titre de la fenêtre.

Ajoutons deux variables pour le calcul du frame rate :

En en-tête de module
Sélectionnez
' Temps écoulé pour calcul du frame rate
Private gElapsedTime As Long
' Nombre d'affichages pour calcul du frame rate
Private gDisplayCount As Long

Puis on calcule le frame rate = nombre d'images affichées / temps écoulé en seconde.

A la fin de la procédure CallBackDraw :

Calcul et affichage du frame rate
Sélectionnez
' Calcul et affichage du frame rate
gDisplayCount = gDisplayCount + 1
If gDisplayCount = 100 Then
    glutSetWindowTitle "Frame rate : " & format(gDisplayCount / (glutGet(GLUT_ELAPSED_TIME) - gElapsedTime) * 1000, "0,0")
    gDisplayCount = 0
    gElapsedTime = glutGet(GLUT_ELAPSED_TIME)
End If

On ne fait cette opération que toutes les 100 images par exemple.

Le nombre d'images par seconde s'affiche maintenant dans la barre de titre :

Image non disponible

IX. Mise en scène

IX-A. Les axes

Il y a bien entendu trois axes pour dessiner une scène en trois dimensions, nommés X, Y et Z.
Par défaut, l'axe X est l'axe horizontal, l'axe Y est l'axe vertical, et l'axe Z est l'axe de profondeur.

L'origine du repère est au centre de la scène.
Les bords droit et haut correspondent à une valeur de 1.
Les bords gauche et bas correspondent à une valeur de -1.
L'axe de profondeur Z est orienté de manière à ce que les valeurs positives partent vers l'avant de l'écran.

Image non disponible

Pour mieux visualiser ce que nous réalisons, nous allons créer un cube à la place du triangle.
Pour dessiner un cube, on peut créer les six faces comme six quads.
On donne à chaque face du cube une couleur différente.

Remplacez le code de dessin du triangle par celui du cube :

Dessin d'un cube
Sélectionnez
' Début de la primitive pour le cube
glBegin GL_QUADS
    ' Face du haut = vert
    Call glColor3d(0, 1, 0)
    Call glVertex3d(1, 1, -1)
    Call glVertex3d(-1, 1, -1)
    Call glVertex3d(-1, 1, 1)
    Call glVertex3d(1, 1, 1)
    ' Face du bas = orange
    Call glColor3d(1, 0.5, 0)
    Call glVertex3f(-1, -1, -1)
    Call glVertex3f(1, -1, -1)
    Call glVertex3f(1, -1, 1)
    Call glVertex3f(-1, -1, 1)
    ' Face de derrière = rouge
    Call glColor3d(1, 0, 0)
    Call glVertex3f(1, -1, -1)
    Call glVertex3f(-1, -1, -1)
    Call glVertex3f(-1, 1, -1)
    Call glVertex3f(1, 1, -1)
    ' Face de devant = jaune
    Call glColor3d(1, 1, 0)
    Call glVertex3f(-1, -1, 1)
    Call glVertex3f(1, -1, 1)
    Call glVertex3f(1, 1, 1)
    Call glVertex3f(-1, 1, 1)
    ' Face de gauche = violet
    Call glColor3d(1, 0, 1)
    Call glVertex3f(-1, 1, 1)
    Call glVertex3f(-1, 1, -1)
    Call glVertex3f(-1, -1, -1)
    Call glVertex3f(-1, -1, 1)
    ' Face de droite = bleu
    Call glColor3d(0, 0, 1)
    Call glVertex3f(1, 1, -1)
    Call glVertex3f(1, 1, 1)
    Call glVertex3f(1, -1, 1)
    Call glVertex3f(1, -1, -1)
glEnd

Évitez l'utilisation de GL_QUADS si vous recherchez la performance.
Utiliser des triangles est plus rapide, car les cartes graphiques travaillent à base de triangles.

Exécutez la fonction FonctionOpenGL.
On voit alors la face avant jaune qui remplit la fenêtre.

Image non disponible

IX-B. Les matrices de transformations

Il existe trois matrices dans OpenGL.
Nous passons d'une matrice à une autre avec la fonction glMatrixMode.

  • GL_PROJECTION est la matrice de projection : elle détermine la position de la caméra et la manière dont est projeté l'environnement 3D sur la fenêtre 2D.
  • GL_MODELVIEW est la matrice de modélisation-visualisation : elle permet de transformer les vertices en leur appliquant une rotation, translation, mise à l'échelle.
  • GL_TEXTURE est la matrice de texture : elle permet d'appliquer des transformations aux textures.

Par défaut la matrice active est la matrice de modélisation-visualisation.

Notez que les transformations appliquées à une matrice se cumulent.
Il est nécessaire lorsqu'on effectue une transformation :

  • soit de charger la matrice identité (la matrice par défaut qui ne correspond à aucune transformation) avec la fonction glLoadIdentity ;
  • soit de sauvegarder et restaurer la matrice avec les fonctions glPushMatrix et glPopMatrix.

Sinon chaque transformation se cumule avec la précédente.

Nous allons détailler ensuite l'utilisation de ces fonctions.

Pour modifier ces matrices, le plus simple est d'utiliser les fonctions :

  • glRotate* pour la rotation ;
  • glTranslate* pour la translation ;
  • glScale* pour la mise à l'échelle.

La fonction glLoadIdentity réinitialise la matrice.

Lorsqu'on souhaite appliquer une transformation à un objet uniquement, on utilise les fonctions :

  • glPushMatrix pour sauvegarder la matrice courante ;
  • glPopMatrix pour la restaurer.

IX-B-1. Les projections

Il y a deux types de projections disponibles :

  • la projection en perspective : utilisée pour le rendu d'une scène en trois dimensions.
    Dans cette projection, les objets sont affichés tels qu'on les verrait dans le monde réel, les objets plus lointains apparaissant plus petits ;
  • la projection orthonormée : souvent utilisée pour un rendu 2D.
    Dans cette projection, les objets ont la même taille, quelle que soit leur distance par rapport au point d'observation.

Attention : les paramètres de profondeur des projections ne sont pas définis sur l'axe Z, mais sur l'axe de visualisation de la scène.
C'est-à-dire l'axe qui passe par le point d'observation (caméra) et le centre de la scène.
Nous définirons cet axe juste après.

IX-B-1-a. La projection en perspective

Pour définir cette projection, on a à notre disposition la fonction OpenGL glFrustum.

Nous disposons également de sa petite sœur gluPerspective de la bibliothèque glu.
gluPerspective appelle la fonction glFrustum.

On peut donc réaliser les mêmes projections avec ces deux fonctions.

Image non disponible   Perspective avec glFrustum :

Image non disponible

Image non disponible   Perspective avec gluPerspective :

Image non disponible

Le volume visible de la scène est une pyramide tronquée délimitée par les deux plans de couleur bleu clair.

IX-B-1-b. La projection orthonormée

Pour cette projection, il faut utiliser la fonction glOrtho.

On définit un plan à travers lequel on voit la scène, puis les valeurs minimum et maximum de profondeur.

Image non disponible   Projection orthonormée avec glOrtho :

Image non disponible

Le volume visible de la scène est un pavé délimité par les deux plans de couleur bleu clair.

IX-C. La caméra

Il nous reste un point important : l'observateur de la scène.
La fonction gluLookAt nous permet de le définir.

La fonction gluLookAt demande neuf paramètres :

  • trois pour la position de la caméra : eyex, eyey et eysez ;
  • trois pour le point de visée : centerx, centery et centerz ;
  • et trois pour l'orientation de l'axe vertical : upx, upy et upz.

Par défaut la caméra est située à une distance de 1 sur l'axe Z et on regarde vers l'origine (de coordonnées 0, 0, 0).

IX-D. Définition de la projection et de la caméra

Nous allons redéfinir la projection et la position de la caméra pour prendre du recul et voir le cube en entier.

Au début de la fonction de rendu Render :

Projection et position de la caméra
Sélectionnez
' Passage en matrice de projection
glMatrixMode GL_PROJECTION
' Initialisation de la matrice
glLoadIdentity
' Définition de la perspective
gluPerspective 45, 1, 0.1, 100
' Passage en matrice de modélisation-visualisation
glMatrixMode GL_MODELVIEW
' Initialisation de la matrice
glLoadIdentity
' Position de la caméra
gluLookAt 0, 0, 10, 0, 0, 0, 0, 1, 0

Image non disponible   Pour la projection :

  • on a défini un angle de visualisation de 45° ;
  • l'aspect est de 1, c'est-à-dire que les plans utilisés pour la projection sont des carrés (sinon le cube serait aplati) ;
  • les plans sont placés à 0.1 et 100, c'est-à-dire qu'on verra les points situés entre 0.1 et 100 par rapport à la position de la caméra.

Évitez une valeur de zNear égale à 0 : placer le premier plan sur la caméra mène souvent à un affichage incorrect.

Image non disponible   Pour la caméra :

  • on se positionne à 10 sur l'axe des Z pour prendre un peu de recul (0, 10, 0) ;
  • on regarde vers l'origine (0, 0, 0) ;
  • l'axe vertical est l'axe Y (0, 1, 0).

Voici notre cube :

Image non disponible

On voit les faces de côté, ce qui n'est pas normal.

Faisons effectuer une rotation au cube pour y voir plus clair.

Avant le glBegin GL_QUADS, ajoutez :

Rotation du cube
Sélectionnez
' Sauvegarde la matrice
glPushMatrix
' Rotation du cube
glRotated 30, 1, 1, 1

Et après le glEnd, ajoutez :

Rotation du cube
Sélectionnez
' Restaure la matrice
glPopMatrix

Notez que l'appel aux fonctions glPushMatrix et glPopMatrix n’est pas indispensable ici, on n'affiche qu'un objet.
Il le deviendrait si on effectuait, après le cube, le dessin d'autres objets.

La fonction glRotated tourne notre cube de 30° autour d'un axe dont :

  • les coordonnées du premier point sont celles de l'origine (0, 0, 0) ;
  • les coordonnées du deuxième point sont (1, 1, 1).

En fait la rotation du cube se cumule avec la matrice de modélisation-visualisation définie par gluLookAt.

Exécutez la fonction FonctionOpenGL : vous voyez le cube légèrement tourné :

Image non disponible

Par la même occasion, on constate des problèmes d'affichage de polygones.
On ne devrait pas voir la face arrière rouge ni la face droite bleue.
En fait les polygones ont été dessinés dans l'ordre qu'on a donné lors du dessin du cube, sans se soucier de leur profondeur.

Pour corriger cela, il faut activer la fonction de test de profondeur.

Dans la fonction InitScene, ajoutez :

Tests de profondeur
Sélectionnez
' Tests de profondeur
glEnable GL_DEPTH_TEST
glDepthFunc GL_LEQUAL

glEnable GL_DEPTH_TEST active les tests de profondeur.
glDepthFunc définit le type de test à effectuer : GL_LEQUAL étant souvent un bon compromis qualité/vitesse.

Testons à nouveau l'affichage :

Image non disponible

L'affichage du cube est maintenant correct.

IX-E. Cadrer l'image dans la fenêtre

Par défaut, l'image occupe toute la fenêtre.
Vous pouvez modifier la position et la taille de l'image avec la fonction glViewport.
La fonction de rappel glutReshapeFunc est utile, car elle nous donne la taille de la fenêtre.
On peut également lire la taille de la fenêtre avec glutGet(GLUT_WINDOW_WIDTH) et glutGet(GLUT_WINDOW_HEIGHT).

Il est alors possible de dessiner plusieurs scènes dans la même fenêtre.
Il suffit d'appeler glViewport entre chaque scène pour la positionner.

Attention : il ne faut par contre qu'un seul appel à glClear pour l'ensemble des scènes.

X. Gestion des entrées clavier et souris : Rotation et Zoom de la scène

Nous allons utiliser :

  • la molette de la souris pour zoomer ou dézoomer ;
  • les touches fléchées du clavier pour tourner autour du cube (ce sont des touches « spéciales »).

Définissons dans la fonction FonctionOpenGL les fonctions de rappel souris et clavier.

Au même endroit que les autres définitions de rappel (glutDisplayFunc et glutTimerFunc) :

Fonctions de rappel souris et clavier
Sélectionnez
' Fonctions de rappel clavier
glutSpecialFunc AddressOf CallBackSpecial
' Fonction de rappel molette de souris
glutMouseWheelFunc AddressOf CallBackMouseWheel

Définissons également des variables pour conserver les valeurs de zoom et de rotation.

En en-tête de module
Sélectionnez
' RotationX
Private gRotateX As Double
' RotationY
Private gRotateY As Double
' Zoom
Private gZoom As Double

On tournera :

  • autour de l'axe Y avec les flèches droite et gauche ;
  • et autour de l'axe X avec les flèches haut et bas.

Initialisons ces variables dans la procédure InitScene :

Initialisation des variables de visualisation
Sélectionnez
' Initialisation des variables de visualisation
gRotateX = 0
gRotateY = 0
gZoom  = 10

Ensuite on gère les fonctions de rappel pour mettre à jour ces variables en fonctions des actions effectuées :

Gestion du clavier
Sélectionnez
' Gestion du clavier 
Public Sub CallBackSpecial(ByVal key As Long, ByVal x As Long, ByVal y As Long)
Select Case key
    Case GLUT_KEY_LEFT
        gRotateY = gRotateY - 10
    Case GLUT_KEY_RIGHT
        gRotateY = gRotateY + 10
    Case GLUT_KEY_UP
        gRotateX = gRotateX - 10
    Case GLUT_KEY_DOWN
        gRotateX = gRotateX + 10
End Select
End Sub
Gestion de la molette de la souris
Sélectionnez
' Gestion de la molette de la souris 
Public Sub CallBackMouseWheel(ByVal wheel As Long, ByVal direction As Long, ByVal x As Long, ByVal y As Long)
gZoom = gZoom + direction
End Sub

Il faut enfin utiliser ces variables pour mettre à jour la caméra :

  • pour le zoom c'est facile : il suffit de remplacer le 10 par gZoom dans l'appel à gluLookat.
    Ainsi on place la caméra à une distance qui dépend de la valeur de gZoom ;
  • pour la rotation, on va utiliser la fonction de transformation gRotated.
    Appelée juste après le gluLookAt, elle va ajouter une transformation de rotation à la matrice de modélisation-visualisation.
Placement de la caméra
Sélectionnez
' Position de la caméra
gluLookAt 0, 0, gZoom, 0, 0, 0, 0, 1, 0
glRotated gRotateX, 1, 0, 0
glRotated gRotateY, 0, 1, 0

Je vous invite à utiliser la molette de la souris et les touches fléchées pour visualiser la scène sous différents angles.

XI. Rappel du code complet

Au cas où je n'ai pas été toujours très clair, je fais ici un rappel du contenu du module VB à ce stade du tutoriel :

Rappel du code complet
Sélectionnez
Option Explicit

' Temps écoulé pour calcul du frame rate
Private gElapsedTime As Long
' Nombre d'affichages pour calcul du frame rate
Private gDisplayCount As Long
' RotationX
Private gRotateX As Double
' RotationY
Private gRotateY As Double
' Zoom
Private gZoom As Double

Function FonctionOpenGL()
' Chargement de freeGLUT
If Not LoadFreeGlut(CurrentProject.Path) Then
    MsgBox "Impossible de charger la bibliothèque freeGLUT"
    Exit Function
End If
' Initialisation de la bibliothèque
glutInit 0&, ""
' Initialisation du mode d'affichage
glutInitDisplayMode GLUT_RGBA Or GLUT_DOUBLE Or GLUT_DEPTH
' Définition de l'option de sortie de boucle
glutSetOption GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS
' Création d'une fenêtre
glutCreateWindow "Tutoriel fenêtre GLUT"
' Fonction d'affichage
glutDisplayFunc AddressOf CallBackDraw
' Fonctions de rappel clavier
glutSpecialFunc AddressOf CallBackSpecial
' Fonction de rappel molette de souris
glutMouseWheelFunc AddressOf CallBackMouseWheel
' Appel de la fonction d'initialisation
InitScene
' Fonction d'attente
glutTimerFunc 1000 / 50, AddressOf CallBackTimer, 0
' Boucle principale
glutMainLoop
End Function

' Fonction d'attente
Public Sub CallBackTimer(ByVal value As Long)
' Rappel de la fonction d'attente
glutTimerFunc 1000 / 50, AddressOf CallBackTimer, 0
' Rafraichir l'affichage si une fenêtre openGL est active
If glutGetWindow <> 0 Then glutPostRedisplay
End Sub

' Fonction d'affichage
Public Sub CallBackDraw()
' Appel de la fonction de rendu
Call Render
' Échange les buffers
glutSwapBuffers
' Calcul et affichage du frame rate
gDisplayCount = gDisplayCount + 1
If gDisplayCount = 100 Then
    glutSetWindowTitle "Frame rate : " & format(gDisplayCount / (glutGet(GLUT_ELAPSED_TIME) - gElapsedTime) * 1000, "0,0")
    gDisplayCount = 0
    gElapsedTime = glutGet(GLUT_ELAPSED_TIME)
End If
End Sub

' Fonction d'initialisation
Public Sub InitScene()
' Mode d'affichage = remplissage
glPolygonMode GL_FRONT_AND_BACK, GL_FILL
' Tests de profondeur
glEnable GL_DEPTH_TEST
glDepthFunc GL_LEQUAL
' Initialisation des variables de visualisation
gRotateX = 0
gRotateY = 0
gZoom = 10
End Sub

' Fonction de rendu
Public Sub Render()
' Passage en matrice de projection
glMatrixMode GL_PROJECTION
' Initialisation de la matrice
glLoadIdentity
' Définition de la perspective
gluPerspective 45, 1, 0.1, 100
' Passage en matrice de modélisation-visualisation
glMatrixMode GL_MODELVIEW
' Initialisation de la matrice
glLoadIdentity
' Position de la caméra
gluLookAt 0, 0, gZoom, 0, 0, 0, 0, 1, 0
glRotated gRotateX, 1, 0, 0
glRotated gRotateY, 0, 1, 0
' Vide les buffers couleur et profondeur
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
' Sauvegarde la matrice
glPushMatrix
' Rotation du cube
glRotated 30, 1, 1, 1
' Début de la primitive pour le cube
glBegin GL_QUADS
    ' Face du haut = vert
    Call glColor3d(0, 1, 0)
    Call glVertex3d(1, 1, -1)
    Call glVertex3d(-1, 1, -1)
    Call glVertex3d(-1, 1, 1)
    Call glVertex3d(1, 1, 1)
    ' Face du bas = orange
    Call glColor3d(1, 0.5, 0)
    Call glVertex3f(-1, -1, -1)
    Call glVertex3f(1, -1, -1)
    Call glVertex3f(1, -1, 1)
    Call glVertex3f(-1, -1, 1)
    ' Face de derrière = rouge
    Call glColor3d(1, 0, 0)
    Call glVertex3f(1, -1, -1)
    Call glVertex3f(-1, -1, -1)
    Call glVertex3f(-1, 1, -1)
    Call glVertex3f(1, 1, -1)
    ' Face de devant = jaune
    Call glColor3d(1, 1, 0)
    Call glVertex3f(-1, -1, 1)
    Call glVertex3f(1, -1, 1)
    Call glVertex3f(1, 1, 1)
    Call glVertex3f(-1, 1, 1)
    ' Face de gauche = violet
    Call glColor3d(1, 0, 1)
    Call glVertex3f(-1, 1, 1)
    Call glVertex3f(-1, 1, -1)
    Call glVertex3f(-1, -1, -1)
    Call glVertex3f(-1, -1, 1)
    ' Face de droite = bleu
    Call glColor3d(0, 0, 1)
    Call glVertex3f(1, 1, -1)
    Call glVertex3f(1, 1, 1)
    Call glVertex3f(1, -1, 1)
    Call glVertex3f(1, -1, -1)
glEnd
' Restaure la matrice
glPopMatrix
End Sub

' Gestion du clavier
Public Sub CallBackSpecial(ByVal key As Long, ByVal x As Long, ByVal y As Long)
Select Case key
    Case GLUT_KEY_LEFT
        gRotateY = gRotateY - 10
    Case GLUT_KEY_RIGHT
        gRotateY = gRotateY + 10
    Case GLUT_KEY_UP
        gRotateX = gRotateX - 10
    Case GLUT_KEY_DOWN
        gRotateX = gRotateX + 10
End Select
End Sub

' Gestion de la molette de la souris
Public Sub CallBackMouseWheel(ByVal wheel As Long, ByVal direction As Long, ByVal x As Long, ByVal y As Long)
gZoom = gZoom + direction
End Sub

précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Thierry GASPERMENT. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.