I'm trying to render to a HWND window using a HGLRC OpenGL rendering context.
I have to initiate the glad but gladLoadGLLoader((GLADloadproc)wglGetProcAddress))
and the gladLoadGL()
seems to be failing.
glad OpenGL version : 4.0 core
I've been using the glfwGetProcAdress function until now.
How can I make the gladLoadGLLoader function work? Would it be that I have to indicate the version of the OpenGL to the wglGetProcAddress function or maybe I should use another loader?
Update 1 :
in the gladLoadGLLoader function the problem is (PFNGLGETSTRINGPROC)load("glGetString")
returns null
int gladLoadGLLoader(GLADloadproc load) {
GLVersion.major = 0; GLVersion.minor = 0;
glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
if(glGetString == NULL) //Returns there (fails)
return 0;
if(glGetString(GL_VERSION) == NULL)
return 0;
find_coreGL();
load_GL_VERSION_1_0(load);
load_GL_VERSION_1_1(load);
load_GL_VERSION_1_2(load);
load_GL_VERSION_1_3(load);
load_GL_VERSION_1_4(load);
load_GL_VERSION_1_5(load);
load_GL_VERSION_2_0(load);
load_GL_VERSION_2_1(load);
load_GL_VERSION_3_0(load);
load_GL_VERSION_3_1(load);
load_GL_VERSION_3_2(load);
load_GL_VERSION_3_3(load);
if (!find_extensionsGL()) return 0;
return GLVersion.major != 0 || GLVersion.minor != 0;
}
Update 2 :
The problem seems to be that wglGetProcAddress
is being used to load core OpenGL functions. However, wglGetProcAddress
can only load specific WGL extensions and not core OpenGL stuff.
Update 3 :
As an additional note to the update 2, it seems that the GLFW library also uses wglGetProcAddress
for the glfwGetProcAddress
function
Solved :
void *GetAnyGLFuncAddress(const char *name)
{
void *p = (void *)wglGetProcAddress(name);
if(p == 0 ||
(p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
(p == (void*)-1) )
{
HMODULE module = LoadLibraryA("opengl32.dll");
p = (void *)GetProcAddress(module, name);
}
return p;
}
void Renderer::initGlad(){
//Init GLAD
if (!gladLoadGLLoader((GLADloadproc)GetAnyGLFuncAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
}
}
Replacing wglGetProcAddress
with the void *GetAnyGLFuncAddress(const char *name)
function solves the problem.
"The problem seems to be that wglGetProcAddress
is being used to load core OpenGL functions. However, wglGetProcAddress
can only load specific WGL extensions and not core OpenGL stuff." Indeed, wglGetProcAddress
does have limitations. But it can load OpenGL functions - in fact, most all of them. The restriction is on loading extremely old GL functions that date back to OpenGL 1.1. This is the reason why glGetString
is null - it's an OpenGL 1.1 function, which isn't supported by it.
Fortunately, these age-old functions are the ones that happen to be directly exported by the Windows libary opengl32.dll
itself. Therefore, you can use the Windows function GetProcAddress
on opengl32.dll
for these functions. However GetProcAddress
, of course, does not work on newer GL functions.
But we can create a new function to 'bridge the gap' between these two:
void *GetAnyGLFuncAddress(const char *name)
{
void *p = (void *)wglGetProcAddress(name); // load newer functions via wglGetProcAddress
if(p == 0 ||
(p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
(p == (void*)-1) ) // does it return NULL - i.e. is the function not found?
{
// could be an OpenGL 1.1 function
HMODULE module = LoadLibraryA("opengl32.dll");
p = (void *)GetProcAddress(module, name); // then import directly from GL lib
}
return p;
}
This function, as you can see, first calls wglGetProcAddress
, which works for OpenGL 1.1+ functions. Next, it determines if p
is null, meaning that this function call was not successful. Then it attempts to call GetProcAddress
, working for GL1.1 functions.
Then, it's simply a matter of calling gladLoadGLLoader((GLADloadproc)GetAnyGLFuncAddress))
.
In practice, it is not neccessary to implement such a function yourself. GLAD has the inbuilt function, gladLoadGL
, which if you look at the code, calls gladLoadGLLoader
for the internal get_proc
function. The code in this function does exactly what we've implemented (removing the #if
/#endif
s for other OSes):
void* get_proc(const char *namez) {
void* result = NULL;
if(libGL == NULL) return NULL;
if(gladGetProcAddressPtr != NULL) {
result = gladGetProcAddressPtr(namez); // essentially wglGetProcAddress - see glad's internal open_gl()
}
if(result == NULL) {
result = (void*)GetProcAddress((HMODULE) libGL, namez);
}
return result;
}
It tries to load the OpenGL function via wglGetProcAddress
, and then if that fails, uses GetProcAddress
. Therefore, you can just call gladLoadGL
.
The wiki page Load OpenGL Functions has a lot of info on this.