try and implement resize in a sane way, but changeing from windowed mode to fullscreen mode is now kind of weird
#include "Graphics.hh"
#include "GameState.hh"
#include <cmath>
#include <sstream>
/*
* XXX: until we figure out a better way to layout stuff
*/
static PixelArea getMessageViewArea (PixelCoordinate resolution) {
return PixelArea(
400,
resolution.y - 100,
resolution.x,
resolution.y
);
}
Graphics::Graphics (Engine &engine, GameState &state, PixelCoordinate resolution, bool fullscreen) :
CL_DisplayWindow(GRAPHICS_WINDOW_TITLE, resolution.x, resolution.y, fullscreen, true),
engine(engine),
state(state),
resolution(resolution),
fullscreen_resolution(0, 0), window_resolution(0, 0),
update_timer(GRAPHICS_UPDATE_INTERVAL_MS),
input(get_ic()->get_keyboard()),
simple_font("Font2", engine.getResourceManager()),
message_view(getMessageViewArea(resolution))
{
// connect timer signal
slots.connect(update_timer.sig_tick(), this, &Graphics::on_update);
slots.connect(this->sig_resize(), this, &Graphics::on_window_resize);
// enable
update_timer.start();
// push something to message_view
message_view.add_message(CL_Color::white, "Hello World");
// GameState events....
state.setEventHandler(this);
// set correct resolution
if (fullscreen) {
fullscreen_resolution = resolution;
} else {
CL_DisplayMode best_mode = getBestMode();
fullscreen_resolution = PixelCoordinate(best_mode.get_resolution().width, best_mode.get_resolution().height);
window_resolution = resolution;
}
}
const std::vector<CL_DisplayMode> & Graphics::getDisplayModes (void) {
return CL_DisplayMode::get_display_modes();
}
const CL_DisplayMode Graphics::getBestMode (void) {
const std::vector<CL_DisplayMode> &modes = Graphics::getDisplayModes();
const CL_DisplayMode *best_mode = NULL;
for (std::vector<CL_DisplayMode>::const_iterator it = modes.begin(); it != modes.end(); it++)
if (best_mode == NULL || (
it->get_resolution().width * it->get_resolution().height >
best_mode->get_resolution().width * best_mode->get_resolution().height
))
best_mode = &*it;
if (best_mode == NULL)
throw Error("No available video modes!");
return *best_mode;
}
void Graphics::check_input (void) {
LocalPlayer *player;
PlayerInput input_mask;
TimeMS input_dt;
// update gui flags
handle_input(input.readGuiInput());
// stop here if we don't have a local player
if ((player = state.getLocalPlayer()) == NULL)
return;
// build input_mask
input.readPlayerInput(input_mask, input_dt);
// apply input if there was any
if (input_mask)
player->handleInput(input_mask, input_dt);
}
void Graphics::toggle_fullscreen (void) {
if (is_fullscreen()) {
// remember current fullscreen resolution
fullscreen_resolution = resolution;
// enter windowed mode
set_windowed();
/*
// do we have a window-mode resolution stored?
if (window_resolution.x && window_resolution.y)
set_size(window_resolution.x, window_resolution.y);
*/
} else {
// remember current window resolution
window_resolution = resolution;
// enter fullscreen mode
set_fullscreen(fullscreen_resolution.x, fullscreen_resolution.y);
// update resolution
resolution = fullscreen_resolution;
// log
message_view.add_message(CL_Color::yellow, CL_String::format("[ Enter fullscreen mode with %1 x %2 resolution ]",
(int) resolution.x, (int) resolution.y));
}
}
void Graphics::handle_input (GuiInput flags) {
// update flags
this->flags = flags;
// quit?
if (flags & GUI_INPUT_QUIT) {
engine.stop();
return;
}
// dump player debug info on stderr
if ((flags & GUI_INPUT_DEBUG_PLAYER) && state.getLocalPlayer()) {
state.getLocalPlayer()->printDebugInfo();
message_view.add_message(CL_Color::green, "...");
}
// toggle fullscreen?
if (flags & GUI_INPUT_TOGGLE_FULLSCREEN)
toggle_fullscreen();
}
static PixelDimension value_between (PixelDimension low, PixelDimension value, PixelDimension high) {
if (high < low)
return (high + low) / 2;
else if (value < low)
return low;
else if (value > high)
return high;
else
return value;
}
void Graphics::do_redraw (void) {
CL_GraphicContext *gc = get_gc();
LocalPlayer *player;
// calculate camera
PixelCoordinate camera(0, 0);
// ...to track our local player
if ((player = state.getLocalPlayer()) != NULL) {
// try and center the screen on the player
PixelCoordinate target = player->getCoordinate() - PixelCoordinate(resolution.x / 2, (resolution.y - 100) / 2);
// ...but keep the world in view
PixelCoordinate max = state.world.getDimensions() - resolution + PixelCoordinate(0, 100);
// ...by limiting the value to 0...max
camera = PixelCoordinate(
value_between(0, target.x, max.x),
value_between(0, target.y, max.y)
);
}
// Black background
gc->clear(CL_Color::black);
// Draw the game
state.draw(this, camera, flags & GUI_INPUT_DISPLAY_WEAPON);
// draw player info box
if (player != NULL) {
draw_player_info(gc, player);
}
// draw messages
message_view.draw(this);
// Flip window buffer, sync
flip(1);
}
void Graphics::on_update (TimeMS tick_length) {
(void) tick_length;
// check keyboard input
check_input();
// redraw display
do_redraw();
}
void Graphics::draw_player_info(CL_GraphicContext *gc, Player *p) {
int box_top = resolution.y - 100;
int box_left = 0;
int box_right = resolution.x;
int box_bottom = resolution.y;
int bar_length = 3; // *100
// draw status info at bottom of display
gc->fill_rect(
CL_Rect(
box_left,
box_top,
box_right,
box_bottom
),
CL_Gradient(
CL_Color(0, 0, 0),
CL_Color(50, 50, 50),
CL_Color(50, 50, 50, 150),
CL_Color(100, 100, 100, 200)
)
);
// Health
gc->draw_rect(
CL_Rect(
box_left + 9,
box_top + 9,
box_left + 11 + 100 * bar_length,
box_top + 31
),
CL_Color(150, 150, 150)
);
gc->fill_rect(
CL_Rect(
box_left + 10,
box_top + 10,
box_left + 10 + (int) (p->getHealthPercent() * bar_length),
box_top + 30
),
CL_Gradient(
CL_Color(200, 0, 0),
CL_Color(200 - (int)(p->getHealthPercent() * 2), (int)(p->getHealthPercent() * 2), 0),
CL_Color(200, 0, 0),
CL_Color(200 - (int)(p->getHealthPercent() * 2), (int)(p->getHealthPercent() * 2), 0)
)
);
// stats - kills
std::stringstream sskills;
sskills << "Kills: " << p->getKills();
getSimpleFont().draw(
box_left + 20 + 100 * bar_length,
box_top + 10,
sskills.str(),
get_gc()
);
// stats - deaths
std::stringstream ssdeaths;
ssdeaths << "Deaths: " << p->getDeaths();
getSimpleFont().draw(
box_left + 20 + 100 * bar_length,
box_top + 30,
ssdeaths.str(),
get_gc()
);
// stats - ratio
std::stringstream ssratio;
ssratio << "Ratio: " << (p->getKills()+1) / (p->getDeaths()+1);
getSimpleFont().draw(
box_left + 20 + 100 * bar_length,
box_top + 50,
ssratio.str(),
get_gc()
);
// Weapon clip / reloading
gc->draw_rect(
CL_Rect(
box_left + 9,
box_top + 69,
box_left + 11 + 100 * bar_length,
box_top + 91
),
CL_Color(150, 150, 150)
);
gc->fill_rect(
CL_Rect(
box_left + 10,
box_top + 70,
box_left + 10 + (100 - (int) (p->getCurrentWeapon()->getReloadTimer() * 100 / p->getCurrentWeapon()->getReloadTime())) * bar_length,
box_top + 90
),
CL_Gradient(
CL_Color(100, 100, 0),
CL_Color(100, 100, 0),
CL_Color(100, 100, 0),
CL_Color(100, 100, 100)
)
);
// current weapon name
getSimpleFont().draw(
box_left + 20 + 100 * bar_length,
box_top + 70,
p->getCurrentWeapon()->getName(),
get_gc()
);
}
void Graphics::on_window_resize (int new_x, int new_y) {
// ignore resize in fullscreen mode
if (is_fullscreen())
return;
// update resolution
resolution = PixelCoordinate(new_x, new_y);
// resize components
message_view.on_resize(getMessageViewArea(resolution));
// log message
message_view.add_message(CL_Color::yellow, CL_String::format("[ Resized window to %1 x %2 ]", new_x, new_y));
}
void Graphics::on_player_joined (Player *p) {
message_view.add_message(CL_Color::white, " *** Player joined");
}
void Graphics::on_player_left (Player *p) {
message_view.add_message(CL_Color::white, " *** Player left");
}