1
2
#include <glad/glad.h>
#include <GLFW/glfw3.h>

请务必在 GLFW 之前包含 GLAD。GLAD 的包含文件在后台包含所需的 OpenGL 头文件(如GL/gl.h),因此请务必在需要 OpenGL 的其他头文件(如 GLFW)之前包含 GLAD。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

首先使用glfwInit()初始化glfw。
然后使用glfwWindowHint()配置glfw。
glfwWindowHint()的第一个参数选择要配置的选项,可以从以GLFW_为前缀的enum集中进行选择。第二个参数是要设定的值。
具体参数不再介绍,可在https://www.glfw.org/docs/latest/window.html#window_hints中查询。

确保您的系统/硬件上安装了 OpenGL 3.3 或更高版本,否则应用程序将崩溃或显示未定义的行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
//glfwCreateWindow创建窗口,并返回GLFWwindow对象。
glfwMakeContextCurrent(window);
//将我们声明好的framebuffer_size_callback()进行绑定。
//注意:我们一般在窗口注册之后和渲染循环之前进行回调函数的注册工作。
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}

// render loop:我们不想要程序绘图之后立即停止并关闭窗口。我们想要程序一直绘图并处理用户输入直到程序被退出。因此我们需要进行循环,即render loop
//frame:render loop的每一次迭代被称为frame。
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);

// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}

在每次循环开始之前,glfwWindowShouldClose()检查窗口是否被命令关闭。如果是则返回true,并且退出render loop。


glfwPollEvents()是一个监听函数。当某个项目被触发时,更新窗口状态并执行对应的回调函数。


glfwSwapBuffers()这个函数暂时不太理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    // glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
//此处使用glfwGetKey()检查用户是否按下了escape键,如果按下了,则会通过glfwSetWindowShouldClose()将窗口的WindowShouldClose设为true。
//因此,在下一次render loop就会退出程序。
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}

还需要通过glViewport()函数告知要渲染窗口的位置和大小。渲染窗口不同于GLFW窗口,它位于GLFW窗口的内部。意味着GLFW窗口内可以包含多个渲染窗口。


framebuffer_size_callback()函数是GLFW窗口大小调整的回调函数。只要GLFW窗口大小发生改变,就调用这个函数。


此处,只要GLFW窗口改变,就调整渲染窗口。