#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "linmath.h"
#include <stdlib.h>
#include <stdio.h>
static const struct
{
float x, y;
float r, g, b;
} vertices[3] =
{
{ -0.6f, -0.4f, 1.f, 0.f, 0.f },
{ 0.6f, -0.4f, 0.f, 1.f, 0.f },
{ 0.f, 0.6f, 0.f, 0.f, 1.f }
};
static const char* vertex_shader_text =
"uniform mat4 MVP;\n"
"attribute vec3 vCol;\n"
"attribute vec2 vPos;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
" color = vCol;\n"
"}\n";
static const char* fragment_shader_text =
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(color, 1.0);\n"
"}\n";
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
当用户按下esc,我们就把windowShouldClose设置为ture,关闭应用
static 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);
}
int main(void)
{
GLFWwindow* window;
GLuint vertex_buffer, vertex_shader, fragment_shader, program;
GLint mvp_location, vpos_location, vcol_location;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
//glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(window, key_callback);
glfwMakeContextCurrent(window);//告诉GLFW创建窗口环境,这个环境是当前线程的主环境
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glfwSwapInterval(1);//可以将该间隔设为1,即每帧更新一次。 它可以设置为更高的值,但这可能导致输入延迟
// NOTE: OpenGL error checks have been omitted for brevity
glGenBuffers(1, &vertex_buffer);// //VBO(顶点缓冲对象)这个缓冲有一个独一无二的ID,所以我们可以使用glGenBuffer函数生成一个缓冲ID
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);// 我们可以使用glBinBuffer函数把创建的缓冲帮点到GL_ARRAY_BUFFER上
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// Give our vertices to OpenGL.// 然后我们可以调用glBUffweData函数它会把之前定义的顶点数据复制到缓冲的内存中
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);//编译着色器
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
/*
首先我们定义一个整型来表示是否成功编译,还需要一个储存错误消息的容器(如果有的话)。然后我们用glGetShaderiv检查是否编译成功了。
如果编译失败,我们应该用glGetShaderInfoLog获取错误消息,然后打印它
*/
if (!success)
{
glGetShaderInfoLog(vertex_shader, 512, NULL, infoLog);
printf("info glshaderinfolog %s\n", infoLog);
//std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
//设置完上面后我们可以调用glUseProgram函数,用新创建的程序对象作为参数,这样就能激活程序对象
//把着色器对象链接到程序对象后,不要忘记删除着色器对象
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
mvp_location = glGetUniformLocation(program, "MVP");
vpos_location = glGetAttribLocation(program, "vPos");
vcol_location = glGetAttribLocation(program, "vCol");
//告诉OpenGL如何解释顶点数据(每一个顶点的属性)
glEnableVertexAttribArray(vpos_location); //开启
glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
sizeof(float) * 5, (void*)0);//使用glVertexAttribPointer的顶点属性配置。
glEnableVertexAttribArray(vcol_location);
glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
sizeof(float) * 5, (void*)(sizeof(float) * 2));
//glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered(注册) VBO as the currently bound vertex buffer object so afterwards we can safely unbind(解绑)
//glBindVertexArray(0); // 解绑定
while (!glfwWindowShouldClose(window))//数从开始便检验每一次循环迭代中gLFW是否已经得到关闭指示
{
float ratio;
int width, height;
mat4x4 m, p, mvp;
glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float)height;
glViewport(0, 0, width, height);//设置渲染窗口
glClear(GL_COLOR_BUFFER_BIT);
// 开始绘制物体
mat4x4_identity(m);
mat4x4_rotate_Z(m, m, (float)glfwGetTime());
mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
mat4x4_mul(mvp, p, m);
glUseProgram(program);//调用渲染程序
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*)mvp);
//glDrawArrays函数第一个参数是我们打算绘制的OpenGL基本图形的类型。由于我们在一开始时说过,
//我们希望绘制三角形,我们传递GL_TRIANGLES给它。第二个参数定义了我们打算绘制的那个顶点数组的起始位置的索引;我们这里填0。
//最后一个参数指定我们打算绘制多少个顶点,这里是3(我们只从我们的数据渲染一个三角形,它只有3个顶点)。
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);//函数会交换颜色缓冲(颜色缓冲是一个GLFW窗口为每一个像素存储的颜色数值的最大缓冲)
检验是否有任务被触发了,(比如鼠标移动和键盘的输入事件),接着...调用相关的回调函数
glfwPollEvents();//当你制作游戏或是动画时,尽量使用轮询。 如果相反,你需要在产生事件后才渲染,可是通过等待来处理事件,即glfwWaitEvent
}
glfwDestroyWindow(window);
glfwTerminate();释放所有的资源
exit(EXIT_SUCCESS);
}