Simple texture loading with DevIL revisited

I wrote an article a while back about loading images to use as textures in OpenGL, and in it I’d written my own single line image to texture-handle function because I couldn’t get the built-in ilutGLLoadImage function to work. Since I’ve been getting blank looks and failure to compile reports about it, I thought I’d go and take a look at it again, and this time ilutGLLoadImage seems to work just fine, so let’s document it up properly shall we?

Pre-requisites

You will need:

  • A C++ compiler of your choice (I prefer Code::Blocks)
  • Working OpenGL drivers
  • A copy of DevIL
  • A copy of GLEW (GL Extension Wrangler – to make the functionality in your OpenGL drivers availble for use)
  • A copy of GLFW (GL FrameWork – to quickly and easily set up a OpenGL context)
  • An image to load

Preparation and libraries

Create a new project in your IDE of choice, and link in the following libraries:
DevIL required libraries

You’ll have to figure out where the libraries are on your own system but these are where they are on mine, where a /usr/local/ address indicates packages I’ve build myself, /usr/lib/ indicates standard system installed packages, and no prefix uses any paths defined by the compiler (in this case /usr/ where the lib and include directories are assumed). I’ve also added /usr/local/ to the include path so that any headers in /usr/local/include/ are picked up before any in /usr/include. Yes, library paths are a pain ;)

Also, be sure that your project includes its own directory as the working directory (i.e. the directory to be in when executing) so that you can place your image (in this example, a file called abstract-image.jpg) in the main project directory and it’ll be picked up when we try to load it. The way that you specify the working directory will vary depending on the IDE you’re using, but in Code::Blocks you set it from Project | Properties | Build targets like this:

Code::Blocks Working Directory

Source Code

Create a new project with source code something like this:

  1. #include <iostream>
  2. #include <cstdlib>
  3.  
  4. #include <GL/glew.h>		// Include GLEW, which pulls in OpenGL headers as required
  5. #include <GL/glfw.h>		// Include OpenGL Framework headers
  6.  
  7. #define ILUT_USE_OPENGL		// This MUST be defined before calling the DevIL headers or we don't get OpenGL functionality
  8. #include <IL/il.h>
  9. #include <IL/ilu.h>
  10. #include <IL/ilut.h>
  11.  
  12. GLuint textureHandle;           // Create a uint to store the handle to our texture
  13.  
  14. GLfloat frameCount = 0.0f;
  15.  
  16. void initGL(int width, int height)
  17. {
  18. 	//  ----- Initialise GLEW -----
  19. 	GLenum err = glewInit();
  20. 	if (GLEW_OK != err)
  21. 	{
  22. 		std::cout << "GLEW initialisation error: " << glewGetErrorString(err) << std::endl;
  23. 		exit(-1);
  24. 	}
  25. 	std::cout << "GLEW intialised successfully. Using GLEW version: " << glewGetString(GLEW_VERSION) << std::endl;
  26.  
  27. 	// ----- Window and Projection Settings -----
  28.  
  29. 	// Set the window title
  30. 	glfwSetWindowTitle("ilutGLLoadImage Test | September 2011 | r3dux.org");
  31.  
  32. 	// Setup our viewport to be the entire size of the window
  33. 	glViewport(0, 0, (GLsizei)width, (GLsizei)height);
  34.  
  35. 	GLfloat ratio = (float)width / (float)height;	// Calculate the window ratio
  36.  
  37. 	// Change to the projection matrix, reset the matrix and set up our projection
  38. 	glMatrixMode(GL_PROJECTION);
  39. 	glLoadIdentity();
  40. 	gluPerspective(45.0f, ratio, 0.1f, 100.0f); // Params: Field-of-Vision, window-ration, near-clip-plane, far-clip-plane
  41.  
  42. 	// ----- OpenGL settings -----
  43.  
  44. 	glfwSwapInterval(1);                               // Lock to vertical sync of monitor (normally 60Hz, so 60fps)
  45. 	glEnable(GL_DEPTH);                                // Enable the depth buffer
  46. 	glDepthFunc(GL_LEQUAL);                            // Set our depth function to overwrite if new value less than or equal to current value
  47. 	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Ask for nicest perspective correction
  48. 	glEnable(GL_TEXTURE_2D);                           // Enable 2D textures
  49.  
  50. 	// ----- Initialize DevIL libraries -----
  51.  
  52. 	// DevIL sanity check
  53. 	if ( (iluGetInteger(IL_VERSION_NUM) < IL_VERSION) || (iluGetInteger(ILU_VERSION_NUM) < ILU_VERSION) || (ilutGetInteger(ILUT_VERSION_NUM) < ILUT_VERSION) )
  54. 	{
  55. 		std::cout << "DevIL versions are different... Exiting." << std::endl;
  56. 		exit(-1);
  57. 	}
  58.  
  59. 	// Initialise all DevIL functionality
  60. 	ilInit();
  61. 	iluInit();
  62. 	ilutInit();
  63. 	ilutRenderer(ILUT_OPENGL);	// Tell DevIL that we're using OpenGL for our rendering
  64. }
  65.  
  66. void drawScene()
  67. {
  68. 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the screen and depth buffer
  69.  
  70. 	// Reset the matrix to identity
  71. 	glMatrixMode(GL_MODELVIEW);
  72. 	glLoadIdentity();
  73.  
  74. 	glTranslatef(0.0f, 0.0f, -40.0f); // Move things back into the screen
  75.  
  76. 	glRotatef(frameCount, 0.1f, 1.0f, 0.3f); // Rotate the MVP matrix orientation
  77.  
  78. 	glBindTexture(GL_TEXTURE_2D, textureHandle); // Select the texture to use and bind to it
  79.  
  80. 	static float hsize = 15.0f; // Vertical size of the quad
  81. 	static float vsize = 10.0f; // Vertical size of the quad
  82.  
  83. 	// Draw our textured geometry (just a rectangle in this instance)
  84. 	glEnable(GL_TEXTURE_2D);
  85. 	glBegin(GL_QUADS);
  86. 		glTexCoord2f(0.0, 0.0); glVertex3f(-hsize, -vsize, 0.0f);  // Top left
  87. 		glTexCoord2f(0.0, 1.0);	glVertex3f(-hsize,  vsize, 0.0f);  // Bottom left
  88. 		glTexCoord2f(1.0, 1.0);	glVertex3f(hsize,   vsize, 0.0f);  // Bottom right
  89. 		glTexCoord2f(1.0, 0.0);	glVertex3f(hsize,  -vsize, 0.0f);  // Top right
  90. 	glEnd();
  91. 	glDisable(GL_TEXTURE_2D);
  92.  
  93. 	// ----- Stop Drawing Stuff! ------
  94.  
  95. 	glfwSwapBuffers(); // Swap the buffers to display the scene (so we don't have to watch it being drawn!)
  96. 	frameCount++;
  97. }
  98.  
  99. int main()
  100. {
  101. 	// Window settings
  102. 	int width      = 800, height   = 600;
  103. 	int redBits    = 8,   greenBits = 8,  blueBits    = 8;
  104. 	int alphaBits  = 8,   depthBits = 24, stencilBits = 8;
  105.  
  106. 	// Flag to keep our main loop running
  107. 	bool running = true;
  108.  
  109. 	// Initialise glfw
  110. 	glfwInit();
  111.  
  112. 	// Create a window
  113. 	if(!glfwOpenWindow(width, height, redBits, greenBits, blueBits, alphaBits, depthBits, stencilBits, GLFW_WINDOW))
  114. 	{
  115. 		std::cout << "Failed to open window!" << std::endl;
  116. 		glfwTerminate();
  117. 		return 0;
  118. 	}
  119.  
  120. 	initGL(width, height); 	                        // Call our initGL function to set up our OpenGL options
  121.  
  122. 	ILstring imageFilename = "abstract-image.jpg";  // Specify filename
  123.  
  124. 	textureHandle = ilutGLLoadImage(imageFilename); // Load image directly to texture
  125.  
  126. 	// Output last image loaded properties
  127. 	// Available properties list is at: http://www-f9.ijs.si/~matevz/docs/DevIL/il/f00027.htm
  128. 	std::cout << "Image width         : " << ilGetInteger(IL_IMAGE_WIDTH)          << std::endl;
  129. 	std::cout << "Image height        : " << ilGetInteger(IL_IMAGE_HEIGHT)         << std::endl;
  130. 	std::cout << "Image bits per pixel: " << ilGetInteger(IL_IMAGE_BITS_PER_PIXEL) << std::endl;
  131.  
  132. 	// Main loop
  133. 	while (running == true)
  134. 	{
  135. 		// Draw our scene
  136. 		drawScene();
  137.  
  138. 		// exit if ESC was pressed or window was closed
  139. 		running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam( GLFW_OPENED);
  140. 	}
  141.  
  142. 	glfwTerminate();
  143.  
  144. 	return 0;
  145. }

End Result

If you’ve linked in the libraries and used source code like the above, you should end up with a working texture that looks something like this:
ilutGLLoadImage Example

And information regarding the image being used that looks something like this:
DevIL Image Data

I’ve attached a copy of my Code::Blocks project here for anyone who wants it.

Cheers!

Credits: The wallpaper I used as the texture in this guide is Life by N.Design Studio, which you can find here.

How to: Build GLEW on Debian

GLEW - The GL Extension WranglerI’ve just jumped ship from Ubuntu to Linux Mint Debian Edition (20011-08 RC1, 64-bit Gnome version) because as much as I tried, I just couldn’t get along with Xfce and Thunar, and I’ve had it up to my eyeballs with the Ubuntu desktop experience *@&%ers making decisions for me.

So now I need to be able to build the latest version of a few packages. Again. In this case, it’s GLEW 1.7.0 – but thankfully this one’s pretty do-able:

1.) Install some GLEW build pre-req’s with:

sudo apt-get install libxmu-headers libxmu-dev libxi-dev

2.) Get the GLEW source and extract it.

3.) If you want to install in /usr/local/ instead of /usr/ (which is generally a good idea for packages you’ve built yourself so you can easily distinguish them from “system packages”) then edit the Makefile in your extracted glew folder and make the following change:

GLEW_DEST ?= /usr

Should be modified to read:

GLEW_DEST ?= /usr/local

4.) On Debian it appears that /usr/local/lib64 doesn’t already exist as a symlink to /usr/local/lib (which means that you could end up with some of your stuff in the local/lib folder and some in the local/lib64 folder – which would be rubbish), so create the symlink yourself first with:

sudo ln -s /usr/local/lib /usr/local/lib64

5.) Run make then sudo make install

6.) Finally, once you have your GLEW stuff installed, don’t forget to link in libGL.so to your OpenGL projects, which if you’re making the switch from Ubuntu to Debian like I am, have now moved from /usr/lib/libGL.so to /usr/lib/x86_64-linux-gnu/libGL.so, at least on my 64-bit setup.

Fun, eh? Sheesh!

How to: manipulate webcam streams with OpenCV and OpenGL

Okay – third and final part… I saw a video, I wanted to recreate the effect they used, and now I have, on a live, real-time-processed webcam stream using C++, OpenCV and OpenGL. Yay! =D

Full source code after the jump =D

Continue reading How to: manipulate webcam streams with OpenCV and OpenGL

2D C++ OpenGL/GLFW Basecode

I’m teaching some games programming stuff this year, and we’d started off using SDL, but the students are having a hard time with it – the main problems being:
– It’s bulky,
– It demands control of the mainline and then bloats it,
– The documentation is okay, but significantly less than stellar.

This isn’t to say that I have much against SDL – it does a lot of good things, but I’m concerned it’s providing too much specific functionality, which I don’t want to rely on and be tied to when (not if) things change in the future. So with this in mind, I’ve spent the evening reading about OpenGL frameworks and have decided to take the class in a new direction – namely GLFW, the cross-platform OpenGL framework.

We’re mainly going to be working in 2D, so I’ve put together some OpenGL/GLFW basecode that initialises a window, sets orthogonal projection (i.e. things further away don’t get any smaller) and just draws a line from the top-left to the bottom-right (so is easy to strip out when you want to adapt it to your own purposes) – and the entire thing is only around 100 lines of code! (and that’s with stacks of whitespace). The equivalent in SDL is closer to 350 lines and is significantly more complex/complex-looking.

Check it out…

  1. // OpenGL/GLFW Basecode | r3dux
  2.  
  3. #include <iostream>
  4. #include <GL/glfw.h> // Include OpenGL Framework library
  5. using namespace std;
  6.  
  7. void initGL(int width, int height)
  8. {
  9. 	// ----- Window and Projection Settings -----
  10.  
  11. 	// Set the window title
  12. 	glfwSetWindowTitle("GLFW Basecode");
  13.  
  14. 	// Setup our viewport to be the entire size of the window
  15. 	glViewport(0, 0, (GLsizei)width, (GLsizei)height);
  16.  
  17. 	// Change to the projection matrix, reset the matrix and set up orthagonal projection (i.e. 2D)
  18. 	glMatrixMode(GL_PROJECTION);
  19. 	glLoadIdentity();
  20. 	glOrtho(0, width, height, 0, 0, 1); // Paramters: left, right, bottom, top, near, far
  21.  
  22. 	// ----- OpenGL settings -----
  23.  
  24. 	glfwSwapInterval(1); 		// Lock to vertical sync of monitor (normally 60Hz, so 60fps)
  25.  
  26. 	glEnable(GL_SMOOTH);		// Enable (gouraud) shading
  27.  
  28. 	glDisable(GL_DEPTH_TEST); 	// Disable depth testing
  29.  
  30. 	glEnable(GL_BLEND);		// Enable blending (used for alpha) and blending function to use
  31. 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  32.  
  33. 	glLineWidth(5.0f);		// Set a 'chunky' line width
  34.  
  35. 	glEnable(GL_LINE_SMOOTH);	// Enable anti-aliasing on lines
  36.  
  37. 	glPointSize(5.0f);		// Set a 'chunky' point size
  38.  
  39. 	glEnable(GL_POINT_SMOOTH);	// Enable anti-aliasing on points
  40. }
  41.  
  42. void drawScene()
  43. {
  44. 	// Clear the screen
  45. 	glClear(GL_COLOR_BUFFER_BIT);
  46.  
  47. 	// Reset the matrix
  48. 	glMatrixMode(GL_MODELVIEW);
  49. 	glLoadIdentity();
  50.  
  51. 	// ----- Draw stuff! -----
  52.  
  53. 	glBegin(GL_LINES);
  54. 		glColor3ub(255, 0, 0);
  55. 		glVertex2f(0.0f, 0.0f);
  56.  
  57. 		glColor3ub(0, 0, 255);
  58. 		glVertex2f(800.0f, 600.0f);
  59. 	glEnd();
  60.  
  61. 	// ----- Stop Drawing Stuff! ------
  62.  
  63. 	glfwSwapBuffers(); // Swap the buffers to display the scene (so we don't have to watch it being drawn!)
  64. }
  65.  
  66. int main()
  67. {
  68. 	// Frame counter and window settings variables
  69. 	int frame      = 0, width     = 800, height      = 600;
  70. 	int redBits    = 8, greenBits = 8,   blueBits    = 8;
  71. 	int alphaBits  = 8, depthBits = 0,   stencilBits = 0;
  72.  
  73. 	// Flag to keep our main loop running
  74. 	bool running = true;
  75.  
  76. 	// Initialise glfw
  77. 	glfwInit();
  78.  
  79. 	// Create a window
  80. 	if(!glfwOpenWindow(width, height, redBits, greenBits, blueBits, alphaBits, depthBits, stencilBits, GLFW_WINDOW))
  81. 	{
  82. 		cout << "Failed to open window!" << endl;
  83. 		glfwTerminate();
  84. 		return 0;
  85.     	}
  86.  
  87. 	// Call our initGL function to set up our OpenGL options
  88. 	initGL(width, height);
  89.  
  90. 	while (running == true)
  91. 	{
  92.     		// Increase our frame counter
  93.         	frame++;
  94.  
  95. 		// Draw our scene
  96. 		drawScene();
  97.  
  98. 		// exit if ESC was pressed or window was closed
  99. 		running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
  100. 	}
  101.  
  102. 	glfwTerminate();
  103.  
  104. 	return 0;
  105. }

How streamlined is that?!? Sweeeeeeet!

Next task – do stuff with it! =D

P.S. If you wanted to add GLEW to it to take care of all your extension wrangling needs, then just add the glew.h header before glfw.h, include the glew library in your project and add the following to the top of the initGL function:

//  ----- Initialise GLEW -----
 
GLenum err = glewInit();
if (GLEW_OK != err)
{
	cout << "GLEW initialisation error: " << glewGetErrorString(err) << endl;
	exit(-1);
}
cout << "GLEW intialised successfully. Using GLEW version: " << glewGetString(GLEW_VERSION) << endl;

Cheers!

Update: Modified initGL() function to disable the depth testing correctly via glDisable(GL_DEPTH_TEST) and not glDisable(GL_DEPTH) – silly mistake.