easy-gl is a toolkit-independent C++20 wrapper over OpenGL and OpenGLES.
It provides a small, modern API for common rendering tasks while keeping platform integration in the host application.
- No windowing toolkit lock-in (
SDL,GLFW,Qt, etc. stay in host code). - No context creation in the library (host owns window + GL context lifecycle).
- Public API under
include/easyglwithout exposing toolkit types. - OpenGL/OpenGLES differences are handled through capability checks.
- Current focus is a small working vertical slice (Hello Triangle first).
This repository currently provides the core needed for initialization, capability detection, and basic draw flow used by:
hello-triangle-sdlexampleeasy-gl-smoke-testseasy-gl-resource-smoke-tests
The API is intentionally compact and evolving.
easy-gl owns OpenGL/OpenGLES interaction.
The host application owns:
- window creation
- GL context creation and activation
- event processing
- swap/present
- providing a
GetProcAddresscallback
easy-gl does not create windows or contexts.
- C++20 compiler
- CMake
3.23+ - A working OpenGL/OpenGLES runtime on target machine
- Host-side context/toolkit integration (example uses
SDL3)
cmake -S . -B build \
-DEASYGL_BUILD_TESTS=ON \
-DEASYGL_BUILD_EXAMPLES=ON
cmake --build build --target easy-gl hello-triangle-sdl easy-gl-smoke-tests easy-gl-resource-smoke-testsEASYGL_BUILD_SHARED(defaultOFF) — build shared instead of static library.EASYGL_BUILD_TESTS(defaultON) — build test executables.EASYGL_BUILD_EXAMPLES(defaultON) — build integration placeholder examples.EASYGL_ENABLE_WARNINGS(defaultON) — enable warning profile.EASYGL_USE_SYSTEM_OPENGL(defaultON) — link system OpenGL where applicable.
ctest --test-dir build --output-on-failureAfter your host app creates and activates a GL context, initialize easy-gl with a loader callback:
#include <easygl/easygl.hpp>
easygl::Device device;
device.initialize(my_get_proc_address); // easygl::GLGetProcAddressFnToolkit-specific examples are available in:
examples/integration-placeholder/README.md
easygl::Device device;
device.initialize(my_get_proc_address);
easygl::Shader vs(easygl::ShaderStage::Vertex);
vs.compile_from_source(vertex_source);
easygl::Shader fs(easygl::ShaderStage::Fragment);
fs.compile_from_source(fragment_source);
easygl::Program program;
program.attach(vs);
program.attach(fs);
program.link();
easygl::VertexArray vao;
vao.create();
easygl::Buffer vbo;
vbo.create();
vbo.bind(easygl::BufferTarget::Array);
vbo.set_data(vertices, vertices_size);
vao.bind();
vao.set_attribute_pointer(0, 3, easygl::DataType::Float, false, stride, offset);
vao.enable_attribute(0);
device.set_clear_color(0.2f, 0.3f, 0.3f, 1.0f);
device.clear(easygl::ClearFlags::Color);
program.use();
vao.bind();
device.draw_arrays(easygl::PrimitiveType::Triangles, 0, 3);For a complete running sample, see:
examples/integration-placeholder/hello-triangle-sdl/HelloTriangle.cpp
Main entry points in include/easygl:
easygl::Device— initialization, state, draw commands.easygl::Capabilities/easygl::ContextInfo— runtime capability/context inspection.easygl::Shader,easygl::Program— shader compile/link/use.easygl::Buffer,easygl::VertexArray,easygl::Texture— GPU resources.easygl::Feature— explicit feature queries and gating.
- Some features are OpenGL-only (for example immediate mode / polygon mode style flags).
- Query support at runtime via
device.supports(...)ordevice.require(...). - Treat unsupported features as unavailable on OpenGLES targets.
Use the umbrella header:
#include <easygl/easygl.hpp>