# HG changeset patch # User Tero Marttila # Date 1232501615 -7200 # Node ID 106aaf6eadfe3f773bb3e0b924d2722fa5942f9b # Parent 41fd46cffc52bd69d8bbab94c7e042c74a101c93 there's a grain of truth in the new graphics code now... diff -r 41fd46cffc52 -r 106aaf6eadfe src/Application.cc --- a/src/Application.cc Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Application.cc Wed Jan 21 03:33:35 2009 +0200 @@ -1,6 +1,7 @@ #include "Application.hh" +#include #include #include #include @@ -104,20 +105,20 @@ break; case ARG_FULLSCREEN: - graphics.fullscreen = true; + display.fullscreen = true; // choose best resolution unless explicitly set if (resolution_default) { - const CL_DisplayMode best_mode = Graphics::getBestMode(); + const CL_DisplayMode best_mode = graphics::Display::getBestMode(); const CL_Size best_resolution = best_mode.get_resolution(); - graphics.resolution = PixelCoordinate(best_resolution.width, best_resolution.height); + display.resolution = PixelDimensions(best_resolution.width, best_resolution.height); } break; case ARG_RESOLUTION: - graphics.resolution = parse_arg_dimensions(args.get_argument(), "--resolution"); + display.resolution = parse_arg_dimensions(args.get_argument(), "--resolution"); resolution_default = false; break; @@ -170,18 +171,18 @@ return int_val; } -PixelCoordinate Main::parse_arg_dimensions (const std::string &arg_val, const char *arg_name) { +PixelDimensions Main::parse_arg_dimensions (const std::string &arg_val, const char *arg_name) { unsigned int w, h; // sccanf as unsigned if (sscanf(arg_val.c_str(), "%ux%u", &w, &h) != 2) throw ArgumentError(std::string() + "invalid format for " + arg_name + ": " + arg_val); - return PixelCoordinate(w, h); + return PixelDimensions(w, h); } void Main::dump_display_modes (void) { - const std::vector &modes = Graphics::getDisplayModes(); + const std::vector &modes = graphics::Display::getDisplayModes(); std::cout << "Available display modes:" << std::endl; @@ -217,7 +218,7 @@ // setup graphics if (graphics_enabled) - engine.setupGraphics(graphics); + engine.setupGraphics(display); // setup either network server, client or singleplayer if (net_server) { diff -r 41fd46cffc52 -r 106aaf6eadfe src/Application.hh --- a/src/Application.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Application.hh Wed Jan 21 03:33:35 2009 +0200 @@ -28,7 +28,7 @@ /** * --fullscreen and --resolution */ - GraphicsConfig graphics; + graphics::DisplayConfig display; /** * --terrain-seed and --terrain-size @@ -66,7 +66,7 @@ /** * Parse unsigned WIDTHxHEIGHT argument */ - PixelCoordinate parse_arg_dimensions (const std::string &arg_val, const char *arg_name); + PixelDimensions parse_arg_dimensions (const std::string &arg_val, const char *arg_name); /** * Print out a list of display modes diff -r 41fd46cffc52 -r 106aaf6eadfe src/CMakeLists.txt --- a/src/CMakeLists.txt Wed Jan 21 01:57:24 2009 +0200 +++ b/src/CMakeLists.txt Wed Jan 21 03:33:35 2009 +0200 @@ -1,5 +1,5 @@ -FILE(GLOB SOURCE_FILES "*.cc" "Network/*.cc") -FILE(GLOB HEADER_FILES "*.hh" "Network/*.hh") +FILE(GLOB SOURCE_FILES "*.cc" "Network/*.cc" "Graphics/*.cc") +FILE(GLOB HEADER_FILES "*.hh" "Network/*.hh" "Graphics/*.hh") set_source_files_properties("version.c" PROPERTIES GENERATED true) set(SOURCES ${SOURCE_FILES} ${HEADER_FILES} "version.c") diff -r 41fd46cffc52 -r 106aaf6eadfe src/Engine.cc --- a/src/Engine.cc Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Engine.cc Wed Jan 21 03:33:35 2009 +0200 @@ -7,7 +7,7 @@ #include Engine::Engine (const std::string resource_xml_path) : - terrain(NULL), game_state(NULL), graphics_config(NULL), graphics(NULL), net_server(NULL), net_client_connect(NULL), + terrain(NULL), game_state(NULL), graphics(NULL), net_server(NULL), net_client_connect(NULL), is_running(true), resources(resource_xml_path) { @@ -22,11 +22,13 @@ // create the GameState game_state = new GameState(*terrain); - - // start graphics? - if (graphics_config) - startGraphics(); - + + // put graphics into GameView mode + // XXX: this state is a mess, this is done in three places in weird ways + // this depends on graphics not yet being set in client mode, but not in singleplayer mode + if (graphics) + graphics->displayGameView(*game_state, game_state->getLocalPlayer()); + return *game_state; } @@ -35,21 +37,9 @@ setupGame(new Terrain(config)); } -void Engine::setupGraphics (const GraphicsConfig &config) { - // store config - graphics_config = &config; - - // start already? - if (game_state) - startGraphics(); -} - -void Engine::startGraphics (void) { - // check state - assert(game_state && graphics_config); - +void Engine::setupGraphics (const graphics::DisplayConfig &config) { // create the graphics - graphics = new Graphics(*this, *game_state, *graphics_config); + graphics = new graphics::Graphics(*this, resources, config); } void Engine::setupNetworkServer (const std::string &listen_port) { @@ -59,6 +49,11 @@ // create the server net_server = new NetworkServer(*game_state, listen_addr); + + // put graphics into GameView mode + if (graphics) + graphics->displayGameView(*game_state, NULL); + } void Engine::setupNetworkClient (const std::string &connect_host, const std::string &connect_port) { @@ -77,6 +72,11 @@ // add to gamestate game_state->setLocalPlayer(lp); + + // put graphics into GameView mode + if (graphics) + graphics->displayGameView(*game_state, game_state->getLocalPlayer()); + } void Engine::stop (void) { diff -r 41fd46cffc52 -r 106aaf6eadfe src/Engine.hh --- a/src/Engine.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Engine.hh Wed Jan 21 03:33:35 2009 +0200 @@ -5,7 +5,7 @@ class Engine; #include "GameState.hh" -#include "Graphics.hh" +#include "Graphics/Graphics.hh" #include "Network/Server.hh" #include "Network/Client.hh" @@ -20,11 +20,8 @@ Terrain *terrain; GameState *game_state; - /** Set if setupGraphics has been called */ - const GraphicsConfig *graphics_config; - // Graphics/Input - Graphics *graphics; + graphics::Graphics *graphics; // network server/client NetworkServer *net_server; @@ -56,7 +53,7 @@ /** * Enable graphics */ - void setupGraphics (const GraphicsConfig &config); + void setupGraphics (const graphics::DisplayConfig &config); /** * Setup server, must call setupGame first diff -r 41fd46cffc52 -r 106aaf6eadfe src/GameMessageView.cc --- a/src/GameMessageView.cc Wed Jan 21 01:57:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ - -#include "GameMessageView.hh" -#include "Graphics.hh" -#include "Engine.hh" - -GameMessageView::GameMessageView (PixelArea area) : - area(area), messages() -{ - -} - -void GameMessageView::add_message (CL_Color color, std::string message) { - GameMessage msg (color, message); - - messages.push_back(msg); -} - -void GameMessageView::draw (Graphics *g) { - // get font - CL_Font &font = g->getSimpleFont(); - - // remember color - CL_Color font_color = font.get_color(); - - // maximum width - CL_Size max_size = CL_Size(area.right - area.left, 0); - - // starting point for drawing - PixelDimension offset_prev = area.bottom; - - // render messages, bottom up - for (std::vector::reverse_iterator it = messages.rbegin(); it != messages.rend(); it++) { - // set message color - font.set_color(it->color); - - // calculate height - PixelDimension height = font.get_height(it->message, max_size) + GRAPHICS_INFO_TEXT_LINE_OFFSET; - - // new draw_point - PixelDimension offset_this = offset_prev - height; - - // break if it doesn't fit anymore - if (offset_this < area.top) - break; - - // draw text - font.draw(CL_Rect(area.left, offset_this, area.right, offset_prev), it->message, g->get_gc()); - - // advance offset - offset_prev = offset_this; - } - - // restore font color - font.set_color(font_color); -} - diff -r 41fd46cffc52 -r 106aaf6eadfe src/GameMessageView.hh --- a/src/GameMessageView.hh Wed Jan 21 01:57:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -#ifndef GRAPHICS_INFO_TEXT_HH -#define GRAPHICS_INFO_TEXT_HH - -#include "GraphicsPointer.hh" -#include "Types.hh" - -#include -#include -#include - -struct GameMessage { - CL_Color color; - std::string message; - - GameMessage (CL_Color color, std::string message) : color(color), message(message) { } - GameMessage (const GameMessage ©) : color(copy.color), message(copy.message) { } - GameMessage &operator= (const GameMessage ©) { color = copy.color; message = copy.message; return *this; } -}; - -class GameMessageView { - protected: - PixelArea area; - std::vector messages; - - public: - /** - * Define the area where messages are drawn - */ - GameMessageView (PixelArea area); - - /** - * Update draw area - */ - void on_resize (PixelArea new_area) { this->area = new_area; } - - /** - * Add a message to the list of messages displayed - */ - void add_message (CL_Color color, std::string message); - - /** - * Draw as many messages as fits - */ - void draw (Graphics *g); -}; - -#endif diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics.cc --- a/src/Graphics.cc Wed Jan 21 01:57:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,352 +0,0 @@ - -#include "Graphics.hh" -#include "GameState.hh" -#include -#include - -/* - * 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, const GraphicsConfig &config) : - CL_DisplayWindow(GRAPHICS_WINDOW_TITLE, config.resolution.x, config.resolution.y, config.fullscreen, true), - engine(engine), - state(state), - resolution(config.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 (config.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 & Graphics::getDisplayModes (void) { - return CL_DisplayMode::get_display_modes(); -} - -const CL_DisplayMode Graphics::getBestMode (void) { - const std::vector &modes = Graphics::getDisplayModes(); - - const CL_DisplayMode *best_mode = NULL; - - for (std::vector::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.terrain.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"); -} diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics.hh --- a/src/Graphics.hh Wed Jan 21 01:57:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -#ifndef GRAPHICS_HH -#define GRAPHICS_HH - -#include "GraphicsPointer.hh" -#include "Types.hh" -#include "Config.hh" - -/** - * Parameters used by Graphics - */ -struct GraphicsConfig { - /** Initial resolution to use */ - PixelCoordinate resolution; - - /* Use fullscreen mode at startup */ - bool fullscreen; - - /** Defaults */ - GraphicsConfig (void) : resolution(GRAPHICS_RESOLUTION_WIDTH, GRAPHICS_RESOLUTION_HEIGHT), fullscreen(GRAPHICS_FULLSCREEN) { } -}; - -#include "GameState.hh" -#include "Input.hh" -#include "Timer.hh" -#include "Engine.hh" - -#include "GameMessageView.hh" - -#include -#include -#include - -/** - * This handles drawing the GameState with an appropriate camera view each frame, loading fonts, and currently, - * handling the input from Input to GameState. - */ -class Graphics : public GameStateEventHandler, public CL_DisplayWindow { -private: - /** - * Our engine reference - */ - Engine &engine; - - /** - * GameState we are associated with - */ - GameState &state; - - /** - * Current window resolution - */ - PixelCoordinate resolution; - - /** - * Target resolution in fullscreen/windowed mode - */ - PixelCoordinate fullscreen_resolution, window_resolution; - - /** - * ClanLib signal slots - */ - CL_SlotContainer slots; - - /** - * Our timer that drives redraws - */ - Timer update_timer; - - /** - * Our input handler for GUI and Player input - */ - Input input; - - /** - * Current GUI input state - */ - GuiInput flags; - - /** - * A basic font - */ - CL_Font simple_font; - - /** - * View components - */ - GameMessageView message_view; - -public: - /** - * - */ - Graphics (Engine &engine, GameState &state, const GraphicsConfig &config); - - /** - * Returns a CL_Font that can be used for drawing text - */ - CL_Font& getSimpleFont (void) { return simple_font; } - - /** - * Returns a vector of CL_DisplayModes that lists possible display modes to use for fullscreen mode. - */ - static const std::vector & getDisplayModes (void); - - /** - * Returns the "best" CL_DisplayMode to use for fullscreen mode. - * - * Currently, this just means the largest resolution. - */ - static const CL_DisplayMode getBestMode (void); - -private: - /** - * Shift back and forth between fullscreen and windowed mode, retaining resolutions - */ - void toggle_fullscreen (void); - - /** - * Reads current input events from Input and applies them, using LocalPlayer::handleInput and - * Graphics::handle_input. - */ - void check_input (void); - - /** - * Handles GuiInput flags read from Input. - */ - void handle_input (GuiInput flags); - - /** - * Redraws entire screen - */ - void do_redraw (void); - - /** - * Handles input and redraws screen - */ - void on_update (TimeMS tick_length); - - /** - * Draws status view - */ - void draw_player_info (CL_GraphicContext *gc, Player *p); - - /** - * Handles window resize. This just updates resolution - */ - void on_window_resize (int new_x, int new_y); - -protected: - /* GameStateEventHandler */ - virtual void on_player_joined (Player *p); - virtual void on_player_left (Player *p); -}; - -#endif /* GRAPHICS_HH */ diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/Display.cc --- a/src/Graphics/Display.cc Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Graphics/Display.cc Wed Jan 21 03:33:35 2009 +0200 @@ -4,11 +4,33 @@ namespace graphics { -const std::vector & Graphics::getDisplayModes (void) { +Display::Display (const DisplayConfig &config) : + CL_DisplayWindow(GRAPHICS_WINDOW_TITLE, config.resolution.width, config.resolution.height, config.fullscreen, true), + config(config), + fullscreen_resolution(0, 0), + update_timer(GRAPHICS_UPDATE_INTERVAL_MS), + target(NULL) +{ + // connect timer signal + slots.connect(update_timer.sig_tick(), this, &Display::on_update); + slots.connect(this->sig_resize(), this, &Display::on_window_resize); + + // set correct fullscreen resolution + if (config.fullscreen) { + fullscreen_resolution = config.resolution; + + } else { + CL_DisplayMode best_mode = getBestMode(); + + fullscreen_resolution = PixelCoordinate(best_mode.get_resolution().width, best_mode.get_resolution().height); + } +} + +const std::vector & Display::getDisplayModes (void) { return CL_DisplayMode::get_display_modes(); } -const CL_DisplayMode Graphics::getBestMode (void) { +const CL_DisplayMode Display::getBestMode (void) { const std::vector &modes = Graphics::getDisplayModes(); const CL_DisplayMode *best_mode = NULL; @@ -26,5 +48,36 @@ return *best_mode; } +void Display::toggle_fullscreen (void) { + if (is_fullscreen()) { + // enter windowed mode + set_windowed(); + + } else { + // enter fullscreen mode + set_fullscreen(fullscreen_resolution.width, fullscreen_resolution.height); + } } +void Display::on_update (TimeMS dt) { + (void) dt; + + // do we have something to draw? + if (target) { + // draw it + target->draw(this); + + // flip buffers, sync + flip(1); + } +} + +void Display::on_window_resize (int new_x, int new_y) { + // ignore resize in fullscreen mode + if (is_fullscreen()) + return; +} + + +} + diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/Display.hh --- a/src/Graphics/Display.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Graphics/Display.hh Wed Jan 21 03:33:35 2009 +0200 @@ -1,12 +1,6 @@ #ifndef GRAPHICS_DISPLAY_HH #define GRAPHICS_DISPLAY_HH -#include "../Types.hh" -#include "../Config.hh" -#include "../Timer.hh" - -#include - namespace graphics { @@ -16,42 +10,57 @@ /** Fullscreen mode? */ bool fullscreen; + + /** Defaults */ + DisplayConfig (void) : resolution(GRAPHICS_RESOLUTION_WIDTH, GRAPHICS_RESOLUTION_HEIGHT), fullscreen(GRAPHICS_FULLSCREEN) { } }; +class Display; + +} + +#include "Drawable.hh" +#include "../Types.hh" +#include "../Config.hh" +#include "../Timer.hh" + +#include + +namespace graphics +{ + /** * We wrap ClanLib's DisplayWindow for our own functionality. This is the core of the graphics code */ class Display : public CL_DisplayWindow { private: /** - * Our engine reference - */ - Engine &engine; - - /** * Our configuration */ DisplayConfig config; + + /** + * Target fullscreen resolution + */ + PixelDimensions fullscreen_resolution; /** * Our timer that drives redraws */ Timer update_timer; + /** + * What we draw + */ + Drawable *target; + CL_SlotContainer slots; public: /** * Construct default display, empty window unless otherwise build */ - Display (Engine &engine, const DisplayConfig &config) : - engine(engine), config(config), update_timer(GRAPHICS_UPDATE_INTERVAL_MS) - { - // connect timer signal - slots.connect(update_timer.sig_tick(), this, &Display::on_update); - slots.connect(this->sig_resize(), this, &Display::on_window_resize); - - } + Display (const DisplayConfig &config); /** * Returns a vector of CL_DisplayModes that lists possible display modes to use for fullscreen mode. @@ -74,6 +83,18 @@ return PixelCoordinate(get_width(), get_height()); } + /** + * Set draw target + */ + void setTarget (Drawable *target) { + this->target = target; + } + + /** + * Shift back and forth between fullscreen and windowed mode, retaining resolutions + */ + void toggle_fullscreen (void); + private: /** * Draw next frame diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/Drawable.hh --- a/src/Graphics/Drawable.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Graphics/Drawable.hh Wed Jan 21 03:33:35 2009 +0200 @@ -1,6 +1,13 @@ #ifndef GRAPHICS_DRAWABLE_HH #define GRAPHICS_DRAWABLE_HH +namespace graphics +{ + +class Drawable; + +} + #include "Display.hh" namespace graphics @@ -15,7 +22,7 @@ * Draw graphics onto the given display */ virtual void draw (Display *display) = 0; -} +}; } diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/FontManager.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Graphics/FontManager.hh Wed Jan 21 03:33:35 2009 +0200 @@ -0,0 +1,43 @@ +#ifndef GRAPHICS_FONT_MANAGER_HH +#define GRAPHICS_FONT_MANAGER_HH + +#include + +namespace graphics +{ + +/** + * Loads fonts and lets other components use them + */ +class FontManager { +private: + /** + * Our resource manager for loading these + */ + CL_ResourceManager &resources; + + /** + * A basic monospace font + */ + CL_Font simple_font; + +public: + /** + * Load fonts + */ + FontManager (CL_ResourceManager &resources) : + resources(resources), simple_font("Font2", &resources) + { + + } + + /** + * Returns a CL_Font that can be used for drawing text + */ + CL_Font& getSimpleFont (void) { return simple_font; } +}; + + +} + +#endif diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/GameView.cc --- a/src/Graphics/GameView.cc Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Graphics/GameView.cc Wed Jan 21 03:33:35 2009 +0200 @@ -1,9 +1,34 @@ #include "GameView.hh" +#include "Graphics.hh" + +#include namespace graphics { +GameView::GameView (GameState &state, LocalPlayer *player) : + View(PixelArea(0, 0, graphics->display.get_width, graphics->display.get_height)), + state(state), player(NULL), info_view(NULL), message_view(getMessageViewArea()) +{ + // have player? + if (player) + setPlayer(player); + + // insert message + message_view.add_message("Hello World!"); +} + +void GameView::setPlayer (LocalPlayer *player) { + assert(!this->player && player); + + // remember it + this->player = player; + + // build the info_view as well + info_view = new PlayerInfoView(getInfoViewArea(), player); +} + void GameView::draw (Display *display) { CL_GraphicContext *gc = display->get_gc(); @@ -35,14 +60,26 @@ // 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 info view? + if (info_view) + info_view->draw(display); + // draw messages message_view.draw(this); } +void GameView::resize (const PixelArea &new_area) { + View::resize(new_area); + + // resize subcomponents + if (info_view) + info_view->resize(getInfoViewArea()); + + message_view.resize(getMessageViewArea()); -}; + // log message + message_view.add_message(CL_Color::yellow, CL_String::format("[ Resized window to %1 x %2 ]", getWidth(), getHeight())); +} + + +} diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/GameView.hh --- a/src/Graphics/GameView.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Graphics/GameView.hh Wed Jan 21 03:33:35 2009 +0200 @@ -2,6 +2,8 @@ #define GRAPHICS_GAME_VIEW_HH #include "Drawable.hh" +#include "PlayerInfoView.hh" +#include "MessageView.hh" #include "../GameState.hh" namespace graphics @@ -10,7 +12,7 @@ /** * This is the main in-game view, which is what the player sees when they are playing */ -class GameView : public Drawable { +class GameView : public View { protected: /** The GameState that we're drawing */ GameState &state; @@ -18,30 +20,53 @@ /** The player that we are controlling, if any */ LocalPlayer *player; + /** + * The PlayerInfo view is built once we have a player + */ + PlayerInfoView *info_view; + + /** + * The message list view + */ + MessageView message_view; + public: /** * Constructed once the game is running */ - GameView (GameState &state, LocalPlayer *player) : - state(state), player(player) - { - - } + GameView (GameState &state, LocalPlayer *player); /** * Set a player where none was set before */ - void setPlayer (LocalPlayer *player) { - assert(!this->player); - - // remember it - this->player = player; + void setPlayer (LocalPlayer *player); + +private: + /** + * Calculate new area for the info_view based on our own area + */ + PixelArea getInfoViewArea (void) { + return PixelArea(0, area.bottom - 100, area.right, area.bottom); } + + /** + * Calculate new area for the message view + */ + PixelArea getMessageViewArea (void) { + return PixelArea(400, area.bottom - 100, area.right, area.bottom); + } + +public: /** * Draw this view onto the given display */ - void draw (Display *display); + virtual void draw (Display *display); + + /** + * Resize sub-views + */ + virtual void resize (const PixelArea &new_area); }; } diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/Graphics.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Graphics/Graphics.cc Wed Jan 21 03:33:35 2009 +0200 @@ -0,0 +1,22 @@ + +#include "Graphics.hh" + +#include + +namespace graphics +{ + +// initialize the global graphics object +static Graphics *graphics = NULL; + +Graphics::Graphics (Engine &engine, CL_ResourceManager &resources, const DisplayConfig &display_config) : + engine(engine), fonts(resources), display(display_config) +{ + assert(!graphics); + + // set the global graphics object + graphics = this; + +} + +} diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/Graphics.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Graphics/Graphics.hh Wed Jan 21 03:33:35 2009 +0200 @@ -0,0 +1,57 @@ +#ifndef GRAPHICS_GRAPHICS_HH +#define GRAPHICS_GRAPHICS_HH + +#include "../Engine.hh" +#include "Display.hh" +#include "FontManager.hh" +#include "GameView.hh" + +namespace graphics +{ + +/** + * Core class that ties everything else together + */ +class Graphics { +public: + /** + * Our reference to the engine + */ + Engine &engine; + + /** + * For loading fonts + */ + FontManager fonts; + + /** + * Our primary display + */ + Display display; + + /** + * Initialize the graphics subsystem + */ + Graphics (Engine &engine, CL_ResourceManager &resources, const DisplayConfig &display_config); + + /** + * Display a new GameView + */ + void displayGameView (GameState &state, LocalPlayer *player) { + // allocate a new GameView + GameView *view = new GameView(state, player); + + // assign it to the display + display.setTarget(view); + } + +}; + +/** + * The global Graphics instance + */ +extern Graphics *graphics; + +} + +#endif diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/MessageView.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Graphics/MessageView.cc Wed Jan 21 03:33:35 2009 +0200 @@ -0,0 +1,59 @@ + +#include "Graphics.hh" +#include "MessageView.hh" + +namespace graphics +{ + +MessageView::MessageView (const PixelArea &area) : + View(area), messages() +{ + +} + +void MessageView::add_message (CL_Color color, std::string message) { + Message msg (color, message); + + messages.push_back(msg); +} + +void MessageView::draw (Display *display) { + // get font + CL_Font &font = graphics->fonts.getSimpleFont(); + + // remember color + CL_Color font_color = font.get_color(); + + // maximum width + CL_Size max_size = CL_Size(area.right - area.left, 0); + + // starting point for drawing + PixelDimension offset_prev = area.bottom; + + // render messages, bottom up + for (std::vector::reverse_iterator it = messages.rbegin(); it != messages.rend(); it++) { + // set message color + font.set_color(it->color); + + // calculate height + PixelDimension height = font.get_height(it->message, max_size) + MESSAGE_VIEW_LINE_OFFSET; + + // new draw_point + PixelDimension offset_this = offset_prev - height; + + // break if it doesn't fit anymore + if (offset_this < area.top) + break; + + // draw text + font.draw(CL_Rect(area.left, offset_this, area.right, offset_prev), it->message, g->get_gc()); + + // advance offset + offset_prev = offset_this; + } + + // restore font color + font.set_color(font_color); +} + +} diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/MessageView.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Graphics/MessageView.hh Wed Jan 21 03:33:35 2009 +0200 @@ -0,0 +1,48 @@ +#ifndef GRAPHICS_MESSAGE_VIEW_HH +#define GRAPHICS_MESSAGE_VIEW_HH + +#include "View.hh" + +#include +#include +#include + +namespace graphics +{ + +/** + * Offset between consecutive lines + */ +const PixelDimension MESSAGE_VIEW_LINE_OFFSET = 5; + +struct Message { + CL_Color color; + std::string message; + + Message (CL_Color color, std::string message) : color(color), message(message) { } +}; + +class MessageView : public View { +protected: + std::vector messages; + +public: + /** + * Define the area where messages are drawn + */ + MessageView (const PixelArea &area); + + /** + * Add a message to the list of messages displayed + */ + void add_message (CL_Color color, std::string message); + + /** + * Draw as many messages as fits + */ + virtual void draw (Display *display); +}; + +} + +#endif diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/PlayerInfo.cc --- a/src/Graphics/PlayerInfo.cc Wed Jan 21 01:57:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ - -#include "PlayerInfo.hh" - -#include - -namespace graphics -{ - -void PlayerInfo::draw (Display *display) { - CL_GraphicContext *gc = display->get_gc(); - - // draw status info at bottom of display - gc->fill_rect( - CL_Rect(area.left, area.top, area.right, area.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( - area.left + 9, - area.top + 9, - area.left + 11 + 100 * bar_length, - area.top + 31 - ), - CL_Color(150, 150, 150) - ); - - gc->fill_rect( - CL_Rect( - area.left + 10, - area.top + 10, - area.left + 10 + (int) (p->getHealthPercent() * bar_length), - area.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( - area.left + 20 + 100 * bar_length, - area.top + 10, - sskills.str(), - get_gc() - ); - - // stats - deaths - std::stringstream ssdeaths; - ssdeaths << "Deaths: " << p->getDeaths(); - getSimpleFont().draw( - area.left + 20 + 100 * bar_length, - area.top + 30, - ssdeaths.str(), - get_gc() - ); - - // stats - ratio - std::stringstream ssratio; - ssratio << "Ratio: " << (p->getKills()+1) / (p->getDeaths()+1); - getSimpleFont().draw( - area.left + 20 + 100 * bar_length, - area.top + 50, - ssratio.str(), - get_gc() - ); - - - // Weapon clip / reloading - gc->draw_rect( - CL_Rect( - area.left + 9, - area.top + 69, - area.left + 11 + 100 * bar_length, - area.top + 91 - ), - CL_Color(150, 150, 150) - ); - - gc->fill_rect( - CL_Rect( - area.left + 10, - area.top + 70, - area.left + 10 + (100 - (int) (p->getCurrentWeapon()->getReloadTimer() * 100 / p->getCurrentWeapon()->getReloadTime())) * bar_length, - area.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( - area.left + 20 + 100 * bar_length, - area.top + 70, - p->getCurrentWeapon()->getName(), - get_gc() - ); -} - - - -} diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/PlayerInfo.hh --- a/src/Graphics/PlayerInfo.hh Wed Jan 21 01:57:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -#ifndef GRAPHICS_PLAYER_INFO_HH -#define GRAPHICS_PLAYER_INFO_HH - -#include "View.hh" -#include "../Player.hh" - -namespace graphics -{ - -class PlayerInfo : public View { -private: - /** - * The player whose info we are drawing - * - * XXX: should this be LocalPlayer or is Player good? - */ - Player *player; - -public: - /** - * Set initial view area and player - */ - PlayerInfo (const PixelArea &area, Player *player) : - View(area), player(player) - { - - } - - /** - * Draw the player info onto the given display - */ - virtual void draw (Display *display); -} - -} - -#endif diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/PlayerInfoView.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Graphics/PlayerInfoView.cc Wed Jan 21 03:33:35 2009 +0200 @@ -0,0 +1,117 @@ + +#include "PlayerInfoView.hh" + +#include + +namespace graphics +{ + +void PlayerInfoView::draw (Display *display) { + CL_GraphicContext *gc = display->get_gc(); + + // draw status info at bottom of display + gc->fill_rect( + CL_Rect(area.left, area.top, area.right, area.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( + area.left + 9, + area.top + 9, + area.left + 11 + 100 * bar_length, + area.top + 31 + ), + CL_Color(150, 150, 150) + ); + + gc->fill_rect( + CL_Rect( + area.left + 10, + area.top + 10, + area.left + 10 + (int) (p->getHealthPercent() * bar_length), + area.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( + area.left + 20 + 100 * bar_length, + area.top + 10, + sskills.str(), + get_gc() + ); + + // stats - deaths + std::stringstream ssdeaths; + ssdeaths << "Deaths: " << p->getDeaths(); + getSimpleFont().draw( + area.left + 20 + 100 * bar_length, + area.top + 30, + ssdeaths.str(), + get_gc() + ); + + // stats - ratio + std::stringstream ssratio; + ssratio << "Ratio: " << (p->getKills()+1) / (p->getDeaths()+1); + getSimpleFont().draw( + area.left + 20 + 100 * bar_length, + area.top + 50, + ssratio.str(), + get_gc() + ); + + + // Weapon clip / reloading + gc->draw_rect( + CL_Rect( + area.left + 9, + area.top + 69, + area.left + 11 + 100 * bar_length, + area.top + 91 + ), + CL_Color(150, 150, 150) + ); + + gc->fill_rect( + CL_Rect( + area.left + 10, + area.top + 70, + area.left + 10 + (100 - (int) (p->getCurrentWeapon()->getReloadTimer() * 100 / p->getCurrentWeapon()->getReloadTime())) * bar_length, + area.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( + area.left + 20 + 100 * bar_length, + area.top + 70, + p->getCurrentWeapon()->getName(), + get_gc() + ); +} + + + +} diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/PlayerInfoView.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Graphics/PlayerInfoView.hh Wed Jan 21 03:33:35 2009 +0200 @@ -0,0 +1,37 @@ +#ifndef GRAPHICS_PLAYER_INFO_VIEW_HH +#define GRAPHICS_PLAYER_INFO_VIEW_HH + +#include "View.hh" +#include "../Player.hh" + +namespace graphics +{ + +class PlayerInfoView : public View { +private: + /** + * The player whose info we are drawing + * + * XXX: should this be LocalPlayer or is Player good? + */ + Player *player; + +public: + /** + * Set initial view area and player + */ + PlayerInfoView (const PixelArea &area, Player *player) : + View(area), player(player) + { + + } + + /** + * Draw the player info onto the given display + */ + virtual void draw (Display *display); +}; + +} + +#endif diff -r 41fd46cffc52 -r 106aaf6eadfe src/Graphics/View.hh --- a/src/Graphics/View.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Graphics/View.hh Wed Jan 21 03:33:35 2009 +0200 @@ -29,8 +29,22 @@ /** * Update the view area */ - void updateArea (const PixelArea &area) { - this->area = area; + virtual void resize (const PixelArea &new_area) { + this->area = new_area; + } + + /** + * Get current width + */ + PixelDimension getWidth (void) const { + return area.right - area.left; + } + + /** + * Get current height + */ + PixelDimension getHeight (void) const { + return area.bottom - area.top; } }; diff -r 41fd46cffc52 -r 106aaf6eadfe src/GraphicsPointer.hh --- a/src/GraphicsPointer.hh Wed Jan 21 01:57:24 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#ifndef GRAPHICS_POINTER_HH -#define GRAPHICS_POINTER_HH - -/* - * Break our #include-loop dependancy - */ -class Graphics; - -#endif diff -r 41fd46cffc52 -r 106aaf6eadfe src/Player.hh --- a/src/Player.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Player.hh Wed Jan 21 03:33:35 2009 +0200 @@ -11,8 +11,9 @@ #include "PhysicsObject.hh" #include "Input.hh" #include "Rope.hh" -#include "GraphicsPointer.hh" #include "Types.hh" +#include "Graphics/Drawable.hh" + #include /** @@ -155,7 +156,11 @@ */ static bool skin_loaded; static CL_Surface skin_surface; - virtual void draw (Graphics *g, PixelCoordinate camera); + + /** + * Draw this player + */ + virtual void draw (Display *display, PixelCoordinate camera); uint16_t getKills() { return kills; } uint16_t getDeaths() { return deaths; } @@ -190,7 +195,7 @@ /** * As Player, but also draws the current weapon name if displayWeapon */ - virtual void draw (Graphics *g, bool displayWeapon, PixelCoordinate camera); + virtual void draw (Display *display, bool displayWeapon, PixelCoordinate camera); }; /** diff -r 41fd46cffc52 -r 106aaf6eadfe src/Terrain.hh --- a/src/Terrain.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Terrain.hh Wed Jan 21 03:33:35 2009 +0200 @@ -30,7 +30,7 @@ */ struct TerrainConfig { /** Size of the terrain field*/ - PixelCoordinate dimensions; + PixelDimensions dimensions; /** Set to nonzero to generate random map */ int random_seed; diff -r 41fd46cffc52 -r 106aaf6eadfe src/Types.hh --- a/src/Types.hh Wed Jan 21 01:57:24 2009 +0200 +++ b/src/Types.hh Wed Jan 21 03:33:35 2009 +0200 @@ -39,7 +39,7 @@ /** Simple constructor */ PixelDimensions (PixelDimension width, PixelDimension height) : width(width), height(height) - { } + { } }; /**