/*
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: " << game->time * 1.0e-9 << "/" << game->frames << "/" << game->frames_behind;
render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White);
}
} // namespace interface