1.编译GLFW生成LIB库文件

由于在Windows平台下初始化OpenGL非常麻烦,不仅需要创建OpenGL上下文,而且更麻烦的是调用OpenGL的GPU驱动的函数(具体多麻烦查看我的博文)。所以推荐使用第三方已经写好的库GLFW,类似的库还有GLUT。

GLFW是跨平台的抽象层,所以同一份代码在Windows和Linux下都可以运行。

GLFW提供了创建窗口,创建OpenGL上下文,管理键盘和鼠标的事件,甚至还提供多线程管理等跨平台的功能。功能越来越多了。

在GLFW官网上,找到他们的源码页,并下载到本地。

进入到glfw目录下

创建build文件夹,然后使用cmake构建出glfw项目文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12


cd glfw


mkdir build


cd build


cmake

用VS打开GLFW.sln

执行项目,执行完毕后,观察src/Release文件夹下多了我们需要的静态链接库文件glfw3.lib

2.使用GLFW库

1.以动态库方式使用

以后使用GLFW库时,在项目中添加包含的头目录和库目录

打开VS开发工具选择下面菜单:

头目录:

“Project>Properties>Configuration Properties>VC++ Directories>General> Include Directories”

添加

“D:\libs\glfw\include”

(上面路劲你根据自己情况填写)

2.以静态库方式使用

在这里我建议直接把静态链接库文件拷贝到项目下。

然后在项目代码中将库文件包含进去。

1
2
3


#pragma comment (lib, “glfw3.lib”)

这样生成的代码就包含静态库的内容了,移植时减少了bug的风险。

代码样例:

  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
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156


#include <GLFW/glfw3.h>


#include <gl/GL.h>


#include <iostream>





#pragma comment (lib, "opengl32.lib")


#pragma comment (lib, "glfw3.lib")





void error_callback(int code, const char* description);





int main(void)


{


    GLFWwindow* window;





    /* Handle GLFW Error */


    glfwSetErrorCallback(error_callback);





    /* Initialize the library */


    if (!glfwInit())


        return -1;





    /* Create a windowed mode window and its OpenGL context */


    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);


    if (!window)


    {


        glfwTerminate();


        return -1;


    }





    /* Make the window's context current */


    glfwMakeContextCurrent(window);





    /* Loop until the user closes the window */


    while (!glfwWindowShouldClose(window))


    {


        /* Render here */


        glClear(GL_COLOR_BUFFER_BIT);





        /* Swap front and back buffers */


        glfwSwapBuffers(window);





        /* Poll for and process events */


        glfwPollEvents();


    }





    glfwTerminate();


    return 0;


}





void error_callback(int code, const char* description)


{


    std::cout << code << ":" << description << std::endl;


}

3. GLFW的基本用法

GLFW初始化和终止

在使用GLFW大部分函数之前需要对GLFW库进行初始化,初始化的工作内容包括检查平台包含的特定功能。GLFW库初始化通过glfwInit进行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12


if(!glfwInit())


{


	// handle initialization failure


}

如果初始化成功则会返回GLFW_TRUE、否则返回GLFW_FALSE。

在初始化之前,GLFW函数中只有下面几个函数可以使用,调用其他函数将会报GLFW_NOT_INITALIZED错误。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15


glfwGetVersion


glfwGetVersionString


glfwGetError


glfwSetErrorCallback


glfwInitHint

在应用程序退出之前应先释放GLFW库占用的系统资源。这可以通过glfwTerminate实现。2.2 GLFW错误处理

有些GLFW函数出错会返回对你解决错误没什么用的错误值,更有甚者有些函数还没返回值。所以处理GLFW的错误就需要独立的通道。在GLFW出现错误时会抛出错误代码,我们可以通过glfwGetError捕获。如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


const char* description;


int code = glfwGetError(&description);


if(code!=GLFW_NO_ERROR)


{


	// display error message...





	// handle error ...


}

字符指针description会指向以UTF-8码形式存储的错误信息内存处。

然而更推荐的做法是设置错误回调函数glfwSetErrorCallback。这样每次glfw出现错误都会调用回调函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18


glfwSetErrorCallback(error_callback);





void error_callback(int code, const char* description)


{


    // display error...


}

创建窗口和OpenGL上下文

GLFW库通过glfwCreateWindow函数进行创建OpenGL上下文和创建窗口。创建之前若想定制自已想要的窗口和上下文而不是系统默认的,可通过window hint设置属性。你可以创建多个窗口和上下文,但是,仅被make current的窗口和上下文是起作用的。要想查询已经创建好的窗口和上下文属性,可通过glfwGetWindowAttrib、glfwGetWindowSize、glfwGetFramebufferSize查询。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21


glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);


glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);


GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL);


if (!window)


{


    // Window or context creation failed


}

上面代码设置了OpenGL上下文的最低版本,如果机器不满足最低版本的限制,将会创建失败。

如果不在需要一个窗口了,摧毁它。

1
2
3


glfwDestroyWindow(window);

Make Context Current

使用OpenGL的API必须有而且只能有一个OpenGL上下文被设置成Current。

OpenGL上下文就是一个个状态机,显卡驱动程序只对Current上下文起作用。

GLFW设置current的语句和Windows的很像。

1
2
3


glfwMakeContextCurrent(window);

注:如果你是通过glad或gl3w来使用OpenGL,你就必需在使用它们之前拥有一个current context。

检查窗口关闭的标识

在GLFW中,每个窗口都有一个标识,用来标记窗口是否应该被关闭。当用户关闭了一个窗口,该标记就被设置成了1,所以窗口并没有被关闭,你需要时刻检查这个标记。

检查的方式是通过函数glfwWindowShouldClose。

返回的就是窗口关闭的标识值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12


while (!glfwWindowShouldClose(window))


{


    // Keep running


}

你也可以设置窗口的回调函数,每次关闭窗口时都会触发该函数。

如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18


glfwSetWindowCloseCallback(window, window_close_callback);


...


void window_close_callback(GLFWwindow* window)


{


    glfwSetWindowShouldClose(window, 0);


}

键盘事件响应

GLFW提供了设置键盘响应的回调函数glfwSetKeyCallback,如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21


glfwSetKeyCallback(window, key_callback);





void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)


{


    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)


        glfwSetWindowShouldClose(window, GLFW_TRUE);


}

交换缓冲区与处理事件

GLFW创建的窗口有两个缓冲区,前缓冲区和后缓冲区,渲染是在后缓冲区上进行的,一旦缓冲区满了,就需要交换前后缓冲区,通过glfwSwapBuffers(window)。

事件发生时,并不是立即得到处理的,而是暂时挂起。这些挂起的事件需要定期处理,通常在缓冲区交换的每一帧后完成。

如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12


/* Swap front and back buffers */


glfwSwapBuffers(window);


/* Poll for and process events */


glfwPollEvents();

参考资料

https://www.glfw.org/docs/latest/quick.html#quick_steps