/* * timer - event timer */ void timer(void) { register struct peer *peer, *next_peer; u_int n; long delta; /* * The basic timerevent is one second. This is used to adjust * the system clock in time and frequency, implement the * kiss-o'-deatch function and implement the association * polling function.. */ current_time += nap_time; get_systime(&sys_time); nap_time = (u_long)-1; if (do_adjtime) { if (adjust_timer <= current_time) { adjust_timer += 1; adj_host_clock(); #ifdef REFCLOCK for (n = 0; n < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; if (peer->flags & FLAG_REFCLOCK) refclock_timer(peer); } } #endif /* REFCLOCK */ } nap_time = 1; } if (awake_timer) { if (awake_timer <= current_time) { for (n = 0; n < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = peer->next) { peer->burst = NSTAGE; peer->nextdate = current_time; peer->throttle = 0; } } allow_panic = TRUE; /* Allow for large time offsets */ init_loopfilter(); state = EVNT_NSET; awake_timer = 0; } else { delta = awake_timer - current_time; if (delta < nap_time) { nap_time = delta; } } } /* * Now dispatch any peers whose event timer has expired. Be * careful here, since the peer structure might go away as the * result of the call. */ for (n = 0; n < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; if (peer->action && peer->nextaction <= current_time) peer->action(peer); /* * Restrain the non-burst packet rate not more * than one packet every 16 seconds. This is * usually tripped using iburst and minpoll of * 128 s or less. */ if (peer->throttle > 0) peer->throttle--; if (peer->nextdate <= current_time) { #ifdef REFCLOCK if (peer->flags & FLAG_REFCLOCK) refclock_transmit(peer); else transmit(peer); #else /* REFCLOCK */ transmit(peer); #endif /* REFCLOCK */ } if (peer->action && peer->nextaction >= current_time) { delta = peer->nextaction - current_time; if (delta < nap_time) { nap_time = delta; } } else if (peer->nextdate >= current_time) { delta = peer->nextdate - current_time; if (delta < nap_time) { nap_time = delta; } } } } /* * Orphan mode is active when enabled and when no servers less * than the orphan statum are available. A server with no other * synchronization source is an orphan It shows offset zero and * reference ID the loopback address. */ if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL) { if (sys_leap == LEAP_NOTINSYNC) { sys_leap = LEAP_NOWARNING; #ifdef OPENSSL if (crypto_flags) crypto_update(); #endif /* OPENSSL */ } sys_stratum = (u_char)sys_orphan; if (sys_stratum > 1) sys_refid = htonl(LOOPBACKADR); else memcpy(&sys_refid, "LOOP", 4); sys_offset = 0; sys_rootdelay = 0; sys_rootdisp = 0; } /* * Leapseconds. If a leap is pending, decrement the time * remaining. If less than one day remains, set the leap bits. * When no time remains, clear the leap bits and increment the * TAI. If kernel suppport is not available, do the leap * crudely. Note a leap cannot be pending unless the clock is * set. */ if (leapsec > 0) { leapsec--; if (leapsec == 0) { sys_leap = LEAP_NOWARNING; sys_tai = leap_tai; #ifdef KERNEL_PLL if (!(pll_control && kern_enable)) step_systime(-1.0); #else /* KERNEL_PLL */ #ifndef SYS_WINNT /* WinNT port has its own leap second handling */ step_systime(-1.0); #endif /* SYS_WINNT */ #endif /* KERNEL_PLL */ report_event(EVNT_LEAP, NULL, NULL); } else { if (leapsec < DAY) sys_leap = LEAP_ADDSECOND; if (leap_tai > 0) sys_tai = leap_tai - 1; } } /* * Update huff-n'-puff filter. */ if (huffpuff_timer <= current_time) { huffpuff_timer += HUFFPUFF; huffpuff(); } if (huffpuff_timer >= current_time) { delta = huffpuff_timer - current_time; if (delta < nap_time) { nap_time = delta; } } #ifdef OPENSSL /* * Garbage collect expired keys. */ if (keys_timer <= current_time) { keys_timer += 1 << sys_automax; auth_agekeys(); } if (keys_timer >= current_time) { delta = keys_timer - current_time; if (delta < nap_time) { nap_time = delta; } } /* * Garbage collect key list and generate new private value. The * timer runs only after initial synchronization and fires about * once per day. */ if (revoke_timer <= current_time && sys_leap != LEAP_NOTINSYNC) { revoke_timer += 1 << sys_revoke; RAND_bytes((u_char *)&sys_private, 4); } if (revoke_timer >= current_time) { delta = revoke_timer - current_time; if (delta < nap_time) { nap_time = delta; } } #endif /* OPENSSL */ /* * Interface update timer */ if (interface_interval && interface_timer <= current_time) { timer_interfacetimeout(current_time + interface_interval); DPRINTF(2, ("timer: interface update\n")); interface_update(NULL, NULL); } if (interface_interval && interface_timer >= current_time) { delta = interface_timer - current_time; if (delta < nap_time) { nap_time = delta; } } if (dns_timer && (dns_timer <= current_time)) { dns_timer = update_dns_peers(); } if (dns_timer >= current_time) { delta = dns_timer - current_time; if (delta < nap_time) { nap_time = delta; } } /* * Finally, write hourly stats. */ if (stats_timer <= current_time) { stats_timer += HOUR; write_stats(); if (sys_tai != 0 && sys_time.l_ui > leap_expire) report_event(EVNT_LEAPVAL, NULL, NULL); } else if (!do_adjtime && drift_file_sw) { write_stats(); /* update more frequently for pacemaker */ } if (stats_timer >= current_time) { delta = stats_timer - current_time; if (delta < nap_time) { nap_time = delta; } } if (nap_time == 0) { nap_time = 1; } if (debug) { msyslog(LOG_INFO, "%s: current_time: %ld, nap_time: %ld", __FUNCTION__, current_time, nap_time); } itimer.it_interval.tv_sec = itimer.it_value.tv_sec = nap_time; setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); }
/* * timer - event timer */ void timer(void) { struct peer * p; struct peer * next_peer; l_fp now; time_t tnow; /* * The basic timerevent is one second. This is used to adjust the * system clock in time and frequency, implement the kiss-o'-death * function and the association polling function. */ current_time++; if (adjust_timer <= current_time) { adjust_timer += 1; adj_host_clock(); #ifdef REFCLOCK for (p = peer_list; p != NULL; p = next_peer) { next_peer = p->p_link; if (FLAG_REFCLOCK & p->flags) refclock_timer(p); } #endif /* REFCLOCK */ } /* * Now dispatch any peers whose event timer has expired. Be * careful here, since the peer structure might go away as the * result of the call. */ for (p = peer_list; p != NULL; p = next_peer) { next_peer = p->p_link; /* * Restrain the non-burst packet rate not more * than one packet every 16 seconds. This is * usually tripped using iburst and minpoll of * 128 s or less. */ if (p->throttle > 0) p->throttle--; if (p->nextdate <= current_time) { #ifdef REFCLOCK if (FLAG_REFCLOCK & p->flags) refclock_transmit(p); else #endif /* REFCLOCK */ transmit(p); } } /* * Orphan mode is active when enabled and when no servers less * than the orphan stratum are available. A server with no other * synchronization source is an orphan. It shows offset zero and * reference ID the loopback address. */ if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL && current_time > orphwait) { if (sys_leap == LEAP_NOTINSYNC) { set_sys_leap(LEAP_NOWARNING); #ifdef AUTOKEY if (crypto_flags) crypto_update(); #endif /* AUTOKEY */ } sys_stratum = (u_char)sys_orphan; if (sys_stratum > 1) sys_refid = htonl(LOOPBACKADR); else memcpy(&sys_refid, "LOOP", 4); sys_offset = 0; sys_rootdelay = 0; sys_rootdisp = 0; } get_systime(&now); time(&tnow); /* * Leapseconds. Get time and defer to worker if either something * is imminent or every 8th second. */ if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7)) check_leapsec(now.l_ui, &tnow, (sys_leap == LEAP_NOTINSYNC)); if (sys_leap != LEAP_NOTINSYNC) { if (leapsec >= LSPROX_ANNOUNCE && leapdif) { if (leapdif > 0) set_sys_leap(LEAP_ADDSECOND); else set_sys_leap(LEAP_DELSECOND); } else { set_sys_leap(LEAP_NOWARNING); } } /* * Update huff-n'-puff filter. */ if (huffpuff_timer <= current_time) { huffpuff_timer += HUFFPUFF; huffpuff(); } #ifdef AUTOKEY /* * Garbage collect expired keys. */ if (keys_timer <= current_time) { keys_timer += 1 << sys_automax; auth_agekeys(); } /* * Generate new private value. This causes all associations * to regenerate cookies. */ if (revoke_timer && revoke_timer <= current_time) { revoke_timer += 1 << sys_revoke; RAND_bytes((u_char *)&sys_private, 4); } #endif /* AUTOKEY */ /* * Interface update timer */ if (interface_interval && interface_timer <= current_time) { timer_interfacetimeout(current_time + interface_interval); DPRINTF(2, ("timer: interface update\n")); interface_update(NULL, NULL); } if (worker_idle_timer && worker_idle_timer <= current_time) worker_idle_timer_fired(); /* * Finally, write hourly stats and do the hourly * and daily leapfile checks. */ if (stats_timer <= current_time) { stats_timer += SECSPERHR; write_stats(); if (leapf_timer <= current_time) { leapf_timer += SECSPERDAY; check_leap_file(TRUE, now.l_ui, &tnow); } else { check_leap_file(FALSE, now.l_ui, &tnow); } } }
/* * timer - dispatch anyone who needs to be */ void timer(void) { register struct peer *peer, *next_peer; #ifdef OPENSSL char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ #endif /* OPENSSL */ u_int n; current_time += (1<<EVENT_TIMEOUT); /* * Adjustment timeout first. */ if (adjust_timer <= current_time) { adjust_timer += 1; adj_host_clock(); kod_proto(); #ifdef REFCLOCK for (n = 0; n < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; if (peer->flags & FLAG_REFCLOCK) refclock_timer(peer); } } #endif /* REFCLOCK */ } /* * Now dispatch any peers whose event timer has expired. Be careful * here, since the peer structure might go away as the result of * the call. */ for (n = 0; n < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; if (peer->action && peer->nextaction <= current_time) peer->action(peer); if (peer->nextdate <= current_time) { #ifdef REFCLOCK if (peer->flags & FLAG_REFCLOCK) refclock_transmit(peer); else transmit(peer); #else /* REFCLOCK */ transmit(peer); #endif /* REFCLOCK */ } } } /* * Garbage collect expired keys. */ if (keys_timer <= current_time) { keys_timer += MINUTE; auth_agekeys(); } /* * Huff-n'-puff filter */ if (huffpuff_timer <= current_time) { huffpuff_timer += HUFFPUFF; huffpuff(); } #ifdef OPENSSL /* * Garbage collect old keys and generate new private value */ if (revoke_timer <= current_time) { revoke_timer += RANDPOLL(sys_revoke); expire_all(); sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp)); record_crypto_stats(NULL, statstr); #ifdef DEBUG if (debug) printf("timer: %s\n", statstr); #endif } #endif /* OPENSSL */ /* * interface update timer */ if (interface_interval && interface_timer <= current_time) { timer_interfacetimeout(current_time + interface_interval); DPRINTF(1, ("timer: interface update\n")); interface_update(NULL, NULL); } /* * Finally, periodically write stats. */ if (stats_timer <= current_time) { if (stats_timer != 0) write_stats(); stats_timer += stats_write_period; } }
/* game_loop() has been turned into a SDL based loop. The code for one iteration of the original game_loop is in game_loop_iter. */ static void game_loop() { /* FPS */ int fps = 0; int fps_ema = 0; int fps_target = 25; const float ema_alpha = 0.003; int drag_button = 0; unsigned int last_down[3] = {0}; unsigned int last_click[3] = {0}; unsigned int current_ticks = SDL_GetTicks(); unsigned int accum = 0; unsigned int accum_frames = 0; SDL_Event event; gui_event_t ev; game_loop_run = 1; while (game_loop_run) { if (SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONUP: if (drag_button == event.button.button) { ev.type = GUI_EVENT_TYPE_DRAG_END; ev.x = event.button.x; ev.y = event.button.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); drag_button = 0; } ev.type = GUI_EVENT_TYPE_BUTTON_UP; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3 && current_ticks - last_down[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (current_ticks - last_click[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_DBL_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); } last_click[event.button.button-1] = current_ticks; } break; case SDL_MOUSEBUTTONDOWN: ev.type = GUI_EVENT_TYPE_BUTTON_DOWN; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3) last_down[event.button.button-1] = current_ticks; break; case SDL_MOUSEMOTION: if (drag_button == 0) { /* Move pointer normally. */ interface_set_cursor(&interface, event.motion.x, event.motion.y); } for (int button = 1; button <= 3; button++) { if (event.motion.state & SDL_BUTTON(button)) { if (drag_button == 0) { drag_button = button; ev.type = GUI_EVENT_TYPE_DRAG_START; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); } ev.type = GUI_EVENT_TYPE_DRAG_MOVE; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); break; } } break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_CTRL)) { game_loop_quit(); break; } switch (event.key.keysym.sym) { /* Map scroll */ case SDLK_UP: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, -1); } break; case SDLK_DOWN: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, 1); } break; case SDLK_LEFT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, -1, 0); } break; case SDLK_RIGHT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 1, 0); } break; /* Panel click shortcuts */ case SDLK_1: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 0); } break; case SDLK_2: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 1); } break; case SDLK_3: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 2); } break; case SDLK_4: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 3); } break; case SDLK_5: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 4); } break; /* Game speed */ case SDLK_PLUS: case SDLK_KP_PLUS: if (game.game_speed < 40) game.game_speed += 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_MINUS: case SDLK_KP_MINUS: if (game.game_speed >= 1) game.game_speed -= 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_0: game.game_speed = DEFAULT_GAME_SPEED; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_p: if (game.game_speed == 0) game_pause(0); else game_pause(1); break; /* Audio */ case SDLK_s: sfx_enable(!sfx_is_enabled()); break; case SDLK_m: midi_enable(!midi_is_enabled()); break; /* Misc */ case SDLK_ESCAPE: if (BIT_TEST(interface.click, 7)) { /* Building road */ interface_build_road_end(&interface); } else if (interface.clkmap != 0) { interface_close_popup(&interface); } break; /* Debug */ case SDLK_g: interface.viewport.layers ^= VIEWPORT_LAYER_GRID; break; case SDLK_j: { int current = 0; for (int i = 0; i < 4; i++) { if (interface.player == game.player[i]) { current = i; break; } } for (int i = (current+1) % 4; i != current; i = (i+1) % 4) { if (PLAYER_IS_ACTIVE(game.player[i])) { interface.player = game.player[i]; LOGD("main", "Switched to player %i.", i); break; } } } break; case SDLK_z: if (event.key.keysym.mod & KMOD_CTRL) { save_game(0); } break; default: break; } break; case SDL_QUIT: game_loop_quit(); break; } } unsigned int new_ticks = SDL_GetTicks(); int delta_ticks = new_ticks - current_ticks; current_ticks = new_ticks; accum += delta_ticks; while (accum >= TICK_LENGTH) { game_update(); /* Autosave periodically */ if ((game.const_tick % AUTOSAVE_INTERVAL) == 0 && game.game_speed > 0) { int r = save_game(1); if (r < 0) LOGW("main", "Autosave failed."); } /* FPS */ fps = 1000*((float)accum_frames / accum); if (fps_ema > 0) fps_ema = ema_alpha*fps + (1-ema_alpha)*fps_ema; else if (fps > 0) fps_ema = fps; if ((game.const_tick % (10*TICKS_PER_SEC)) == 0) { LOGV("main", "FPS: %i", fps_ema); } accum -= TICK_LENGTH; accum_frames = 0; } /* Update and draw interface */ interface_update(&interface); interface.flags &= ~BIT(4); interface.flags &= ~BIT(7); gui_object_redraw((gui_object_t *)&interface, game.frame); /* TODO very crude dirty marking algortihm: mark everything. */ sdl_mark_dirty(0, 0, sdl_frame_get_width(game.frame), sdl_frame_get_height(game.frame)); /* Swap video buffers */ sdl_swap_buffers(); accum_frames += 1; /* Reduce framerate to target */ if (fps_target > 0) { int delay = 0; if (fps_ema > 0) delay = (1000/fps_target) - (1000/fps_ema); if (delay > 0) SDL_Delay(delay); } } }
/* game_loop() has been turned into a SDL based loop. The code for one iteration of the original game_loop is in game_loop_iter. */ static void game_loop() { /* FPS */ int fps = 0; float fps_ema = 0; int fps_target = 25; /* TODO: compute alpha dynamically based on frametime */ const float ema_alpha = 0.07; const int frametime_target = 1000 / fps_target; /* in milliseconds */ int last_frame = SDL_GetTicks(); int drag_button = 0; unsigned int last_down[3] = {0}; unsigned int last_click[3] = {0}; unsigned int current_ticks = SDL_GetTicks(); unsigned int accum = 0; SDL_Event event; gui_event_t ev; game_loop_run = 1; while (game_loop_run) { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONUP: if (drag_button == event.button.button) { ev.type = GUI_EVENT_TYPE_DRAG_END; ev.x = event.button.x; ev.y = event.button.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); drag_button = 0; } ev.type = GUI_EVENT_TYPE_BUTTON_UP; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3 && current_ticks - last_down[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (current_ticks - last_click[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_DBL_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); } last_click[event.button.button-1] = current_ticks; } break; case SDL_MOUSEBUTTONDOWN: ev.type = GUI_EVENT_TYPE_BUTTON_DOWN; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3) last_down[event.button.button-1] = current_ticks; break; case SDL_MOUSEMOTION: if (drag_button == 0) { /* Move pointer normally. */ interface_set_cursor(&interface, event.motion.x, event.motion.y); } for (int button = 1; button <= 3; button++) { if (event.motion.state & SDL_BUTTON(button)) { if (drag_button == 0) { drag_button = button; ev.type = GUI_EVENT_TYPE_DRAG_START; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); } ev.type = GUI_EVENT_TYPE_DRAG_MOVE; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); break; } } break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_CTRL)) { game_loop_quit(); break; } switch (event.key.keysym.sym) { /* Map scroll */ case SDLK_UP: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, -1); } break; case SDLK_DOWN: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, 1); } break; case SDLK_LEFT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, -1, 0); } break; case SDLK_RIGHT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 1, 0); } break; /* Panel click shortcuts */ case SDLK_1: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 0); } break; case SDLK_2: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 1); } break; case SDLK_3: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 2); } break; case SDLK_4: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 3); } break; case SDLK_5: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 4); } break; case SDLK_TAB: if (event.key.keysym.mod & KMOD_SHIFT) { interface_return_from_message(&interface); } else { interface_open_message(&interface); } break; /* Game speed */ case SDLK_PLUS: case SDLK_KP_PLUS: if (game.game_speed < 40) game.game_speed += 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_MINUS: case SDLK_KP_MINUS: if (game.game_speed >= 1) game.game_speed -= 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_0: game.game_speed = DEFAULT_GAME_SPEED; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_p: if (game.game_speed == 0) game_pause(0); else game_pause(1); break; /* Audio */ case SDLK_s: sfx_enable(!sfx_is_enabled()); break; case SDLK_m: midi_enable(!midi_is_enabled()); break; /* Video */ case SDLK_f: if (event.key.keysym.mod & KMOD_CTRL) { sdl_set_fullscreen(!sdl_is_fullscreen()); } break; /* Misc */ case SDLK_ESCAPE: if (GUI_OBJECT(&interface.popup)->displayed) { interface_close_popup(&interface); } else if (interface.building_road) { interface_build_road_end(&interface); } break; /* Debug */ case SDLK_g: interface.viewport.layers ^= VIEWPORT_LAYER_GRID; break; case SDLK_b: interface.viewport.show_possible_build = !interface.viewport.show_possible_build; break; case SDLK_j: { int current = 0; for (int i = 0; i < 4; i++) { if (interface.player == game.player[i]) { current = i; break; } } for (int i = (current+1) % 4; i != current; i = (i+1) % 4) { if (PLAYER_IS_ACTIVE(game.player[i])) { interface.player = game.player[i]; LOGD("main", "Switched to player %i.", i); break; } } } break; case SDLK_z: if (event.key.keysym.mod & KMOD_CTRL) { save_game(0); } break; case SDLK_F10: interface_open_game_init(&interface); break; default: break; } break; case SDL_VIDEORESIZE: sdl_set_resolution(event.resize.w, event.resize.h, 0); frame_t *screen = sdl_get_screen_frame(); int width = sdl_frame_get_width(screen); int height = sdl_frame_get_height(screen); screen_frame.clip.w = width; screen_frame.clip.h = height; gui_object_set_size((gui_object_t *)&interface, width, height); break; case SDL_QUIT: game_loop_quit(); break; } } unsigned int new_ticks = SDL_GetTicks(); int delta_ticks = new_ticks - current_ticks; current_ticks = new_ticks; /* Update FPS EMA per frame */ fps = 1000*(1.0 / (float)delta_ticks); if (fps_ema > 0) fps_ema = ema_alpha*fps + (1-ema_alpha)*fps_ema; else if (fps > 0) fps_ema = fps; accum += delta_ticks; while (accum >= TICK_LENGTH) { game_update(); /* Autosave periodically */ if ((game.const_tick % AUTOSAVE_INTERVAL) == 0 && game.game_speed > 0) { int r = save_game(1); if (r < 0) LOGW("main", "Autosave failed."); } /* Print FPS */ if ((game.const_tick % (10*TICKS_PER_SEC)) == 0) { LOGV("main", "FPS: %i", (int)fps_ema); } accum -= TICK_LENGTH; } /* Update and draw interface */ interface_update(&interface); gui_object_redraw(GUI_OBJECT(&interface), game.frame); /* TODO very crude dirty marking algortihm: mark everything. */ sdl_mark_dirty(0, 0, sdl_frame_get_width(game.frame), sdl_frame_get_height(game.frame)); /* Swap video buffers */ sdl_swap_buffers(); /* Reduce framerate to target if we finished too fast */ int now = SDL_GetTicks(); int frametime_spent = now - last_frame; if (frametime_spent < frametime_target) { SDL_Delay(frametime_target - frametime_spent); } last_frame = SDL_GetTicks(); } }