MainDialog.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2003
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <stdlib.h>
00022 #include <wx/wx.h>
00023 #include <wx/image.h>
00024 #include <wx/process.h>
00025 #include <wx/txtstrm.h>
00026 #include <wx/msgdlg.h>
00027 #include <wx/dcbuffer.h>
00028 #include <wx/splash.h>
00029 #define WIN32_LEAN_AND_MEAN
00030 #include <windows.h>
00031 #include <SDL/SDL.h>
00032 #include <wxdialogs/MainDialog.h>
00033 #include <wxdialogs/DisplayDialog.h>
00034 #include <wxdialogs/ServerSDialog.h>
00035 #include <wxdialogs/TrueTypeFont.h>
00036 #include <scorched/ScorchedParams.h>
00037 #include <graph/OptionsDisplay.h>
00038 #include <common/Defines.h>
00039 
00040 extern char scorched3dAppName[128];
00041 static wxFrame *mainDialog = 0;
00042 bool wxWindowExit = false;
00043 
00044 enum
00045 {
00046         ID_MAIN_TIMER
00047 };
00048 
00049 wxString convertString(const std::string &input)
00050 {
00051         wxString result(input.c_str(), wxConvUTF8);
00052         return result;
00053 }
00054 
00055 void addTitleToWindow(
00056         wxWindow *parent,
00057         wxSizer *sizer,
00058         const char *fileName,
00059         int buttonId)
00060 {
00061         wxBitmap scorchedBitmap;
00062         if (scorchedBitmap.LoadFile(wxString(fileName, wxConvUTF8), 
00063                 wxBITMAP_TYPE_BMP) &&
00064                 scorchedBitmap.Ok())
00065         {
00066                 wxBitmapButton *button = new wxBitmapButton(
00067                         parent, buttonId, scorchedBitmap);
00068                 wxBoxSizer *boxSizer = new wxBoxSizer(wxHORIZONTAL);
00069                 boxSizer->Add(button, 0, wxALL, 5);
00070                 sizer->Add(boxSizer, 0, wxALIGN_CENTER | wxALL, 5);
00071         }
00072 }
00073 
00074 static SDL_mutex *messageMutex_ = 0;
00075 static std::string messageString_;
00076 static int exitCode_ = 0;
00077 
00078 class ScorchedProcess : public wxProcess
00079 {
00080 public:
00081         ScorchedProcess(bool server) : 
00082                 wxProcess(!server?wxPROCESS_REDIRECT:0),
00083                 server_(server)
00084         { 
00085                 if (server_) serverProcessesRunning_++;
00086                 else clientProcessesRunning_++;
00087         }
00088         
00089         virtual void OnTerminate(int pid, int status) 
00090         {
00091                 if (server_) serverProcessesRunning_--;
00092                 else clientProcessesRunning_--;
00093 
00094                 if (status != 0)
00095                 {
00096                         SDL_LockMutex(messageMutex_);
00097                         if (server_) exitCode_ = 64; // So it doesn't say to load failsafe
00098                         else exitCode_ = status;
00099 
00100                         if (status != 64)
00101                         {
00102                                 messageString_ = "The Scorched3d process "
00103                                         "terminated unexpectedly.\n";
00104                         }
00105                         else
00106                         {
00107                                 messageString_ = "The Scorched3d process "
00108                                         "terminated due to configuration errors.\n";
00109                         }
00110                         while (IsInputAvailable())
00111                         {
00112                                 wxTextInputStream tis(*GetInputStream());
00113                                 wxString line = tis.ReadLine();
00114                                 messageString_.append((const char *) line.mb_str(wxConvUTF8));
00115                                 messageString_.append("\n");
00116                         }
00117                         SDL_UnlockMutex(messageMutex_);
00118                 }
00119                 Detach();
00120                 wxProcess::OnTerminate(pid, status);
00121         }
00122 
00123         static unsigned int getClientProcessesRunning()
00124         {
00125                 return clientProcessesRunning_;
00126         }
00127 
00128         static unsigned int getServerProcessesRunning()
00129         {
00130                 return serverProcessesRunning_;
00131         }
00132 
00133 protected:
00134         bool server_;
00135         static unsigned int clientProcessesRunning_;
00136         static unsigned int serverProcessesRunning_;
00137 };
00138 
00139 unsigned int ScorchedProcess::clientProcessesRunning_(0);
00140 unsigned int ScorchedProcess::serverProcessesRunning_(0);
00141 
00142 void runScorched3D(const char *text, bool server)
00143 {
00144         if (!server &&
00145                 ScorchedProcess::getClientProcessesRunning() > 0)
00146         {
00147                 if (::wxMessageBox(
00148                         wxT("You are already running the game, do you wish to run another copy?"),
00149                         wxT("Scorched3D"),
00150                         wxCANCEL | wxOK | wxICON_EXCLAMATION) == wxCANCEL)
00151                 {
00152                         return;
00153                 }
00154         }
00155 
00156         std::string exeName = S3D::getExeName();
00157         const char *exePart = strstr(exeName.c_str(), ".exe");
00158         if (exePart) ((char *)exePart)[0] = '\0';
00159         exePart = strstr(exeName.c_str(), ".EXE");
00160         if (exePart) ((char *)exePart)[0] = '\0';
00161 
00162         char path[1024];
00163         snprintf(path, 1024, "\"%s%s%s\" %s -settingsdir %s %s", 
00164                 exeName.c_str(), 
00165                 (server?"s":"c"),
00166                 (exePart?".exe":""),
00167                 (ScorchedParams::instance()->getAllowExceptions()?" -allowexceptions":""),
00168                 ScorchedParams::instance()->getSettingsDir(), 
00169                 text);
00170 
00171         ScorchedProcess *process = new ScorchedProcess(server);
00172         long result = ::wxExecute(wxString(path, wxConvUTF8), wxEXEC_ASYNC, process);
00173         if (result == 0)
00174         {
00175                 delete process;
00176                 S3D::dialogMessage(scorched3dAppName, S3D::formatStringBuffer(
00177                         "Error: Failed to execute scorched3d using commandline :-\n"
00178                         "%s",
00179                         path));
00180         }
00181 }
00182 
00183 wxButton *addButtonToWindow(
00184         int id,
00185         const char *text,
00186         const char *bitmapName,
00187         wxWindow *parent,
00188         wxSizer *sizer,
00189         wxObjectRefData *data)
00190 {
00191         wxButton *button = 0;
00192         wxBitmap bitmap;
00193         if (bitmap.LoadFile(wxString(bitmapName, wxConvUTF8), wxBITMAP_TYPE_BMP) &&
00194                 bitmap.Ok())
00195         {
00196                 button = new wxBitmapButton(parent, id, bitmap);
00197         }
00198         else
00199         {
00200                 button = new wxButton(parent, id, wxT("Select"));
00201         }
00202         if (data) button->SetRefData(data);
00203 
00204         wxStaticText *staticText = new wxStaticText(
00205                 parent, -1, 
00206                 wxString(text, wxConvUTF8));
00207 
00208         sizer->Add(button, 0, wxRIGHT, 5);
00209         sizer->Add(staticText, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5);
00210 
00211         return button;
00212 }
00213 
00214 class MainFrame: public wxFrame
00215 {
00216 public:
00217         MainFrame();
00218 
00219         void onTimer(wxTimerEvent &event);
00220         void onPaint(wxPaintEvent& event);
00221         void onMotion(wxMouseEvent &event);     
00222         void onEraseBackground(wxEraseEvent &event);
00223 
00224         void onDisplayButton();
00225         void onQuitButton();
00226         void onSingleButton();
00227         void onServerButton();
00228         void onDonateClick();
00229         void onHelpButton();
00230 
00231 private:
00232         DECLARE_EVENT_TABLE()
00233 
00234         struct ImageData
00235         {
00236                 int x, y;
00237                 wxImage loadedImage;
00238                 wxImage descriptionImage;
00239                 wxBitmap cachedBitmap1;
00240                 wxBitmap cachedBitmap2;
00241                 wxBitmap cachedDescription;
00242         };
00243 
00244         wxTimer timer_;
00245         wxBitmap backdropBitmap_;
00246         wxImage backdropImage_;
00247         std::list<ImageData *> images_;
00248         long mouseX_, mouseY_;
00249         int lastPos_;
00250 
00251         void generateCachedImage(int x, int y, 
00252                 wxImage &src, wxBitmap &destBitamp, 
00253                 bool highlight = false);
00254 };
00255 
00256 BEGIN_EVENT_TABLE(MainFrame, wxFrame)
00257         EVT_TIMER(ID_MAIN_TIMER, MainFrame::onTimer)
00258         EVT_PAINT(MainFrame::onPaint) 
00259         EVT_MOUSE_EVENTS(MainFrame::onMotion)
00260         EVT_ERASE_BACKGROUND(MainFrame::onEraseBackground)
00261 END_EVENT_TABLE()
00262 
00263 MainFrame::MainFrame() :
00264         wxFrame((wxFrame *)NULL, -1, wxString(scorched3dAppName, wxConvUTF8), 
00265                 wxDefaultPosition, wxDefaultSize,
00266                 wxMINIMIZE_BOX | wxCAPTION | wxSYSTEM_MENU),
00267         mouseX_(0), mouseY_(0), lastPos_(-1)
00268 {
00269         if (!messageMutex_) messageMutex_ = SDL_CreateMutex();
00270 
00271         // Set the frame's icon
00272         wxIcon icon(convertString(S3D::getDataFile("data/windows/tank2.ico")), wxBITMAP_TYPE_ICO);
00273         SetIcon(icon);
00274 
00275 #if wxCHECK_VERSION(2, 6, 0)
00276         SetBackgroundStyle(wxBG_STYLE_CUSTOM);
00277 #endif
00278 
00279         // Load the backdrop bitmaps
00280         if (!backdropImage_.LoadFile(
00281                 convertString(S3D::getDataFile("data/windows/backdrop.gif")), 
00282                 wxBITMAP_TYPE_GIF))
00283         {
00284                 S3D::dialogMessage("Scorched", "Failed to load backdrop");
00285         }
00286         backdropBitmap_ = wxBitmap(backdropImage_, -1);
00287 
00288         // Load all of the button bitmaps
00289         struct ImageDefinition
00290         {
00291                 const char *name;
00292                 const char *description;
00293                 int x, y;
00294         } imageDefinitions[] = {
00295                 "Play", "- Play a game.", 30, 150,
00296                 "Start Server", "- Start a LAN or internet server.", 30, 180,
00297                 "Settings", "- Change the display, sound or other settings.", 30, 210,
00298                 "Help", "- View the online help.", 30, 260,
00299                 "Donate", "- Show support for Scorched3D.", 30, 290,
00300                 "Quit", "- Exit the game.", 30, 340
00301         };
00302 
00303         TrueTypeFont largeImageFont(S3D::getDataFile("data/fonts/dejavusans.ttf"), 14);
00304         TrueTypeFont smallImageFont(S3D::getDataFile("data/fonts/dejavusans.ttf"), 12);
00305 
00306         for (int i=0; i<sizeof(imageDefinitions) / sizeof(ImageDefinition); i++)
00307         {
00308                 ImageData *image = new ImageData();
00309                 image->x = imageDefinitions[i].x;
00310                 image->y = imageDefinitions[i].y;
00311 
00312                 if (!largeImageFont.getImageForText(imageDefinitions[i].name, image->loadedImage) ||
00313                         !smallImageFont.getImageForText(imageDefinitions[i].description, image->descriptionImage))
00314                 {
00315                         S3D::dialogMessage("Scorched", 
00316                                 S3D::formatStringBuffer("Failed to load button %s", imageDefinitions[i].name));
00317                 }
00318                 else
00319                 {
00320                         images_.push_back(image);
00321                 }
00322         }
00323 
00324         // Setup timer
00325         timer_.SetOwner(this, ID_MAIN_TIMER);
00326         timer_.Start(1000, false);
00327 
00328         // use the sizer for layout
00329         // Create the positioning sizer
00330         wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
00331         topsizer->SetMinSize(533, 400);
00332         SetSizer(topsizer); 
00333         topsizer->SetSizeHints(this); // set size hints to honour minimum size
00334 
00335         CentreOnScreen();
00336 }
00337 
00338 void MainFrame::onMotion(wxMouseEvent &event)
00339 {
00340         mouseX_ = event.m_x;
00341         mouseY_ = event.m_y;
00342 
00343         int foundPos = -1;
00344         int pos = 0;
00345         std::list<ImageData *>::iterator itor;
00346         for (itor = images_.begin();
00347                 itor != images_.end();
00348                 itor++, pos++)
00349         {
00350                 ImageData *imageData = (*itor);
00351                 if (mouseX_ > imageData->x &&
00352                         mouseY_ > imageData->y &&
00353                         mouseX_ < imageData->x + imageData->cachedBitmap1.GetWidth() &&
00354                         mouseY_ < imageData->y + imageData->cachedBitmap1.GetHeight())
00355                 {
00356                         foundPos = pos;
00357                 }
00358         }
00359 
00360         if (event.ButtonDown() &&
00361                 foundPos != -1)
00362         {
00363                 switch (foundPos)
00364                 {
00365                 case 0:
00366                         onSingleButton();
00367                         break;
00368                 case 1:
00369                         onServerButton();
00370                         break;
00371                 case 2:
00372                         onDisplayButton();
00373                         break;
00374                 case 3:
00375                         onHelpButton();
00376                         break;
00377                 case 4:
00378                         onDonateClick();
00379                         break;
00380                 case 5:
00381                         onQuitButton();
00382                         break;
00383                 }
00384         }
00385 
00386         if (lastPos_ != foundPos)
00387         {
00388                 lastPos_ = foundPos;
00389                 Refresh();
00390         }
00391 }
00392 
00393 void MainFrame::generateCachedImage(int x, int y, 
00394         wxImage &src, wxBitmap &destBitamp,
00395         bool highlight)
00396 {
00397         wxImage dest(
00398                 src.GetWidth(),
00399                 src.GetHeight());
00400 
00401         unsigned char *backdropdata = backdropImage_.GetData();
00402         backdropdata += 
00403                 3 * x +
00404                 3 * y * backdropImage_.GetWidth();
00405         
00406         unsigned char *srcdata = src.GetData();
00407         unsigned char *destdata = dest.GetData();
00408         for (int y=0; y<src.GetHeight(); y++)
00409         {
00410                 unsigned char *backdropstart = backdropdata;
00411                 for (int x=0; x<src.GetWidth(); x++)
00412                 {
00413                         float alpha = srcdata[0] + srcdata[1] + srcdata[2];
00414                         alpha /= 255.0f + 255.0f + 255.0f;
00415 
00416                         float mult = (highlight?1.5f:1.0f);
00417                         float src0 = float(srcdata[0]) * mult; if (src0 > 255.0f) src0 = 255.0f;
00418                         float src1 = float(srcdata[1]) * mult; if (src1 > 255.0f) src1 = 255.0f;
00419                         float src2 = float(srcdata[2]) * mult; if (src2 > 255.0f) src2 = 255.0f;
00420                         destdata[0] = (unsigned char) ((1.0f - alpha) * float(backdropdata[0]) + alpha * float(src0));
00421                         destdata[1] = (unsigned char) ((1.0f - alpha) * float(backdropdata[1]) + alpha * float(src1));
00422                         destdata[2] = (unsigned char) ((1.0f - alpha) * float(backdropdata[2]) + alpha * float(src2));
00423 
00424                         srcdata += 3;
00425                         destdata += 3;
00426                         backdropdata += 3;
00427                 }
00428                 backdropdata = backdropstart + 3 * backdropImage_.GetWidth();
00429                 
00430         }
00431 
00432         destBitamp = wxBitmap(dest, -1);
00433 }
00434 
00435 void MainFrame::onPaint(wxPaintEvent& event)
00436 {
00437         wxBufferedPaintDC dc(this);
00438 
00439         dc.DrawBitmap(backdropBitmap_, 0, 0, false);
00440 
00441         // So its easy to display an alpha blended bitmap in wxWindows then!!!
00442         std::list<ImageData *>::iterator itor;
00443         for (itor = images_.begin();
00444                 itor != images_.end();
00445                 itor++)
00446         {
00447                 ImageData *imageData = (*itor);
00448 
00449                 if (!imageData->cachedBitmap1.Ok())
00450                 {
00451                         generateCachedImage(imageData->x, imageData->y, 
00452                                 imageData->loadedImage, imageData->cachedBitmap1, false);
00453                         generateCachedImage(imageData->x, imageData->y, 
00454                                 imageData->loadedImage, imageData->cachedBitmap2, true);
00455                         generateCachedImage(imageData->x + 135, imageData->y + 2, 
00456                                 imageData->descriptionImage, imageData->cachedDescription, true);
00457                 }
00458 
00459                 if (mouseX_ > imageData->x &&
00460                         mouseY_ > imageData->y &&
00461                         mouseX_ < imageData->x + imageData->cachedBitmap1.GetWidth() &&
00462                         mouseY_ < imageData->y + imageData->cachedBitmap1.GetHeight())
00463                 {
00464                         dc.DrawBitmap(imageData->cachedBitmap2, imageData->x, imageData->y, false);
00465                         dc.DrawBitmap(imageData->cachedDescription, imageData->x + 135, imageData->y + 2, false);
00466                 }
00467                 else
00468                 {
00469                         dc.DrawBitmap(imageData->cachedBitmap1, imageData->x, imageData->y, false);
00470                 }
00471         }
00472 }
00473 
00474 void MainFrame::onEraseBackground(wxEraseEvent &event)
00475 {
00476 }
00477 
00478 void MainFrame::onTimer(wxTimerEvent &event)
00479 {
00480         std::string newString;
00481         SDL_LockMutex(messageMutex_);
00482         if (!messageString_.empty())
00483         {
00484                 newString = messageString_;
00485                 messageString_ = "";
00486         }
00487         SDL_UnlockMutex(messageMutex_);
00488 
00489         if (!newString.empty())
00490         {
00491                 if (exitCode_ != 64)
00492                 {
00493                         newString.append("\n"
00494                                 "Would you like to load the failsafe "
00495                                 "scorched3d settings?\n"
00496                                 "This gives the best chance of working but "
00497                                 "at the cost of graphical detail.\n"
00498                                 "You can adjust this later in the Scorched3D "
00499                                 "display settings dialog.\n"
00500                                 "Note: Most problems can be fixed by using "
00501                                 "the very latest drivers\n"
00502                                 "for your graphics card.");
00503                         int answer = ::wxMessageBox(
00504                                 wxString(newString.c_str(), wxConvUTF8),
00505                                 wxT("Scorched3D Abnormal Termination"),
00506                                 wxYES_NO | wxICON_ERROR);
00507                         if (answer == wxYES)
00508                         {
00509                                 OptionsDisplay::instance()->loadSafeValues();
00510                                 OptionsDisplay::instance()->writeOptionsToFile();
00511                         }
00512                 }
00513                 else
00514                 {
00515                         ::wxMessageBox(
00516                                 wxString(newString.c_str(), wxConvUTF8),
00517                                 wxT("Scorched3D Termination"),
00518                                 wxICON_ERROR);
00519                 }
00520         }
00521 }
00522 
00523 void MainFrame::onDonateClick()
00524 {
00525         const char *exec = 
00526                 "\"https://www.paypal.com/xclick/business=donations%40"
00527                 "scorched3d.co.uk&item_name=Scorched3D&no_note=1&tax=0&currency_code=GBP\"";
00528         S3D::showURL(exec);
00529 }
00530 
00531 void MainFrame::onDisplayButton()
00532 {
00533         showDisplayDialog();
00534 }
00535 
00536 void MainFrame::onSingleButton()
00537 {
00538         runScorched3D("", false);
00539 }
00540 
00541 void MainFrame::onServerButton()
00542 {
00543         showServerSDialog();
00544 }
00545 
00546 void MainFrame::onQuitButton()
00547 {
00548         wxWindowExit = true;
00549         Close();
00550 }
00551 
00552 void MainFrame::onHelpButton()
00553 {
00554         S3D::showURL("http://www.scorched3d.co.uk/wiki");
00555 }
00556 
00557 extern bool newVersion;
00558 void showMainDialog()
00559 {
00560         mainDialog = new MainFrame;
00561         mainDialog->Show(TRUE);
00562 
00563         if (newVersion)
00564         {
00565                 wxBitmap bitmap;
00566                 if (bitmap.LoadFile(convertString(S3D::getDataFile("data/windows/splash.gif")), 
00567                         wxBITMAP_TYPE_GIF))
00568                 {
00569                         wxSplashScreen* splash = new wxSplashScreen(bitmap,
00570                                 wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT,
00571                                 9000, NULL, -1, wxDefaultPosition, wxDefaultSize,
00572                                 wxSIMPLE_BORDER | wxSTAY_ON_TOP);
00573                 }
00574         }
00575 }
00576 
00577 wxFrame *getMainDialog()
00578 {
00579         return mainDialog;
00580 }

Generated on Mon Feb 16 15:14:52 2009 for Scorched3D by  doxygen 1.5.3