OpenGL Cheatsheet
Basics
Use this OpenGL reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Setup and Initialization
OpenGL is a state machine. You set state, then draw; state persists until changed. A context must be created before any GL call — the context owns all GL objects.
// Typical GLFW + GLAD bootstrap #include <glad/glad.h> #include <GLFW/glfw3.h> glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // macOS GLFWwindow* window = glfwCreateWindow(800, 600, "Title", nullptr, nullptr); glfwMakeContextCurrent(window); // bind context to this thread if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { /* fail */ }
Context Hints (common glfwWindowHint values)
| Hint | Values | Notes |
|---|---|---|
GLFW_CONTEXT_VERSION_MAJOR | 3–4 | Major GL version |
GLFW_CONTEXT_VERSION_MINOR | 0–6 | Minor GL version |
GLFW_OPENGL_PROFILE | GLFW_OPENGL_CORE_PROFILE / GLFW_OPENGL_COMPAT_PROFILE | Core removes deprecated APIs |
GLFW_OPENGL_FORWARD_COMPAT | GL_TRUE | Required on macOS |
GLFW_SAMPLES | 0, 2, 4, 8 | MSAA sample count |
GLFW_DOUBLEBUFFER | GL_TRUE (default) | Double-buffered swap |
GLFW_RESIZABLE | GL_TRUE / GL_FALSE | Window resizable |
GLFW_VISIBLE | GL_TRUE / GL_FALSE | Show on creation |
The Render Loop
glViewport(0, 0, 800, 600); // map NDC to pixel coords while (!glfwWindowShouldClose(window)) { glfwPollEvents(); // process input events glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // set clear color (RGBA, 0–1) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // --- draw calls here --- glfwSwapBuffers(window); // present back buffer } glfwTerminate();
Clear mask bits
| Bit | Clears |
|---|---|
GL_COLOR_BUFFER_BIT | Color buffer to glClearColor value |
GL_DEPTH_BUFFER_BIT | Depth buffer to glClearDepth value (default 1.0) |
GL_STENCIL_BUFFER_BIT | Stencil buffer to glClearStencil value (default 0) |
Querying Capabilities
GLint maxTexUnits; glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTexUnits); const GLubyte* vendor = glGetString(GL_VENDOR); const GLubyte* renderer = glGetString(GL_RENDERER); const GLubyte* version = glGetString(GL_VERSION); const GLubyte* glsl = glGetString(GL_SHADING_LANGUAGE_VERSION);
Common glGetIntegerv queries
| Token | Description |
|---|---|
GL_MAX_TEXTURE_SIZE | Max 1D/2D texture dimension |
GL_MAX_3D_TEXTURE_SIZE | Max 3D texture dimension |
GL_MAX_TEXTURE_IMAGE_UNITS | Max texture units in fragment shader |
GL_MAX_VERTEX_ATTRIBS | Max vertex attribute slots (≥16) |
GL_MAX_UNIFORM_BLOCK_SIZE | Max UBO size in bytes |
GL_MAX_SAMPLES | Max MSAA samples |
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS | Across all shader stages |
Error Handling
// Poll every error (can be called in a loop) GLenum err; while ((err = glGetError()) != GL_NO_ERROR) { // err is one of the values below }
Error codes
| Code | Meaning |
|---|---|
GL_NO_ERROR | No error |
GL_INVALID_ENUM | Enum argument out of range |
GL_INVALID_VALUE | Numeric argument out of range |
GL_INVALID_OPERATION | Invalid operation for current state |
GL_INVALID_FRAMEBUFFER_OPERATION | Framebuffer not complete |
GL_OUT_OF_MEMORY | Not enough memory |
// GL 4.3+ debug output (preferred over polling) glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); // call on the thread that triggered it glDebugMessageCallback([](GLenum src, GLenum type, GLuint id, GLenum sev, GLsizei len, const GLchar* msg, const void* param) { fprintf(stderr, "GL: %s\n", msg); }, nullptr); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE); // silence trivial notifications
Enable / Disable Capabilities
glEnable(cap); // turn on glDisable(cap); // turn off GLboolean b = glIsEnabled(cap);
Common capability tokens
| Token | Effect |
|---|---|
GL_DEPTH_TEST | Fragment depth comparison |
GL_STENCIL_TEST | Stencil test |
GL_BLEND | Alpha blending |
GL_CULL_FACE | Back/front face culling |
GL_SCISSOR_TEST | Restrict rendering to scissor rect |
GL_MULTISAMPLE | MSAA (usually on by default) |
GL_LINE_SMOOTH | Anti-aliased lines (legacy) |
GL_POLYGON_OFFSET_FILL | Depth offset for filled polys |
GL_PRIMITIVE_RESTART | Restart index in index buffers |
GL_DEBUG_OUTPUT | Async debug messages (4.3+) |
GL_FRAMEBUFFER_SRGB | sRGB-correct writes to sRGB FBOs |
Viewport and Scissor
glViewport(x, y, width, height); // lower-left origin, pixels glDepthRange(nearVal, farVal); // NDC Z → window Z (default 0,1) glScissor(x, y, width, height); // must also glEnable(GL_SCISSOR_TEST)
Gotcha: after a window resize you must call
glViewportagain. GLFW does not do it automatically.
Object Naming Pattern
Every GL object follows the same generate / bind / delete lifecycle:
GLuint id; glGen*(1, &id); // allocate name (no storage yet) glBind*(target, id); // bind → subsequent calls operate on it // ... configure / upload ... glDelete*(1, &id); // free GPU resources
This pattern applies to: textures, buffers, VAOs, framebuffers, renderbuffers, samplers, queries, transform-feedback objects, and program pipelines.