Génération
de terrain (1/2) Par Xavier Michelon |
/************************************************************/ /* terrain .c */ /************************************************************/ /* Generation de terrain a partir d'une image JPEG */ /************************************************************/ #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <jpeglib.h> #include <jerror.h> #define NB_SUBDIV_INIT 32 #define NB_SUBDIV_MAX 64 #define ECHELLE_VERT_INIT 0.3 #define ECHELLE_VERT_MAX 1.0 #define DISTANCE_INIT 4.0 #define DISTANCE_MAX 15.0 /* Variables globales */ unsigned char image[256][256]; /* l'image du terrain */ unsigned char afficheRepere=TRUE; /* Affichage du repere */ unsigned char faceArriere=FALSE; /* Affichage des faces arrieres de polygones */ unsigned char areteTransv=FALSE; /* Affichage de l'arete transversale */ int repere,terrain; /* Identifiants des listes d'affichage */ int nbSubdiv=NB_SUBDIV_INIT; /* Nombre de subdivisions du maillage */ float echelleVert=ECHELLE_VERT_INIT; /* echelle verticale du relief */ char b_gauche=0,b_droit=0; /* bouton de souris presse ? */ int theta=-30,phi=300; /* Position de l'observateur */ int xprec,yprec; /* sauvegarde de la position de la souris */ float distance=DISTANCE_INIT; /* distance de l'observateur a l'origine */ /* Prototypes des fonctions */ void init(); void affichage(); void clavier(unsigned char touche,int x,int y); void souris(int bouton,int etat,int x,int y); void mouvement(int x,int y); void redim(int l,int h); void creeRepere(); void creeTerrain(); float elevation(int i,int j); void loadJpegImage(char *filename); int main(int argc,char **argv) { /* Initialisation de glut */ glutInit(&argc,argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(500,500); glutCreateWindow(argv[0]); /*Initialisation d'OpenGL */ init(); loadJpegImage(argv[1]); /* Creation des objets */ creeRepere(); creeTerrain(); glutMainLoop(); return 0; } void init() { glClearColor(0.8,0.8,0.8,1.0); glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); glCullFace(GL_BACK); if (faceArriere) glDisable(GL_CULL_FACE); else glEnable(GL_CULL_FACE); /* Mise en place de la perspective */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0,1.0,0.1,20.0); glMatrixMode(GL_MODELVIEW); /* Mise en place des fonction de rappel */ glutDisplayFunc(affichage); glutKeyboardFunc(clavier); glutMouseFunc(souris); glutMotionFunc(mouvement); glutReshapeFunc(redim); } /* Fonction de rappel pour l'affichage */ void affichage() { glClear(GL_COLOR_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,0.0,1.0); glCallList(terrain); if (afficheRepere) glCallList(repere); glutSwapBuffers(); } /* Fonction de rappel pour le clavier */ void clavier(unsigned char touche,int x,int y) { switch (touche) { case 27: /* touche 'ESC' pour quitter */ exit(0); case '+': /* augmentation du nombre de subdivisions */ nbSubdiv++; if (nbSubdiv>NB_SUBDIV_MAX) nbSubdiv=NB_SUBDIV_MAX; creeTerrain(); glutPostRedisplay(); break; case '-': /* diminution du nombre de subdivisions*/ nbSubdiv--; if (nbSubdiv<1) nbSubdiv=1; creeTerrain(); glutPostRedisplay(); break; case 'p': /* augmentation de l'echelle verticale */ echelleVert+=0.02; if (echelleVert>ECHELLE_VERT_MAX) echelleVert=ECHELLE_VERT_MAX; creeTerrain(); glutPostRedisplay(); break; case 'o': /* diminution de l'echelle verticale */ echelleVert-=0.02; if (echelleVert<-ECHELLE_VERT_MAX) echelleVert=-ECHELLE_VERT_MAX; creeTerrain(); glutPostRedisplay(); break; case 'r': /* Affichage du repere ON/OFF */ afficheRepere=1-afficheRepere; glutPostRedisplay(); break; case 'c': /* affichage des faces arrieres ON/OFF */ faceArriere=1-faceArriere; if (faceArriere) glDisable(GL_CULL_FACE); else glEnable(GL_CULL_FACE); glutPostRedisplay(); break; case 't': /* affichage des aretes transversales */ areteTransv=1-areteTransv; creeTerrain(); glutPostRedisplay(); break; } } /* fonction de rappel pour l'appui sur les boutons de souris*/ void souris(int bouton,int etat,int x,int y) { if (bouton == GLUT_LEFT_BUTTON && etat == GLUT_DOWN) { b_gauche = 1; xprec = x; yprec=y; } if (bouton == GLUT_LEFT_BUTTON && etat == GLUT_UP) b_gauche=0; if (bouton == GLUT_RIGHT_BUTTON && etat == GLUT_DOWN) { b_droit = 1; yprec=y; } if (bouton == GLUT_RIGHT_BUTTON && etat == GLUT_UP) b_droit=0; } /* Fonction de rappel pour les mouvements de souris */ void mouvement(int x,int y) { /* si le bouton gauche est presse */ if (b_gauche) { theta+=x-xprec; if (theta>=360) while (theta>=360) theta-=360; phi+=y-yprec; if (phi<0) while (phi<0) phi+=360; xprec=x; yprec=y; glutPostRedisplay(); } /* si le bouton gauche est presse */ if (b_droit) { distance+=((float)(y-yprec))/10.0; if (distance<1.0) distance=1.0; if (distance>DISTANCE_MAX) distance=DISTANCE_MAX; glutPostRedisplay(); yprec=y; } } /* Fonction de rappel pour le redimensionnement de fenetre */ void redim(int l,int h) { if (l<h) glViewport(0,(h-l)/2,l,l); else glViewport((l-h)/2,0,h,h); } /* Creation de la liste d'affichage pour le repere */ void creeRepere() { repere=glGenLists(1); glNewList(repere,GL_COMPILE); glLineWidth(2.0); glBegin(GL_LINES); glColor3f(1.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.3,0.0,0.0); glColor3f(0.0,1.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,0.3,0.0); glColor3f(0.0,0.0,1.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,0.0,0.3); glEnd(); glEndList(); } /* Creation de la liste d'afffichage pour le terrain */ void creeTerrain() { int i,j; float pas=2.0/nbSubdiv; float P1[3],P2[3],P3[3],P4[3]; /* Liste pour l'objet terrain */ if (glIsList(terrain)) glDeleteLists(terrain,1); terrain=glGenLists(1); glNewList(terrain,GL_COMPILE); glColor3f(0.0,0.0,0.0); glLineWidth(1.0); for (i=0;i<nbSubdiv;i++) for (j=0;j<nbSubdiv;j++) { P1[0]=-1.0+i*pas; P1[1]=-1.0+j*pas ; P1[2]=elevation(i,j); P2[0]=-1.0+(i+1)*pas; P2[1]=-1.0+j*pas ; P2[2]=elevation(i+1,j); P3[0]=-1.0+(i+1)*pas; P3[1]=-1.0+(j+1)*pas ; P3[2]=elevation(i+1,j+1); P4[0]=-1.0+i*pas; P4[1]=-1.0+(j+1)*pas ; P4[2]=elevation(i,j+1); glBegin(GL_TRIANGLES); /* triangle 1 */ glEdgeFlag(TRUE); glVertex3fv(P1); glVertex3fv(P2); if (!areteTransv) glEdgeFlag(FALSE); glVertex3fv(P3); /*triangle 2 */ glVertex3fv(P1); if (!areteTransv) glEdgeFlag(TRUE); glVertex3fv(P3); glVertex3fv(P4); glEnd(); } glEndList(); } /* Calcul de la hauteur d'un point */ float elevation(int i,int j) { int valeur=image[(int)((float)i/nbSubdiv*255)][(int)((float)j/nbSubdiv*255)]; return ((float)valeur/128.0-1.0)*echelleVert; } /* Chargement d'une image jpeg */ void loadJpegImage(char *filename) { FILE *file; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; unsigned char *im=(unsigned char *)image,*ligne; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* On mets en place une image par defaut si filename=NULL*/ if (filename==NULL){ filename=(char *)malloc(128); strcpy(filename,"terrain.jpg"); } if (!(file=fopen(filename,"rb"))) { fprintf(stderr,"Erreur : impossible d'ouvrir %s\n",filename); exit(1); } jpeg_stdio_src(&cinfo, file); jpeg_read_header(&cinfo, TRUE); if ((cinfo.image_width!=256) || (cinfo.image_height!=256)) { fprintf(stderr,"Erreur : l'image doit etre de taille 256x256\n"); exit(1); } if (cinfo.out_color_space!=JCS_GRAYSCALE){ fprintf(stderr,"Error : l'image doit etre en niveaux de gris\n"); exit(1); } jpeg_start_decompress(&cinfo); while (cinfo.output_scanline>256){ ligne=im+256*cinfo.output_scanline; jpeg_read_scanlines(&cinfo,&ligne,1); } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); }
|