现代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
【OpenGL】GLFW环境配置 + 扩展GLFW使其可以成为MFC子窗口-LMLPHP
将源码中的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声明,如下:
【OpenGL】GLFW环境配置 + 扩展GLFW使其可以成为MFC子窗口-LMLPHP
在原本glfwCreateWindow函数的参数列表中新加入了参数int hParent或者HWND hParent

然后打开win32_platform.h文件,找到其中struct _GLFWwindowWin32定义所在的位置,新加入int handleParent或者HWND handleParent,用来保存父窗口的句柄作为参数传递给创建窗口的函数。如下图所示:
【OpenGL】GLFW环境配置 + 扩展GLFW使其可以成为MFC子窗口-LMLPHP
修改好参数结构体之后,现在实现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,如下图所示。
【OpenGL】GLFW环境配置 + 扩展GLFW使其可以成为MFC子窗口-LMLPHP
修改好了之后, 对代码进行编译,生成新的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));
11-22 14:33