存储在全局变量中的函数指针在进入函数时被设置为 0,并在退出函数时返回到之前的状态
Function Pointers stored in global variables get set to 0 when entering function, and get back to previous state when exiting function
我喜欢将编程作为一种爱好,因此我通常在非常低的水平上玩得很开心。
这几天学习了WindowsAPI,如何设置window,打开它,管理消息队列。
为了渲染,我决定使用 OpenGL,并开始学习它。如果不使用像 GLEW 这样自动加载所有功能的库,我必须手动完成所有这些工作。
实际上一切都很顺利。我设法正确加载了所有函数指针并将它们存储在全局变量中,任何人都可以访问,包括这个 .h 文件:
#pragma once
#include "glCoreARB.h"
#include "wglExt.h"
#define internal static
extern "C"
{
//FUNCTION POINTERS
// Debug/Init Functions
static PFNGLGETERRORPROC glGetError;
static PFNGLGETINTEGERVPROC glGetIntegerv;
static PFNGLGETSTRINGIPROC glGetStringi;
static PFNGLGETSTRINGPROC glGetString;
... AND MANY MORE (Not gonna write all of them down, you get it)
//LOADING FUNCTIONS
internal 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;
}
internal void LoadGLFunc(HDC DeviceContext)
{
glGetIntegerv = (PFNGLGETINTEGERVPROC)GetAnyGLFuncAddress("glGetIntegerv");
glGetStringi = (PFNGLGETSTRINGIPROC)GetAnyGLFuncAddress("glGetStringi");
glGetString = (PFNGLGETSTRINGPROC)GetAnyGLFuncAddress("glGetString");
glGetError = (PFNGLGETERRORPROC)GetAnyGLFuncAddress("glGetError");
GLint Version = getGLVersion();
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)GetAnyGLFuncAddress("wglGetExtensionsStringARB");
const char *extensions = wglGetExtensionsStringARB(DeviceContext);
//Once I got the extensions I Loaded all of those function pointers
wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GetAnyGLFuncAddress("wglGetPixelFormatAttribivARB");
... And so on
//Then based on the available OpenGL Version
if (Version >= 33)
{
glGetShaderiv = (PFNGLGETSHADERIVPROC)GetAnyGLFuncAddress("glGetShaderiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)GetAnyGLFuncAddress("glGetShaderInfoLog");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)GetAnyGLFuncAddress("glGetProgramiv");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)GetAnyGLFuncAddress("glGetProgramInfoLog");
... And many more...
所有这些函数指针都通过函数加载到我的 Windows 平台代码中,ScreenInfo 结构包含预先检索到的 DeviceContext 和 WindowHandle
internal VOID Win32_SetupOpenGLRenderingContext(ScreenInfo *Screen)
{
PIXELFORMATDESCRIPTOR PixelFormat = {};
PixelFormat.nSize = sizeof(PIXELFORMATDESCRIPTOR);
PixelFormat.nVersion = 1;
PixelFormat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
PixelFormat.iPixelType = PFD_TYPE_RGBA;
PixelFormat.cColorBits = 32; //Colordepth of the framebuffer
PixelFormat.cDepthBits = 24; //Number of bits for the depthbuffer
PixelFormat.cStencilBits = 8; //Number of bits for the stencilbuffer
Screen->DeviceContext = GetDC(Screen->WindowHandle);
s32 PixelFormatValue = ChoosePixelFormat(Screen->DeviceContext, &PixelFormat);
SetPixelFormat(Screen->DeviceContext, PixelFormatValue, &PixelFormat);
Screen->RenderingContext = wglCreateContext(Screen->DeviceContext);
wglMakeCurrent(Screen->DeviceContext, Screen->RenderingContext);
LoadGLFunc(Screen->DeviceContext);
}
现在,到目前为止一切正常,所有函数指针都已正确加载,我可以调用 Windows 平台代码中的所有 GL 函数.
但是显然,平台代码在其消息循环中调用了应用程序的 MainLoop:
while(Running)
{
MSG Msg;
while (PeekMessageA(&Msg, Screen.WindowHandle, 0, 0, PM_REMOVE))
{
Win32_ProcessKeyboard(&Keyboard, Msg);
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
if (Keyboard.isQuitting)
{
Running = FALSE;
}
}
Loop(&Screen); // THIS FUNCTION HERE!
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (SwapBuffers(Screen.DeviceContext) == FALSE)
{
DWORD Error = GetLastError();
LogError("In swapping buffers error: ", Error);
}
}
在进入循环功能之前一切正常。这是 Loop 函数代码,它在另一个文件中:
extern "C" void GameLoop(ScreenInfo *Screen)
{
RenderTriangle(Screen);
return;
}
RenderTriangle 调用:
internal void RenderTriangle(ScreenInfo *Screen)
{
GLuint shaderProgram;
GLuint VAO = 0;
if (Screen->wasTriangleInit == FALSE)
{
glViewport(0, 0, Screen->Width, Screen->Height);
glBindVertexArray(VAO);
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
THERE IS MORE TO THIS FUNCTION, BUT THE PROBLEM HAPPENS WAY BEFORE, SO I'M PRETTY SURE IT'S IRRELEVANT.
一旦我从平台代码进入循环函数,所有且仅指向 GL 函数的指针用于 RenderTriangle CALL GET SET TO 0x0
我尝试通过在 RenderTriangle 调用中的所有内容之上添加一个 if(0) {} 块来欺骗应用程序以避免崩溃,如下所示:
internal void RenderTriangle(ScreenInfo *Screen)
{
GLuint shaderProgram;
GLuint VAO = 0;
if(0)
{
if (Screen->wasTriangleInit == FALSE)
{
glViewport(0, 0, Screen->Width, Screen->Height);
glBindVertexArray(VAO);
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
像这样,在进入函数的时候,所有的指针还是设置为0x0,但是当我出来重新进入Windows平台文件的那一刻,所有的函数指针被重新设置为正确的值.
我真的不知道在这里做什么或发生了什么。有帮助吗?
如果在头文件中写入
static PFNGLGETERRORPROC glGetError;
每个 c/cpp
都有自己的 glGetError
的私有副本并且它不会与其他副本冲突,因为它 static
- 所以不同的 cpp
文件使用不同版本的 glGetError
- 在一个 cpp 单元中你初始化一个版本并且它!=0,当你进入另一个 cpp 单元时 - 你使用 uninit 版本,ant it 0. 当你 return 到原始单元时 - 再次!= 0 ;
所以错误声明的问题。
您需要将其声明为
extern PFNGLGETERRORPROC glGetError;
在 .h
文件中并作为
PFNGLGETERRORPROC glGetError;
在任何单个 cpp 中。文件。
或声明为
__declspec(selectany) PFNGLGETERRORPROC glGetError;
我喜欢将编程作为一种爱好,因此我通常在非常低的水平上玩得很开心。
这几天学习了WindowsAPI,如何设置window,打开它,管理消息队列。
为了渲染,我决定使用 OpenGL,并开始学习它。如果不使用像 GLEW 这样自动加载所有功能的库,我必须手动完成所有这些工作。
实际上一切都很顺利。我设法正确加载了所有函数指针并将它们存储在全局变量中,任何人都可以访问,包括这个 .h 文件:
#pragma once
#include "glCoreARB.h"
#include "wglExt.h"
#define internal static
extern "C"
{
//FUNCTION POINTERS
// Debug/Init Functions
static PFNGLGETERRORPROC glGetError;
static PFNGLGETINTEGERVPROC glGetIntegerv;
static PFNGLGETSTRINGIPROC glGetStringi;
static PFNGLGETSTRINGPROC glGetString;
... AND MANY MORE (Not gonna write all of them down, you get it)
//LOADING FUNCTIONS
internal 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;
}
internal void LoadGLFunc(HDC DeviceContext)
{
glGetIntegerv = (PFNGLGETINTEGERVPROC)GetAnyGLFuncAddress("glGetIntegerv");
glGetStringi = (PFNGLGETSTRINGIPROC)GetAnyGLFuncAddress("glGetStringi");
glGetString = (PFNGLGETSTRINGPROC)GetAnyGLFuncAddress("glGetString");
glGetError = (PFNGLGETERRORPROC)GetAnyGLFuncAddress("glGetError");
GLint Version = getGLVersion();
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)GetAnyGLFuncAddress("wglGetExtensionsStringARB");
const char *extensions = wglGetExtensionsStringARB(DeviceContext);
//Once I got the extensions I Loaded all of those function pointers
wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GetAnyGLFuncAddress("wglGetPixelFormatAttribivARB");
... And so on
//Then based on the available OpenGL Version
if (Version >= 33)
{
glGetShaderiv = (PFNGLGETSHADERIVPROC)GetAnyGLFuncAddress("glGetShaderiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)GetAnyGLFuncAddress("glGetShaderInfoLog");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)GetAnyGLFuncAddress("glGetProgramiv");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)GetAnyGLFuncAddress("glGetProgramInfoLog");
... And many more...
所有这些函数指针都通过函数加载到我的 Windows 平台代码中,ScreenInfo 结构包含预先检索到的 DeviceContext 和 WindowHandle
internal VOID Win32_SetupOpenGLRenderingContext(ScreenInfo *Screen)
{
PIXELFORMATDESCRIPTOR PixelFormat = {};
PixelFormat.nSize = sizeof(PIXELFORMATDESCRIPTOR);
PixelFormat.nVersion = 1;
PixelFormat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
PixelFormat.iPixelType = PFD_TYPE_RGBA;
PixelFormat.cColorBits = 32; //Colordepth of the framebuffer
PixelFormat.cDepthBits = 24; //Number of bits for the depthbuffer
PixelFormat.cStencilBits = 8; //Number of bits for the stencilbuffer
Screen->DeviceContext = GetDC(Screen->WindowHandle);
s32 PixelFormatValue = ChoosePixelFormat(Screen->DeviceContext, &PixelFormat);
SetPixelFormat(Screen->DeviceContext, PixelFormatValue, &PixelFormat);
Screen->RenderingContext = wglCreateContext(Screen->DeviceContext);
wglMakeCurrent(Screen->DeviceContext, Screen->RenderingContext);
LoadGLFunc(Screen->DeviceContext);
}
现在,到目前为止一切正常,所有函数指针都已正确加载,我可以调用 Windows 平台代码中的所有 GL 函数.
但是显然,平台代码在其消息循环中调用了应用程序的 MainLoop:
while(Running)
{
MSG Msg;
while (PeekMessageA(&Msg, Screen.WindowHandle, 0, 0, PM_REMOVE))
{
Win32_ProcessKeyboard(&Keyboard, Msg);
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
if (Keyboard.isQuitting)
{
Running = FALSE;
}
}
Loop(&Screen); // THIS FUNCTION HERE!
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (SwapBuffers(Screen.DeviceContext) == FALSE)
{
DWORD Error = GetLastError();
LogError("In swapping buffers error: ", Error);
}
}
在进入循环功能之前一切正常。这是 Loop 函数代码,它在另一个文件中:
extern "C" void GameLoop(ScreenInfo *Screen)
{
RenderTriangle(Screen);
return;
}
RenderTriangle 调用:
internal void RenderTriangle(ScreenInfo *Screen)
{
GLuint shaderProgram;
GLuint VAO = 0;
if (Screen->wasTriangleInit == FALSE)
{
glViewport(0, 0, Screen->Width, Screen->Height);
glBindVertexArray(VAO);
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
THERE IS MORE TO THIS FUNCTION, BUT THE PROBLEM HAPPENS WAY BEFORE, SO I'M PRETTY SURE IT'S IRRELEVANT.
一旦我从平台代码进入循环函数,所有且仅指向 GL 函数的指针用于 RenderTriangle CALL GET SET TO 0x0
我尝试通过在 RenderTriangle 调用中的所有内容之上添加一个 if(0) {} 块来欺骗应用程序以避免崩溃,如下所示:
internal void RenderTriangle(ScreenInfo *Screen)
{
GLuint shaderProgram;
GLuint VAO = 0;
if(0)
{
if (Screen->wasTriangleInit == FALSE)
{
glViewport(0, 0, Screen->Width, Screen->Height);
glBindVertexArray(VAO);
GLfloat vertices[] =
{
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
像这样,在进入函数的时候,所有的指针还是设置为0x0,但是当我出来重新进入Windows平台文件的那一刻,所有的函数指针被重新设置为正确的值.
我真的不知道在这里做什么或发生了什么。有帮助吗?
如果在头文件中写入
static PFNGLGETERRORPROC glGetError;
每个 c/cpp
都有自己的 glGetError
的私有副本并且它不会与其他副本冲突,因为它 static
- 所以不同的 cpp
文件使用不同版本的 glGetError
- 在一个 cpp 单元中你初始化一个版本并且它!=0,当你进入另一个 cpp 单元时 - 你使用 uninit 版本,ant it 0. 当你 return 到原始单元时 - 再次!= 0 ;
所以错误声明的问题。
您需要将其声明为
extern PFNGLGETERRORPROC glGetError;
在 .h
文件中并作为
PFNGLGETERRORPROC glGetError;
在任何单个 cpp 中。文件。
或声明为
__declspec(selectany) PFNGLGETERRORPROC glGetError;