Last active
August 23, 2021 00:52
-
-
Save bynect/d7b093507e23399d696cce5ce93214b7 to your computer and use it in GitHub Desktop.
Very basic color gradient application made with OpenGL and glfw.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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