00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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;
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
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
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
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
00325 timer_.SetOwner(this, ID_MAIN_TIMER);
00326 timer_.Start(1000, false);
00327
00328
00329
00330 wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
00331 topsizer->SetMinSize(533, 400);
00332 SetSizer(topsizer);
00333 topsizer->SetSizeHints(this);
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
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¤cy_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 }