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:
M | Tupfile | | | 2 | ++ |
A | src/gl-3d.c | | | 122 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/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 */
+}