Creating an OpenGL Window

Go to OpenGL Home

Last time we saw how to setup OpenGL to work with Visual Studio 2013. Now we want to create our first OpenGL window. There are a couple of ways to do that:

  1. Native code, used for large applications where you need to control every option available. Check the Nehe Tutorials for an introduction or a DirectX beginner tutorial.
  2. Using FreeGLUT, designed for small/medium sized OpenGL programs.
  3. Using other library like FreeGLUT e.g. SDL, GLFW, GLUT, GLOW etc

Because we already set up Visual Studio to work with FreeGLUT we will use…FreeGLUT :). FreeGLUT is super easy and simple. With just a few methods we can setup and run the most basic window. These methods are prefixed with “glut” (OpenGL Utility Toolkit) and are really easy to follow and read through your code. Remember that FreeGLUT is not OpenGL, it’s just a window manager.

Modify your main.cpp file that we have created in the previous tutorial with the following code. Make sure you add the correct include files if you didn’t named those folders like me ( I’m talking about these two folders: Dependencies\glew and Dependencies\freeglut )


#include "Dependencies\glew\glew.h"
#include "Dependencies\freeglut\freeglut.h"
#include <iostream>

int main(int argc, char **argv)
{

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(500, 500);//optional
glutInitWindowSize(800, 600); //optional
glutCreateWindow("OpenGL First Window");

glutMainLoop();

return 0;
}

If you try not to compile you will get this message: “The program can’t start because freeglut.dll is missing from your computer. Try reinstalling the program to fix this problem“. The message is pretty clear, we don’t have freeglut.dll in our project. To solve it we have to copy freeglut.dll file from the same place where we extracted FreeGLUT and took freeglut.lib in the previous tutorial (path: lib/x86/Debug ) and copy it to your Debug folder from your project (Debug folder can be found in the same place with .sln file)There should be an .exe file already created there. After that we have to do the same thing for GLEW. Find glew32.dll file where you extracted GLEW (path: bin/Release/Win32) and copy in your Debug Folder. (If you have x64 architecture copy frome x64 folders).
 
freeglut.dll missing

freeglut.dll missing

So far you should have a window and a console displayed on your screen. If you have linker errors (LNK), please check your freeglut.lib and glew.lib files and go back to previous tutorial and make sure that they have been added correctly. For example don’t combine x86 lib files with a x64 build from Visual Studio , also check your paths from  Visual Studio properties.

Freeglut First Window

Freeglut First Window (click to zoom)

 

If everything is good so far, let’s take a look at those functions step by step to see what they actually do:

    • glutInit function will initialize the GLUT library.
    • glutInitDisplayMode is used to to determine the OpenGL display mode for the new window. This function accepts only an unsigned int as an argument and there are a couple of options which can be used. To use more than one option we have to use bitwise OR and the order we OR these options doesn’t matter (it’s an OR). The most common combination is GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA. These options activates some buffers which are required to store data needed for drawing operations.
      1. GLUT_DEPTH tells OpenGL that we want a depth buffer (also called a Z buffer) which is required to determine what colors to draw for a pixel when two or more objects overlaps in our scene (e.g. two triangles overlapping).
      2. GLUT_DOUBLE tells OpenGL that we want a double buffer (back buffer and front buffer) to have a smooth animation and to prevent flickering. In this way OpenGL will draw in a back buffer and will swap this back buffer with front buffer when a complete rendering cycle is finish. The front buffer is the visible one. This technique is also known as Double Buffering or Page Flipping. An advanced form of buffering is where you can also have three buffers known as Triple Buffering but with the adaption of nVidia’s G-Sync or AMD’s FreeSync Triple Buffering is no longer needed. Check out this video.
      3. GLUT_RGBA tells OpenGL how to allocate a 32-bit Framebuffer for the four 8-bit color channels: Red, Green, Blue, and Alpha.
    • glutInitWindowPosition the position of the window on the screen. Arguments are given in pixels.
    • glutInitWindowSize the width and height of our window. Arguments are given in pixels.
    • glutCreateWindow will create the actual window. The argument will be the window’s name. This function also returns the window id.
    • glutMainLoop enters the GLUT processing loop, interupted only by callbacks.

The next step is to render something on the window that we just created. We have to create a simple function called renderScene. In this function we first need to clear the color of our window. Let’s clear it with red. But there is one problem. GLUT doesn’t know anything about this function, so we have to tell him somehow about it. This process is called Callback Registration. We have to tell GLUT how to behave and respond when different events occur. There are different types of events e.g: drawing, reshaping, mouse and keyboard input etc. You can read more about them here.

For the moment we are intersted in the rendering function and we will going to use glutDisplayFunc to register our renderScene function.

OpenGL Clear Color

OpenGL Clear Color

Because we are using a depth buffer we tell OpenGL to enable depth testing which is done by your video card. Sometimes for a more complex scene, you don’t need this test and you can disable and enable it agian in your renderScene function or renderLoop, however you want to call it.  For the moment we just set it outside the loop; it’s optional at the moment for our simple scene.


#include "Dependencies\glew\glew.h"
#include "Dependencies\freeglut\freeglut.h"
#include <iostream>

void renderScene(void)
{

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glClearColor(1.0, 0.0, 0.0, 1.0);//clear red

    glutSwapBuffers();
}

int main(int argc, char **argv)
{

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(500, 500);
glutInitWindowSize(800, 600);
glutCreateWindow("OpenGL First Window");

glEnable(GL_DEPTH_TEST);

// register callbacks
glutDisplayFunc(renderScene);

glutMainLoop();

return 0;
}

Now, dissecting the renderScene function, we see that it’s super easy.

  • glClear tells OpenGL to clear its buffers. In our case Depth and Color. To clear them simultaneously we OR them
  • glClearColor specify clear values for color buffers. These values must be between 0.0 and 1.0. Arguments are : red, green, blue, alpha.
  • glutSwapBuffers swaps between back buffer and front buffer. Remember that we are using double buffering.

Until now we didn’t use GLEW at all. GLEW is used to access OpenGL’s newest methods and extensions. Let’s use it to check OpenGL’s version compatibility for our graphics card.

OpenGL Version

OpenGL Version

Just like FreeGLUT we have to initialize GLEW using glewInit() method. To check GLEW’s version we will use glewIsSupported() method where we need to pass a string as an argument which contains OpenGL version.


#include "Dependencies\glew\glew.h"
#include "Dependencies\freeglut\freeglut.h"
#include <iostream>

void renderScene(void)
 {

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glClearColor(0.0, 0.3, 0.3, 1.0);

    glutSwapBuffers();
}

int main(int argc, char **argv)
{

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(500, 500);
glutInitWindowSize(800, 600);
glutCreateWindow("OpenGL First Window");

glewInit();
if (glewIsSupported("GL_VERSION_4_5"))
{
  std::cout << " GLEW Version is 4.5\n ";
}
else
{
   std::cout << "GLEW 4.5 not supported\n ";
}

glEnable(GL_DEPTH_TEST);
// register callbacks
glutDisplayFunc(renderScene);

glutMainLoop();

return 0;
}

My video card supports OpenGL 4.5 which is the latest version. Check on the Internet which is the latest OpenGL version supported by your video card and modify the string with your version. Here is a list of nVidia video cards compatibile with OpenGL 4.5. If OpenGL 4.5 is not supported by your card just lower the version (e.g. 3.3).

Remarks:

Analyzing the code we can see that OpenGL is a finite state machine. This machine will stay in a persistent state until it receives another message to change the current state. This is good to know for later tutorials when we deal with other techniques where we need to enable/disable options or bind and unbind different OpenGL objects.

Another thing that I want to point out is that OpenGL is a procedural API — it doesn’t  have an OOP (Object-Oriented Programming) API at all. I saw lots and lots of tutorials with just the main.cpp file. Hunderds and hunderds of lines of code in the same file; for a bigger project this leads to a mess. At the end of this chapter, we are going to build a solid OOP wrapper to be able to work more efficiently with OpenGL. This way we will create a design principle called Modular Programming or Separation of Concerns (SoC). This is just a fancy way to describe our architecture — our program is broken down into separate components that are NOT dependent on other pieces — if they were that would be “coupling.”  This lets us use these modules as small “building blocks”  and we can change the inner implementation details without affecting the rest of the program. See: http://en.wikipedia.org/wiki/Separation_of_concerns or http://en.wikipedia.org/wiki/Modular_programming

Until then, let’s go to the next theoretical tutorial to see what is a vertex and a pixel.

Homework:

  • Change clear color to blue.
  • Change clear color to black.


blog comments powered by Disqus