Skip to content

Instantly share code, notes, and snippets.

@bynect
Last active August 23, 2021 00:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bynect/d7b093507e23399d696cce5ce93214b7 to your computer and use it in GitHub Desktop.
Save bynect/d7b093507e23399d696cce5ce93214b7 to your computer and use it in GitHub Desktop.
Very basic color gradient application made with OpenGL and glfw.
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <GLFW/glfw3.h>
#include <GL/gl.h>
#define WIDTH 800
#define HEIGHT 600
#define TITLE "Gradient"
#define SL(str) sizeof(str "") - 1
#define NL(str) str "\n"
#ifdef DYN_PROCS
static GLuint (*glCreateShader)(GLenum type);
static void (*glShaderSource)(GLuint shader, GLsizei count, const GLchar *const *strs, const GLuint *lens);
static void (*glCompileShader)(GLuint shader);
static void (*glGetShaderiv)(GLuint shader, GLenum name, GLint *pars);
static void (*glGetShaderInfoLog)(GLuint shader, GLsizei size, GLsizei *len, GLchar *buf);
static GLuint (*glCreateProgram)(void);
static void (*glAttachShader)(GLuint prog, GLuint shader);
static void (*glLinkProgram)(GLuint prog);
static void (*glGetProgramiv)(GLuint prog, GLenum name, GLint *pars);
static void (*glGetProgramInfoLog)(GLuint shader, GLsizei size, GLsizei *len, GLchar *buf);
static void (*glUseProgram)(GLuint prog);
static void (*glGenVertexArrays)(GLsizei count, GLuint *arrays);
static void (*glBindVertexArray)(GLuint array);
static GLint (*glGetUniformLocation)(GLuint prog, const GLchar *name);
static void (*glUniform1f)(GLint loc, GLfloat v);
#else
extern GLuint glCreateShader(GLenum type);
extern void glShaderSource(GLuint shader, GLsizei count, const GLchar *const *strs, const GLuint *lens);
extern void glCompileShader(GLuint shader);
extern void glGetShaderiv(GLuint shader, GLenum name, GLint *pars);
extern void glGetShaderInfoLog(GLuint shader, GLsizei size, GLsizei *len, GLchar *buf);
extern GLuint glCreateProgram(void);
extern void glAttachShader(GLuint prog, GLuint shader);
extern void glLinkProgram(GLuint prog);
extern void glGetProgramiv(GLuint prog, GLenum name, GLint *pars);
extern void glGetProgramInfoLog(GLuint shader, GLsizei size, GLsizei *len, GLchar *buf);
extern void glUseProgram(GLuint prog);
extern void glGenVertexArrays(GLsizei count, GLuint *arrays);
extern void glBindVertexArray(GLuint array);
extern GLint glGetUniformLocation(GLuint prog, const GLchar *name);
extern void glUniform1f(GLint loc, GLfloat v);
#endif
static inline void
err(const char *msg)
{
fprintf(stderr, "!! %s\n", msg);
}
static inline void
dbg(const char *msg)
{
fprintf(stdout, "?? %s\n", msg);
}
static inline void
die(const char *msg)
{
err(msg);
exit(1);
}
static void
err_callback(int code, const char *msg)
{
fprintf(stderr, "!! Error code %d\n", code);
err(msg);
}
static void
key_callback(GLFWwindow *win, int key, int code, int action, int mods)
{
fprintf(stdout, "?? Key %d; Code %d; Action %d; Mods %d\n", key, code, action, mods);
if (key == GLFW_KEY_ESCAPE)
{
glfwSetWindowShouldClose(win, GLFW_TRUE);
}
}
static GLuint
shader_compile(GLenum type, const GLchar *src)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
GLint comp = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &comp);
if (comp == 0)
{
GLchar buf[1024];
GLsizei len = 0;
glGetShaderInfoLog(shader, sizeof(buf), &len, buf);
buf[len - 1] = '\0';
err(buf);
die("Failed to compile shader");
}
return shader;
}
static GLuint
shader_link(GLuint *shaders, GLsizei len)
{
GLuint prog = glCreateProgram();
for (GLsizei i = 0; i < len; ++i)
{
glAttachShader(prog, shaders[i]);
}
glLinkProgram(prog);
GLint link = 0;
glGetProgramiv(prog, GL_LINK_STATUS, &link);
if (link == 0)
{
GLchar buf[1024];
GLsizei len = 0;
glGetProgramInfoLog(prog, sizeof(buf), &len, buf);
buf[len - 1] = '\0';
err(buf);
die("Failed to link shader program");
}
return prog;
}
int
main(int argc, char **argv)
{
glfwSetErrorCallback(err_callback);
if (!glfwInit())
{
die("Failed to initialize OpenGL");
}
dbg("Initialized OpenGL");
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow *win = glfwCreateWindow(WIDTH, HEIGHT, TITLE, NULL, NULL);
if (win == NULL)
{
glfwTerminate();
die("Failed to create a Window");
}
dbg("Created window");
glfwSetKeyCallback(win, key_callback);
glfwMakeContextCurrent(win);
glfwSwapInterval(1);
#ifdef DYN_PROCS
glCreateShader = (void *)glfwGetProcAddress("glCreateShader");
glShaderSource = (void *)glfwGetProcAddress("glShaderSource");
glCompileShader = (void *)glfwGetProcAddress("glCompileShader");
glGetShaderiv = (void *)glfwGetProcAddress("glGetShaderiv");
glGetShaderInfoLog = (void *)glfwGetProcAddress("glGetShaderInfoLog ");
glCreateProgram = (void *)glfwGetProcAddress("glCreateProgram");
glAttachShader = (void *)glfwGetProcAddress("glAttachShader");
glLinkProgram = (void *)glfwGetProcAddress("glLinkProgram");
glGetProgramiv = (void *)glfwGetProcAddress("glGetProgramiv");
glGetProgramInfoLog = (void *)glfwGetProcAddress("glGetProgramInfoLog");
glUseProgram = (void *)glfwGetProcAddress("glUseProgram");
glGenVertexArrays = (void *)glfwGetProcAddress("glGenVertexArrays");
glBindVertexArray = (void *)glfwGetProcAddress("glBindVertexArray");
glGetUniformLocation = (void *)glfwGetProcAddress("glGetUniformLocation");
glUniform1f = (void *)glfwGetProcAddress("glUniform1f");
dbg("Loaded dynamic OpenGL proc addresses");
#endif
GLuint vert_shader = shader_compile(
GL_VERTEX_SHADER,
NL("#version 330 core")
NL("out vec2 uv;")
NL("")
NL("void main()")
NL("{")
NL(" uv = vec2(gl_VertexID & 1, gl_VertexID >> 1);")
NL(" gl_Position = vec4(2.0 * uv - 1.0, 0.0, 1.0);")
NL("}")
);
dbg("Created vertex shader");
GLuint frag_shader = shader_compile(
GL_FRAGMENT_SHADER,
NL("#version 330 core")
NL("uniform float time;")
NL("in vec2 uv;")
NL("out vec4 color;")
NL("")
NL("float norm_sin(float x)")
NL("{")
NL(" return (sin(x) + 1.0) / 2.0;")
NL("}")
NL("")
NL("float norm_cos(float x)")
NL("{")
NL(" return (cos(x) + 1.0) / 2.0;")
NL("}")
NL("")
NL("void main()")
NL("{")
NL(" color = vec4(norm_sin(uv.x + time), norm_cos(uv.y + time),")
NL(" norm_sin(uv.x + uv.y + time), 1.0);")
NL("}")
);
dbg("Created fragment shader");
GLuint shaders[] = {vert_shader, frag_shader};
GLuint prog = shader_link(shaders, sizeof(shaders) / sizeof(GLuint));
glUseProgram(prog);
dbg("Created and linked shader program");
GLuint vert_arr = 0;
glGenVertexArrays(1, &vert_arr);
glBindVertexArray(vert_arr);
dbg("Created and bound vertex array");
GLint loc = glGetUniformLocation(prog, "time");
while (!glfwWindowShouldClose(win))
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
GLfloat time = glfwGetTime();
glUniform1f(loc, time);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glfwSwapBuffers(win);
glfwPollEvents();
}
glfwDestroyWindow(win);
dbg("Destroyed window");
glfwTerminate();
dbg("Terminated OpenGL");
return 0;
}
# Uncomment -DDYN_PROCS if dynamic loading of OpenGL function is preferable over static linking
CFLAGS=-O2 -Wall -Wextra #-DDYN_PROCS
LDFLAGS=-lglfw -lGL
gradient: gradient.o
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^
%.o: %.c
$(CC) -o $@ -c $(CFLAGS) $^
.PHONY: clean
clean:
rm gradient.o gradient
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment