Overview
In the Environment Setup lab (Lab 00) you installed the toolchain and verified the project compiles. This lab focuses on what happens at runtime: initialising GLFW to create an OS window, establishing an OpenGL 4.3 Core Profile context, and loading OpenGL function pointers with GLEW. You will then write the main render loop that drives every frame for the rest of the module.
All subsequent labs build directly on the skeleton you produce here. Getting this foundation right, including correct error handling and context version targeting, prevents hard-to-debug failures later.
Prerequisites
- Lab 00 complete: the project compiles and runs without errors.
- GLFW, GLEW, and GLM are available via vcpkg and linked in the project.
- You can open
src/main.cppin Visual Studio.
Learning Objectives
By the end of this lab you will be able to:
- Initialise GLFW and configure OpenGL version hints before window creation.
- Create a GLFW window and make its OpenGL context current on the calling thread.
- Initialise GLEW to load all available OpenGL function pointers at runtime.
- Implement a render loop that clears the colour buffer, swaps buffers, and polls OS events.
- Shut down GLFW and release the window correctly when the loop exits.
Concept
OpenGL does not manage windows or input. It is purely a rendering API. Without a window
there is nowhere to draw, and without a context the GPU driver does not know which
application's state to modify. GLFW solves the first problem: it provides
a cross-platform API for creating OS windows and an attached OpenGL context. Once a
window exists, calling glfwMakeContextCurrent binds that context to the
current thread so every subsequent OpenGL call targets it.
OpenGL function addresses (pointers like glClear, glGenBuffers,
etc.) are not statically linked. They are resolved at runtime from the GPU driver.
GLEW queries the driver for every function the application might use and
stores the addresses in global function pointers. Setting
glewExperimental = GL_TRUE before calling glewInit forces GLEW
to load all extensions even in a Core Profile context, which would otherwise cause some
pointers to remain null.
The main loop runs once per frame. Each iteration clears the previous
frame's pixels with glClear, renders the scene, then calls
glfwSwapBuffers to flip the back buffer to the screen (double-buffering).
Finally, glfwPollEvents processes any queued OS messages such as keyboard
input or window resize. Calling glfwSwapInterval(1) before the loop enables
V-Sync, which ties the swap to the display refresh rate and prevents
screen tearing.
Tasks
Task 1 - Initialise GLFW and Set Version Hints
Open src/main.cpp and add the following at the top of main().
- Call
glfwInit()and check its return value. Print an error message and return-1if it fails. -
Call
glfwWindowHintthree times to target OpenGL 4.3 Core Profile:GLFW_CONTEXT_VERSION_MAJORset to4GLFW_CONTEXT_VERSION_MINORset to3GLFW_OPENGL_PROFILEset toGLFW_OPENGL_CORE_PROFILE
// file: src/main.cpp
int main() {
// TODO: Call glfwInit() and return -1 with an error message if it fails.
// TODO: Set GLFW_CONTEXT_VERSION_MAJOR to 4.
// TODO: Set GLFW_CONTEXT_VERSION_MINOR to 3.
// TODO: Set GLFW_OPENGL_PROFILE to GLFW_OPENGL_CORE_PROFILE.
}
Task 2 - Create the Window and Make the Context Current
Immediately after the hints, create the window and bind its context.
-
Call
glfwCreateWindow(800, 600, "OpenGL Window", NULL, NULL)and store the result in aGLFWwindow*namedwindow. - Check that
windowis notnullptr. If it is, callglfwTerminate()and return-1. - Call
glfwMakeContextCurrent(window)to bind the context to this thread.
// file: src/main.cpp (after the window hints)
// TODO: Create an 800x600 window titled "OpenGL Window".
// Store the result in GLFWwindow* window.
// TODO: If window is nullptr, terminate GLFW and return -1.
// TODO: Make the window's context current on this thread.
Task 3 - Initialise GLEW
After the context is current, load OpenGL function pointers.
- Set
glewExperimental = GL_TRUEbefore callingglewInit. - Call
glewInit(). If it does not returnGLEW_OK, print an error, callglfwTerminate(), and return-1. -
Print the loaded OpenGL version to confirm everything is working:
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl; - Call
glfwSwapInterval(1)to enable V-Sync.
// file: src/main.cpp (after glfwMakeContextCurrent)
// TODO: Set glewExperimental = GL_TRUE.
// TODO: Call glewInit(). If it fails, terminate GLFW and return -1.
// TODO: Print the OpenGL version string using glGetString(GL_VERSION).
// TODO: Call glfwSwapInterval(1) to cap to the monitor refresh rate.
Task 4 - Write the Main Render Loop
Add the loop that runs every frame until the window is closed.
- Write a
whileloop that continues as long as!glfwWindowShouldClose(window)is true. - Inside the loop, call
glClearColor(0.1f, 0.1f, 0.15f, 1.0f)to set a dark blue-grey clear colour. - Call
glClear(GL_COLOR_BUFFER_BIT)to clear the colour buffer. - Call
glfwSwapBuffers(window)to present the back buffer. - Call
glfwPollEvents()to process queued OS events.
// file: src/main.cpp (after glfwSwapInterval)
// TODO: Loop while the window should not close.
while (!glfwWindowShouldClose(window)) {
// TODO: Set the clear colour to a dark blue-grey (r=0.1, g=0.1, b=0.15, a=1.0).
// TODO: Clear the colour buffer.
// TODO: Swap front and back buffers.
// TODO: Poll for OS events (keyboard, mouse, window close).
}
Task 5 - Shutdown and Cleanup
After the loop exits, release all GLFW resources. The code below is provided as a reference - add it after the closing brace of your render loop.
// file: src/main.cpp (after the render loop) -- provided for reference
glfwDestroyWindow(window);
glfwTerminate();
return 0;
- Build the project with Ctrl+Shift+B and check the Output window for errors.
- Run with F5 (Debug) or Ctrl+F5 (without debugger).
- Verify the console prints the OpenGL version string before the window opens.
Expected Result
An 800x600 window titled "OpenGL Window" opens. The interior is filled with a solid dark blue-grey colour (no flickering). The console prints a line similar to:
OpenGL version: 4.3.0 NVIDIA 560.94
Clicking the window's close button exits the application cleanly with no crash or assertion failure. The frame rate is capped to the monitor's refresh rate (typically 60 fps) due to V-Sync.
Extension Challenge
Optional: Make the clear colour pulse smoothly over time. Use
glfwGetTime() inside the loop to get the elapsed seconds as a
float, then pass sin(time) * 0.5f + 0.5f as the red channel
of glClearColor. The window should cycle from dark to a warm reddish tint
and back roughly once per second. Try mapping different channels to sine waves of
different frequencies to produce a colour cycling effect.