#include "game.h" #include "sys.h" #include #include #define DEBUG 1 typedef struct { SDL_Window *window; i32 width; i32 height; SDL_Renderer *renderer; u64 last_counter; f32 dt; } sdl_context_t; static sdl_context_t init_sdl(i32 width, i32 height, i32 debug) { sdl_context_t ctx = {0}; ctx.width = width; ctx.height = height; SDL_Init(SDL_INIT_VIDEO); u64 flags = SDL_WINDOW_OPENGL; SDL_CreateWindowAndRenderer("breakout", ctx.width, ctx.height, flags, &ctx.window, &ctx.renderer); if (debug) SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); SDL_GLContext glctx = SDL_GL_CreateContext(ctx.window); SDL_GL_MakeCurrent(ctx.window, glctx); SDL_GL_SetSwapInterval(0); ctx.last_counter = SDL_GetPerformanceCounter(); glewInit(); return ctx; } static void process_sdl_key(input_t *input, i32 scancode, i32 pressed) { switch (scancode) { case SDL_SCANCODE_ESCAPE: input->escape.current = pressed; break; case SDL_SCANCODE_RIGHT: input->right.current = pressed; break; case SDL_SCANCODE_LEFT: input->left.current = pressed; break; case SDL_SCANCODE_SPACE: input->space.current = pressed; break; default: break; } } static void process_sdl_events(game_t *game) { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: process_sdl_key(&game->input, event.key.scancode, event.key.down); default: break; } } } static f32 get_elapsed(u64 last_counter) { u64 frequency = SDL_GetPerformanceFrequency(); u64 current_counter = SDL_GetPerformanceCounter(); return (f32)(current_counter - last_counter) / (f32)frequency; } static void lock_framerate_sdl(sdl_context_t *ctx, i32 fps) { f32 elapsed = get_elapsed(ctx->last_counter) * 1000.0f; f32 target = 1000.0f / (f32)fps; f32 sleep = target - elapsed; if (sleep > 0) SDL_Delay((u32)sleep); do { elapsed = get_elapsed(ctx->last_counter) * 1000.0f; } while (elapsed < target); ctx->dt = get_elapsed(ctx->last_counter); ctx->last_counter = SDL_GetPerformanceCounter(); } static void fps_info(f32 dt, i32 again) { static f32 time = 0; static i32 lastsec = 0; static f32 sumdt = 0; static i32 sumfps = 0; static f32 frame_count = 0; time += dt; sumdt += dt; sumfps += (i32)(1.0f / dt); frame_count++; i32 sec = (i32)time; if (sec != 0 && sec % again == 0) { if (lastsec != sec) { f32 mean_dt = sumdt / frame_count; f32 mean_fps = sumfps / frame_count; info("time: %d dt: %f fps: %f", sec, mean_dt, mean_fps); lastsec = sec; sumdt = 0; sumfps = 0; frame_count = 0; } } } i32 main(void) { sdl_context_t ctx = init_sdl(1600, 800, DEBUG); game_t game = init_game(ctx.width, ctx.height); while (game.running) { process_sdl_events(&game); process_input(&game); update_game(&game, ctx.dt); update_input(&game.input); lock_framerate_sdl(&ctx, 60); fps_info(ctx.dt, 10); render_game(game); SDL_GL_SwapWindow(ctx.window); } return 0; }