examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

commit b1cf63a36c74da863cb66b9aa9bb7e50b2dc76fe
parent 7d6ab667ba562573e922a302b350e4d834c22f9a
Author: Henry Wilson <henry@henryandlizzy.uk>
Date:   Fri, 14 Apr 2023 23:06:54 +0100

gl: Add simple 3D and lighting examples

Diffstat:
MTupfile | 2++
Asrc/gl-3d.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gl-lighting.c | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 315 insertions(+), 0 deletions(-)

diff --git a/Tupfile b/Tupfile @@ -6,6 +6,8 @@ CXXFLAGS = -std=c++20 $(COMMON_FLAGS) LDLIBS_aio = -lrt LDLIBS_alsa-simple = -lasound LDLIBS_gl = -lglfw -lGL +LDLIBS_gl-3d = -lglfw -lGL -lm +LDLIBS_gl-lighting = -lglfw -lGL -lm LDLIBS_gl-asteroids = -lglfw -lGL -lm -lasound LDLIBS_io_uring = -luring LDLIBS_pulse-async-client = -lpulse diff --git a/src/gl-3d.c b/src/gl-3d.c @@ -0,0 +1,122 @@ +#include <GLFW/glfw3.h> +#include <assert.h> +#include <math.h> + +#define DEFAULT_W 800 +#define DEFAULT_H 450 + +#define ENABLE_GUARD(x) glEnable(x); for (int i = 1; i--; glDisable(x)) +#define MATRIX_GUARD glPushMatrix(); for (int i = 1; i--; glPopMatrix()) +#define PROJECTION_GUARD glMatrixMode(GL_PROJECTION); for (int i = 1; i--; glMatrixMode(GL_MODELVIEW)) + +struct vertex +{ + float colour[3]; + float vertex[3]; +} const octahedron_vertices[6] = +{ + {{0,0,1}, {0 ,0 , .5}}, + {{0,1,0}, {0 , .5, 0}}, + {{0,1,1}, {-.5,0 , 0}}, + {{1,0,1}, {0 ,-.5, 0}}, + {{1,0,0}, { .5, 0, 0}}, + {{1,1,0}, {0 ,0 ,-.5}}, +}; + +unsigned char const octahedron_indices[] = +{ + 0,1,2,3,4,1, + 5,4,3,2,1,4, +}; + +static void draw_octahedron() +{ + glInterleavedArrays(GL_C3F_V3F, 0, octahedron_vertices); + glDrawElements(GL_TRIANGLE_FAN, 6, GL_UNSIGNED_BYTE, octahedron_indices + 0); + glDrawElements(GL_TRIANGLE_FAN, 6, GL_UNSIGNED_BYTE, octahedron_indices + 6); +} + +static void key_cb(GLFWwindow* w, int key, int /*scancode*/, int action, int /*mods*/) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(w, GLFW_TRUE); +} + +static void set_frustum_size(int w, int h) +{ + double fru_horz = w / sqrt(w*w + h*h); + double fru_vert = h / sqrt(w*w + h*h); + + PROJECTION_GUARD + { + glLoadIdentity(); + glFrustum(-fru_horz, fru_horz, -fru_vert, fru_vert, 1.5, 8); + glTranslated(0, 0, -5); + } +} + +static void fb_resize_cb(GLFWwindow*, int w, int h) +{ + glViewport(0, 0, w, h); + set_frustum_size(w, h); +} + +int main(int, char* argv[]) +{ + assert(glfwInit()); + GLFWwindow* window = glfwCreateWindow(DEFAULT_W, DEFAULT_H, argv[0], NULL, NULL); + assert(window); + glfwMakeContextCurrent(window); + set_frustum_size(DEFAULT_W, DEFAULT_H); + glfwSetKeyCallback(window, key_cb); + glfwSetFramebufferSizeCallback(window, fb_resize_cb); + glfwSwapInterval(1); + glClearColor(0, 0, 0, 1); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + double t = glfwGetTime() / 8; + double turns = t * 6.283185307; + double deg = t * 360; + + glLoadIdentity(); + glTranslated(0, -.2, 0); + glRotated(-60, 1, 0, 0); + glRotated(deg / 7, 0, 0, 1); + + MATRIX_GUARD + { + glRotated(deg, 0, 0, 1); + draw_octahedron(); + } + + MATRIX_GUARD + { + glTranslated(0, 0, 1); + glRotated(90, 0, 0, 1); + draw_octahedron(); + } + + MATRIX_GUARD + { + glTranslated(0, 0, -1); + glRotated(-90, 0, 0, 1); + draw_octahedron(); + } + + MATRIX_GUARD + { + glTranslated(sin(2*turns), cos(2*turns), sin(turns)); + glRotated(180+deg, 0, 0, 1); + draw_octahedron(); + } + + glfwSwapBuffers(window); + glfwPollEvents(); + } + glfwTerminate(); /* Implicit window destroy */ +} diff --git a/src/gl-lighting.c b/src/gl-lighting.c @@ -0,0 +1,191 @@ +#include <GLFW/glfw3.h> +#include <assert.h> +#include <math.h> + +#define DEFAULT_W 800 +#define DEFAULT_H 450 + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) +#define FOR_EACH(a, x) for (typeof(&*(a)) x = a; x < (a) + ARRAY_SIZE(a); ++x) + +#define ENABLE_GUARD(x) glEnable(x); for (int i = 1; i--; glDisable(x)) +#define MATRIX_GUARD glPushMatrix(); for (int i = 1; i--; glPopMatrix()) +#define PROJECTION_GUARD glMatrixMode(GL_PROJECTION); for (int i = 1; i--; glMatrixMode(GL_MODELVIEW)) +#define DRAW_GUARD(mode) glBegin(mode); for (int i = 1; i--; glEnd()) + +struct vertex +{ + float colour[3]; + float vertex[3]; +} const octahedron_vertices[6] = +{ + {{0,0,1}, {0 ,0 , .5}}, + {{0,1,0}, {0 , .5, 0}}, + {{0,1,1}, {-.5,0 , 0}}, + {{1,0,1}, {0 ,-.5, 0}}, + {{1,0,0}, { .5, 0, 0}}, + {{1,1,0}, {0 ,0 ,-.5}}, +}; + +struct triangle +{ + float normal[3]; + unsigned char index[3]; +} const octahedron_triangles[8] = { + {{-1, 1, 1}, {0,1,2}}, + {{-1,-1, 1}, {0,2,3}}, + {{ 1,-1, 1}, {0,3,4}}, + {{ 1, 1, 1}, {0,4,1}}, + {{ 1, 1,-1}, {5,1,4}}, + {{ 1,-1,-1}, {5,4,3}}, + {{-1,-1,-1}, {5,3,2}}, + {{-1, 1,-1}, {5,2,1}}, +}; + +static void draw_octahedron() +{ + glInterleavedArrays(GL_C3F_V3F, 0, octahedron_vertices); + FOR_EACH (octahedron_triangles, t) + { + glNormal3fv(t->normal); + glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, t->index); + } +} + +static void key_cb(GLFWwindow* w, int key, int /*scancode*/, int action, int /*mods*/) +{ + if (action != GLFW_PRESS) + return; + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(w, GLFW_TRUE); + return; + case GLFW_KEY_F11: + GLFWmonitor* monitor = glfwGetWindowMonitor(w); + if (!monitor) + { + monitor = glfwGetPrimaryMonitor(); + GLFWvidmode const* mode = glfwGetVideoMode(monitor); + glfwSetWindowMonitor(w, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); + } else + glfwSetWindowMonitor(w, NULL, 0, 0, DEFAULT_W, DEFAULT_H, GLFW_DONT_CARE); + return; + case GLFW_KEY_F10: + return; + } +} + +static void set_frustum_size(int w, int h) +{ + double fru_horz = w / sqrt(w*w + h*h); + double fru_vert = h / sqrt(w*w + h*h); + + PROJECTION_GUARD + { + glLoadIdentity(); + glFrustum(-fru_horz, fru_horz, -fru_vert, fru_vert, 1.5, 8); + glTranslated(0, 0, -5); + } +} + +static void fb_resize_cb(GLFWwindow*, int w, int h) +{ + glViewport(0, 0, w, h); + set_frustum_size(w, h); +} + +static float const ambient_light[4] = {.1, .1, .1, 1}; +static float const light_colour[4] = {1, 1, 1, 1}; +static float const material_specular[4] = {.000001, .000001, .000001, 1}; +static float light_position0[4] = {0, 0, 1, 1}; +static float light_position1[4] = {-.5, -.5, 1.6, 1}; + +int main(int, char* argv[]) +{ + assert(glfwInit()); + GLFWwindow* window = glfwCreateWindow(DEFAULT_W, DEFAULT_H, argv[0], NULL, NULL); + assert(window); + glfwMakeContextCurrent(window); + set_frustum_size(DEFAULT_W, DEFAULT_H); + glfwSetKeyCallback(window, key_cb); + glfwSetFramebufferSizeCallback(window, fb_resize_cb); + glfwSwapInterval(1); + glClearColor(0, 0, 0, 1); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_RESCALE_NORMAL); + + for (GLuint light = GL_LIGHT0; light <= GL_LIGHT1; ++light) + { + glEnable(light); + glLightfv(light, GL_DIFFUSE, light_colour); + glLightfv(light, GL_SPECULAR, light_colour); + } + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient_light); + + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 24); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material_specular); + glPointSize(10); + glEnable(GL_POINT_SMOOTH); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + double t = glfwGetTime() / 8; + double turns = t * 6.283185307; + double deg = t * 360; + + glLoadIdentity(); + glTranslated(0, -.2, 0); + glRotated(-60, 1, 0, 0); + glRotated(deg / 7, 0, 0, 1); + + light_position0[0] = -sin(2*turns)*1.5; + light_position0[1] = -cos(2*turns)*1.5; + + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + DRAW_GUARD(GL_POINTS) + glColor4fv(light_colour), glVertex4fv(light_position0), glVertex4fv(light_position1); + + ENABLE_GUARD(GL_LIGHTING) + { + MATRIX_GUARD + { + glRotated(deg, 0, 0, 1); + draw_octahedron(); + } + + MATRIX_GUARD + { + glTranslated(0, 0, 1); + glRotated(90, 0, 0, 1); + draw_octahedron(); + } + + MATRIX_GUARD + { + glTranslated(0, 0, -1); + glRotated(-90, 0, 0, 1); + draw_octahedron(); + } + + MATRIX_GUARD + { + glTranslated(sin(2*turns), cos(2*turns), sin(turns)); + glRotated(180+deg, 0, 0, 1); + draw_octahedron(); + } + } + + glfwSwapBuffers(window); + glfwPollEvents(); + } + glfwTerminate(); /* Implicit window destroy */ +}