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