Support me!
If you enjoy these webpages and you want to show your gratitude, feel free to support me in anyway!
Like Me On Facebook! Megabyte Softworks Facebook
Like Me On Facebook! Megabyte Softworks Patreon
Donate $1
Donate $2
Donate $5
Donate $10
Donate Custom Amount
001.) Creating OpenGL4 Window

Welcome to OpenGL4 tutorials series! This is a brand new series of tutorials, that might be similar to OpenGL3 tutorials, but this time, I really want to make things right and optimal and systematic. The old tutorials contained several mistakes and bad practices, so I decided to start on a "green field", from the scratch. Also I have decided to use GLFW library now, as it seems to be very widely used and people reading this might have already experience with it, so I think this is the right way to go. Also, I will try to write these tutorials in a platform-agnostic sense, so that one might compile them on Linux and Mac as well.

This series will focus on the most modern features of OpenGL and will try to cover them, step by step. These tutorials are hosted on GitHub, as I really find git really nice and easy to use. For those, who have no idea, what is git and how does it work, check out my tutorial on git:

What is git? For absolute git newbies (to be written)

So let's get started straight away! First thing that we should discuss, is how to set-up the tutorials, so that you can compile and run them on your own computer.

Setting up the tutorials - cloning repository and dependencies

These tutorials are hosted on GitHub, so first of all, you should clone the repository from GitHub to your computer. Basically, all you have to do is to call something like this from your command line / terminal / git bash:

git clone https://github.com/michalbb1/opengl4-tutorials-mbsoftworks.git

After successfully cloning the whole repository, there is one more step to do. Because my repository has several dependencies (like glm), I have added them to repository as git submodules. Submodule is like another repository in your repository, but they are really independent and you just keep a local copy of them normally. So to properly initialize and download all sumbodules in this repository, you need to go to the cloned repository and run following two commands:

git submodule update --init --recursive
git submodule update --recursive

What those two commands do is, that they first initialize all the submodules (that's the first command) and second downloads them locally. Now you have all the dependencies that you need ! All of the dependencies (a.k.a. libraries we use in our tutorials) are located in the dependencies subdirectory. So far there are GLFW pre-built binaries and also glad library, which stands for GL loader and it loads OpenGL function pointers.

Building tutorials - Visual Studio 2017

If you have Visual Studio (2017 or higher) installed, then setting up these tutorials should really be easy. When you have clone the repository and initialized submodules, building the tutorials in Visual Studio could not have been easier! All you have to do is to open a solution file (as seen on picture below) and press Build :

Now that you have successfully built the tutorials, we can start with the code of first tutorial. It's important that you understand how I keep the files in this new series of tutorials, so that you don't get lost when things get more advanced .

OpenGLWindow class

As mentioned before, these tutorials are using GLFW library to handle most basic stuff, like creating OpenGL window, where we can render our stuff. In my older OpenGL3 tutorials, I have done this manually (using pure Win32 API), but this way is really super-unnecessary, because it just complicates stuff. But anyway, I like wrapping lower-level things into higher level structures, so this time it's gonna be the same and I will wrap the GLFW functionality into my own OpenGLWindow class. You might have noticed, that this class is located in common_classes subdirectory. Basically every class, that will be reused by multiple tutorials will be located there (working with window, shaders, textures etc.).

So here is how the OpenGLWindow class looks like (the header file), we will go through all the important methods:

class OpenGLWindow
{
public:
   OpenGLWindow();

   bool createOpenGLWindow(const std::string& windowTitle, int majorVersion, int minorVersion, bool showFullscreen);

   GLFWwindow* getWindow();

   void runApp();

   void initializeScene();
   void renderScene();
   void releaseScene();

   void handleInput();

   bool keyPressed(int keyCode);
   bool keyPressedOnce(int keyCode);

   void onWindowSizeChanged(GLFWwindow* window, int width, int height);

   void closeWindow(bool hasErrorOccured = false);

   bool hasErrorOccured();

private:
   GLFWwindow* _window = nullptr;
   bool _keyWasPressed[512];
   bool _hasErrorOccured = false;

   static void onWindowSizeChangedStatic(GLFWwindow* window, int width, int height);

   static std::map<GLFWwindow*, OpenGLWindow*> _windows;
};

The idea is to make use of the GLFW easy and to reduce the number of calls needed to have a working OpenGL application to minimum. Let's go all the important functions through. I won't go deep into details, if you want to understand everything deeply, you can investigate those functions yourself and feel free to ask me about the details. But now I really want to focus on OpenGL stuff only in the working OpenGL environment.

  • bool createOpenGLWindow(const std::string& windowTitle, int majorVersion, int minorVersion, bool showFullscreen)
    Calling this method creates OpenGL Window, with specified title and major / minor version of OpenGL. You can decide, if you want to start in fullscreen mode too!
  • GLFWwindow* getWindow()
    Retrieves an instance of GLFWWindow.
  • void runApp()
    Runs OpenGL application. This method is executing the main application loop.
  • void initializeScene()
    This is a method, that gets called, after OpenGL context has been created. It initializes the scene, a.k.a. loads shaders / textures / models etc. This method is implemented by every tutorial, there is no default implementation (that's why it is in header only).
  • void renderScene()
    This method contains whole rendering, that we perform in this tutorial. It's like a main function for rendiering. This method is implemented by every tutorial, there is no default implementation (same as renderScene() method).
  • void releaseScene()
    And this one should release all unreleased resources, that is shaders, models, textures etc. This method is also implemented by every tutorial separately.
  • void handleInput()
    In almost every tutorial, there will be some interaction, like pressing keyboard, camera, mouse etc. We will handle stuff like that in this method.
  • bool keyPressed(int keyCode)
    Helper function, that tells us, if a given key is currently pressed.
  • bool keyPressedOnce(int keyCode)
    Another helper function, but returns true for every keystroke only (that is, holding a key does not count).
  • void onWindowSizeChanged(GLFWwindow* window, int width, int height)
    Callback method, that gets called whenever size of our window changes. That's when you usually recalculate matrices and similar stuff. This is also implemented by every tutorial, because different tutorials might have different needs when changing size of a window.
  • void closeWindow(bool hasErrorOccured = false)
    Call this method anytime to quit the application. It also sets the error flag (that can be used when application quitted to inform user what happened).
  • bool hasErrorOccured()
    Checks if error flag has been set.
  • static void onWindowSizeChangedStatic(GLFWwindow* window, int width, int height)
    Just a static version of window resize method (because GLFW does not use modern stuff like std::func, we have to also provide static method that will call instance method then).

So that's about it! I guess everything important has been covered, you can see the detailed implementation of every function. You can feel free to ask me how it works further, but I hope you got the big picture . Let's now move on to the first tutorial and the first OpenGL scene initilization.

Preparing & rendering first OpenGL Scene

Our first OpenGL scene is going to be super simple. It's just going to be an OpenGL Window with a heavenly blue background. But the point is, that that background will be rendered using OpenGL . Let's examine the 001-creating-opengl4-window.cpp file now:

#include "../common_classes/OpenGLWindow.h"

void OpenGLWindow::initializeScene()
{
   glClearColor(0, 0.5f, 1.0f, 1.0f);
}

void OpenGLWindow::renderScene()
{
   glClear(GL_COLOR_BUFFER_BIT);
}

void OpenGLWindow::releaseScene()
{
   // nothing to release at the moment
}

void OpenGLWindow::handleInput()
{
   if (keyPressedOnce(GLFW_KEY_ESCAPE))
   {
      closeWindow();
   }
}

void OpenGLWindow::onWindowSizeChanged(GLFWwindow* window, int width, int height)
{
   glViewport(0, 0, width, height);
}

In the void OpenGLWindow::initializeScene() method, we simply call OpenGL function glClearColor(0, 0.5f, 1.0f, 1.0f). The name might sound to you as it somehow clears the color, but what it actually does is that it SETS the color, with which we shall clear the framebuffer - the thing that we render to and what we see on our screens in the end. It just takes RGBA color components as parameters (red, green, blue and alpha, where alpha is transparency, but will get to that in later tutorials). Calling this method with provided parameters sets the color to the nice heavenly blue color .

In the void OpenGLWindow::renderScene() we are actually doing rendering! What we say with glClear(GL_COLOR_BUFFER_BIT) is that we want to clear the framebuffer's colors. And because we have set the clear color to the blue, the result is that we actually paint blue color all over the window!

void OpenGLWindow::releaseScene() does nothing this time. There is nothing to release in the first tutorial.

void OpenGLWindow::handleInput() is observing, if we haven't pressed ESCAPE key. If we did, we quit the application.

The last function - void OpenGLWindow::onWindowSizeChanged(GLFWwindow* window, int width, int height) will perform action, when we resize the window. What we do is, that we set the OpenGL viewport. OpenGL viewport is just part of the window, that OpenGL takes and where it renders to. Feel free to play with these values, but basically the first two parameters (0, 0) is the lower left corner of the viewport rectangle, in pixels and width and height is... let me guess... yes! Width and height, also in pixels !

Result

This is the fruit of today's effort:

Not very impressive, but hey, it's just the beginning! We will get to impressive stuff later! . You can now continue with the second tutorial, but get ready for an influx of new information - you will learn about shaders, vertex buffer objects and vertex array objects at once!