// Shaders // Fabrice Aubert #include #include #define GLAPIENTRY #include #include #include #include #include #include "textfile.h" #include "snapshot.h" #include "trackball.h" using namespace std; SnapShot snap(512,512); GLuint location_time; // identifiant (handle) pour la variable time du shader float looping=0.0; // valeur qui sera affectée à la variable time du shader float increment=0.01; GLuint prog_shader; // identifiant du shader (une fois compilé et linké) GLuint vertex_shader; // identifiant du vertex GLuint frag_shader; // identifiant du fragment int num_shader=1; int max_num_shader=3; int display_texture=0; GLuint image_id1,image_id2; GLuint tex_id[3]; int texture_mode=0; static void erreur(std::string mes) { cout << "*******************************" << endl; cout << "Erreur : " << mes << endl; exit(0); } GLint initTexture(const char *nom) { GLubyte *image; GLuint result; GLint longueur,largeur,format,bpp,depth; ILenum il_erreur; bool ok=ilLoadImage(nom); if (!ok) { cout << "impossible de lire " << nom << endl; erreur("initTexture"); } longueur=ilGetInteger(IL_IMAGE_WIDTH); largeur=ilGetInteger(IL_IMAGE_HEIGHT); format=ilGetInteger(IL_IMAGE_FORMAT); bpp=ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL); cout << "lecture image " << nom << " : " << longueur << "," << largeur << "," << bpp << endl; image=new GLubyte[longueur*largeur*bpp]; // Attention : memory leak ! ilCopyPixels(0,0,0,longueur,largeur,1,IL_RGB,IL_UNSIGNED_BYTE,image); il_erreur=ilGetError(); if (il_erreur!=IL_NO_ERROR) { erreur("Chargement texture"); } glGenTextures(1,&result); // génération d'un identifiant par OpenGL glBindTexture(GL_TEXTURE_2D,result); // la texture courante 2D correspond à glPixelStorei(GL_UNPACK_ALIGNMENT,1); glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,longueur,largeur,0,GL_RGB,GL_UNSIGNED_BYTE,image); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); return result; } void activerTextureCoord(GLint texId) { glBindTexture(GL_TEXTURE_2D,texId); glEnable(GL_TEXTURE_2D); } void desactiverTextureCoord() { glDisable(GL_TEXTURE_2D); } void materielBleuVert() { GLfloat ambient[4]={0.1,0.1,0.1,0.0}; GLfloat diffus[4]={0.0,0.2,0.7,0.0}; GLfloat speculaire[4]={0.0,1,0.2,0.0}; // spéculaire vert GLint brillance=120; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient); glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffus); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,speculaire); glMateriali(GL_FRONT_AND_BACK,GL_SHININESS,brillance); } void myReshape(int w, int h) { snap.resize(w,h); tbReshape(w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(0, 0, w, h); gluPerspective(45,(float)w/h,1,50); glMatrixMode(GL_MODELVIEW); } void tracerCube() { glBegin(GL_POLYGON); glNormal3f(0,0,1); glTexCoord2f(0,0); glVertex3f(1,1,1); glTexCoord2f(1,0); glVertex3f(-1,1,1); glTexCoord2f(1,1); glVertex3f(-1,-1,1); glTexCoord2f(0,1); glVertex3f(1,-1,1); glEnd(); glBegin(GL_POLYGON); glNormal3f(0,0,-1); glTexCoord2f(0,0); glVertex3f(1,1,-1); glTexCoord2f(1,0); glVertex3f(-1,1,-1); glTexCoord2f(1,1); glVertex3f(-1,-1,-1); glTexCoord2f(0,1); glVertex3f(1,-1,-1); glEnd(); glBegin(GL_POLYGON); glNormal3f(0,1,0); glTexCoord2f(0,0); glVertex3f(1,1,1); glTexCoord2f(1,0); glVertex3f(-1,1,1); glTexCoord2f(1,1); glVertex3f(-1,1,-1); glTexCoord2f(0,1); glVertex3f(1,1,-1); glEnd(); glBegin(GL_POLYGON); glNormal3f(0,-1,0); glTexCoord2f(0,0); glVertex3f(1,-1,1); glTexCoord2f(1,0); glVertex3f(-1,-1,1); glTexCoord2f(1,1); glVertex3f(-1,-1,-1); glTexCoord2f(0,1); glVertex3f(1,-1,-1); glEnd(); glBegin(GL_POLYGON); glNormal3f(1,0,0); glTexCoord2f(0,0); glVertex3f(1,1,-1); glTexCoord2f(1,0); glVertex3f(1,-1,-1); glTexCoord2f(1,1); glVertex3f(1,-1,1); glTexCoord2f(0,1); glVertex3f(1,1,1); glEnd(); glBegin(GL_POLYGON); glNormal3f(-1,0,0); glTexCoord2f(0,0); glVertex3f(-1,1,-1); glTexCoord2f(1,0); glVertex3f(-1,-1,-1); glTexCoord2f(1,1); glVertex3f(-1,-1,1); glTexCoord2f(0,1); glVertex3f(-1,1,1); glEnd(); } void tracerScene() { if (display_texture==0) desactiverTextureCoord(); else activerTextureCoord(tex_id[display_texture-1]); glPushMatrix(); glTranslatef(-1.5,0,0); glScalef(0.5,0.5,0.5); tbMatrix(); tracerCube(); glPopMatrix(); glPushMatrix(); glTranslatef(0.8,0,0); tbMatrix(); glutSolidTeapot(1); glPopMatrix(); } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); materielBleuVert(); glLoadIdentity(); glTranslatef(0,0,-6); // tracé avec shader glPushMatrix(); glTranslatef(0,-1,0); glUseProgramObjectARB(prog_shader); location_time = glGetUniformLocationARB(prog_shader,"looping"); glUniform1fARB(location_time,looping); tracerScene(); glPopMatrix(); // tracé sans shader glPushMatrix(); glTranslatef(0,1,0); glUseProgramObjectARB(0); materielBleuVert(); tracerScene(); glPopMatrix(); snap.shotIfRequested(); glutSwapBuffers(); } /* ********************************************/ // Affichage des messages d'erreurs des shaders void printShaderInfoLog(GLuint obj) { int infologLength = 0; int charsWritten = 0; char *infoLog; // glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength); if (infologLength > 0) { infoLog = (char *)malloc(infologLength); glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog); printf("%s\n",infoLog); free(infoLog); } } void printProgramInfoLog(GLuint obj) { int infologLength = 0; int charsWritten = 0; char *infoLog; // glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength); if (infologLength > 0) { infoLog = (char *)malloc(infologLength); glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog); printf("%s\n",infoLog); free(infoLog); } } /* **************************************************/ // initialisation des shaders void myShader() { cout << "Lecture/compilation des shaders" << endl; cout << "*******************************" << endl; GLchar *v_source,*f_source; // creation handle : vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER); frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); // lecture du GLSL source : string nom="glsl"; ostringstream nbre; nbre << num_shader; nom+=nbre.str(); v_source = textFileRead((nom+".vert").c_str()); f_source = textFileRead((nom+".frag").c_str()); // affectation des sources aux handles glShaderSourceARB(vertex_shader, 1, (const char **)&v_source,NULL); glShaderSourceARB(frag_shader, 1, (const char **)&f_source,NULL); // compilation des sources glCompileShaderARB(vertex_shader); printShaderInfoLog(vertex_shader); glCompileShaderARB(frag_shader); printShaderInfoLog(frag_shader); // mise en place dans le pipeline : prog_shader = glCreateProgramObjectARB(); glAttachObjectARB(prog_shader,vertex_shader); glAttachObjectARB(prog_shader,frag_shader); glLinkProgramARB(prog_shader); printProgramInfoLog(prog_shader); // free(v_source); // free(f_source); cout << "-------------------------------------------" << endl; cout << "Fin (cf ci-dessus pour erreurs éventuelles)" << endl; cout << "*******************************************" << endl; } void detachShader() { glUseProgramObjectARB(0); glDetachObjectARB(prog_shader,vertex_shader); glDetachObjectARB(prog_shader,frag_shader); glDeleteObjectARB(vertex_shader); glDeleteObjectARB(frag_shader); glDeleteObjectARB(prog_shader); } /* *******************************************************/ // Evénements glut void myKey(char unsigned key,int x,int y) { switch (key) { case 'p':snap.request();break; case ' ':detachShader();myShader();break; case 's':detachShader();num_shader+=1; if (num_shader>max_num_shader) num_shader=1; myShader(); break; case 't':display_texture=(display_texture+1)%4; break; case 27:exit(0);break; } } void myMotion(int x,int y) { tbMotion(x,y); } void myMouse(int button, int status, int x, int y) { tbMouse(button,status,x,y); } void myIdle() { looping+=increment; if (looping>1) { looping=1;increment=-increment; } if (looping<0) { looping=0;increment=-increment; } glutPostRedisplay(); } /* **********************************************************/ // Initialisations appli void myInit() { ilInit(); // image_id1=ilGenImage(); ilBindImage(image_id1); ilEnable(IL_ORIGIN_SET); ilOriginFunc(IL_ORIGIN_LOWER_LEFT); tex_id[0]=initTexture("../data/marble.jpg"); tex_id[1]=initTexture("../data/p3d.jpg"); tex_id[2]=initTexture("../data/p3d2.jpg"); glEnable(GL_DEPTH_TEST); glClearColor(1.0,1.0,1.0,1.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); tbInit(GLUT_LEFT_BUTTON); // utilisation de glew pour savoir si les shaders sont bien présents glewInit(); if (glewIsSupported("GL_VERSION_1_5")) { cout << "Version OpenGL 1.5 (shader ARB) supportée" << endl; } else { cout << "OpenGL 1.5 (shader ARB) non supporté" << endl; exit(0); } myShader(); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(512,512); glutCreateWindow("TP Shaders"); glutDisplayFunc(myDisplay); glutIdleFunc(myIdle); glutReshapeFunc(myReshape); glutKeyboardFunc(myKey); glutMouseFunc(myMouse); glutMotionFunc(myMotion); myInit(); glutMainLoop(); return 0; }