Skip to content

Instantly share code, notes, and snippets.

@christopherfujino
Created June 9, 2025 23:13
Show Gist options
  • Save christopherfujino/31ac9d2f45e5903ace260be888ed78cc to your computer and use it in GitHub Desktop.
Save christopherfujino/31ac9d2f45e5903ace260be888ed78cc to your computer and use it in GitHub Desktop.
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define WIDTH 100
#define HEIGHT 100
#define ERROR_MSG_BUFFER_LEN 512
// Explicitly specify core functionality, i.e. no deprecated features
// "in vec3" means input is 3 floats
// gl_Position is a predefined vec4 output variable
// the final 1.0 is the w-dimension in the vec4
//
// This does nothing interesting because the input is already in the right
// format.
const char *vertexShaderSrc = "\
#version 330 core \n\
layout (location = 0) in vec3 aPos;\n\
\n\
void main() { \n\
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n\
}";
// FragColor = RGBA
const char *fragmentShaderSrc = "\
#version 330 core \n\
\n\
out vec4 FragColor; \n\
\n\
void main() { \n\
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); \n\
}";
// A shader program links multiple shaders
static unsigned int shaderProgram = 0;
static unsigned int vertexShader = 0;
static unsigned int fragmentShader = 0;
/** Vertex Buffer Object */
static unsigned int VBO = 0;
/** Vertex Array Object */
static unsigned int VAO = 0;
static GLFWwindow *win = NULL;
/** Normalized device coordinates */
const float vertices[] = { // x, y, z from -1.0 to 1.0
// They will later be transformed by viewport transform
// vertex 1
-0.5f, -0.5f, 0.0f,
// vertex 2
0.5f, -0.5f, 0.0f,
// vertex 3
0.0f, 0.5f, 0.0f};
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow *window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, 1);
}
}
void init() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
win = glfwCreateWindow(WIDTH, HEIGHT, "Foo Bar",
// monitor
NULL,
// share
NULL);
if (win == NULL) {
glfwTerminate();
fprintf(stderr, "Could not create a window!\n");
exit(1);
}
glfwMakeContextCurrent(win);
glfwSetFramebufferSizeCallback(win, framebuffer_size_callback);
// bind func pointer
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
fprintf(stderr, "Failed to initialize GLAD\n");
exit(1);
}
glViewport(
// x
0,
// y
0,
// width
WIDTH,
// height
HEIGHT);
// Shaders
vertexShader = glCreateShader(GL_VERTEX_SHADER);
// Bind the source to the shader
// glShaderSource(shader, count, src, length)
glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL);
glCompileShader(vertexShader);
// check if compilation succeeded
int success = 0;
char infoLog[ERROR_MSG_BUFFER_LEN] = {0};
// (shader, pname, *params)
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, ERROR_MSG_BUFFER_LEN, NULL, infoLog);
fprintf(stderr, "vertex shader compilation failed: %s\n", infoLog);
exit(1);
}
// Now compile fragment shader
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, ERROR_MSG_BUFFER_LEN, NULL, infoLog);
fprintf(stderr, "fragment shader compilation failed: %s\n", infoLog);
exit(1);
}
// Now link shaders together to shaderProgram
shaderProgram = glCreateProgram();
// (program, shader)
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, ERROR_MSG_BUFFER_LEN, NULL, infoLog);
fprintf(stderr, "shader program linking failed: %s\n", infoLog);
exit(1);
}
// Garbage collection
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// VAO = vertex array object
//
// after binding, all future vertex attribute calls will be stored in the
// VAO.
//
// A vertex array object stores the following:
//
// Calls to glEnableVertexAttribArray or glDisableVertexAttribArray.
// - Vertex attribute configurations via glVertexAttribPointer.
// - Vertex buffer objects associated with vertex attributes by calls to
// glVertexAttribPointer.
glGenVertexArrays(
// size
1,
// VAO pointer
&VAO);
glGenBuffers(
// size
1,
// pointer to buffers
&VBO);
glBindVertexArray(VAO);
// After this binding, future buffer calls will now refer to VBO
glBindBuffer(
// GL_ENUM_TARGET
GL_ARRAY_BUFFER,
// buffer ID
VBO);
// Copy user-defined data into the currently bound buffer.
// First arg is the type of data we are passing.
//
// The fourth parameter is one of:
// GL_STREAM_DRAW: the data is set only once and used by the GPU at most a few
// times. GL_STATIC_DRAW: the data is set only once and used many times.
// GL_DYNAMIC_DRAW: the data is changed a lot and used many times.
//
// glBufferData(GL_ENUM_TARGET, buffer size, buffer data, draw mode)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Tell OpenGL how to interpret the vertex data (per vertex attribute)
glVertexAttribPointer(
// Which vertex attribute we want to configure.
// Since we specified layout (location = 0) in vertex shader,
// use 0
0,
// the size of the vertex attribute; vec3 -> 3
3,
// type, vec* in GLSL constists of C floats
GL_FLOAT,
// should data be normalized
GL_FALSE,
// stride, or space between elements
sizeof(float) * 3,
// offset where position data begins in the buffer
NULL);
// Each vertex attribute takes its data from memory managed by a VBO and which
// VBO it takes its data from (you can have multiple VBOs) is determined by
// the VBO currently bound to GL_ARRAY_BUFFER when calling
// glVertexAttribPointer. Since the previously defined VBO is still bound
// before calling glVertexAttribPointer vertex attribute 0 is now associated
// with its vertex data.
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Is this real or an example?
// bind VAO to context
glBindVertexArray(0);
}
void render(GLFWwindow *window) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
// glfw uses double buffering
glfwSwapBuffers(win);
}
int main() {
init();
while (!glfwWindowShouldClose(win)) {
processInput(win);
render(win);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment