环境搭建好之后,现在我们需要创建GL Hello Window 程序,让opengl 创建一个新的窗口。与Win32 C++ api 创建窗口相似,opengl 创建窗口需要经历如下几个过程:注册,创建窗口,窗口内容设置,游戏循环。游戏循环(Game Loop)的机制类似与Win32的消息循环。
完整的代码在此:
https://learnopengl.com/code_viewer.php?code=getting-started/hellowindow2
头文件声明
#include <iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;
在此程序中,我们使用静态链接的方法。下面简述一下静态链接和动态链接
静态链接: 如果使用静态链接,即链接.lib文件就需要使用 GLEW_STATIC 宏定义。静态链接的优点在于库文件可以直接集成进入可执行程序。静态链接的缺点也很明显,可执行文件会比较庞大。
动态链接: 动态链接不需要使用此宏定义。动态链接需要添加dll文件。动态链接的优点在于可执行程序会比较小,有利于软件的发布,缺点在于软件发布的时候文件夹下需要带有相应的.dll文件。
main 函数代码
glfw的初始化以及
std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
glfwInit
: 此函数主要用于初始化glfw窗口。其中GLFW_CONTEXT_VERSION_MAJOR
和 GLFW_CONTEXT_VERSION_MINOR
表示支持的opengl 的主要版本和最小版本。 GLFW_OPENGL_PROFILE
是在macOS 中必须使用的项目, Windows 可以省略, 主要是获取macOS 中的OpenGL 许可证。GLFW_RESIZABLE
决定了GLFW 窗口是否可以重定义大小。GL_TRUE
表示可以,GL_FALSE
表示不可以。
当前程序的功能主要是进行glfw窗口的创建。glfwMakeContextCurrent
这个函数位窗口申请一个线程,单个上下文(context)只能使用一个线程,每个线程在同时也只能拥有一个context。 glfwSetKeyCallback
是让窗口响应命令的函数。
// Create a GLFWwindow object that we can use for GLFW's functions
glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
// This function makes the context of the specified window call current on calling thread.
// A context can only be made current on a single thread at a time and each thread can have
// only a single current context at a time
glfwMakeContextCurrent(window);
// This function set the key callback of the specific window, which is call when key is pressed
glfwSetKeyCallback(window, key_callback);
glfwSetKeyCallback
中的key_callback
函数如下,该函数重载了GLFW库中的GLFWkeyfun
.
其中GLFW_KEY_ESCAPE
表示esc按键操作,GLFW_PRESS
表示按下按键,glfwSetWindowShouldClose
是关闭glfw窗口的函数。
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
其中glewExperimental
设置为ture是为了让GLEW知道用新方法处理函数指针,glewInit
是GLEW的初始化函数
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
glfwGetFramebufferSize
这个函数主要是获取glfw窗口的宽度和高度,在窗口没有拉伸的情况下,width和height的值和之前设定的值相同。
glViewport
这个函数主要是仿射(affine)普通的设备坐标,即x,y参数,到窗口坐标,计算公式如下
// Define the viewport dimensions
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
这个循环是glfw窗口获取消息的循环,glfwPollEvents
这个函数获取发生的事件,比如按键,鼠标移动等等。glClearColor
是重置窗口颜色的函数, glClear
这个函数用于清空当前窗口的framebuffer.
Framebuffer 在后续的文章中会介绍,这个对象的作用主要是负责窗口的渲染。glfwSwapBuffers
这个函数主要用于将旧的framebuffer 替换成新的framebuffer
glfwTerminate
函数负责整个窗口函数的关闭,并且回收所有系统占用过的资源。同时也表示这程序的结束。
while (!glfwWindowShouldClose(window))
{
// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents();
// Render
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Swap the screen buffers
glfwSwapBuffers(window);
}
glfwTerminate();