Code Source
/************************************************************/
/* 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);
}