#include #include #include #include #include #include #include "glad/gl.h" #include "glad/glx.h" #include "vertex.h" #include "mons_math/vec4.h" #include "mons_math/quat.h" #include "embedded/shaders/basic.vert.glsl.h" #include "embedded/shaders/basic_lit.frag.glsl.h" #include "shader.h" #include "mesh.h" #include "qoi.h" #include "texture.h" #include "transform.h" #include "model.h" #include "projection.h" #include "json.h" #include "hashmap.h" #include "gltf.h" #include "input.h" #include "camera.h" #include #include "color.h" #include "light.h" struct timespec current_time; double delta_time = 0; int main(void) { // Make Window Display *display = XOpenDisplay(NULL); if (display == NULL) { printf("Cannot connect to X server\n"); return EXIT_FAILURE; } int screen = DefaultScreen(display); int glx_version = gladLoaderLoadGLX(display, screen); if (!glx_version) { printf("Unable to load GLX\n"); return EXIT_FAILURE; } printf("Loaded GLX %d.%d\n", GLAD_VERSION_MAJOR(glx_version), GLAD_VERSION_MINOR(glx_version)); Window root = RootWindow(display, screen); GLint visual_attributes[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, None}; XVisualInfo *visual_info = glXChooseVisual(display, screen, visual_attributes); Colormap colormap = XCreateColormap(display, root, visual_info->visual, AllocNone); XSetWindowAttributes attributes; attributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask; attributes.colormap = colormap; Window window = XCreateWindow( display, root, 0, 0, 640, 480, 0, visual_info->depth, InputOutput, visual_info->visual, CWColormap | CWEventMask, &attributes); // XSizeHints hints = { // .flags = PMinSize | PMaxSize, // .min_width = 640, // .min_height = 480, // .max_width = 640, // .max_height = 480, // }; // XSetWMNormalHints(display, window, &hints); XMapWindow(display, window); XStoreName(display, window, "Hello World!"); if (!window) { printf("Unable to create window\n"); return EXIT_FAILURE; } GLXContext context = glXCreateContext(display, visual_info, NULL, GL_TRUE); glXMakeCurrent(display, window, context); // Load GL int version = gladLoaderLoadGL(); if (!version) { printf("Unable to load GL\n"); return EXIT_FAILURE; } printf("Loaded GL %d.%d\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)); XWindowAttributes gwa; XGetWindowAttributes(display, window, &gwa); glViewport(0, 0, gwa.width, gwa.height); // Setup Shaders mons_shader vertex_shader = mons_create_shader( MONS_SHADER_TYPE_VERTEX, (char *)__embed_shaders_basic_vert_glsl, __embed_shaders_basic_vert_glsl_len); mons_shader fragment_shader = mons_create_shader( MONS_SHADER_TYPE_FRAGMENT, (char *)__embed_shaders_basic_lit_frag_glsl, __embed_shaders_basic_lit_frag_glsl_len); mons_program shader_program = mons_create_program(vertex_shader, fragment_shader); FILE *texture_file = fopen("test.qoi", "rb"); mons_texture texture = mons_texture_load(texture_file); mons_camera camera = { .projection = { .near = 0.01f, .far = 100.0f, .fov = M_PI / 4.0f, .aspect_ratio = gwa.width / (float)gwa.height, }, .transform = { .translation = mons_vec3_mul_i(MONS_VEC3_Z, 3), .rotation = MONS_QUAT_IDENTITY, .scale = MONS_VEC3_ONE, }}; clock_gettime(CLOCK_MONOTONIC_RAW, ¤t_time); mons_model *models = NULL; int model_count = 0; mons_load_gltf("marble_bust/marble_bust_01_4k.gltf", shader_program, &models, &model_count); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); mons_directional_light light = { .transform = (mons_transform) { .translation = (mons_vec3) { 0.0f, 0.0f, 3.0f }, .rotation = MONS_QUAT_IDENTITY, .scale = MONS_VEC3_ONE, }, .color = MONS_COLOR_WHITE, }; mons_shader_set_vec4_global("light_color", light.color); mons_shader_set_vec3_global("light_position", light.transform.translation); float ambient_light = 0.1f; mons_shader_set_float_global("ambient_strength", ambient_light); // Main Loop bool key_pressed[256] = {false}; bool key_just_pressed[256] = {false}; bool quit = false; while (!quit) { memset(key_just_pressed, false, 256); while (XPending(display)) { XEvent xev; XNextEvent(display, &xev); switch (xev.type) { case KeyPress: key_pressed[xev.xkey.keycode] = true; key_just_pressed[xev.xkey.keycode] = true; break; case KeyRelease: key_pressed[xev.xkey.keycode] = false; break; case ConfigureNotify: if (xev.xconfigure.window == window) { camera.projection.aspect_ratio = xev.xconfigure.width / (float)xev.xconfigure.height; glViewport(0, 0, xev.xconfigure.width, xev.xconfigure.height); } default: break; } } glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); struct timespec new_time; clock_gettime(CLOCK_MONOTONIC_RAW, &new_time); delta_time = (new_time.tv_sec - current_time.tv_sec) + (new_time.tv_nsec - current_time.tv_nsec) / 1.0e9; current_time = new_time; mons_shader_set_mat4_global("view", mons_mat4_inverse(mons_transform_matrix(camera.transform)), GL_TRUE); mons_shader_set_mat4_global("projection", mons_projection_matrix(camera.projection), GL_FALSE); for (int i = 0; i < model_count; i++) { mons_model_draw(models[i]); mons_transform_rotate(&models[i].transform, mons_quat_from_axis_angle(MONS_VEC3_Y, (M_PI / 4.0f) * delta_time)); } glBindVertexArray(0); if (key_pressed[MONS_KEY_ESCAPE]) { quit = true; } int x_axis_input = key_pressed[MONS_KEY_D] - key_pressed[MONS_KEY_A]; mons_transform_translate( &camera.transform, mons_vec3_mul_f(mons_transform_right(camera.transform), delta_time * x_axis_input)); int y_axis_input = key_pressed[MONS_KEY_SPACE] - key_pressed[MONS_KEY_LSHIFT]; mons_transform_translate( &camera.transform, mons_vec3_mul_f(mons_transform_up(camera.transform), delta_time * y_axis_input)); int z_axis_input = key_pressed[MONS_KEY_W] - key_pressed[MONS_KEY_S]; mons_transform_translate( &camera.transform, mons_vec3_mul_f(mons_transform_forward(camera.transform), delta_time * -z_axis_input)); int y_rot_input = key_pressed[MONS_KEY_RIGHT] - key_pressed[MONS_KEY_LEFT]; mons_transform_rotate( &camera.transform, mons_quat_from_axis_angle(MONS_VEC3_Y, -M_PI / 2.0f * y_rot_input * delta_time)); int x_rot_input = key_pressed[MONS_KEY_UP] - key_pressed[MONS_KEY_DOWN]; mons_transform_rotate( &camera.transform, mons_quat_from_axis_angle(MONS_VEC3_X, M_PI / 2.0f * x_rot_input * delta_time)); int fov_input = key_pressed[MONS_KEY_MINUS] - key_pressed[MONS_KEY_EQUAL]; camera.projection.fov += (fov_input * M_PI / 8.0 * delta_time); if(key_just_pressed[MONS_KEY_BACKSPACE]) { mons_transform_look_at(&camera.transform, MONS_VEC3_ZERO, MONS_VEC3_Y); } glXSwapBuffers(display, window); } glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); glXMakeCurrent(display, 0, 0); glXDestroyContext(display, context); XDestroyWindow(display, window); XFreeColormap(display, colormap); XCloseDisplay(display); gladLoaderUnloadGLX(); return EXIT_SUCCESS; }