【OpenGL】GLFW环境配置 + 扩展GLFW使其可以成为MFC子窗口
文章目录
- OpenGL环境配置
- GLFW配置
- GLFW创建窗口
- 扩展GLFW使其可以成为MFC子窗口
- MFC中使用GLFW
现代OpenGL项目推荐使用GLFW + GLAD来配置使用OpenGL。配置环境:
- VS2017
- glfw-3.4
- glad-opengl4.6-core
OpenGL环境配置
opengl32.lib
已经包含在Microsoft SDK里了,它在Visual Studio安装的时候就默认安装了。将opengl32.lib
添加进链接器设置里即可。
GLFW配置
下载源码 -> CMake生成VS2017项目 -> 编译生成glfw3.lib
将源码中的include/GLFW
目录和生成的glfw3.lib
添加进VS工程属性Linker(链接器)选项卡里的Input(输入)选项卡中。
#include <GLFW/glfw3.h>
GLFW创建窗口
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpengl", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create CLFW window" << std::endl;
glfwTerminate();
return;
}
glfwMakeContextCurrent(window);
//GLAD
/*if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Fail to initialize GLAD";
return;
}*/
//渲染循环
while (!glfwWindowShouldClose(window)) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //状态设置
glClear(GL_COLOR_BUFFER_BIT); //状态使用
// glfw:交换缓冲区和轮询IO事件(按键按下或释放,鼠标移动等)
glfwSwapBuffers(window);
glfwPollEvents();
}
//回收前面分配的GLFW资源
glfwTerminate();
-
初始化GLFW库
int glfwInit(void);
This function initializes the GLFW library. Before most GLFW functions can be used, GLFW must be initialized, and before an application terminates GLFW should be terminated in order to free any resources allocated during or after initialization.
@reentrancy This function must not be called from a callback.
@thread_safety This function must only be called from the main thread. -
终止GLFW库
销毁窗口,回收已分配资源void glfwTerminate(void);
-
将指定的窗口提示设置为所需值。
void glfwWindowHint(int hint, int value);
-
创建窗口
GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share);
-
将窗口上下文设置为当前线程上下文
void glfwMakeContextCurrent(GLFWwindow* window);
-
获取/设置窗口关闭flag
int glfwWindowShouldClose(GLFWwindow* window); void glfwSetWindowShouldClose(GLFWwindow* window, int value);
-
交换指定窗口的
前缓冲区
和后缓冲区
前缓冲区:屏幕上显示的图像。
后缓冲区:正在渲染的图像。void glfwSwapBuffers(GLFWwindow* window);
-
轮询IO事件
void glfwPollEvents(void);
Processes all pending events.
- This function processes only those events that are already in the event queue and then returns immediately. Processing events will cause the window and input callbacks associated with those events to be called.
- On some platforms, a window move, resize or menu operation will cause event processing to block. This is due to how event processing is designed on those platforms. You can use the [window refresh callback](@ref window_refresh) to redraw the contents of your window when necessary during such operations.
- Do not assume that callbacks you set will only be called in response to event processing functions like this one. While it is necessary to poll for events, window systems that require GLFW to register callbacks of its own can pass events to GLFW in response to many window system function calls. GLFW will pass those events on to the application callbacks before returning.
- Event processing is not required for joystick input to work.
扩展GLFW使其可以成为MFC子窗口
修改glfw源码使其可以成为MFC子窗口,重新生成lib。
参考来源:https://blog.csdn.net/sunbibei/article/details/51783783
在VS中,找到glfwCreateWindow
函数的定义位置,是在 glfw3.h
文件中,新加入一个函数glfwCreateWindowEx
声明,如下:
在原本glfwCreateWindow
函数的参数列表中新加入了参数int hParent
或者HWND hParent
然后打开win32_platform.h
文件,找到其中struct _GLFWwindowWin32
定义所在的位置,新加入int handleParent
或者HWND handleParent
,用来保存父窗口的句柄作为参数传递给创建窗口的函数。如下图所示:
修改好参数结构体之后,现在实现glfwCreateWindowEx
定位glfwCreateWindow
函数的定义,定义于文件window.c中。复制glfwCreateWindow
函数的定义, 粘贴在下方,更改函数名为glfwCreateWindowEx
并加入参数 int hParent
在该函数的实现中找到 _glfw.platform.createWindow
函数的调用地方, 在其前方加入window->win32.handleParent = hParent;
GLFWAPI GLFWwindow* glfwCreateWindowEx(int width, int height,
const char* title,
GLFWmonitor* monitor,
GLFWwindow* share,
/*HWND*/int hPerant)
{
_GLFWfbconfig fbconfig;
_GLFWctxconfig ctxconfig;
_GLFWwndconfig wndconfig;
_GLFWwindow* window;
assert(title != NULL);
assert(width >= 0);
assert(height >= 0);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (width <= 0 || height <= 0)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid window size %ix%i",
width, height);
return NULL;
}
fbconfig = _glfw.hints.framebuffer;
ctxconfig = _glfw.hints.context;
wndconfig = _glfw.hints.window;
wndconfig.width = width;
wndconfig.height = height;
wndconfig.title = title;
ctxconfig.share = (_GLFWwindow*)share;
if (!_glfwIsValidContextConfig(&ctxconfig))
return NULL;
window = _glfw_calloc(1, sizeof(_GLFWwindow));
window->next = _glfw.windowListHead;
_glfw.windowListHead = window;
window->videoMode.width = width;
window->videoMode.height = height;
window->videoMode.redBits = fbconfig.redBits;
window->videoMode.greenBits = fbconfig.greenBits;
window->videoMode.blueBits = fbconfig.blueBits;
window->videoMode.refreshRate = _glfw.hints.refreshRate;
window->monitor = (_GLFWmonitor*)monitor;
window->resizable = wndconfig.resizable;
window->decorated = wndconfig.decorated;
window->autoIconify = wndconfig.autoIconify;
window->floating = wndconfig.floating;
window->focusOnShow = wndconfig.focusOnShow;
window->mousePassthrough = wndconfig.mousePassthrough;
window->cursorMode = GLFW_CURSOR_NORMAL;
window->doublebuffer = fbconfig.doublebuffer;
window->minwidth = GLFW_DONT_CARE;
window->minheight = GLFW_DONT_CARE;
window->maxwidth = GLFW_DONT_CARE;
window->maxheight = GLFW_DONT_CARE;
window->numer = GLFW_DONT_CARE;
window->denom = GLFW_DONT_CARE;
window->title = _glfw_strdup(title);
window->win32.handleParent = hPerant; //新增
if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig))
{
glfwDestroyWindow((GLFWwindow*)window);
return NULL;
}
return (GLFWwindow*)window;
}
然后,沿着 _glfwPlatformCreateWindow
函数的函数调用一直找到API CreateWindowExW
函数的调用地方,位于 win32_window.c
文件定义的 static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig)
函数中被调用。在CreateWindowExW
函数前加入下述代码,
if (NULL != window->win32.handleParent) {
exStyle = 0;
style = WS_CHILDWINDOW | (wndconfig->visible ? WS_VISIBLE : 0);
}
并将 CreateWindowExW
函数的倒数第四个参数改成 window->win32.handleParent
,如下图所示。
修改好了之后, 对代码进行编译,生成新的lib
MFC中使用GLFW
HWND hparent = GetDlgItem(IDC_PLAYWND)->m_hWnd;
CRect rect;
GetDlgItem(IDC_PLAYWND)->GetWindowRect(&rect);
int width = rect.Width(),
int height = rect.Height()
std::string title = "WindowName";
glfwInit();
GLFWwindow *glfw_window;
glfw_window = (-1 != hparent)
? (glfwCreateWindowEx(width, height, title.c_str(), NULL, NULL, hparent))
: (glfwCreateWindow(width, height, title.c_str(), NULL, NULL));