gui.cpp

Go to the documentation of this file.
00001 
00002 //            Copyright (C) 2004-2007 by The Allacrost Project
00003 //                         All Rights Reserved
00004 //
00005 // This code is licensed under the GNU GPL version 2. It is free software
00006 // and you may modify it and/or redistribute it under the terms of this license.
00007 // See http://www.gnu.org/copyleft/gpl.html for details.
00009 
00010 #include "utils.h"
00011 #include "gui.h"
00012 #include "video.h"
00013 
00014 using namespace std;
00015 using namespace hoa_utils;
00016 
00017 template<> hoa_video::private_video::GUISupervisor* Singleton<hoa_video::private_video::GUISupervisor>::_singleton_reference = NULL;
00018 
00019 namespace hoa_video {
00020 
00021 namespace private_video {
00022 
00023 GUISupervisor* GUIManager = NULL;
00024 
00025 // *****************************************************************************
00026 // ******************************* GUIElement **********************************
00027 // *****************************************************************************
00028 
00029 GUIElement::GUIElement() :
00030   _xalign(VIDEO_X_LEFT),
00031   _yalign(VIDEO_Y_TOP),
00032   _x_position(0.0f),
00033   _y_position(0.0f),
00034   _initialized(false)
00035 {}
00036 
00037 
00038 
00039 void GUIElement::SetAlignment(int32 xalign, int32 yalign) {
00040   if (_xalign != VIDEO_X_LEFT && _xalign != VIDEO_X_CENTER && _xalign != VIDEO_X_RIGHT) {
00041     if (VIDEO_DEBUG)
00042       cerr << "VIDEO ERROR: Invalid xalign value (" << xalign << ") passed to GUIElement::SetAlignment()" << endl;
00043     return;
00044   }
00045 
00046   if (_yalign != VIDEO_Y_TOP && _yalign != VIDEO_Y_CENTER && _yalign != VIDEO_Y_BOTTOM) {
00047     if (VIDEO_DEBUG)
00048       cerr << "VIDEO ERROR: Invalid yalign value (" << yalign << ") passed to GUIElement::SetAlignment()" << endl;
00049     return;
00050   }
00051 
00052   _xalign = xalign;
00053   _yalign = yalign;
00054 }
00055 
00056 
00057 
00058 void GUIElement::CalculateAlignedRect(float &left, float &right, float &bottom, float &top) {
00059   float width  = right - left;
00060   float height = top - bottom;
00061 
00062   if (width < 0.0f)
00063     width = -width;
00064 
00065   if (height < 0.0f)
00066     height = -height;
00067 
00068   if (VideoManager->_coord_sys.GetVerticalDirection() < 0.0f)
00069     top = -top;
00070 
00071   if (VideoManager->_coord_sys.GetHorizontalDirection() < 0.0f)
00072     right = -right;
00073 
00074   float x_off, y_off;
00075 
00076   x_off = _x_position + ((VideoManager->_x_align + 1) * width)  * 0.5f * -VideoManager->_coord_sys.GetHorizontalDirection();
00077   y_off = _y_position + ((VideoManager->_y_align + 1) * height) * 0.5f * -VideoManager->_coord_sys.GetVerticalDirection();
00078 
00079   left   += x_off;
00080   right  += x_off;
00081 
00082   top    += y_off;
00083   bottom += y_off;
00084 } // void GUIElement::CalculateAlignedRect(float &left, float &right, float &bottom, float &top)
00085 
00086 // *****************************************************************************
00087 // ******************************* GUIControl **********************************
00088 // *****************************************************************************
00089 
00090 void GUIControl::CalculateAlignedRect(float &left, float &right, float &bottom, float &top) {
00091   GUIElement::CalculateAlignedRect(left, right, bottom, top);
00092 
00093   // calculate the position offsets due to the owner window
00094   if (_owner) {
00095     // first, calculate the owner menu's rectangle
00096     float menu_left, menu_right, menu_bottom, menu_top;
00097     float menu_height, menu_width;
00098 
00099     _owner->GetDimensions(menu_width, menu_height);
00100     menu_left = 0.0f;
00101     menu_right = menu_width;
00102     menu_bottom = 0.0f;
00103     menu_top = menu_height;
00104     VideoManager->PushState();
00105 
00106     int32 xalign, yalign;
00107     _owner->GetAlignment(xalign, yalign);
00108 
00109     VideoManager->SetDrawFlags(xalign, yalign, 0);
00110     _owner->CalculateAlignedRect(menu_left, menu_right, menu_bottom, menu_top);
00111     VideoManager->PopState();
00112 
00113     // now, depending on the alignment of the control, add an offset
00114     if (menu_left < menu_right) {
00115       left += menu_left;
00116       right += menu_left;
00117     }
00118     else {
00119       left += menu_right;
00120       right += menu_right;
00121     }
00122 
00123     if (menu_top < menu_bottom) {
00124       top += menu_top;
00125       bottom += menu_top;
00126     }
00127     else {
00128       top += menu_bottom;
00129       bottom += menu_bottom;
00130     }
00131   } // if (_owner)
00132 }
00133 
00134 // *****************************************************************************
00135 // ****************************** GUISupervisor ********************************
00136 // *****************************************************************************
00137 
00138 GUISupervisor::GUISupervisor() {
00139   _fps_sum = 0;
00140   _current_sample = 0;
00141   _number_samples = 0;
00142 
00143   for (uint32 sample = 0; sample < FPS_SAMPLES; sample++)
00144      _fps_samples[sample] = 0;
00145 }
00146 
00147 
00148 
00149 GUISupervisor::~GUISupervisor() {
00150   // Determine if any MenuWindows have not yet been deleted, and delete them if they exist
00151   if (_menu_windows.empty() == false) {
00152     if (VIDEO_DEBUG)
00153       cerr << "VIDEO WARNING: When GUISupervison destructor was invoked, there were still undestroyed MenuWindows" << endl;
00154     std::map<uint32, MenuWindow*> window_copies = _menu_windows;
00155     for (std::map<uint32, MenuWindow*>::iterator i = window_copies.begin(); i != window_copies.end(); i++) {
00156       i->second->Destroy();
00157     }
00158     window_copies.clear();
00159   }
00160 
00161   // Delete all menu skins which are still active
00162   for (map<string, MenuSkin>::iterator i = _menu_skins.begin(); i != _menu_skins.end(); i++) {
00163     // Delete all border images and connectors
00164     for (uint32 x = 0; x < 3; x++) {
00165       for (uint32 y = 0; y < 3; y++) {
00166         VideoManager->DeleteImage(i->second.borders[x][y]);
00167       }
00168     }
00169 
00170     for (uint32 x = 0; x < 5; x++) {
00171       VideoManager->DeleteImage(i->second.connectors[x]);
00172     }
00173     
00174     // Delete background image only if one has been loaded
00175     if (i->second.background.GetWidth() != 0) {
00176       VideoManager->DeleteImage(i->second.background);
00177     }
00178   }
00179 
00180   _menu_skins.clear();
00181 }
00182 
00183 
00184 bool GUISupervisor::SingletonInitialize() {
00185   return true;
00186 }
00187 
00188 
00189 
00190 bool GUISupervisor::LoadMenuSkin(string skin_name, string border_image, string background_image,
00191   Color top_left, Color top_right, Color bottom_left, Color bottom_right, bool make_default)
00192 {
00193   // ----- (1) Check that the skin_name is not already used by another skin
00194   if (_menu_skins.find(skin_name) != _menu_skins.end()) {
00195     cerr << "VIDEO ERROR: In GUI::LoadMenuSkin(), the skin name " << skin_name << " is already used by another skin" << endl;
00196     return false;
00197   }
00198 
00199   _menu_skins.insert(make_pair(skin_name, MenuSkin()));
00200   MenuSkin& new_skin = _menu_skins[skin_name];
00201 
00202   // ----- (2) Load the MultiImage containing the borders of the skin.
00203   std::vector<StillImage> skin_borders;
00204   if (VideoManager->LoadMultiImageFromNumberElements(skin_borders, border_image, 3, 6) == false) {
00205     _menu_skins.erase(skin_name);
00206     return false;
00207   }
00208 
00209   // Copy the borders over to the new MenuSkin and delete the unused images
00210   new_skin.borders[0][0] = skin_borders[0];
00211   new_skin.borders[0][1] = skin_borders[1];
00212   new_skin.borders[0][2] = skin_borders[2];
00213   new_skin.borders[1][0] = skin_borders[6];
00214   new_skin.borders[1][2] = skin_borders[8];
00215   new_skin.borders[2][0] = skin_borders[12];
00216   new_skin.borders[2][1] = skin_borders[13];
00217   new_skin.borders[2][2] = skin_borders[14];
00218 
00219   new_skin.connectors[0] = skin_borders[4];
00220   new_skin.connectors[1] = skin_borders[16];
00221   new_skin.connectors[2] = skin_borders[9];
00222   new_skin.connectors[3] = skin_borders[11];
00223   new_skin.connectors[4] = skin_borders[10];
00224 
00225   // Set the four background colors for the vertices of the middle image
00226   new_skin.borders[1][1].SetVertexColors(top_left, top_right, bottom_left, bottom_right);
00227 
00228   VideoManager->DeleteImage(skin_borders[3]);
00229   VideoManager->DeleteImage(skin_borders[5]);
00230   VideoManager->DeleteImage(skin_borders[7]);
00231   VideoManager->DeleteImage(skin_borders[15]);
00232   VideoManager->DeleteImage(skin_borders[17]);
00233 
00234   // ----- (3) Load the background image, if one has been specified
00235   if (background_image != "") {
00236     new_skin.background.SetFilename(background_image);
00237     if (VideoManager->LoadImage(new_skin.background) == false) {
00238       cerr << "VIDEO ERROR: In GUI::LoadMenuSkin(), the background image file could not be loaded" << endl;
00239       _menu_skins.erase(skin_name);
00240       return false;
00241     }
00242   }
00243 
00244   // ----- (4) Determine if this new skin should be made the default skin 
00245   if (make_default == true || _menu_skins.size() == 1) {
00246     _default_skin = &new_skin;
00247   }
00248 
00249   return true;
00250 } // bool GUISupervisor::LoadMenuSkin(string skin_name, string border_image, string background_image, ...)
00251 
00252 
00253 
00254 void GUISupervisor::SetDefaultMenuSkin(std::string& skin_name) {
00255   if (_menu_skins.find(skin_name) == _menu_skins.end()) {
00256     if (VIDEO_DEBUG)
00257       cerr << "VIDEO WARNING: In GUI::SetDefaultMenuSkin(), the skin name " << skin_name << " was not registered" << endl;
00258     return;
00259   }
00260 
00261   _default_skin = &_menu_skins[skin_name];
00262 }
00263 
00264 
00265 
00266 void GUISupervisor::DeleteMenuSkin(std::string& skin_name) {
00267   if (_menu_skins.find(skin_name) == _menu_skins.end()) {
00268     if (VIDEO_DEBUG)
00269       cerr << "VIDEO WARNING: In GUI::DeleteMenuSkin(), the skin name " << skin_name << " was not registered" << endl;
00270     return;
00271   }
00272 
00273   MenuSkin* dead_skin = &_menu_skins[skin_name];
00274 
00275   map<uint32, MenuWindow*>::iterator i = _menu_windows.begin();
00276   while (i != _menu_windows.end()) {
00277     if (dead_skin == i->second->_skin) {
00278       if (VIDEO_DEBUG)
00279         cerr << "VIDEO ERROR: In GUI::DeleteMenuSkin(), the MenuSkin \"" << skin_name <<
00280           "\" was not deleted because a MenuWindow object was found to be using it" << endl;
00281       return;
00282     }
00283     ++i;
00284   }
00285 
00286   _menu_skins.erase(skin_name);
00287 }
00288 
00289 
00290 
00291 void GUISupervisor::AddMenuWindow(MenuWindow* new_window) {
00292   if (_menu_windows.find(new_window->_id) != _menu_windows.end()) {
00293     if (VIDEO_DEBUG)
00294       cerr << "VIDEO WARNING: GUISupervisor::AddMenuWindow() failed because there already existed a window with the same ID" << endl;
00295     return;
00296   }
00297   _menu_windows.insert(std::make_pair(new_window->_id, new_window));
00298 }
00299 
00300 
00301 
00302 void GUISupervisor::RemoveMenuWindow(MenuWindow* old_window) {
00303   map<uint32, MenuWindow*>::iterator i = _menu_windows.find(old_window->_id);
00304 
00305   if (i != _menu_windows.end()) {
00306     _menu_windows.erase(i);
00307   }
00308   else {
00309     if (VIDEO_DEBUG)
00310       cerr << "VIDEO WARNING: GUISupervisor::RemoveMenuWindow() did not find a corresponding entry in the menu windows map" << endl;
00311   }
00312 }
00313 
00314 
00315 
00316 void GUISupervisor::DrawFPS(uint32 frame_time) {
00317   VideoManager->SetTextColor(Color::white);
00318   VideoManager->SetDrawFlags(VIDEO_X_LEFT, VIDEO_Y_BOTTOM, VIDEO_X_NOFLIP, VIDEO_Y_NOFLIP, VIDEO_BLEND, 0);
00319 
00320   // Calculate the FPS for the current frame
00321   uint32 current_fps = 1000;
00322   if (frame_time) {
00323     current_fps /= frame_time;
00324   }
00325 
00326   // The number of times to insert the current FPS sample into the fps_samples array
00327   uint32 number_insertions;
00328 
00329   if (_number_samples == 0) {
00330     // If the FPS display is uninitialized, set the entire FPS array to the current FPS
00331     _number_samples = FPS_SAMPLES;
00332     number_insertions = FPS_SAMPLES;
00333   }
00334   else if (current_fps >= 500) {
00335      // If the game is going at 500 fps or faster, 1 insertion is enough
00336     number_insertions = 1;
00337   }
00338   else {
00339     // Find if there's a discrepancy between the current frame time and the averaged one.
00340     // If there's a large difference, add extra samples so the FPS display "catches up" more quickly.
00341     float avg_frame_time = 1000.0f * FPS_SAMPLES / _fps_sum;
00342     int32 time_difference = static_cast<int32>(avg_frame_time) - static_cast<int32>(frame_time);
00343 
00344     if (time_difference < 0)
00345       time_difference = -time_difference;
00346 
00347     if (time_difference <= static_cast<int32>(MAX_FTIME_DIFF))
00348       number_insertions = 1;
00349     else
00350       number_insertions = FPS_CATCHUP; // Take more samples to catch up to the current FPS
00351   }
00352 
00353   // Insert the current_fps samples into the fps_samples array for the number of times specified
00354   for (uint32 j = 0; j < number_insertions; j++) {
00355     _fps_sum -= _fps_samples[_current_sample];
00356     _fps_sum += current_fps;
00357     _fps_samples[_current_sample] = current_fps;
00358     _current_sample = (_current_sample + 1) % FPS_SAMPLES;
00359   }
00360 
00361   uint32 avg_fps = _fps_sum / FPS_SAMPLES;
00362 
00363   // The text to display to the screen
00364   char fps_text[16];
00365   sprintf(fps_text, "FPS: %d", avg_fps);
00366 
00367   if (!VideoManager->SetFont("debug_font")) {
00368     if (VIDEO_DEBUG)
00369       cerr << "VIDEO WARNING: In GUISupervisor::DrawFPS(), the font \"debug_font\" could not be set and the FPS was not drawn" << endl;
00370     return;
00371   }
00372 
00373   VideoManager->Move(930.0f, 720.0f); // Upper right hand corner of the screen
00374   VideoManager->DrawText(fps_text);
00375 } // void GUISupervisor::DrawFPS(uint32 frame_time)
00376 
00377 } // namespace private_video
00378 
00379 } // namespace hoa_video

Generated on Fri Jul 6 23:11:15 2007 for Hero of Allacrost by  doxygen 1.5.1