src/Graphics.cc
branchnew_graphics
changeset 411 106aaf6eadfe
parent 410 41fd46cffc52
child 412 721c60072091
equal deleted inserted replaced
410:41fd46cffc52 411:106aaf6eadfe
     1 
       
     2 #include "Graphics.hh"
       
     3 #include "GameState.hh"
       
     4 #include <cmath>
       
     5 #include <sstream>
       
     6 
       
     7 /*
       
     8  * XXX: until we figure out a better way to layout stuff
       
     9  */
       
    10 static PixelArea getMessageViewArea (PixelCoordinate resolution) {
       
    11     return PixelArea(
       
    12             400,
       
    13             resolution.y - 100,
       
    14             resolution.x,
       
    15             resolution.y
       
    16     );
       
    17 }
       
    18 
       
    19 Graphics::Graphics (Engine &engine, GameState &state, const GraphicsConfig &config) :
       
    20     CL_DisplayWindow(GRAPHICS_WINDOW_TITLE, config.resolution.x, config.resolution.y, config.fullscreen, true),
       
    21     engine(engine), 
       
    22     state(state), 
       
    23     resolution(config.resolution),
       
    24     fullscreen_resolution(0, 0), window_resolution(0, 0),
       
    25     update_timer(GRAPHICS_UPDATE_INTERVAL_MS),
       
    26     input(get_ic()->get_keyboard()),
       
    27     simple_font("Font2", engine.getResourceManager()),
       
    28     message_view(getMessageViewArea(resolution))
       
    29 {
       
    30 
       
    31     // connect timer signal
       
    32     slots.connect(update_timer.sig_tick(), this, &Graphics::on_update);
       
    33     slots.connect(this->sig_resize(), this, &Graphics::on_window_resize);
       
    34 
       
    35     // enable
       
    36     update_timer.start();
       
    37 
       
    38     // push something to message_view
       
    39     message_view.add_message(CL_Color::white, "Hello World"); 
       
    40 
       
    41     // GameState events....
       
    42     state.setEventHandler(this);
       
    43 
       
    44     // set correct resolution
       
    45     if (config.fullscreen) {
       
    46         fullscreen_resolution = resolution;
       
    47 
       
    48     } else {
       
    49         CL_DisplayMode best_mode = getBestMode();
       
    50 
       
    51         fullscreen_resolution = PixelCoordinate(best_mode.get_resolution().width, best_mode.get_resolution().height);
       
    52         window_resolution = resolution;
       
    53     }
       
    54 
       
    55 }
       
    56 
       
    57 const std::vector<CL_DisplayMode> & Graphics::getDisplayModes (void) {
       
    58     return CL_DisplayMode::get_display_modes();
       
    59 }
       
    60 
       
    61 const CL_DisplayMode Graphics::getBestMode (void) {
       
    62     const std::vector<CL_DisplayMode> &modes = Graphics::getDisplayModes();
       
    63 
       
    64     const CL_DisplayMode *best_mode = NULL;
       
    65     
       
    66     for (std::vector<CL_DisplayMode>::const_iterator it = modes.begin(); it != modes.end(); it++)
       
    67         if (best_mode == NULL || (
       
    68                 it->get_resolution().width * it->get_resolution().height > 
       
    69                 best_mode->get_resolution().width * best_mode->get_resolution().height    
       
    70         ))
       
    71             best_mode = &*it;
       
    72     
       
    73     if (best_mode == NULL)
       
    74         throw Error("No available video modes!");
       
    75     
       
    76     return *best_mode;
       
    77 }
       
    78 
       
    79 void Graphics::check_input (void) {
       
    80     LocalPlayer *player;
       
    81     PlayerInput input_mask;
       
    82     TimeMS input_dt;
       
    83     
       
    84     // update gui flags
       
    85     handle_input(input.readGuiInput());
       
    86 
       
    87     // stop here if we don't have a local player
       
    88     if ((player = state.getLocalPlayer()) == NULL)
       
    89         return;
       
    90     
       
    91     // build input_mask
       
    92     input.readPlayerInput(input_mask, input_dt);
       
    93     
       
    94     // apply input if there was any
       
    95     if (input_mask)
       
    96         player->handleInput(input_mask, input_dt);
       
    97 }
       
    98     
       
    99 void Graphics::toggle_fullscreen (void) {
       
   100     if (is_fullscreen()) {
       
   101         // remember current fullscreen resolution
       
   102         fullscreen_resolution = resolution;
       
   103         
       
   104         // enter windowed mode
       
   105         set_windowed();
       
   106 
       
   107 /*        
       
   108         // do we have a window-mode resolution stored?
       
   109         if (window_resolution.x && window_resolution.y)
       
   110             set_size(window_resolution.x, window_resolution.y);
       
   111 */
       
   112     } else {
       
   113         // remember current window resolution
       
   114         window_resolution = resolution;
       
   115 
       
   116         // enter fullscreen mode
       
   117         set_fullscreen(fullscreen_resolution.x, fullscreen_resolution.y);
       
   118         
       
   119         // update resolution
       
   120         resolution = fullscreen_resolution;
       
   121         
       
   122         // log
       
   123         message_view.add_message(CL_Color::yellow, CL_String::format("[ Enter fullscreen mode with %1 x %2 resolution ]", 
       
   124                 (int) resolution.x, (int) resolution.y));
       
   125     }
       
   126 }
       
   127 
       
   128 void Graphics::handle_input (GuiInput flags) {
       
   129     // update flags
       
   130     this->flags = flags;
       
   131 
       
   132     // quit?
       
   133     if (flags & GUI_INPUT_QUIT) {
       
   134         engine.stop();
       
   135 
       
   136         return;
       
   137     }
       
   138 
       
   139     // dump player debug info on stderr
       
   140     if ((flags & GUI_INPUT_DEBUG_PLAYER) && state.getLocalPlayer()) {
       
   141         state.getLocalPlayer()->printDebugInfo();
       
   142         
       
   143         message_view.add_message(CL_Color::green, "...");
       
   144     }
       
   145     
       
   146     // toggle fullscreen?
       
   147     if (flags & GUI_INPUT_TOGGLE_FULLSCREEN)
       
   148         toggle_fullscreen();
       
   149 }
       
   150 
       
   151 static PixelDimension value_between (PixelDimension low, PixelDimension value, PixelDimension high) {
       
   152     if (high < low)
       
   153         return (high + low) / 2;
       
   154 
       
   155     else if (value < low)
       
   156         return low;
       
   157 
       
   158     else if (value > high)
       
   159         return high;
       
   160 
       
   161     else
       
   162         return value;
       
   163 }
       
   164 
       
   165 void Graphics::do_redraw (void) {
       
   166     CL_GraphicContext *gc = get_gc();
       
   167     LocalPlayer *player;
       
   168 
       
   169     // calculate camera
       
   170     PixelCoordinate camera(0, 0);
       
   171     
       
   172     // ...to track our local player
       
   173     if ((player = state.getLocalPlayer()) != NULL) {
       
   174         // try and center the screen on the player
       
   175         PixelCoordinate target = player->getCoordinate() - PixelCoordinate(resolution.x / 2, (resolution.y - 100) / 2);
       
   176 
       
   177         // ...but keep the world in view
       
   178         PixelCoordinate max = state.terrain.getDimensions() - resolution + PixelCoordinate(0, 100);
       
   179         
       
   180         // ...by limiting the value to 0...max
       
   181         camera = PixelCoordinate(
       
   182             value_between(0, target.x, max.x),
       
   183             value_between(0, target.y, max.y)
       
   184         );
       
   185     }
       
   186     
       
   187     // Black background
       
   188     gc->clear(CL_Color::black);
       
   189 
       
   190     // Draw the game
       
   191     state.draw(this, camera, flags & GUI_INPUT_DISPLAY_WEAPON);
       
   192     
       
   193     // draw player info box
       
   194     if (player != NULL) {
       
   195         draw_player_info(gc, player);
       
   196     }
       
   197     
       
   198     // draw messages
       
   199     message_view.draw(this);
       
   200 
       
   201     // Flip window buffer, sync
       
   202     flip(1);
       
   203 }
       
   204 
       
   205 void Graphics::on_update (TimeMS tick_length) {
       
   206     (void) tick_length;
       
   207 
       
   208     // check keyboard input
       
   209     check_input();
       
   210 
       
   211     // redraw display
       
   212     do_redraw();
       
   213 }
       
   214 
       
   215 void Graphics::draw_player_info(CL_GraphicContext *gc, Player *p) {
       
   216     int box_top = resolution.y - 100;
       
   217     int box_left = 0;
       
   218     int box_right = resolution.x;
       
   219     int box_bottom = resolution.y;
       
   220     int bar_length = 3; // *100
       
   221 
       
   222     // draw status info at bottom of display
       
   223     gc->fill_rect(
       
   224         CL_Rect(
       
   225             box_left,
       
   226             box_top,
       
   227             box_right,
       
   228             box_bottom
       
   229         ),
       
   230         CL_Gradient(
       
   231             CL_Color(0, 0, 0),
       
   232             CL_Color(50, 50, 50),
       
   233             CL_Color(50, 50, 50, 150),
       
   234             CL_Color(100, 100, 100, 200)
       
   235         )
       
   236     );
       
   237     
       
   238     // Health
       
   239     gc->draw_rect(
       
   240         CL_Rect(
       
   241             box_left + 9,
       
   242             box_top + 9,
       
   243             box_left + 11 + 100 * bar_length,
       
   244             box_top + 31
       
   245         ),
       
   246         CL_Color(150, 150, 150)
       
   247     );
       
   248 
       
   249     gc->fill_rect(
       
   250         CL_Rect(
       
   251             box_left + 10,
       
   252             box_top + 10,
       
   253             box_left + 10 + (int) (p->getHealthPercent() * bar_length),
       
   254             box_top + 30
       
   255         ),
       
   256         CL_Gradient(
       
   257             CL_Color(200, 0, 0),
       
   258             CL_Color(200 - (int)(p->getHealthPercent() * 2), (int)(p->getHealthPercent() * 2), 0),
       
   259             CL_Color(200, 0, 0),
       
   260             CL_Color(200 - (int)(p->getHealthPercent() * 2), (int)(p->getHealthPercent() * 2), 0)
       
   261         )
       
   262     );
       
   263 
       
   264     // stats - kills
       
   265     std::stringstream sskills;
       
   266     sskills << "Kills:  " << p->getKills();
       
   267     getSimpleFont().draw(
       
   268         box_left + 20 + 100 * bar_length,
       
   269         box_top + 10,
       
   270         sskills.str(),
       
   271         get_gc()
       
   272     );
       
   273     
       
   274     // stats - deaths
       
   275     std::stringstream ssdeaths;
       
   276     ssdeaths << "Deaths:  " << p->getDeaths();
       
   277     getSimpleFont().draw(
       
   278         box_left + 20 + 100 * bar_length,
       
   279         box_top + 30,
       
   280         ssdeaths.str(),
       
   281         get_gc()
       
   282     );
       
   283     
       
   284     // stats - ratio
       
   285     std::stringstream ssratio;
       
   286     ssratio << "Ratio:  " << (p->getKills()+1) / (p->getDeaths()+1);
       
   287     getSimpleFont().draw(
       
   288         box_left + 20 + 100 * bar_length,
       
   289         box_top + 50,
       
   290         ssratio.str(),
       
   291         get_gc()
       
   292     );
       
   293     
       
   294 
       
   295     // Weapon clip / reloading
       
   296     gc->draw_rect(
       
   297         CL_Rect(
       
   298             box_left + 9,
       
   299             box_top + 69,
       
   300             box_left + 11 + 100 * bar_length,
       
   301             box_top + 91
       
   302         ),
       
   303         CL_Color(150, 150, 150)
       
   304     );
       
   305 
       
   306     gc->fill_rect(
       
   307         CL_Rect(
       
   308             box_left + 10,
       
   309             box_top + 70,
       
   310             box_left + 10 + (100 - (int) (p->getCurrentWeapon()->getReloadTimer() * 100 / p->getCurrentWeapon()->getReloadTime())) * bar_length,
       
   311             box_top + 90
       
   312         ),
       
   313         CL_Gradient(
       
   314             CL_Color(100, 100, 0),
       
   315             CL_Color(100, 100, 0),
       
   316             CL_Color(100, 100, 0),
       
   317             CL_Color(100, 100, 100)
       
   318         )
       
   319     );
       
   320    
       
   321     // current weapon name
       
   322     getSimpleFont().draw(
       
   323         box_left + 20 + 100 * bar_length,
       
   324         box_top + 70,
       
   325         p->getCurrentWeapon()->getName(),
       
   326         get_gc()
       
   327     );
       
   328 
       
   329 }
       
   330 
       
   331 void Graphics::on_window_resize (int new_x, int new_y) {
       
   332     // ignore resize in fullscreen mode
       
   333     if (is_fullscreen())
       
   334         return;
       
   335     
       
   336     // update resolution
       
   337     resolution = PixelCoordinate(new_x, new_y);
       
   338     
       
   339     // resize components
       
   340     message_view.on_resize(getMessageViewArea(resolution));
       
   341     
       
   342     // log message
       
   343     message_view.add_message(CL_Color::yellow, CL_String::format("[ Resized window to %1 x %2 ]", new_x, new_y));
       
   344 }
       
   345     
       
   346 void Graphics::on_player_joined (Player *p) {
       
   347     message_view.add_message(CL_Color::white, " *** Player joined");
       
   348 }
       
   349     
       
   350 void Graphics::on_player_left (Player *p) {
       
   351     message_view.add_message(CL_Color::white, " *** Player left");
       
   352 }