/** * Copyright (c) 2024 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "dawnglfw.h" #include "game.h" #include "assert/assert.h" #include "assert/assertgl.h" #include "display/backbuffer.h" dawnglfw_t DAWN_GLFW; int32_t dawnGlfwStart() { memset(&DAWN_GLFW, 0, sizeof(DAWN_GLFW)); // Init GLFW if(!glfwInit()) { assertUnreachable("Failed to initialize GLFW"); return -1; } // Setup window hints glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, false); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Create Window DAWN_GLFW.window = glfwCreateWindow( DAWN_GLFW_WIDTH_DEFAULT, DAWN_GLFW_HEIGHT_DEFAULT, "Dawn", NULL, NULL ); if(DAWN_GLFW.window == NULL) { glfwTerminate(); assertUnreachable("Failed to create GLFW window"); } // Load GLAD glfwMakeContextCurrent(DAWN_GLFW.window); glfwSwapInterval(1); gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); assertNoGLError(); // Override the defaults int32_t fbWidth, fbHeight; int32_t windowWidth, windowHeight; glfwGetFramebufferSize(DAWN_GLFW.window, &fbWidth, &fbHeight); glfwGetWindowSize(DAWN_GLFW.window, &windowWidth, &windowHeight); assertNoGLError(); assertTrue(fbWidth > 0, "Detected framebuffer width is too small?"); assertTrue(fbWidth > 0, "Detected framebuffer height is too small?"); assertTrue(windowWidth > 0, "Detected window width is too small?"); assertTrue(windowHeight > 0, "Detected window height is too small?"); DAWN_GLFW.width = windowWidth; DAWN_GLFW.height = windowHeight; backBufferSetSize( fbWidth, fbHeight, ((float_t)fbWidth) / ((float_t)windowWidth) ); // Init game gameInit(); // Set the input binds dawnGlfwInputBind(INPUT_BIND_UP, GLFW_KEY_W); dawnGlfwInputBind(INPUT_BIND_UP, GLFW_KEY_UP); dawnGlfwInputBind(INPUT_BIND_DOWN, GLFW_KEY_S); dawnGlfwInputBind(INPUT_BIND_DOWN, GLFW_KEY_DOWN); dawnGlfwInputBind(INPUT_BIND_LEFT, GLFW_KEY_A); dawnGlfwInputBind(INPUT_BIND_LEFT, GLFW_KEY_LEFT); dawnGlfwInputBind(INPUT_BIND_RIGHT, GLFW_KEY_D); dawnGlfwInputBind(INPUT_BIND_RIGHT, GLFW_KEY_RIGHT); dawnGlfwInputBind(INPUT_BIND_ACCEPT, GLFW_KEY_ENTER); dawnGlfwInputBind(INPUT_BIND_ACCEPT, GLFW_KEY_SPACE); dawnGlfwInputBind(INPUT_BIND_ACCEPT, GLFW_KEY_E); dawnGlfwInputBind(INPUT_BIND_PAUSE, GLFW_KEY_ESCAPE); dawnGlfwInputBind(INPUT_BIND_PAUSE, GLFW_KEY_P); dawnGlfwInputBind(INPUT_BIND_CANCEL, GLFW_KEY_Q); dawnGlfwInputBind(INPUT_BIND_CANCEL, GLFW_KEY_BACKSPACE); // Event callbacks glfwSetFramebufferSizeCallback(DAWN_GLFW.window, &dawnGlfwOnResize); // Main Loop double_t time, newTime; float_t fDelta; uint8_t updateResult; // Main Render Loop time = 0.0f; while(!glfwWindowShouldClose(DAWN_GLFW.window)) { // Determine the delta. newTime = glfwGetTime(); fDelta = (float_t)(newTime - time); time = newTime; // Perform updates updateResult = gameUpdate(fDelta); // Update GLFW glfwSwapBuffers(DAWN_GLFW.window); glfwPollEvents(); if(updateResult == GAME_UPDATE_RESULT_EXIT) break; if(updateResult != GAME_UPDATE_RESULT_CONTINUE) break; } // Terminate GLFW glfwDestroyWindow(DAWN_GLFW.window); glfwTerminate(); // Reset the state incase of re-start. DAWN_GLFW.window = NULL; DAWN_GLFW.width = 0; DAWN_GLFW.height = 0; return updateResult; } void dawnGlfwInputBind(inputbind_t bind, int32_t key) { assertTrue(bind < INPUT_BIND_COUNT, "Invalid input bind"); assertTrue( DAWN_GLFW.inputBinds[bind].keyCount < DAWN_GLFW_BIND_KEYS_MAX, "Too many keys bound to input" ); DAWN_GLFW.inputBinds[bind].keys[DAWN_GLFW.inputBinds[bind].keyCount++] = key; } void dawnGlfwOnResize(GLFWwindow *window, int32_t w, int32_t h) { assertTrue(window == DAWN_GLFW.window, "glfwOnResize: Window mismatch"); int32_t windowWidth, windowHeight; glfwGetWindowSize(window, &windowWidth, &windowHeight); // TODO: I may throttle this, it calls for every frame the window's resized. backBufferSetSize(w, h, ((float_t)w) / ((float_t)windowWidth)); }