platform_sdl.c (9363B)
1 #include "platform_sdl.h" 2 3 #include "sim.h" 4 5 #include <stdbool.h> 6 #include <stdio.h> 7 #include <string.h> 8 9 #ifndef MAP_ANONYMOUS 10 #define MAP_ANONYMOUS MAP_ANON 11 #endif 12 13 extern bool PAUSED; 14 extern bool BRUTE_FORCE; 15 extern bool RENDER_GRID; 16 extern bool RENDER_BOUNDING_BOX; 17 extern bool RENDER_TRAILS; 18 19 static struct SDLOffscreenBuffer global_back_buffer; 20 21 22 struct SDLWindowDimension sdl_get_window_dimension(SDL_Window *window) 23 { 24 struct SDLWindowDimension result; 25 SDL_GetWindowSize(window, &result.width, &result.height); 26 return(result); 27 } 28 29 30 void sdl_resize_texture(struct SDLOffscreenBuffer *buffer, SDL_Renderer *renderer, int width, int height) 31 { 32 if (buffer->memory) 33 { 34 free(buffer->memory); 35 } 36 37 if (buffer->texture) 38 { 39 SDL_DestroyTexture(buffer->texture); 40 } 41 42 buffer->texture = SDL_CreateTexture( 43 renderer, 44 SDL_PIXELFORMAT_ARGB8888, 45 SDL_TEXTUREACCESS_STREAMING, 46 width, height); 47 48 buffer->width = width; 49 buffer->height = height; 50 buffer->pitch = width * BYTES_PER_PIXEL; 51 52 buffer->memory = malloc(width * height * BYTES_PER_PIXEL); 53 } 54 55 56 void sdl_update_window(SDL_Renderer *renderer, struct SDLOffscreenBuffer *buffer) 57 { 58 if (SDL_UpdateTexture(buffer->texture, 0, buffer->memory, buffer->pitch)) 59 { 60 // TODO(amin): Handle this error 61 } 62 63 SDL_RenderCopy(renderer, buffer->texture, 0, 0); 64 SDL_RenderPresent(renderer); 65 } 66 67 68 void clear_screen(struct SDLOffscreenBuffer *buffer, uint32_t pixel_value) 69 { 70 // NOTE(amin): Memset is faster than nested for loops, but can only set 71 // pixels to single byte values 72 memset(buffer->memory, pixel_value, buffer->height * buffer->width * BYTES_PER_PIXEL); 73 } 74 75 76 bool handle_event(SDL_Event *event) 77 { 78 bool should_quit = false; 79 80 switch(event->type) 81 { 82 case SDL_QUIT: 83 { 84 printf("SDL_QUIT\n"); 85 should_quit = true; 86 } break; 87 88 case SDL_KEYDOWN: 89 case SDL_KEYUP: 90 { 91 SDL_Keycode key_code = event->key.keysym.sym; 92 bool is_down = (event->key.state == SDL_PRESSED); 93 if (is_down) 94 { 95 if (key_code == SDLK_b) 96 { 97 RENDER_BOUNDING_BOX = !RENDER_BOUNDING_BOX; 98 } 99 if (key_code == SDLK_f) 100 { 101 BRUTE_FORCE = !BRUTE_FORCE; 102 } 103 if (key_code == SDLK_g) 104 { 105 RENDER_GRID = !RENDER_GRID; 106 } 107 if (key_code == SDLK_p) 108 { 109 PAUSED = !PAUSED; 110 } 111 if (key_code == SDLK_t) 112 { 113 RENDER_TRAILS = !RENDER_TRAILS; 114 clear_screen(&global_back_buffer, COLOR_BACKGROUND); 115 } 116 } 117 } break; 118 case SDL_WINDOWEVENT: 119 { 120 switch(event->window.event) 121 { 122 case SDL_WINDOWEVENT_SIZE_CHANGED: 123 { 124 SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); 125 SDL_Renderer *renderer = SDL_GetRenderer(window); 126 printf("SDL_WINDOWEVENT_SIZE_CHANGED (%d, %d)\n", event->window.data1, event->window.data2); 127 sdl_resize_texture(&global_back_buffer, renderer, event->window.data1, event->window.data2); 128 } break; 129 130 case SDL_WINDOWEVENT_FOCUS_GAINED: 131 { 132 printf("SDL_WINDOWEVENT_FOCUS_GAINED\n"); 133 } break; 134 135 case SDL_WINDOWEVENT_EXPOSED: 136 { 137 SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); 138 SDL_Renderer *renderer = SDL_GetRenderer(window); 139 sdl_update_window(renderer, &global_back_buffer); 140 } break; 141 } 142 } break; 143 } 144 return(should_quit); 145 } 146 147 148 int main(int argc, char *argv[]) 149 { 150 if (SDL_Init(SDL_INIT_VIDEO)) 151 { 152 // TODO(amin): log SDL_Init error 153 } 154 155 SDL_Window *window = SDL_CreateWindow( 156 TITLE, 157 SDL_WINDOWPOS_UNDEFINED, 158 SDL_WINDOWPOS_UNDEFINED, 159 SCREEN_WIDTH, 160 SCREEN_HEIGHT, 161 SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); 162 163 #ifdef FULLSCREEN 164 SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); 165 #endif 166 167 if (window) 168 { 169 SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); 170 171 if (renderer) 172 { 173 struct SDLWindowDimension dimension = sdl_get_window_dimension(window); 174 sdl_resize_texture(&global_back_buffer, renderer, dimension.width, dimension.height); 175 176 bool running = true; 177 178 #ifdef USE_TEST_SEED 179 srand((uint32_t)0); 180 #else 181 srand((uint32_t)time(NULL)); 182 #endif 183 184 uint64_t lag = 0; 185 uint64_t previous_ms = (SDL_GetPerformanceCounter() * SECOND) / SDL_GetPerformanceFrequency(); 186 187 struct SimState sim_state; 188 sim_init(&sim_state, dimension.width, dimension.height); 189 190 while (running) 191 { 192 uint64_t current_ms = (SDL_GetPerformanceCounter() * SECOND) / SDL_GetPerformanceFrequency(); 193 uint64_t elapsed_ms = current_ms - previous_ms; 194 previous_ms = current_ms; 195 lag += elapsed_ms; 196 //printf("%" PRIu64 ", %" PRIu64 ", %f\n", elapsed_ms, lag, MS_PER_UPDATE); 197 198 SDL_Event event; 199 200 while (SDL_PollEvent(&event)) 201 { 202 running = !handle_event(&event); 203 } 204 205 SDL_PumpEvents(); 206 207 dimension = sdl_get_window_dimension(window); 208 209 const uint8_t *keystate = SDL_GetKeyboardState(0); 210 211 // TODO: move this to a function 212 if (keystate[SDL_SCANCODE_A] || keystate[SDL_SCANCODE_H]) 213 { 214 sim_state.view.dx += 5 / sim_state.view.zoom; 215 } 216 if (keystate[SDL_SCANCODE_D] || keystate[SDL_SCANCODE_L]) 217 { 218 sim_state.view.dx -= 5 / sim_state.view.zoom; 219 } 220 if (keystate[SDL_SCANCODE_W] || keystate[SDL_SCANCODE_K]) 221 { 222 sim_state.view.dy += 5 / sim_state.view.zoom; 223 } 224 if (keystate[SDL_SCANCODE_S] || keystate[SDL_SCANCODE_J]) 225 { 226 sim_state.view.dy -= 5 / sim_state.view.zoom; 227 } 228 if (keystate[SDL_SCANCODE_LEFT]) 229 { 230 sim_state.view.dx += 1 / sim_state.view.zoom; 231 } 232 if (keystate[SDL_SCANCODE_RIGHT]) 233 { 234 sim_state.view.dx -= 1 / sim_state.view.zoom; 235 } 236 if (keystate[SDL_SCANCODE_UP]) 237 { 238 sim_state.view.dy += 1 / sim_state.view.zoom; 239 } 240 if (keystate[SDL_SCANCODE_DOWN]) 241 { 242 sim_state.view.dy -= 1 / sim_state.view.zoom; 243 } 244 if (keystate[SDL_SCANCODE_EQUALS]) 245 { 246 sim_state.view.zoom *= 1.01; 247 } 248 if (keystate[SDL_SCANCODE_MINUS]) 249 { 250 sim_state.view.zoom *= 0.99; 251 } 252 if (keystate[SDL_SCANCODE_0]) 253 { 254 sim_state.view.zoom = 1; 255 } 256 if (keystate[SDL_SCANCODE_HOME]) 257 { 258 sim_state.view.dx = 0; 259 sim_state.view.dy = 0; 260 sim_state.view.zoom = 1; 261 } 262 263 struct OffscreenBuffer buffer; 264 // WARNING: these pointers are aliased until the end of the 265 // loop 266 buffer.memory = global_back_buffer.memory; 267 buffer.width = global_back_buffer.width; 268 buffer.height = global_back_buffer.height; 269 buffer.pitch = global_back_buffer.pitch; 270 271 if (PAUSED) 272 { 273 lag = 0; 274 } 275 else 276 { 277 while (lag >= MS_PER_UPDATE) 278 { 279 sim_update(&sim_state, buffer.width, buffer.height); 280 //printf("\t%" PRIu64 ", %f\n", lag, MS_PER_UPDATE); 281 lag -= MS_PER_UPDATE; 282 } 283 } 284 285 if (!RENDER_TRAILS) 286 { 287 clear_screen(&global_back_buffer, COLOR_BACKGROUND); 288 } 289 290 sim_render(&buffer, lag/SECOND, &sim_state); 291 sdl_update_window(renderer, &global_back_buffer); 292 if (elapsed_ms <= MS_PER_FRAME) 293 { 294 SDL_Delay(MS_PER_FRAME - elapsed_ms); 295 } 296 } 297 298 sim_cleanup(&sim_state); 299 } 300 else 301 { 302 // TODO(amin): log SDL_Renderer error 303 } 304 } 305 else 306 { 307 // TODO(amin): log SDL_Window error 308 } 309 310 SDL_Quit(); 311 return(0); 312 }