#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <iostream>
// our size_callback function
void size_callback(GLFWwindow* window, int width, int height) {
std::cout << "New width: " << width << "\theight: " << height << std::endl;
glViewport(0, 0, width, height);
}
int main() {
// |>----------<>----------<>----------<>----------<>----------<|
// |> CREATE GLFW WINDOW <|
// |>----------<>----------<>----------<>----------<>----------<|
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
GLFWwindow* window = glfwCreateWindow(640, 480, "My 3D app", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, size_callback); // we bind callback to our size_callback func.
// |>----------<>----------<>----------<>----------<>----------<|
// |> LOAD OPENGL FUNCTION POINTERS <|
// |>----------<>----------<>----------<>----------<>----------<|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
exit(EXIT_FAILURE);
}
// |>----------<>----------<>----------<>----------<>----------<|
// |> COMPILE SHADERS <|
// |>----------<>----------<>----------<>----------<>----------<|
const char* vertexShaderSource =
"\n #version 330 core "
"\n "
"\n layout (location = 0) in vec2 aPos; "
"\n "
"\n "
"\n void main() { "
"\n gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); "
"\n } ";
const char* fragmentShaderSource =
"\n #version 330 core "
"\n "
"\n out vec4 FragColor; "
"\n "
"\n "
"\n void main() { "
"\n FragColor = vec4(0.9f, 0.2f, 0.2f, 1.0f); "
"\n } ";
// build and compile our shader program
// ------------------------------------
// vertex shader
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char 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;
}
// fragment shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// link shaders to a program
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// delete shader after linking program because we dont need them
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
//bind shader
glUseProgram(shaderProgram);
// |>----------<>----------<>----------<>----------<>----------<|
// |> DEFINE VERTICES <|
// |>----------<>----------<>----------<>----------<>----------<|
// We initialize a buffer on CPU
float vertices[]{
-0.5f, -0.5f, // 0
0.0f, 0.5f, // 1
0.5f, -0.5f // 2
};
unsigned int VBO;
glGenBuffers(1, &VBO); // Generate a buffer objet and assing it's ID to VBO variable
glBindBuffer(GL_ARRAY_BUFFER, VBO); // We connect/bind VBO to ARRAY_BUFFER
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // create a new data store for a buffer object
// glBindBuffer: Specifies the target to which the buffer object is bound
// we give meanings to our data. Because it is just a bunch of byte
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// |>----------<>----------<>----------<>----------<>----------<|
// |> RENDER LOOP <|
// |>----------<>----------<>----------<>----------<>----------<|
while (!glfwWindowShouldClose(window)) {
glClearColor(0.2f, 0.2f, 0.2f, 1.0f); // Background color -clear color-
glClear(GL_COLOR_BUFFER_BIT); // clear color of current buffer
// we draw a triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
}
Refactor
main
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <iostream>
#include "Shader.h"
void size_callback(GLFWwindow* window, int width, int height);
GLFWwindow* create_GLFWwindow();
void init_glad();
int main() {
GLFWwindow* window = create_GLFWwindow();
init_glad();
Shader shader;
shader.compile();
shader.bind();
// |>----------<>----------<>----------<>----------<>----------<|
// |> DEFINE VERTICES <|
// |>----------<>----------<>----------<>----------<>----------<|
// We initialize a buffer on CPU
float vertices[]{
-0.5f, -0.5f, // 0
0.0f, 0.5f, // 1
0.5f, -0.5f // 2
};
unsigned int VBO;
glGenBuffers(1, &VBO); // Generate a buffer objet and assing it's ID to VBO variable
glBindBuffer(GL_ARRAY_BUFFER, VBO); // We connect/bind VBO to ARRAY_BUFFER
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // create a new data store for a buffer object
// glBindBuffer: Specifies the target to which the buffer object is bound
// we give meanings to our data. Because it is just a bunch of byte
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// |>----------<>----------<>----------<>----------<>----------<|
// |> RENDER LOOP <|
// |>----------<>----------<>----------<>----------<>----------<|
while (!glfwWindowShouldClose(window)) {
glClearColor(0.2f, 0.2f, 0.2f, 1.0f); // Background color -clear color-
glClear(GL_COLOR_BUFFER_BIT); // clear color of current buffer
// we draw a triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
}
void size_callback(GLFWwindow* window, int width, int height) {
std::cout << "New width: " << width << "\theight: " << height << std::endl;
glViewport(0, 0, width, height);
}
GLFWwindow* create_GLFWwindow(){
// |>----------<>----------<>----------<>----------<>----------<|
// |> CREATE GLFW WINDOW <|
// |>----------<>----------<>----------<>----------<>----------<|
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
GLFWwindow* window = glfwCreateWindow(640, 480, "My 3D app", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
//return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, size_callback); // we bind callback to our size_callback func.
return window;
}
void init_glad(){
// |>----------<>----------<>----------<>----------<>----------<|
// |> LOAD OPENGL FUNCTION POINTERS <|
// |>----------<>----------<>----------<>----------<>----------<|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
exit(EXIT_FAILURE);
}
}
Shader Class
#pragma once
#include <string>
class Shader
{
unsigned int ID{};
unsigned int compile_shader(std::string source, unsigned int shader_type);
void compile_program(unsigned int vs, unsigned int fs);
public:
void compile();
void bind();
void unbind();
};
#include "Shader.h"
#include "glad/glad.h"
#include <iostream>
void Shader::compile(){
std::string vertexShaderSource =
"\n #version 330 core "
"\n "
"\n layout (location = 0) in vec2 aPos; "
"\n "
"\n "
"\n void main() { "
"\n gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); "
"\n } ";
std::string fragmentShaderSource =
"\n #version 330 core "
"\n "
"\n out vec4 FragColor; "
"\n "
"\n "
"\n void main() { "
"\n FragColor = vec4(0.9f, 0.2f, 0.2f, 1.0f); "
"\n } ";
unsigned int vs = compile_shader(vertexShaderSource, GL_VERTEX_SHADER);
unsigned int fs = compile_shader(fragmentShaderSource, GL_FRAGMENT_SHADER);
compile_program(vs, fs);
}
unsigned int Shader::compile_shader(std::string source, unsigned int shader_type)
{
const char* source_code = source.c_str();
unsigned int shaderID = glCreateShader(shader_type);
glShaderSource(shaderID, 1, &source_code, NULL);
glCompileShader(shaderID);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shaderID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::" << (shader_type == GL_VERTEX_SHADER ? "VERTEX" : "FRAGMENT") << "::COMPILATION_FAILED\n" << infoLog << std::endl;
}
return shaderID;
}
void Shader::compile_program(unsigned int vs, unsigned int fs){
// link shaders to a program
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glLinkProgram(shaderProgram);
// check for linking errors
int success;
char infoLog[512];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// delete shader after linking program because we dont need them
glDeleteShader(vs);
glDeleteShader(fs);
ID = shaderProgram;
}
void Shader::bind(){
glUseProgram(ID);
}
void Shader::unbind(){
glUseProgram(0);
}
Leave a Reply