platform_windows.c (5994B)
1 // NOTE(amin): On windows, even with clang and -std=c11, assert.h doesn't 2 // define static_assert. 3 #define static_assert _Static_assert 4 5 #include <time.h> 6 7 #include "platform_info.h" 8 #include "am_gl.h" 9 #include <GLFW/glfw3.h> 10 11 // LOL, Windef.h 12 #undef near 13 #undef far 14 15 #include "game.c" 16 #include "platform.h" 17 #include "platform_windows.h" 18 19 internal void framebuffer_size_callback(GLFWwindow* window, int width, int height); 20 internal void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); 21 22 // TODO: map this in a nicer way 23 global_variable int platform_input_map[NUM_GAME_BUTTONS] = { 24 [BTN_LEFT] = GLFW_KEY_LEFT, 25 [BTN_RIGHT] = GLFW_KEY_RIGHT, 26 [BTN_UP] = GLFW_KEY_UP, 27 [BTN_DOWN] = GLFW_KEY_DOWN, 28 [BTN_JUMP] = GLFW_KEY_S, 29 [BTN_DEBUG_FLOAT] = GLFW_KEY_F11, 30 }; 31 32 int main(void) 33 { 34 glfwSetErrorCallback(error_callback); 35 36 if (!glfwInit()) 37 { 38 fprintf(stderr, "GLFW initialization failed\n"); 39 return -1; 40 } 41 42 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 43 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 44 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 45 glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); 46 47 GLFWwindow *window = glfwCreateWindow(PLATFORM_SCR_WIDTH, PLATFORM_SCR_HEIGHT, "A Game", NULL, NULL); 48 if (!window) 49 { 50 fprintf(stderr, "GLFW window creation failed\n"); 51 glfwTerminate(); 52 return -1; 53 } 54 glfwMakeContextCurrent(window); 55 glfwSetKeyCallback(window, key_callback); 56 57 if (!am_gl_init()) 58 { 59 fprintf(stderr, "OpenGL function loading failed\n."); 60 glfwDestroyWindow(window); 61 glfwTerminate(); 62 return -1; 63 } 64 65 #ifdef USE_TEST_SEED 66 srand((uint32_t)0); 67 #else 68 srand((uint32_t)time(NULL)); 69 #endif 70 71 struct GameMemory game_memory = { 72 .buffer_size = MEBIBYTES(64), 73 .platform = { 74 &windows_read_entire_file, 75 &windows_memory_free, 76 }, 77 }; 78 // TODO: replace with VirtualAlloc 79 game_memory.buffer = malloc(game_memory.buffer_size); 80 if (!game_memory.buffer) 81 { 82 fprintf(stderr, "Game memory allocation failed\n"); 83 glfwTerminate(); 84 return -1; 85 } 86 87 struct GameInput game_input = {0}; 88 glfwSetWindowUserPointer(window, &game_input); 89 game_init(&game_memory, (v2u) {PLATFORM_SCR_WIDTH, PLATFORM_SCR_HEIGHT}); 90 91 // NOTE(amin): lag should always be very small, so it's fine to use a float 92 // to store it. We will not run out of precision. 93 uint64_t previous_wall_clock_time = glfwGetTimerValue(); 94 uint64_t timer_frequency = glfwGetTimerFrequency(); 95 96 while (!glfwWindowShouldClose(window)) 97 { 98 uint64_t current_wall_clock_time = glfwGetTimerValue(); 99 100 { 101 uint64_t previous_frame_duration = current_wall_clock_time - previous_wall_clock_time; 102 previous_wall_clock_time = current_wall_clock_time; 103 f32 dt = (float)previous_frame_duration / (float)timer_frequency; 104 // TODO: Debug periodic dropped frame on linux when fullscreen 105 //printf("ms per frame: %f\n", dt * 1000.0f); 106 game_input.dt = dt; 107 } 108 109 int32_t framebuffer_width = PLATFORM_SCR_WIDTH; 110 int32_t framebuffer_height = PLATFORM_SCR_HEIGHT; 111 glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height); 112 assert(framebuffer_width >= 0); 113 assert(framebuffer_height >= 0); 114 v2u framebuffer = {framebuffer_width, framebuffer_height}; 115 116 game_update_and_render(&game_memory, &game_input, framebuffer); 117 118 // TODO: Do something sane when vsync is disabled 119 glfwSwapBuffers(window); 120 glfwPollEvents(); 121 } 122 123 game_cleanup(&game_memory); 124 125 // TODO: replace with VirtualFree 126 free(game_memory.buffer); 127 128 glfwDestroyWindow(window); 129 glfwTerminate(); 130 return 0; 131 } 132 133 internal void error_callback(int error, const char *description) 134 { 135 fprintf(stderr, "Error: %s\n", description); 136 } 137 138 internal void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) 139 { 140 struct GameInput *game_input = (struct GameInput *)glfwGetWindowUserPointer(window); 141 142 enum GameButton game_button = NULL_GAME_BUTTON; 143 // TODO: Determine the button in a nicer way 144 for (enum GameButton b = 0; b < NUM_GAME_BUTTONS; b++) 145 { 146 if (platform_input_map[b] == key) 147 { 148 game_button = b; 149 } 150 } 151 if (game_button != NULL_GAME_BUTTON) 152 { 153 switch (action) 154 { 155 case GLFW_PRESS: 156 game_input->button_states |= (1 << game_button); 157 break; 158 case GLFW_RELEASE: 159 game_input->button_states &= ~(1 << game_button); 160 break; 161 case GLFW_REPEAT: 162 // Do nothing 163 break; 164 default: 165 exit(1); 166 break; 167 } 168 } 169 } 170 171 PLATFORM_MEMORY_FREE(windows_memory_free) 172 { 173 free(ptr); 174 } 175 176 internal PLATFORM_READ_ENTIRE_FILE(windows_read_entire_file) 177 { 178 assert(a); 179 FILE *handle = fopen(file_path, "rb"); 180 u8 *buffer = NULL; 181 182 if (handle) 183 { 184 // get file size 185 fseek(handle, 0, SEEK_END); 186 u32 num_bytes_in_file = ftell(handle); 187 rewind(handle); 188 189 if (out_num_bytes) 190 { 191 *out_num_bytes = num_bytes_in_file; 192 } 193 194 buffer = mem_st_alloc_buffer(a, u8, num_bytes_in_file + 1); 195 196 u32 bytes_read = fread(buffer, sizeof(u8), num_bytes_in_file, handle); 197 // IMPORTANT! fread() doesn't add the '\0' 198 buffer[num_bytes_in_file] = '\0'; 199 200 // TODO: handle this case more loudly 201 if (num_bytes_in_file != bytes_read) 202 { 203 buffer = NULL; 204 } 205 206 fclose(handle); 207 } 208 else 209 { 210 printf("Error: Couldn't open file at path: %s", file_path); 211 // TODO: handle errors here in a better way 212 exit(1); 213 } 214 215 return buffer; 216 }