/* This file is part of Minitrem. Minitrem is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Minitrem is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Minitrem. If not, see . */ #include "game.hpp" #include namespace interface { using namespace game; // FIXME state_t::state_t(sf::RenderWindow *window_, game::state_t *game_) { window = window_; game = game_; } static sf::Vector2f compute_pan(sf::RenderWindow *window, sf::Vector2f pan_ref) { sf::Vector2i mouse = sf::Mouse::getPosition(*window); sf::Vector2f vmouse = window->mapPixelToCoords(mouse); return -(vmouse - pan_ref); } void state_t::start_following(void) { camera.following = true; camera.zero_point_s = camera.center; camera.center = v2f_t(0, 0); print(text::get(text::FOLLOWING_ON)); } void state_t::stop_following(void) { camera.following = false; camera.center += camera.zero_point_s; camera.zero_point_s = v2f_t(0, 0); print(text::get(text::FOLLOWING_OFF)); } void state_t::tick(double dt) { vec_t window_size; sf::Event event; v2f_t view_size; v2f_t follow_center(0, 0), view_center, pan_delta; float view_scale; v2f_t wmouse; // Mouse position in world space; window_size = window->getSize(); expfade(&camera.zoom_s, camera.zoom, 15, dt); view_scale = 4.5 * exp(camera.zoom_s * 0.12); if (window_size[0] < window_size[1]) { view_size[1] = view_scale; view_size[0] = view_scale * window_size[0] / window_size[1]; } else { view_size[0] = view_scale; view_size[1] = view_scale * window_size[1] / window_size[0]; } if (!game->selected_units.size() && camera.following) stop_following(); if (camera.following) { float limit; for (entity_t *ent : game->selected_units) follow_center += ent->render_bounds.center(); follow_center /= game->selected_units.size(); expfade(&camera.zero_point_s, follow_center, 15, dt); limit = view_scale * 0.2f; if (camera.center.len() > limit * 2.0f) stop_following(); else if (camera.center.len() > limit) expfade(&camera.center, camera.center.norm() * limit, 3, dt); } view_center = camera.zero_point_s + camera.center; window->setView(sf::View(view_center, view_size)); if (camera.panning) { pan_delta = compute_pan(window, camera.pan_ref); view_center += compute_pan(window, camera.pan_ref); window->setView(sf::View(view_center, view_size)); } wmouse = window->mapPixelToCoords(sf::Mouse::getPosition(*window)); while (window->pollEvent(event)) { // FIXME: refactor this nested switch clusterfuck switch (event.type) { case sf::Event::Closed: window->close(); return; case sf::Event::MouseButtonPressed: switch (event.mouseButton.button) { case sf::Mouse::Button::Left: select.selecting = true; select.rect[0] = wmouse; select.rect[1] = wmouse; break; case sf::Mouse::Button::Right: game->command(wmouse); break; case sf::Mouse::Button::Middle: camera.panning = true; camera.pan_ref = wmouse; break; default:; } break; case sf::Event::MouseButtonReleased: switch (event.mouseButton.button) { case sf::Mouse::Button::Left: if (select.selecting) game->select(select.rect); select.selecting = false; break; case sf::Mouse::Button::Middle: if (camera.panning) camera.center += pan_delta; camera.panning = false; break; default:; } break; case sf::Event::MouseWheelScrolled: camera.zoom -= event.mouseWheelScroll.delta; if (camera.zoom < 0) camera.zoom = 0; if (camera.zoom > 17) camera.zoom = 17; break; case sf::Event::KeyPressed: switch (event.key.code) { case sf::Keyboard::Key::Space: if (!game->paused) { game->pause(); print(text::get(text::PAUSED)); } else { game->resume(); print(text::get(text::UNPAUSED)); } break; case sf::Keyboard::Key::F: if (camera.following) stop_following(); else start_following(); break; case sf::Keyboard::Key::H: game->spawn_soldier(wmouse); break; case sf::Keyboard::Key::F1: debug_draw_cmodels ^= 1; print("debug_draw_cmodels = " + std::to_string(debug_draw_cmodels)); break; case sf::Keyboard::Key::F2: debug_draw_paths ^= 1; print("debug_draw_paths = " + std::to_string(debug_draw_paths)); break; case sf::Keyboard::Key::F3: debug_draw_tile_coords ^= 1; print("debug_draw_tile_coords = " + std::to_string(debug_draw_tile_coords)); break; case sf::Keyboard::Key::F4: debug_AI ^= 1; print("debug_AI = " + std::to_string(debug_AI)); break; default:; } default:; } } if (select.selecting) select.rect[1] = wmouse; } void state_t::print(std::string str) { log.push_back((log_entry_t){game->now, str}); std::cout << str << std::endl; } void state_t::render_to(render::state_t *render) { size_t w = window->getSize().x, h = window->getSize().y; v2f_t x; std::stringstream ss; double fps; if (select.selecting) render->render_hlrect(select.rect, sf::Color(60, 60, 150)); window->setView(sf::View(sf::FloatRect(0, 0, w, h))); em = std::max(w, h) * 0.017; for (auto i = log.begin(); i != log.end(); ) { if (i->time + 3 < game->now) i = log.erase(i); else i++; } x = v2f_t(0.0f, 0.0f); for (log_entry_t &entry : log) { render->render_text(x, em, entry.text, render::ALIGN_LEFT_TOP, sf::Color::White); x[1] += em; } x = v2f_t(0.0f, h - em * 5.5); ss << "World S/T:"; ss << game->world.stats.sectors << "/"; ss << game->world.stats.tiles; render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White); x[1] += em; ss.str(std::string()); ss << "Awake: " << game->awake_entities.size() << "/" << game->world.stats.entities; render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White); x[1] += em; ss.str(std::string()); ss << "View S/T/E: "; ss << render->stats.sectors << "/"; ss << render->stats.tiles << "/"; ss << render->stats.entities; render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White); perf_hist_index = (perf_hist_index + 1) % COUNT(perf_hist); perf_hist[perf_hist_index] = 1.0 / render->dt; fps = 0.0; for (size_t i = 0; i < COUNT(perf_hist); i++) fps += perf_hist[i]; fps /= COUNT(perf_hist); x[1] += em; ss.str(std::string()); ss << std::fixed << std::setprecision(1); ss << "FPS: " << fps; render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White); x[1] += em; ss.str(std::string()); ss << std::fixed << std::setprecision(3); ss << "Game t/F/B/PFT: "; ss << game->time * 1.0e-9 << "/"; ss << game->frames << "/"; ss << game->frames_behind << "/"; ss << game->pathfinder_time * 1.0e-9 << " (" << ((float)game->pathfinder_time / game->time * 100.0f) << "%)"; render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White); } } // namespace interface