#include <iostream>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
using namespace std;
// 窗口大小
const GLuint WIDTH = 800, HEIGHT = 600;
// 着色器 GLSL
const GLchar* vertexShaderSource = "#version 330 core\n"
"uniform vec3 change;\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 color;\n"
"out vec3 ourColor;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position, 1.0f);\n"
"if(color.x > 0.0f) ourColor = change.xyz;\n"
"if(color.y > 0.0f) ourColor = change.yzx;\n"
"if(color.z > 0.0f) ourColor = change.zxy;\n"
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"in vec3 ourColor;\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(ourColor, 1.0f);\n"
"}\n\0";
int main(void) {
// 初始化 GLFW
glfwInit();
// glfwWindowHint() // 配置 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);
// Mac OS 使用
// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// 创建一个窗口
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "ColorChange", nullptr, nullptr);
glfwMakeContextCurrent(window);
// 初始化 GLEW
glewExperimental = GL_TRUE;
glewInit();
// 设置窗口大小
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
// 配置着色器
// 创建一个着色器对象(GL_VERTEX_SHADER:顶点着色器)
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
// 把着色器源码附加到着色器对象上,然后编译它
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// 检测编译时错误,输出错误信息
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 创建一个着色器对象(GL_FRAGMENT_SHADER:片段着色器)
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// 着色器源码附加及编译
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// 检测编译时错误,输出错误信息
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 创建一个着色器程序对象
GLuint shaderProgram;
shaderProgram = glCreateProgram();
// 链接着色器程序
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// 激活对象
glUseProgram(shaderProgram);
// 检查错误,输出日志
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// 激活后需要删除着色器对象
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 输入顶点数据(这是一个平面的三角形,z 坐标表示深度)
/*GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f, };
*/
GLfloat vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
// 生成一个 VBO 对象
GLuint VBO;
glGenBuffers(1, &VBO);
// 把新创建的缓冲绑定到 GL_ARRAY_BUFFER 目标上
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 把之前定义的顶点数据复制到缓冲的内存中(静态图形方式)
// glBufferData() // 复制数据到当前绑定缓冲(缓冲类型,数据大小,数据,显存数据的管理方式)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 创建一个 VAO
GLuint VAO;
glGenVertexArrays(1, &VAO);
// 把新创建的缓冲绑定到 GL_ARRAY_BUFFER 目标上
glBindBuffer(GL_ARRAY_BUFFER, VAO);
glBindVertexArray(VAO);
// glVertexAttribPointer() // 解析顶点数据(1.顶点属性[对应前面的 layout (location = 0)],2.顶点属性的大小[3分量向量],
// 3.数据类型[浮点数],4.是否标准化为(-1,1)范围内,5.单位步长,6.从起始位置的偏移量)
/*glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);*/
// 位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// 解绑
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// 创建游戏循环
while (!glfwWindowShouldClose(window)) {
// 事件处理
glfwPollEvents();
// 指定背景色(深蓝色)
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 实时改变三角形的颜色
glUseProgram(shaderProgram);
GLfloat timeValue = glfwGetTime();
float speedDown = 5;
timeValue = timeValue / speedDown;
GLint intValue = timeValue;
GLfloat xValue = (timeValue - intValue)*3;
GLint vertexColorLocation = glGetUniformLocation(shaderProgram, "change");
GLfloat redValue = xValue < 1.0f ? 1.0f - xValue : (xValue >= 2.0f ? xValue - 2.0f : 0.0f);
GLfloat greenValue = xValue < 2.0f && xValue >= 1.0f ? 2.0f - xValue : (xValue < 1.0f ? xValue : 0.0f);
GLfloat blueValue = xValue >= 2.0f ? 3.0f - xValue : (xValue < 2.0f && xValue >= 1.0f ? xValue - 1.0f : 0.0f);
glUniform3f(vertexColorLocation, redValue, greenValue, blueValue);
// 使用着色器程序, glDrawArrays():绘制图元函数
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
// 交换缓冲
glfwSwapBuffers(window);
}
// 删除 VAO 和 VBO,释放空间
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// 释放 GLFW 内存
glfwTerminate();
return 0;
}