现代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);
-
终止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);
扩展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));