基本框架
第一版
自从上一次环境搭建的笔记写完很久之后,今天终于又能继续做笔记了。目前的进度比较混乱,很多资料相互参杂着看,我打算这里先从整体开始,在逐渐向细节填充。这一篇就先记一下框架,也就是借用了GLFW和GLAD来创建窗口,以及之后如何在窗口中绘制自己的内容。
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
int main() {
//初始化glfw
glfwInit();
//设置当前使用的opengl版本
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//设置opengl使用的渲染模式(这里是核心模式,也就是opengl3.0以后建议使用的新特性)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
//mac平台兼容需要前向兼容
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//创建glfw窗口
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;
}
//将opengl渲染渲染到这个窗口
glfwMakeContextCurrent(window);
//通过glad读取对应的opengl函数地址
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//一直做这个事情
while (!glfwWindowShouldClose(window)) {
//设置缓存清除的颜色
glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
//清除缓存
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//交换缓存
glfwSwapBuffers(window);
//通过glfw调用所有的事件
glfwPollEvents();
}
//关闭窗口
glfwTerminate();
return 0;
}
虽然上面这些都不需要深究,但有几个点需要记一下:
1. 使用GLFW创建窗口一定要先初始化GLFW,这是当然的,必须包括的是OpenGL版本、OpenGL渲染模式。
2. 通过GLAD来获取OpenGL的函数地址,这是因为OpenGL本身并没有具体的API实现,真正的实现都是由各硬件厂商提供的,因此需要通过GLAD来获取具体的函数地址,否则,调用OpenGL函数的时候就会因为找不到具体的函数地址而出错了。
3. 在使用GLAD来获取函数地址之前,应当先调用glfwMakeContextCurrent(window)这个函数设置当前的绘制窗口,具体原因尚不明确,只是若非如此将会导致GLAD初始化失败。
4. glfwSwapBuffers(window)和glfwPollEvents()这两个函数是固定套路。
第一版的代码就长这样,加上了注释,忘记了就回来看看。有些函数现在只知道大概作用却不知道具体有什么特点,但是没关系,以后有需要的话再了解。
后面要做的就是给它重构一下,不然很大一堆放在一起太扎眼了。所以,就有了第二版。
第二版
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
void init();
GLFWwindow* createWindow();
void onDraw(GLFWwindow*);
int main() {
init();
onDraw(createWindow());
glfwTerminate();
return 0;
}
void onDraw(GLFWwindow* window){
if(!window)
return;
while (!glfwWindowShouldClose(window)) {
glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
}
void init(){
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
}
GLFWwindow* createWindow(){
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
if (window == NULL)
{
std::cout << "Failed to create GLFW window!" << std::endl;
glfwTerminate();
return nullptr;
}
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD!" << std::endl;
return nullptr;
}
return window;
}
这么组织一下的好处在于,逻辑更清晰了,以后只要关注onDraw()函数里的while循环就好了(不用因为main函数里的大量代码而逼死强迫症了)。当然,由于后面的着色器什么的,可能还需要在onDraw前面再加一个函数来处理。
记到这里就差不多了,其他的想法就是把上面这些东西封装到一个类里去,利用C++的一些特性可能会产生更好的效果。嗯,但是目前做这个没什么意义,就先放着吧。