// Library initialisation #define RAYMATH_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION #define TINYOBJ_LOADER_C_IMPLEMENTATION // Project #include "lib/djstdlib/core.c" #include "gfx/gfx.c" #include "world/world.c" #include "ui.c" #include "render.c" #include "debug.c" // Graphics bindings and libs #include "lib/raymath.h" #include "lib/glad/glad.c" #include "GLFW/glfw3.h" typedef struct Frame Frame; struct Frame { uint32 width; uint32 height; int32 x; int32 y; Camera cam; }; typedef struct GlobalState GlobalState; struct GlobalState { struct { GLFWwindow *handle; int32 width; int32 height; struct { GLFWcursor *pointer; GLFWcursor *arrow; GLFWcursor *forbidden; } cursors; } window; UI_Context *ui; }; void framebufferSizeCallback(GLFWwindow *window, int width, int height) { Soma *soma = (Soma *)glfwGetWindowUserPointer(window); soma->renderer->width = width; soma->renderer->height = height; } GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) { if (!glfwInit()) { return NULL; } #ifdef GLFW_WAYLAND_APP_ID glfwWindowHintString(GLFW_WAYLAND_APP_ID, "Somaesque"); #endif glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_SAMPLES, 4); GLFWwindow *window = glfwCreateWindow( windowWidth, windowHeight, #ifdef DJSTDLIB_DEBUG "Somaesque (djstdlib_debug)", #else "Somaesque", #endif NULL, NULL); if (window == NULL) { print("Failed to create GLFW window\n"); glfwTerminate(); return NULL; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { print("Failed to initilaize GLAD\n"); return NULL; } glViewport(0, 0, windowWidth, windowHeight); glfwSwapInterval(1); glfwSetInputMode(window, GLFW_CURSOR | GLFW_RAW_MOUSE_MOTION, GLFW_CURSOR_NORMAL); glfwSetWindowSize(window, windowWidth, windowHeight); glEnable(GL_DEPTH_TEST); glEnable(GL_MULTISAMPLE); return window; } static void onMouseScroll(GLFWwindow *window, real64 deltaX, real64 deltaY) { Soma *soma = (Soma *)glfwGetWindowUserPointer(window); soma->ui->input->mouse.scroll.dX += deltaX; soma->ui->input->mouse.scroll.dY += deltaY; } static void updateWindow(Soma *soma) { glfwGetWindowSize(soma->window.handle, &soma->window.width, &soma->window.height); soma->renderer->width = soma->window.width; soma->renderer->height = soma->window.height; } const int32 TARGET_FPS = 144; void APIENTRY glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { fprintf(stderr, "GL: %s\n", message); } int mainGfx() { Arena *arena = arenaAlloc(Megabytes(128)); Arena *solutionsArena = arenaAlloc(Megabytes(128)); int32 winWidth = 800; int32 winHeight = 600; GLFWwindow *windowHandle = initWindowAndGL(winWidth, winHeight); if (!windowHandle) { return 1; } glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(glDebugCallback, NULL); Scene mainScene = createScene(arena); Camera cam = createCamera(winWidth, winHeight); Renderer renderer = createRenderer(arena, &mainScene, &cam, createSceneGraphNode(&mainScene)); renderer.solidShader = &solidColorShader; renderer.phongShader = &phongShader; renderer.cubeMesh = &cubeMesh; Arena *uiArena = arenaAlloc(Megabytes(64)); UI_Context ui = ui_initContext(uiArena, &renderer); glfwSetWindowUserPointer(windowHandle, &soma); glfwSetFramebufferSizeCallback(windowHandle, framebufferSizeCallback); glfwSetScrollCallback(windowHandle, onMouseScroll); // Render loop real64 lastFrame = glfwGetTime(); real64 timeDelta = 1.0f / TARGET_FPS; real64 frameStart = lastFrame; Input lastInput = {0}; Input currInput = {0}; while (!glfwWindowShouldClose(soma.window.handle)) { glfwPollEvents(); lastInput = currInput; currInput = getCurrentInput(soma.window.handle); ui.prevInput = &lastInput; ui.input = &currInput; updateWindow(&soma); processInput(&soma); Render(&renderer) { UI_Pass(&ui) { ui_Soma(&ui, &soma); } switch (ui.cursorType) { case UI_Cursor_Arrow: glfwSetCursor(soma.window.handle, soma.window.cursors.arrow); break; case UI_Cursor_Pointer: glfwSetCursor(soma.window.handle, soma.window.cursors.pointer); break; case UI_Cursor_Forbidden: glfwSetCursor(soma.window.handle, soma.window.cursors.forbidden); break; default: glfwSetCursor(soma.window.handle, soma.window.cursors.arrow); break; } } updatePolycubeDisplay(&soma); recalcScene(soma.scene); glfwSwapBuffers(soma.window.handle); real64 frameEnd = glfwGetTime(); real64 frameTime = frameEnd - frameStart; lastFrame = frameStart; //println("FPS: %.7f", 1/(frameTime)); frameStart = glfwGetTime(); soma.prevState = soma.state; soma.state.isInitialState = false; } glfwTerminate(); return 0; }