#include "gpu.h" #include #include #include #include #ifndef M_PI #define M_PI 3.14159265358979324 #endif #define W 800 #define H 600 static const vertex_t vertices[] = { { { 0.000, 0.612, 0.000 }, { 1, 0, 0 } }, { { -0.500, -0.204, -0.289 }, { 0, 1, 0 } }, { { 0.500, -0.204, -0.289 }, { 0, 0, 1 } }, { { 0.000, -0.204, 0.577 }, { 1, 1, 1 } }, }; static const uint16_t indices[] = { 0, 3, 1, 0, 1, 2, 0, 2, 3, 3, 2, 1, }; typedef enum { AXIS_X, AXIS_Y, AXIS_Z, } axis_t; static axis_t rot_axis = AXIS_Y; #define ID \ { \ { 1, 0, 0, 0 }, \ { 0, 1, 0, 0 }, \ { 0, 0, 1, 0 }, \ { 0, 0, 0, 1 }, \ } #define SCALE(sf) \ { \ { sf, 0, 0, 0 }, \ { 0, sf, 0, 0 }, \ { 0, 0, sf, 0 }, \ { 0, 0, 0, 1 }, \ } #define TRANSLATE(x, y, z) \ { \ { 1, 0, 0, 0 }, \ { 0, 1, 0, 0 }, \ { 0, 0, 1, 0 }, \ { x, y, z, 1 }, \ } #define ROT_X(a) \ { \ { 1, 0, 0, 0 }, \ { 0, cosf(a), sinf(a), 0 }, \ { 0, -sinf(a), cosf(a), 0 }, \ { 0, 0, 0, 1 }, \ } #define ROT_Y(a) \ { \ { cosf(a), 0, -sinf(a), 0 }, \ { 0, 1, 0, 0 }, \ { sinf(a), 0, cosf(a), 0 }, \ { 0, 0, 0, 1 }, \ } #define ROT_Z(a) \ { \ { cosf(a), sinf(a), 0, 0 }, \ { -sinf(a), cosf(a), 0, 0 }, \ { 0, 0, 1, 0 }, \ { 0, 0, 0, 1 }, \ } static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { (void)window; (void)scancode; (void)mods; if (action != GLFW_PRESS) return; switch (key) { case GLFW_KEY_Q: glfwSetWindowShouldClose(window, GL_TRUE); break; case GLFW_KEY_X: rot_axis = AXIS_X; break; case GLFW_KEY_Y: rot_axis = AXIS_Y; break; case GLFW_KEY_Z: rot_axis = AXIS_Z; break; } } static vec3_t sub(vec3_t v, vec3_t u) { return (vec3_t) { v.x - u.x, v.y - u.y, v.z - u.z }; } static float len(vec3_t v) { return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); } static vec3_t norm(vec3_t v) { const float s = len(v); return (vec3_t) { v.x / s, v.y / s, v.z / s }; } static float dot(vec3_t v, vec3_t u) { return v.x * u.x + v.y * u.y + v.z * u.z; } static vec3_t cross(vec3_t v, vec3_t u) { return (vec3_t) { v.y * u.z - v.z * u.y, v.z * u.x - v.x * u.z, v.x * u.y - v.y * u.x, }; } static mat4_t mul(mat4_t m, mat4_t n) { #define ELEM(i, j) m.x.i *n.j.x + m.y.i *n.j.y + m.z.i *n.j.z + m.w.i *n.j.w return (mat4_t) { { ELEM(x, x), ELEM(y, x), ELEM(z, x), ELEM(w, x) }, { ELEM(x, y), ELEM(y, y), ELEM(z, y), ELEM(w, y) }, { ELEM(x, z), ELEM(y, z), ELEM(z, z), ELEM(w, z) }, { ELEM(x, w), ELEM(y, w), ELEM(z, w), ELEM(w, w) }, }; #undef MUL_ELEM } static mat4_t lookat(vec3_t cam, vec3_t tgt, vec3_t up) { const vec3_t s = sub(tgt, cam); const vec3_t s_hat = norm(s); const vec3_t u_hat = norm(cross(up, s_hat)); const vec3_t v_hat = cross(s_hat, u_hat); return (mat4_t) { { u_hat.x, v_hat.x, s_hat.x, 0 }, { u_hat.y, v_hat.y, s_hat.y, 0 }, { u_hat.z, v_hat.z, s_hat.z, 0 }, { -dot(u_hat, cam), -dot(v_hat, cam), -dot(s_hat, cam), 1 }, }; } static mat4_t persp(float aspect, float fov, float ncp, float fcp) { const float r = 2 * ncp * tanf(fov / 2); const float t = r * aspect; return (mat4_t) { { ncp / t, 0, 0, 0 }, { 0, -ncp / r, 0, 0 }, { 0, 0, fcp / (fcp - ncp), 1 }, { 0, 0, -fcp * ncp / (fcp - ncp), 0 }, }; } int main() { // Set up window glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); GLFWwindow *window = glfwCreateWindow(W, H, "Foo", nullptr, nullptr); assert(window); // Register input callbacks glfwSetKeyCallback(window, key_callback); // Initialise GPU const gpu_config_t gpu_config = { .application_name = "Foo", .window = window, .vertex_data = vertices, .vertex_data_size = sizeof(vertices), .index_data = indices, .index_data_size = sizeof(indices), }; gpu_ctx_t gpu; gpu_init(&gpu, &gpu_config); const vec3_t cam = { 2, 2, -2 }; const vec3_t tgt = { 0, 0, 0 }; mvp_t mvp = { .model = SCALE(2), .view = lookat(cam, tgt, (vec3_t) { 0, 1, 0 }), .proj = persp((float)W / H, M_PI / 6, 0.1, 10.0), }; const mat4_t rotx = ROT_X(M_PI / 128); const mat4_t roty = ROT_Y(M_PI / 128); const mat4_t rotz = ROT_Z(M_PI / 128); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); switch (rot_axis) { case AXIS_X: mvp.model = mul(rotx, mvp.model); break; case AXIS_Y: mvp.model = mul(roty, mvp.model); break; case AXIS_Z: mvp.model = mul(rotz, mvp.model); break; } gpu_render(&gpu, &mvp); } // Clean up gpu_cleanup(&gpu); glfwDestroyWindow(window); glfwTerminate(); return 0; }