-
Notifications
You must be signed in to change notification settings - Fork 450
Generate the bindings you need with the online generator, most commonly you just want to select an OpenGL version, add the OpenGL extensions you want and click generate.
If you're not using GLFW
, SDL
, Qt
or a windowing library that provides some kind of GetProcAddress
function, you also need to tick the loader
option.
Add the generated files to your project and compile with them:
src
└── main.c
glad
├── src
│ └── gl.c
├── include
│ ├── glad
│ │ └── gl.h
│ └── KHR
│ └── khrplatform.h
# gcc src/main.c glad/src/gl.c -Iglad/include -lglfw -ldl
Include glad before GLFW:
#include <glad/gl.h>
#include <GLFW/glfw3.h>
Initialize glad after creating a context:
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "[glad] GL with GLFW", NULL, NULL);
glfwMakeContextCurrent(window);
int version = gladLoadGL(glfwGetProcAddress);
printf("GL %d.%d\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
The full example: gl_glfw.c.
Include glad before SDL:
#include <glad/gl.h>
#include <SDL.h>
#include <SDL_opengl.h>
Initialize glad after creating a context:
SDL_GLContext context = SDL_GL_CreateContext(window);
int version = gladLoadGL((GLADloadfunc) SDL_GL_GetProcAddress);
printf("GL %d.%d\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
The full example: gl_sdl2.c.
In the previous glfw
and SDL
examples the windowing library is used to load OpenGL through
glfwGetProcAddress
or SDL_GL_GetProcAddress
.
Glad can be configured to include a loader (by ticking the loader option) and makes the loading independent from the windowing library (you should use the one from the windowing library if you use one!).
// Create OpenGL context first
// Load glad
int version = gladLoaderLoadGL();
printf("GL %d.%d\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
// .. Render
// Unload glad before exiting
gladLoaderUnloadGL();
You can simply download the glad sources from the online generator and compile with them:
glad
├── src
│ └── gl.c
├── include
│ ├── glad
│ │ └── gl.h
│ └── KHR
│ └── khrplatform.h
And in your CMakesLists.txt
:
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/glad/include)
file(GLOB BUTTERFLIES_SOURCES_C ${CMAKE_CURRENT_SOURCE_DIR} *.c glad/src/gl.c)
Using glad with CMake requires a slight modification of your CMakeLists.txt
,
a Python interpreter and the glad sources (e.g. embedded as a git submodule).
cmake_minimum_required(VERSION 3.1)
project(my_project C CXX)
find_package(glfw3 REQUIRED)
# Path to glad directory
set(GLAD_SOURCES_DIR "${PROJECT_SOURCE_DIR}/external/glad/")
# Path to glad cmake files
add_subdirectory("${GLAD_SOURCES_DIR}/cmake" glad_cmake)
# Specify glad settings
glad_add_library(glad_gl_core_33 REPRODUCIBLE API gl:core=3.3)
add_executable(multiwin_mx
multiwin_mx.cpp
)
# Add glad to your project
target_link_libraries(multiwin_mx
PUBLIC
glad_gl_core_33
glfw
)
The full example: multiwin_mx.
All public and glad specific symbols follow certain rules:
- All symbols contain the API (GL, GLES2, WGL, etc.), in the following this will be marked as
{API}
- All symbols are equally named across all APIs (e.g.
gladLoad{API}
) - Functions are prefixed with
glad
- Structs are prefixed with
Glad
- Macros are prefixed with
GLAD_
- Constants/Globals are prefixed with
GLAD_
- Typedefs are prefixed with
GLAD
Everything generated by glad needs to be initialized through one loader function. Glad exposes two with similiar APIs by default:
typedef void (*GLADapiproc)(void);
typedef GLADapiproc (*GLADloadfunc)(const char *name);
typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
int gladLoad{API}(GLADloadfunc load);
int gladLoad{API}UserPtr(GLADuserptrloadfunc load, void *userptr);
gladLoad{API}UserPtr
allows you to pass a userpointer which will be forwarded to your loader function,
this allows you to write a loader function which is independent of global state (useful for GUI frameworks like Qt).
In most cases you will be using gladLoad{API}
, it integrates seamlessly with popular windowing frameworks
like GLFW or SDL:
// GLFW + GL
int version = gladLoadGL(glfwGetProcAddress);
// SDL + GL
int version = gladLoadGL((GLADloadfunc) SDL_GL_GetProcAddress);
int major = GLAD_VERSION_MAJOR(version);
int minor = GLAD_VERSION_MINOR(version);
printf("Loaded OpenGL version %d.%d\n", major, minor);
The return value of gladLoad{API}UserPtr
and gladLoad{API}
is the actual loaded version of the API.
To extract the major and minor version out of the return value you can use the GLAD_VERSION_MAJOR(version)
and GLAD_VERSION_MINOR(version)
macros.
NOTE: since some APIs require additional information in order to be initialized the loader signature may vary depending on the API (e.g. WGL and EGL have different signatures).
After glad was initialized a few variables will be populated. Glad creates a global boolean for every version and extension generated.
int GLAD_{API}_VERSION_3_0;
int GLAD_{API}_VERSION_3_1;
// ...
int GLAD_{API}_EXT_texture_buffer_object;
int GLAD_{API}_KHR_debug;
// ...
If a version/extension was successfully loaded the global will be set to true (1).
Sometimes you want to write glad agnostic code, for this glad generates and defines a few macros dependent on the generation options used.
#define GLAD_{API}
#define GLAD_OPTION_{API}_LOADER
#define GLAD_OPTION_{API}_ALIAS
#define GLAD_OPTION_{API}_{OPTION} // {OPTION} is the enabled loader option
Initializing glad with glfwGetProcAddress
and extracting the loaded major and minor versions:
int version = gladLoadGL(glfwGetProcAddress);
if (version == 0)
{
std::cout << "Failed to initialize OpenGL context" << std::endl;
return -1;
}
// Successfully loaded OpenGL
std::cout << "Loaded OpenGL " << GLAD_VERSION_MAJOR(version) << "." << GLAD_VERSION_MINOR(version) << std::endl;
More examples can be found in the glad repository
The header only option combines source and header into a single header file.
The implementation will be guarded by GLAD_{API}_IMPLEMENTATION
. In order to not end
up with missing symbols you need to define this macro in ONE source file before including
glad.
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
int main(void) {
// ... setup context
if (!gladLoadGL(glfwGetProcAddress)) {
return -1;
}
// ...
}
The loader option adds an internal loader into the generated files. This is useful if you are using a windowing library that does not come with a loader or doing the windowing yourself.
The following functions will be added:
int gladLoaderLoad{API}(void);
void gladLoaderUnload{API}(void); // <- may not exist for certain APIs
If you are using the internal loader gladLoaderLoad{API}
you don't have to call gladLoad{API}
.
int main(void) {
// ... setup context
int version = gladLoaderLoadGL();
if (!version) {
printf("Unable to load OpenGL\n");
return 1;
}
// ... render
gladLoaderUnloadGL();
return 0;
}
NOTE: Even after multiple calls to gladLoaderLoad{API}
only one call to gladLoaderUnload{API}
is required.
The debugging option adds an additional layer of indirection allowing you to intercept and modify any call made.
A non-debug glad build "forwards" your calls using a define to a function pointer prefixed with glad_
, e.g. glClear() -> glad_glClear()
.
With the debug option an additional layer is inserted between glClear
and glad_glClear
:
glClear() -> glad_debug_glClear() -> glad_glClear()
.
By default the additional layer (glad_debug_glClear
) calls the "pre callback",
then the actual function (glad_glClear
) and afterwards the "post callback".
Callbacks can be set with the following functions:
typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
void gladSet{API}PreCallback(GLADprecallback cb);
void gladSet{API}PostCallback(GLADpostcallback cb);
NOTE: the debug option cannot be used together with the multi context option.
Enables automatic alias resolution. A lot of functions and features are implemented in multiple extensions and version.
So you end up with a bunch of function which do exactly the same but are named differently and may be available or not based on the environment you are in.
Glad will automatically include all extensions which have an alias to a function you specified in the feature set and at runtime all functions will be initialized using their aliases.
An excerpt of the generated code:
// executed after initial loading phase:
if (glVertexAttrib2sv == NULL && glVertexAttrib2svARB != NULL) glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)glVertexAttrib2svARB;
if (glVertexAttrib2sv == NULL && glVertexAttrib2svNV != NULL) glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)glVertexAttrib2svNV;
As you can see glVertexAttrib2sv
will be useable if either glVertexAttrib2svARB
or glVertexAttrib2svNV
are available.
By default glad generates everything as a global variable, which works fine for most usecases.
But when you have to support multiple contexts it becomes basically impossible to do so.
If multi context is enabled all function pointers and variables are placed inside a struct
.
Glad generates a struct
called Glad{API}Context
which can be passed to the appropriate
loader function (loader functions are suffixed with Context
).
The symbols within the struct have their prefix stripped, e.g. glClear
turns into gl->Clear
,
this also applies to flags like GLAD_GL_EXT_framebuffer_multisample
which turn into
gl->EXT_framebuffer_multisample
.
By default glad does not generate global aliases. This can be turned on using the "mx global"
option. Next to the context struct a global instance of said struct will be generated, which can be
populated through gladSet{API}Context(struct Glad{API}Context *context)
and queried through struct Glad{API}Context* gladGet{API}Context()
.
// ... setup GL context
GladGLContext context;
int version = gladLoadGLContext(&context, glfwGetProcAddress);
// Alternatively use the internal loader
// int version = gladLoaderLoadGLContext(&context);
if (version == 0)
{
std::cout << "Failed to initialize OpenGL context" << std::endl;
return -1;
}
gl->Viewport(0, 0, WIDTH, HEIGHT);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
gl->ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
gl->Clear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
}
NOTE: the mx option can not be used together with the debug option.