OpenGL avec GtkGLArea
Par Xavier Michelon


 
   
Code Source
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <gtkgl/gtkglarea.h>
#include <GL/gl.h>
#include <GL/glu.h>

#define DISTANCE_INIT 6.0
#define DISTANCE_MIN 4.5
#define DISTANCE_MAX 25.0

GtkWidget *fenetre,*glarea,*boiteh,*boitev,*boitev2,*bouton,*frame;
GSList *groupe;
int listeAttributs[] = {
  GDK_GL_RGBA,
  GDK_GL_DOUBLEBUFFER,
  GDK_GL_DEPTH_SIZE, 1,
  GDK_GL_NONE
};
int theta=-35,phi=20,xprec,yprec;
float distance=DISTANCE_INIT;

/* Parametres d'éclairage */
GLfloat L0pos[]={ 0.0,2.0,1.0};
GLfloat L0dif[]={ 0.3,0.3,0.8};
GLfloat L1pos[]={ 2.0,2.0,2.0};
GLfloat L1dif[]={ 0.5,0.5,0.5};
GLfloat Mspec[]={0.5,0.5,0.5};
GLfloat Mshiny=50;


/* Prototypes des fonctions */
void creeInterface();
void affichage(GtkWidget *widget,GdkEventExpose *evenement);
void initGlarea(GtkWidget* widget);
void redimGlarea(GtkWidget* widget, GdkEventConfigure* evenement);
void mouvementSouris(GtkWidget* widget, GdkEventMotion* evenement);
void rappelMap(GtkWidget* widget, GdkEventAny* evenement);
void modeAffichage(GtkWidget* widget, char *chaine);
void basculeEclairage(GtkWidget* widget,gpointer donnee);
void basculeFacesArrieres(GtkWidget *widget,gpointer donnee);

int main(int argc,char **argv)
{
  gtk_init(&argc,&argv);
  creeInterface();


  /* affichage de l'interface */
  gtk_widget_show_all(fenetre);

  gtk_main();
  return 0;
}



/* Fonction de creation de l'interface graphique */
void creeInterface()
{
  /* la fenetre principale */
  fenetre=gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(fenetre),"Example GtkGLArea");
  gtk_signal_connect(GTK_OBJECT(fenetre),"destroy",GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
  gtk_signal_connect(GTK_OBJECT(fenetre),"delete_event",GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
  
  /* un boite verticale */
  boiteh=gtk_hbox_new(FALSE,0);
  gtk_container_add(GTK_CONTAINER(fenetre),boiteh);


  /* une glarea */
  if(gdk_gl_query() == FALSE) {
    fprintf(stderr,"Impossible d'utiliser OpenGL\n");
    exit(1);
  }
  glarea = gtk_gl_area_new(listeAttributs);
  gtk_widget_set_events(GTK_WIDGET(glarea),
                        GDK_EXPOSURE_MASK|
                        GDK_BUTTON_PRESS_MASK|
			GDK_BUTTON_RELEASE_MASK|
			GDK_POINTER_MOTION_MASK|
                        GDK_POINTER_MOTION_HINT_MASK);
  gtk_widget_set_usize(GTK_WIDGET(glarea),300,300);
  gtk_box_pack_start(GTK_BOX(boiteh),glarea,TRUE,TRUE,0);
  gtk_signal_connect (GTK_OBJECT(glarea), "realize",
                      GTK_SIGNAL_FUNC(initGlarea), NULL);
  gtk_signal_connect (GTK_OBJECT(glarea), "expose_event",
                      GTK_SIGNAL_FUNC(affichage), NULL);
  gtk_signal_connect (GTK_OBJECT(glarea), "configure_event",
                      GTK_SIGNAL_FUNC(redimGlarea), NULL);
  gtk_signal_connect (GTK_OBJECT(glarea), "motion_notify_event",
                      GTK_SIGNAL_FUNC(mouvementSouris), NULL);
  gtk_signal_connect (GTK_OBJECT(glarea), "map_event",
                      GTK_SIGNAL_FUNC(rappelMap), NULL);

  /* une boite verticale */
  boitev=gtk_vbox_new(FALSE,0);
  gtk_box_pack_start(GTK_BOX(boiteh),boitev,FALSE,FALSE,0);

  /* une frame */
  frame=gtk_frame_new("Mode d'affichage");
  gtk_box_pack_start(GTK_BOX(boitev),frame,FALSE,FALSE,0);

  /* un boite verticale pour la frame */
  boitev2=gtk_vbox_new(FALSE,0);
  gtk_container_add(GTK_CONTAINER(frame),boitev2);

  /* un groupe de bouton radio */
  bouton=gtk_radio_button_new_with_label(NULL,"Plein");
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bouton),TRUE);
  gtk_box_pack_start(GTK_BOX(boitev2),bouton,FALSE,FALSE,0);
  gtk_signal_connect(GTK_OBJECT(bouton),"toggled",GTK_SIGNAL_FUNC(modeAffichage),"a");
  
  groupe=gtk_radio_button_group(GTK_RADIO_BUTTON(bouton));  
  bouton=gtk_radio_button_new_with_label(groupe,"Fil de fer");
  gtk_box_pack_start(GTK_BOX(boitev2),bouton,FALSE,FALSE,0);
  gtk_signal_connect(GTK_OBJECT(bouton),"toggled",GTK_SIGNAL_FUNC(modeAffichage),"b");
  

  groupe=gtk_radio_button_group(GTK_RADIO_BUTTON(bouton));  
  bouton=gtk_radio_button_new_with_label(groupe,"Points");
  gtk_box_pack_start(GTK_BOX(boitev2),bouton,FALSE,FALSE,0);
  gtk_signal_connect(GTK_OBJECT(bouton),"toggled",GTK_SIGNAL_FUNC(modeAffichage),"c");
  

  /* un bouton pour bascule pour l'éclairage */
  bouton=gtk_check_button_new_with_label("Eclairage");
  gtk_box_pack_start(GTK_BOX(boitev),bouton,FALSE,FALSE,0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bouton),TRUE);
  gtk_signal_connect(GTK_OBJECT(bouton),"toggled",GTK_SIGNAL_FUNC(basculeEclairage),NULL);

  /* un bouton pour le masquage des faces arrieres*/
  bouton=gtk_check_button_new_with_label("Masquage des face arrières");
  gtk_box_pack_start(GTK_BOX(boitev),bouton,FALSE,FALSE,0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bouton),TRUE);
  gtk_signal_connect(GTK_OBJECT(bouton),"toggled",GTK_SIGNAL_FUNC(basculeFacesArrieres),NULL);
  
  /* un bouton Quitter */
  bouton=gtk_button_new_with_label("Quitter");
  gtk_box_pack_end(GTK_BOX(boitev),bouton,FALSE,FALSE,0);
  gtk_signal_connect(GTK_OBJECT(bouton),"clicked",GTK_SIGNAL_FUNC(gtk_main_quit),NULL);

}



/* Fonction de rappel pour l'affichage */
void affichage(GtkWidget *widget,GdkEventExpose *evenement)
{
  if (evenement->count > 0)
    return;

  if (gtk_gl_area_make_current(GTK_GL_AREA(widget))) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(0.0,0.0,distance,0.0,0.0,0.0,0.0,1.0,0.0);
    glRotatef(phi,1.0,0.0,0.0);
    glRotatef(theta,0.0,1.0,0.0);

    glBegin(GL_POLYGON);
      glNormal3d(0,0,1); glColor3d(1,0,0);
      glVertex3d(-1,1,1); glVertex3f(-1,-1,1); glVertex3f(1,-1,1); glVertex3f(1,1,1);
    glEnd();
    glBegin(GL_POLYGON);
      glNormal3d(1,0,0); glColor3d(0,1,0);
      glVertex3d(1,1,1); glVertex3f(1,-1,1); glVertex3f(1,-1,-1); glVertex3f(1,1,-1);
    glEnd();

    glBegin(GL_POLYGON);
      glNormal3d(0,0,-1); glColor3d(0,0,1);
      glVertex3d(1,1,-1); glVertex3f(1,-1,-1); glVertex3f(-1,-1,-1); glVertex3f(-1,1,-1);
    glEnd();

    glBegin(GL_POLYGON);
      glNormal3d(-1,0,0); glColor3d(1,1,0);
      glVertex3d(-1,1,-1); glVertex3f(-1,-1,-1); glVertex3f(-1,-1,1); glVertex3f(-1,1,1);
    glEnd();

    glBegin(GL_POLYGON);
      glNormal3d(0,1,0); glColor3d(1,0,1);
      glVertex3d(-1,1,-1); glVertex3f(-1,1,1); glVertex3f(1,1,1); glVertex3f(1,1,-1);
    glEnd();

    glBegin(GL_POLYGON);
      glNormal3d(0,-1,0); glColor3d(0,1,1);
      glVertex3d(-1,-1,1); glVertex3f(-1,-1,-1); glVertex3f(1,-1,-1); glVertex3f(1,-1,1);
    glEnd();

    gtk_gl_area_swapbuffers(GTK_GL_AREA(widget));
  }
}


/* fonction d'initialisation d'OpenGL*/
void initGlarea(GtkWidget* widget)
{
  if (gtk_gl_area_make_current(GTK_GL_AREA(widget))) {
    glClearColor(0.4,0.4,0.4,1.0);
    glColor3d(1,0,0);
    glPointSize(4.0);
    glLineWidth(2.0);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    /* Mise en place de la perspective */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();  
    gluPerspective(45.0,1.0,0.1,DISTANCE_MAX+2);
    glMatrixMode(GL_MODELVIEW);

    /* Parametrage de l'éclairage */
    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,L0dif);
    glLightfv(GL_LIGHT0,GL_SPECULAR,L0dif);
    glLightfv(GL_LIGHT1,GL_DIFFUSE,L1dif);
    glLightfv(GL_LIGHT1,GL_SPECULAR,L1dif); 
    
    /* Paramétrage du matériau */
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,Mspec);
    glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,Mshiny);
  }
}



/* Fonction de rappel pour le redimensionnement du widget OpenGL  */
void redimGlarea(GtkWidget* widget, GdkEventConfigure* evenement) 
{
  int l = widget->allocation.width;
  int h = widget->allocation.height;
  if (gtk_gl_area_make_current(GTK_GL_AREA(widget))) {
    if (l<h)
      glViewport(0,(h-l)/2,l,l);
    else 
      glViewport((l-h)/2,0,h,h);
  }
}



/* fonction de rappel pour les mouvements de la souris */
void mouvementSouris(GtkWidget* widget, GdkEventMotion* evenement)
{
  int x,y;
  GdkModifierType etat;
  if (evenement->is_hint)
    gdk_window_get_pointer(evenement->window,&x,&y,&etat);
  else {
    x=evenement->x;
    y=evenement->y;
    etat=evenement->state;
  }

  /* bouton gauche = rotation */
  if (etat & GDK_BUTTON1_MASK){
    theta+=x-xprec;
    phi+=y-yprec;
    gtk_widget_queue_draw(widget);
  }

  /* bouton droit = Zoom */
  if (etat & GDK_BUTTON3_MASK){
    distance+=((float)(y-yprec))/20.0;
    if (distance<DISTANCE_MIN)
      distance=DISTANCE_MIN;
    if (distance>DISTANCE_MAX)
      distance=DISTANCE_MAX;
    gtk_widget_queue_draw(widget);
  }
  xprec=x;yprec=y;
}



/* Fonction de rappel pour le mapping du widget */
void rappelMap(GtkWidget* widget, GdkEventAny* evenement)
{
  int x,y;
  gdk_window_get_pointer(glarea->window,&x,&y,NULL);
  xprec=x;
  yprec=y;
}

/* Fonction de bascule du mode d'affichage */
void modeAffichage(GtkWidget* widget, char *chaine)
{
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
    if (gtk_gl_area_make_current(GTK_GL_AREA(glarea))) {
      switch (chaine[0]) {
      case 'a':
	glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
	break;
      case 'b':
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	break;
      case 'c':
	glPolygonMode(GL_FRONT_AND_BACK,GL_POINT);
	break;
      }
      gtk_widget_queue_draw(GTK_WIDGET(glarea));
    }
}



/* Fonction de bascule du mode d'eclairage */
void basculeEclairage(GtkWidget* widget,gpointer donnee)
{
  if (gtk_gl_area_make_current(GTK_GL_AREA(glarea))) {
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
      glEnable(GL_LIGHTING);
    else
      glDisable(GL_LIGHTING);
    gtk_widget_queue_draw(GTK_WIDGET(glarea));
  }
}



/* Fonction de bacule pour le masquage des faces arrieres */
void basculeFacesArrieres(GtkWidget *widget,gpointer donnee)
{
  if (gtk_gl_area_make_current(GTK_GL_AREA(glarea))) {
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
      glEnable(GL_CULL_FACE);
    else
      glDisable(GL_CULL_FACE);
    gtk_widget_queue_draw(GTK_WIDGET(glarea));
  }
}