Create a Game Engine: Part II Preparing OpenGL

As I pointed out in the pervious tutorial, too many things are declared in the main.cpp file and this might affect us later on. I don’t want a main.cpp file with 5000 lines of code. For now we can separate all GL initialization and functionality in other classes/structures and just call them in main.cpp. Of course we could do this in just a single class but I think that would be much better to have a few classes with specific roles in OpenGL preparation.

So here is what we are going to accomplish in this part:

  • Create a Init folder in the already existing Core folder to put our classes
  • Create a WindowInfo structure which keeps our window name, window width and height and start position on the screen.
  • Create a ContextInfo structure to hold information about OpenGL context (eg OpenGL version)
  • Create a FrameBufferInfo structure to keep info about the main buffer.
  • Create the Init_GLEW class to initialize GLEW.

Creating the Init_GLUT class which ties together this structures and call GL functions is presented in the part III.

To be more clear to what we are going to work with, let’s take a look over the Game Engine Architecture image.

Game Engine Architecture. Preparation

Game Engine Architecture. Preparation

 

Let’s create the Init folder first and then we add our classes and structures inside this folder.

init_folder

Add the init folder

Now, add a WindowInfo.h file and create a struct called WindowInfo with the following properties: start position, width and height and the possibility to redimension the  window.

//windowInfo.h
#pragma once
#include <string>

namespace Core
{
  struct WindowInfo
  {
    std::string name;
    int width, height;
    int position_x, position_y;
    bool isReshapable;

    WindowInfo()
    {
      name = "OpenGL tutorial";
      width = 800; height = 600;
      position_x = 300;
      position_y = 300;
      isReshapable = true;
    }

    WindowInfo(std::string name,
               int start_position_x, int start_position_y,
               int width, int height,
               bool is_reshapable)
     {

       this->name = name;
       this->position_x = start_position_x;
       this->position_y = start_position_y;

       this->width = width;
       this->height = height;
       this->isReshapable = is_reshapable;
     }

     //copy constructor
     WindowInfo(const WindowInfo& windowInfo)
     {
       name = windowInfo.name;
       position_x = windowInfo.position_x;
       position_y = windowInfo.position_y;

       width = windowInfo.width;
       height = windowInfo.height;
       isReshapable = windowInfo.isReshapable;
     }

     void operator=(const WindowInfo& windowInfo)
     {

       name = windowInfo.name;

       position_x = windowInfo.position_x;
       position_y = windowInfo.position_y;

       width = windowInfo.width;
       height = windowInfo.height;
       isReshapable = windowInfo.isReshapable;
     }

  };
}

Similar with WindowInfo, we add a ContextInfo.h file and create a struct called ContextInfo with the following properties: major_version, minor_version and core. These settings will be used by OpenGL to set the right version. Back in the Creating an OpenGL Window tutorial we interrogated GLEW to see if version OpenGL 4.5 is supported by GLEW but we didn’t actually set the FreeGLUT OpenGL version manually. By default FreeGLUT tries to use the latest version. In my case 4.5.

OpenGL 1.0 was released back in 1992 when I was 2 years old :). Since then lots of versions have been released. So we have to tell what version we are going to use. Major version is represented by the first number (eg 4) and the minor version is represented by the second number (eg 5). So 4.5 is a valid OpenGL version.

Now, beside version we also have to set the context mode. We can choose between a Core context or a Compatibility context. The Compatibility context is required if you want to have a higher GL version but still want to access deprecated methods from older versions (before OpenGL 3.0). Check out this article for better explanations.

Trick: As I said FreeGLUT uses the latest OpenGL version found on your hardware. But if you try to use a lower version (eg 4.0 or 3.3) and you are in compatibility mode, it won’t work, your version will still be 4.5, the latest version found by FreeGLUT. Lowering your version works only under Core context mode.

//ContextInfo.h
namespace Core{

  //OpenGL versions
  struct ContextInfo
  {
     int major_version, minor_version;
     bool core;

     ContextInfo()//default
     {
       major_version = 3;
       minor_version = 3;
       core = true;
     }

     ContextInfo(int major_version, int minor_version, bool core)
     {
       this->major_version = major_version;
       this->minor_version = minor_version;
       this->core = core;
     }

    //just like windowInfo.h
    //implement copy constructor
    //implement assignment operator
    //these implementations are optional because are special functions
  //http://en.wikipedia.org/wiki/Special_member_functions
  };
}

Now it’s time to create a simple FrameBufferInfo structure. This structure keeps info about the OpenGL display mode. We already talked about this buffer options in  Creating an OpenGL Window tutorial. We need to keep just a simple flag with the OR value result from GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA. However there are other options which can be added by default when we create the window:

  • GLUT_ALPHA tells OpenGL to add an alpha component to color buffer
  • GLUT_STENCIL tells OpenGL to add a stencil buffer. This buffer can store  per-pixel information.We can set a custom behavior based on this information in the rendering process.
  • GLUT_MULTISAMPLE tells OpenGL to create a window with multisampling support but doesn’t enable it. To enable it later you must call glEnable(GL_MULTISAMPLE).
  • More options here : https://www.opengl.org/resources/libraries/glut/spec3/node12.html
#pragma once
#include "../../Dependencies/glew/glew.h"
#include "../../Dependencies/freeglut/freeglut.h"

namespace Core{

  struct FramebufferInfo{

    unsigned int flags;
    bool msaa;//to enable or disable it when wee need it

    FramebufferInfo()
    {
      //default
      flags = GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH;
      msaa = false;
    }

    FramebufferInfo(bool color, bool depth, bool stencil, bool msaa)
    {
      flags = GLUT_DOUBLE; //this is a must
      if (color)
        flags |= GLUT_RGBA | GLUT_ALPHA;
     if (depth)
        flags |= GLUT_DEPTH;
     if (stencil)
        flags |= GLUT_STENCIL;
     if (msaa)
        flags |= GLUT_MULTISAMPLE;
    this->msaa = msaa;
  }

   //(optional)implement copy constructor and assignment operator
 };
}

So far you should have something like this:

Init folder

Init Folder

Also you can compile and run the program to make sure that everything is right even if we didn’t use these structs.

If everything is OK, let’s create the Init_GLEW class first because it is much lighter. Here we create a static method called Init, so we don’t have to initialize this class.

//Init_GLEW.h
#pragma once
#include <iostream>
#include "../../Dependencies/glew/glew.h"
#include "../../Dependencies/freeglut/freeglut.h"
namespace Core{
       //notice that I added another namespace here(optional)
     namespace Init{ 

           class Init_GLEW
          {
             public:
                static void Init();
           };
      }
}

Now let’s see the Init_GLEW.cpp

//Init_GLEW.cpp
#include "Init_GLEW.h"
using namespace Core;
using namespace Core::Init;

void Init_GLEW::Init(){

   glewExperimental = true;
   if (glewInit() == GLEW_OK)
   {
     std::cout << "GLEW: Initialize" << std::endl;
  }

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

That’s all for now, see you in the next part when we put together the Init_GLUT class.

 


blog comments powered by Disqus