there's a grain of truth in the new graphics code now... new_graphics
authorTero Marttila <terom@fixme.fi>
Wed, 21 Jan 2009 03:33:35 +0200
branchnew_graphics
changeset 411 106aaf6eadfe
parent 410 41fd46cffc52
child 412 721c60072091
there's a grain of truth in the new graphics code now...
src/Application.cc
src/Application.hh
src/CMakeLists.txt
src/Engine.cc
src/Engine.hh
src/GameMessageView.cc
src/GameMessageView.hh
src/Graphics.cc
src/Graphics.hh
src/Graphics/Display.cc
src/Graphics/Display.hh
src/Graphics/Drawable.hh
src/Graphics/FontManager.hh
src/Graphics/GameView.cc
src/Graphics/GameView.hh
src/Graphics/Graphics.cc
src/Graphics/Graphics.hh
src/Graphics/MessageView.cc
src/Graphics/MessageView.hh
src/Graphics/PlayerInfo.cc
src/Graphics/PlayerInfo.hh
src/Graphics/PlayerInfoView.cc
src/Graphics/PlayerInfoView.hh
src/Graphics/View.hh
src/GraphicsPointer.hh
src/Player.hh
src/Terrain.hh
src/Types.hh
--- 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 <ClanLib/gl.h>
 #include <stdexcept>
 #include <sstream>
 #include <cstdio>
@@ -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<CL_DisplayMode> &modes = Graphics::getDisplayModes();
+    const std::vector<CL_DisplayMode> &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) {
--- 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
--- 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")
--- 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 <iostream>
 
 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) {
--- 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
--- 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<GameMessage>::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);
-}
-
--- 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 <string>
-#include <vector>
-#include <ClanLib/display.h>
-
-struct GameMessage {
-    CL_Color color;
-    std::string message;
-
-    GameMessage (CL_Color color, std::string message) : color(color), message(message) { }
-    GameMessage (const GameMessage &copy) : color(copy.color), message(copy.message) { }
-    GameMessage &operator= (const GameMessage &copy) { color = copy.color; message = copy.message; return *this; }
-};
-
-class GameMessageView {
-    protected:
-        PixelArea area;
-        std::vector<GameMessage> 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
--- 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 <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, 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<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.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");
-}
--- 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 <ClanLib/core.h>
-#include <ClanLib/gl.h>
-#include <ClanLib/display.h>
-
-/**
- * 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<CL_DisplayMode> & 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 */
--- 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<CL_DisplayMode> & 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<CL_DisplayMode> & Display::getDisplayModes (void) {
     return CL_DisplayMode::get_display_modes();
 }
 
-const CL_DisplayMode Graphics::getBestMode (void) {
+const CL_DisplayMode Display::getBestMode (void) {
     const std::vector<CL_DisplayMode> &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;
+}
+
+
+}
+
--- 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 <ClanLib/display.h>
-
 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 <ClanLib/display.h>
+
+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
--- 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;
-}
+};
 
 }
 
--- /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 <ClanLib/display.h>
+
+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
--- 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 <cassert>
 
 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()));
+}
+
+
+}
--- 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);
 };
 
 }
--- /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 <cassert>
+
+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;
+    
+}
+
+}
--- /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
--- /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<Message>::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);
+}
+
+}
--- /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 <ClanLib/display.h>
+#include <string>
+#include <vector>
+
+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<Message> 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
--- 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 <sstream>
-
-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()
-    );
-}
-
-
-
-}
--- 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
--- /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 <sstream>
+
+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()
+    );
+}
+
+
+
+}
--- /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
--- 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;
     }
 };
 
--- 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 
--- 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 <vector>
 
 /**
@@ -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);
 };
 
 /**
--- 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;
--- 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)
-    { }
+    { }
 };
 
 /**