Extensions and GLEW
Last Updated: Aug 9th, 2012
There's core OpenGL functionality and then there's extended OpenGL functionality. OpenGL version 1.1 only has two modes of texture wrap. OpenGL 2.1 has 5. Using the OpenGL Extension Wrangler (GLEW), we'll get the addresses of the function pointers and the constants we need to use the new forms of texture wrap.Setting up GLEW
OpenGL has no built in capability to get function pointers for new functionality. Typically, the developer of the platform gives APIs to get the function pointers (like wgl on Windows) but it's a pain having write routines to get extended functionality for each platform you work on. GLEW allows you to get all the function pointers you need with a single function call.You can download GLEW here. Windows users will want to download the Windows SDK (again, I'm assuming we're using 32bit binaries for this tutorial). MinGW users may have to compile the dll themselves. Fortunately, this is as easy as compiling glew.c as a dll.
As with freeGLUT you need to make sure:
- Your compiler can find the header files
- Your compiler can find the library files
- You tell the linker to link against the library. In this case we need to link against glew32 on windows and glew on *nix
- The library binaries are in a place where the OS can find them
From LOpenGL.h
#ifndef LOPENGL_H #define LOPENGL_H #include <GL/glew.h> #include <GL/freeglut.h> #include <GL/gl.h> #include <GL/glu.h> #endif
Here we're augmenting our OpenGL header to include GLEW functionality. When using GLEW, make sure to include glew.h before any other OpenGL headers or it will throw a fit.
From LUtil.cpp
bool initGL() { //Initialize GLEW GLenum glewError = glewInit(); if( glewError != GLEW_OK ) { printf( "Error initializing GLEW! %s\n", glewGetErrorString( glewError ) ); return false; } //Make sure OpenGL 2.1 is supported if( !GLEW_VERSION_2_1 ) { printf( "OpenGL 2.1 not supported!\n" ); return false; }
At the top of our initialization function, we want to grab our OpenGL extended functionality with glewInit(). This function initializes all the extended OpenGL capabilities that
your OpenGL driver supports and leaves it ready for us to use.
GLEW also comes with some useful constants. If "GLEW_VERSION_2_1" is true, we have at least OpenGL 2.1 core functionality.
In this chunk of code, we verify that we have 2.1 functionality available to us before we do the rest of our initialization.
GLEW also comes with some useful constants. If "GLEW_VERSION_2_1" is true, we have at least OpenGL 2.1 core functionality.
In this chunk of code, we verify that we have 2.1 functionality available to us before we do the rest of our initialization.
From LUtil.cpp
//Set the viewport glViewport( 0.f, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT ); //Initialize Projection Matrix glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( 0.0, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0, 1.0, -1.0 ); //Initialize Modelview Matrix glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); //Initialize clear color glClearColor( 0.f, 0.f, 0.f, 1.f ); //Enable texturing glEnable( GL_TEXTURE_2D ); //Set blending glEnable( GL_BLEND ); glDisable( GL_DEPTH_TEST ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); //Check for error GLenum error = glGetError(); if( error != GL_NO_ERROR ) { printf( "Error initializing OpenGL! %s\n", gluErrorString( error ) ); return false; } //Initialize DevIL and DevILU ilInit(); iluInit(); ilClearColour( 255, 255, 255, 000 ); //Check for error ILenum ilError = ilGetError(); if( ilError != IL_NO_ERROR ) { printf( "Error initializing DevIL! %s", iluErrorString( ilError ) ); return false; } return true; }
As you can see, the rest of our initialization is the same as before.
From LUtil.cpp
bool loadMedia() { //Load texture if( !gRepeatingTexture.loadTextureFromFile( "15_extensions_and_glew/texture.png" ) ) { printf( "Unable to load repeating texture!\n" ); return false; } return true; } void update() { //Scroll texture gTexX++; gTexY++; //Cap scrolling if( gTexX >= gRepeatingTexture.textureWidth() ) { gTexX = 0.f; } if( gTexY >= gRepeatingTexture.textureHeight() ) { gTexY = 0.f; } } void render() { //Clear color buffer glClear( GL_COLOR_BUFFER_BIT ); //Calculate texture maxima GLfloat textureRight = (GLfloat)SCREEN_WIDTH / (GLfloat)gRepeatingTexture.textureWidth(); GLfloat textureBottom = (GLfloat)SCREEN_HEIGHT / (GLfloat)gRepeatingTexture.textureHeight(); //Use repeating texture glBindTexture( GL_TEXTURE_2D, gRepeatingTexture.getTextureID() ); //Switch to texture matrix glMatrixMode( GL_TEXTURE ); //Reset transformation glLoadIdentity(); //Scroll texture glTranslatef( gTexX / gRepeatingTexture.textureWidth(), gTexY / gRepeatingTexture.textureHeight(), 0.f ); //Render glBegin( GL_QUADS ); glTexCoord2f( 0.f, 0.f ); glVertex2f( 0.f, 0.f ); glTexCoord2f( textureRight, 0.f ); glVertex2f( SCREEN_WIDTH, 0.f ); glTexCoord2f( textureRight, textureBottom ); glVertex2f( SCREEN_WIDTH, SCREEN_HEIGHT ); glTexCoord2f( 0.f, textureBottom ); glVertex2f( 0.f, SCREEN_HEIGHT ); glEnd(); //Update screen glutSwapBuffers(); }
For this tutorial, we're doing the same texture mapping/rendering as in the previous tutorial. What we're doing different is how we set our texture wrapping.
From LUtil.cpp
void handleKeys( unsigned char key, int x, int y ) { //If q is pressed if( key == 'q' ) { //Cycle through texture wraps gTextureWrapType++; if( gTextureWrapType >= 5 ) { gTextureWrapType = 0; } //Set texture repetition glBindTexture( GL_TEXTURE_2D, gRepeatingTexture.getTextureID() ); switch( gTextureWrapType ) { case 0: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); printf( "%d: GL_REPEAT\n", gTextureWrapType ); break; case 1: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); printf( "%d: GL_CLAMP\n", gTextureWrapType ); break; case 2: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); printf( "%d: GL_CLAMP_TO_BORDER\n", gTextureWrapType ); break; case 3: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); printf( "%d: GL_CLAMP_TO_EDGE\n", gTextureWrapType ); break; case 4: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT ); printf( "%d: GL_MIRRORED_REPEAT\n", gTextureWrapType ); break; } } }
Thanks to GLEW, we now have a total of 5 ways to wrap texture. "GL_CLAMP_TO_BORDER" will clamp to the texture's border, which causes the texture to stop mapping past 0.0 or 1.0.
"GL_CLAMP_TO_EDGE" will clamp the texture at 0.0 or 1.0 and then use the texel values at the edge and stretch them to the edge of the polygon. "GL_MIRRORED_REPEAT" will make the
texture repeat past 0.0 or 1.0, only now it will mirror itself past every texture unit.