#include "program.h" #include "camera.h" #include "game_world.h" #include "physics_world.h" #include "level.h" #include "time.h" #include "assets.h" #include "debug.h" #include "input.h" #include #include SDL_Window* g_window; static double _target_delta_time = 0.0; static double _delta_time; static double _frame_start; static double _game_start_time; #define INITFLAGS SDL_INIT_EVENTS | SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK static inline double tstos(struct timespec ts) { return (double)ts.tv_sec + (double)ts.tv_nsec * 1E-09; } struct timespec get_time() { struct timespec ts; (void)timespec_get(&ts, TIME_UTC); return ts; } double get_time_s() { return tstos(get_time()); } static void program_tick(const struct ProgramSettings* settings, float delta_time) { settings->on_tick(); game_world_update(); physics_world_tick(); } void program_run(const struct ProgramSettings* settings) { LOG_INFO("Starting program..."); if(settings->target_fps <= 0) { _target_delta_time = 0; } else { _target_delta_time = 1.0f/settings->target_fps; } _game_start_time = get_time_s(); _frame_start = _game_start_time; if(SDL_Init(INITFLAGS) != 0) { LOG_ERROR("SDL init error: %s", SDL_GetError()); } g_window = SDL_CreateWindow( settings->title, SDL_WINDOWPOS_CENTERED_DISPLAY(0), SDL_WINDOWPOS_CENTERED_DISPLAY(0), settings->view_resolution.x, settings->view_resolution.y, SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE); physics_world_init(); render_init(g_window, settings); camera_init(); assets_init(); input_init(); game_world_init(); level_init(); LOG_INFO("settings->on_play"); settings->on_play(); LOG_INFO("Starting program loop"); for(;;) { render_present(); double current_time = get_time_s(); _delta_time += current_time - _frame_start; _frame_start = current_time; program_handle_events(); if(settings->target_fps == 0) { program_tick(settings, _delta_time); _delta_time = 0.f; } else { while(_delta_time > _target_delta_time) { _delta_time -= _target_delta_time; program_tick(settings, _target_delta_time); } } settings->on_draw(); game_world_draw(); SDL_Delay(1); } ASSERT_RETURN(0,, "Program escaped containment, nuking from orbit..."); abort(); } void program_quit() { level_clean(); game_world_close(); input_clean(); assets_clean(); render_clean(); physics_world_clean(); SDL_DestroyWindow(g_window); SDL_Quit(); exit(0); } void program_handle_events() { SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { default: break; case SDL_KEYUP: case SDL_KEYDOWN: case SDL_CONTROLLERBUTTONUP: case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERAXISMOTION: input_handle_event(event); break; case SDL_WINDOWEVENT: if(event.window.windowID == SDL_GetWindowID(g_window)) { program_handle_windowevent(&event.window); } break; case SDL_QUIT: program_quit(); break; } } } void program_handle_windowevent(SDL_WindowEvent* event) { switch(event->type) { default: render_handle_resize(); break; } } inline float delta_time() { return (float)(_target_delta_time == 0 ? _delta_time : _target_delta_time); } inline float game_time() { return (float)(get_time_s() - _game_start_time); }