#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"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
const GLchar* fragmentShaderSource0 = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(0.5f, 0.2f, 1.0f, 1.0f);\n"
"}\n\0";
const GLchar* fragmentShaderSource1 = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f, 0.8f, 0.0f, 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, "FirstTriangle", 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;
}
// 創建第1個着色器對象(GL_FRAGMENT_SHADER:片段着色器)
GLuint fragmentShader0 = glCreateShader(GL_FRAGMENT_SHADER);
// 着色器源碼附加及編譯
glShaderSource(fragmentShader0, 1, &fragmentShaderSource0, NULL);
glCompileShader(fragmentShader0);
// 檢測編譯時錯誤,輸出錯誤信息
glGetShaderiv(fragmentShader0, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(fragmentShader0, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 創建第2個着色器對象(GL_FRAGMENT_SHADER:片段着色器)
GLuint fragmentShader1 = glCreateShader(GL_FRAGMENT_SHADER);
// 着色器源碼附加及編譯
glShaderSource(fragmentShader1, 1, &fragmentShaderSource1, NULL);
glCompileShader(fragmentShader1);
// 檢測編譯時錯誤,輸出錯誤信息
glGetShaderiv(fragmentShader1, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader1, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 創建 2個着色器程序對象
GLuint shaderProgram0 = glCreateProgram();
GLuint shaderProgram1 = glCreateProgram();
// 鏈接着色器程序
glAttachShader(shaderProgram0, vertexShader);
glAttachShader(shaderProgram1, vertexShader);
glAttachShader(shaderProgram0, fragmentShader0);
glAttachShader(shaderProgram1, fragmentShader1);
glLinkProgram(shaderProgram0);
glLinkProgram(shaderProgram1);
// 激活對象
glUseProgram(shaderProgram0);
// 檢查錯誤,輸出日志
glGetProgramiv(shaderProgram0, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram0, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glUseProgram(shaderProgram1);
glGetProgramiv(shaderProgram1, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram1, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// 激活后需要刪除着色器對象
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader0);
glDeleteShader(fragmentShader1);
// 輸入頂點數據(這是一個平面的三角形,z 坐標表示深度)
//GLfloat vertices[] = {
// -0.5f, -0.5f, 0.0f,
// 0.5f, -0.5f, 0.0f,
// 0.0f, 0.5f, 0.0f, };
// 輸入頂點數據(這是 2個平面的三角形)
GLfloat vertices0[] = {
-0.5f, -0.5f, 0.0f,
0.0f, 0.0f, 0.0f,
-0.3f, 0.3f, 0.0f, };
GLfloat vertices1[] = {
0.5f, -0.5f, 0.0f,
0.0f, 0.0f, 0.0f,
0.3f, 0.3f, 0.0f, };
// 生成 2個 VBO 對象
GLuint VBOs[2];
glGenBuffers(2, VBOs);
// 創建 2個 VAO
GLuint VAOs[2];
glGenVertexArrays(2, VAOs);
// 把新創建的緩沖綁定到 GL_ARRAY_BUFFER 目標上
glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
// 把之前定義的頂點數據復制到緩沖的內存中(靜態圖形方式)
// glBufferData() // 復制數據到當前綁定緩沖(緩沖類型,數據大小,數據,顯存數據的管理方式)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices0), vertices0, GL_STATIC_DRAW);
// 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);
// 第2個三角形
glBindVertexArray(VAOs[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 解綁
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);
// 使用着色器程序, glDrawArrays():繪制圖元函數
glUseProgram(shaderProgram0);
glBindVertexArray(VAOs[0]);
//glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, 3);
// 第2個三角形
glUseProgram(shaderProgram1);
glBindVertexArray(VAOs[1]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
// 交換緩沖
glfwSwapBuffers(window);
}
// 刪除 VAO 和 VBO,釋放空間
glDeleteVertexArrays(1, VAOs);
glDeleteBuffers(1, VBOs);
// 釋放 GLFW 內存
glfwTerminate();
return 0;
}