Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

wince-sdl.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *
 */


// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL

#include "backends/platform/wince/wince-sdl.h"

#include "common/config-manager.h"
#include "common/debug.h"
#include "common/events.h"
#include "common/util.h"
#include "common/textconsole.h"
#include "common/timer.h"
#include "common/translation.h"

#include "engines/engine.h"

#include "base/main.h"
#include "base/plugins.h"

#include "audio/mixer_intern.h"
#include "audio/fmopl.h"

#include "backends/timer/sdl/sdl-timer.h"

#include "gui/Actions.h"
#include "gui/KeysDialog.h"
#include "gui/message.h"

#include "backends/platform/wince/CEActionsPocket.h"
#include "backends/platform/wince/CEActionsSmartphone.h"
#include "backends/platform/wince/CEgui/ItemAction.h"

#include "graphics/scaler/downscaler.h"
#include "graphics/scaler/aspect.h"

#include "backends/platform/wince/CEException.h"
#include "backends/platform/wince/CEScaler.h"

#include "backends/graphics/wincesdl/wincesdl-graphics.h"
#include "backends/events/wincesdl/wincesdl-events.h"
#include "backends/mixer/wincesdl/wincesdl-mixer.h"

#ifdef DYNAMIC_MODULES
#include "backends/plugins/win32/win32-provider.h"
#endif

#ifdef __GNUC__
extern "C" _CRTIMP FILE *__cdecl   _wfreopen(const wchar_t *, const wchar_t *, FILE *);
#endif

using namespace CEGUI;

// ********************************************************************************************

// stdin/err redirection
#define STDOUT_FNAME "\\scummvm_stdout.txt"
#define STDERR_FNAME "\\scummvm_stderr.txt"
static FILE *stdout_file = NULL, *stderr_file = NULL;
static char stdout_fname[MAX_PATH], stderr_fname[MAX_PATH];

// Static member inits
typedef void (*SoundProc)(void *param, byte *buf, int len);
bool OSystem_WINCE3::_soundMaster = true;

bool _isSmartphone = false;
bool _hasSmartphoneResolution = false;

#define DEFAULT_CONFIG_FILE "scummvm.ini"

// ********************************************************************************************

bool isSmartphone() {
      //return _isSmartphone;
      return _hasSmartphoneResolution;
}

const TCHAR *ASCIItoUnicode(const char *str) {
      static TCHAR ustr[MAX_PATH];    // size good enough

      MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, ustr, sizeof(ustr) / sizeof(TCHAR));
      return ustr;
}

// MAIN
#ifndef __GNUC__
int handleException(EXCEPTION_POINTERS *exceptionPointers) {
      CEException::writeException(TEXT("\\scummvmCrash"), exceptionPointers);
      drawError("Unrecoverable exception occurred - see crash dump in latest \\scummvmCrash file");
      fclose(stdout_file);
      fclose(stderr_file);
      CEDevice::end();
      SDL_Quit();
      exit(0);
      return EXCEPTION_EXECUTE_HANDLER;
}
#endif

extern "C" char *getcwd(char *buf, int size);
int SDL_main(int argc, char **argv) {
      FILE *newfp = NULL;
#ifdef __GNUC__
      // Due to incomplete crt0.o implementation, we go through the constructor function
      // list provided by the linker and init all of them
      // thanks to joostp and DJWillis
      extern void (*__CTOR_LIST__)();
      void (**constructor)() = &__CTOR_LIST__;
      constructor++;  // First item in list of constructors has special meaning (platform dependent), ignore it.
      while (*constructor) {
            (*constructor)();
            constructor++;
      }
#endif

      CEDevice::init();

      /* Redirect standard input and standard output */
      strcpy(stdout_fname, getcwd(NULL, MAX_PATH));
      strcpy(stderr_fname, getcwd(NULL, MAX_PATH));
      strcat(stdout_fname, STDOUT_FNAME);
      strcat(stderr_fname, STDERR_FNAME);
#ifndef __GNUC__
      stdout_file = fopen(stdout_fname, "w");
      stderr_file = fopen(stderr_fname, "w");
#else
      stdout_file = newfp = _wfreopen(ASCIItoUnicode(stdout_fname), TEXT("w"), stdout);
      if (newfp == NULL) {
#if !defined(stdout)
            stdout = fopen(stdout_fname, "w");
            stdout_file = stdout;
#else
            newfp = fopen(stdout_fname, "w");
            if (newfp) {
                  //*stdout = *newfp;
                  stdout_file = stdout;
            }
#endif
      }
      stderr_file = newfp = _wfreopen(ASCIItoUnicode(stderr_fname), TEXT("w"), stderr);
      if (newfp == NULL) {
#if !defined(stderr)
            stderr = fopen(stderr_fname, "w");
            stderr_file = stderr;
#else
            newfp = fopen(stderr_fname, "w");
            if (newfp) {
                  //*stderr = *newfp;
                  stderr_file = stderr;
            }
#endif
      }
#endif

#ifdef DYNAMIC_MODULES
      PluginManager::instance().addPluginProvider(new Win32PluginProvider());
#endif


      int res = 0;
#if !defined(DEBUG) && !defined(__GNUC__)
      __try {
#endif
            g_system = new OSystem_WINCE3();
            assert(g_system);

            // Pre initialize the backend
            ((OSystem_WINCE3 *)g_system)->init();

            // Invoke the actual ScummVM main entry point:
            res = scummvm_main(argc, argv);

            // Free OSystem
            delete(OSystem_WINCE3 *)g_system;
#if !defined(DEBUG) && !defined(__GNUC__)
      }
      __except(handleException(GetExceptionInformation())) {
      }
#endif

      return res;
}

#ifdef DYNAMIC_MODULES

/* This is the OS startup code in the case of a plugin-enabled build.
 * It contains copied and slightly modified parts of SDL's win32/ce startup functions.
 * We copy these here because the calling stub already has a WinMain procedure
 * which overrides SDL's one and hence we essentially re-implement the startup procedure.
 * Note also that this has to be here and not in the stub because SDL is statically
 * linked in the scummvm.dll archive.
 * Take a look at the comments in stub.cpp as well.
 */

int console_main(int argc, char *argv[]) {
      int n;
      char *bufp, *appname;

      appname = argv[0];
      if ((bufp = strrchr(argv[0], '\\')) != NULL)
            appname = bufp + 1;
      else if ((bufp = strrchr(argv[0], '/')) != NULL)
            appname = bufp + 1;

      if ((bufp = strrchr(appname, '.')) == NULL)
            n = strlen(appname);
      else
            n = (bufp - appname);

      bufp = (char *) alloca(n + 1);
      strncpy(bufp, appname, n);
      bufp[n] = '\0';
      appname = bufp;

      if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) {
            error("WinMain() error: %d", SDL_GetError());
            return(FALSE);
      }

      SDL_SetModuleHandle(GetModuleHandle(NULL));

      // Run the application main() code
      SDL_main(argc, argv);

      return(0);
}

static int ParseCommandLine(char *cmdline, char **argv) {
      char *bufp;
      int argc;

      argc = 0;
      for (bufp = cmdline; *bufp;) {
            // Skip leading whitespace
            while (isspace(*bufp))
                  ++bufp;

            // Skip over argument
            if (*bufp == '"') {
                  ++bufp;
                  if (*bufp) {
                        if (argv)
                              argv[argc] = bufp;
                        ++argc;
                  }
                  // Skip over word
                  while (*bufp && (*bufp != '"'))
                        ++bufp;
            } else {
                  if (*bufp) {
                        if (argv)
                              argv[argc] = bufp;
                        ++argc;
                  }
                  // Skip over word
                  while (*bufp && ! isspace(*bufp))
                        ++bufp;
            }
            if (*bufp) {
                  if (argv)
                        *bufp = '\0';
                  ++bufp;
            }
      }
      if (argv)
            argv[argc] = NULL;

      return(argc);
}

int dynamic_modules_main(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw) {
      HINSTANCE handle;
      char **argv;
      int argc;
      char *cmdline;
      wchar_t *bufp;
      int nLen;

      if (wcsncmp(szCmdLine, TEXT("\\"), 1)) {
            nLen = wcslen(szCmdLine) + 128 + 1;
            bufp = (wchar_t *) alloca(nLen * 2);
            wcscpy(bufp, TEXT("\""));
            GetModuleFileName(NULL, bufp + 1, 128 - 3);
            wcscpy(bufp + wcslen(bufp), TEXT("\" "));
            wcsncpy(bufp + wcslen(bufp), szCmdLine, nLen - wcslen(bufp));
      } else
            bufp = szCmdLine;

      nLen = wcslen(bufp) + 1;
      cmdline = (char *) alloca(nLen);
      WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);

      // Parse command line into argv and argc
      argc = ParseCommandLine(cmdline, NULL);
      argv = (char **) alloca((argc + 1) * (sizeof * argv));
      ParseCommandLine(cmdline, argv);

      // fix gdb-emulator combo
      while (argc > 1 && !strstr(argv[0], ".exe")) {
            OutputDebugString(TEXT("SDL: gdb argv[0] fixup\n"));
            *(argv[1] - 1) = ' ';
            int i;
            for (i = 1; i < argc; i++)
                  argv[i] = argv[i + 1];
            argc--;
      }

      // Run the main program (after a little SDL initialization)
      return(console_main(argc, argv));

}
#endif

// ********************************************************************************************

// ********************************************************************************************

void pumpMessages() {
      MSG msg;
      while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
      }
}

void drawError(char *error) {
      TCHAR errorUnicode[200];
      MultiByteToWideChar(CP_ACP, 0, error, strlen(error) + 1, errorUnicode, sizeof(errorUnicode));
      pumpMessages();
      MessageBox(GetActiveWindow(), errorUnicode, TEXT("ScummVM error"), MB_OK | MB_ICONERROR);
      pumpMessages();
}

// ********************************************************************************************
static DefaultTimerManager *_int_timer = NULL;
static Uint32 timer_handler_wrapper(Uint32 interval) {
      _int_timer->handler();
      return interval;
}

00364 void OSystem_WINCE3::initBackend() {

      assert(!_inited);

      // Create the backend custom managers
      if (_eventSource == 0)
            _eventSource = new WINCESdlEventSource();

      if (_mixerManager == 0) {
            _mixerManager = new WINCESdlMixerManager();

            // Setup and start mixer
            _mixerManager->init();
      }

      if (_graphicsManager == 0)
            _graphicsManager = new WINCESdlGraphicsManager(_eventSource);

      ((WINCESdlEventSource *)_eventSource)->init((WINCESdlGraphicsManager *)_graphicsManager);

      // Create the timer. CE SDL does not support multiple timers (SDL_AddTimer).
      // We work around this by using the SetTimer function, since we only use
      // one timer in scummvm (for the time being)
      _timer = _int_timer = new DefaultTimerManager();
      //_timerID = NULL;  // OSystem_SDL will call removetimer with this, it's ok
      SDL_SetTimer(10, &timer_handler_wrapper);

      // Chain init
      OSystem_SDL::initBackend();

      // Initialize global key mapping
      GUI::Actions::init();
      GUI_Actions::Instance()->initInstanceMain(this);
      if (!GUI_Actions::Instance()->loadMapping()) {  // error during loading means not present/wrong version
            warning("Setting default action mappings");
            GUI_Actions::Instance()->saveMapping(); // write defaults
      }

      // Call parent implementation of this method
      //OSystem_SDL::initBackend();

      _inited = true;
}

int OSystem_WINCE3::getScreenWidth() {
      return _platformScreenWidth;
}

void OSystem_WINCE3::initScreenInfos() {
      // sdl port ensures that we use correctly full screen
      _isOzone = 0;
      SDL_Rect **r;
      r = SDL_ListModes(NULL, 0);
      _platformScreenWidth = r[0]->w;
      _platformScreenHeight = r[0]->h;
}

int OSystem_WINCE3::getScreenHeight() {
      return _platformScreenHeight;
}

bool OSystem_WINCE3::isOzone() {
      return _isOzone;
}

00429 Common::String OSystem_WINCE3::getDefaultConfigFileName() {
      char configFile[MAXPATHLEN];
      strcpy(configFile, getcwd(NULL, MAX_PATH));
      strcat(configFile, "\\");
      strcat(configFile, DEFAULT_CONFIG_FILE);
      return configFile;
}

// ********************************************************************************************


OSystem_WINCE3::OSystem_WINCE3() : OSystem_SDL(),
      _forcePanelInvisible(false) {
      // Initialze File System Factory
      _fsFactory = new WindowsFilesystemFactory();
      _mixer = 0;
}

OSystem_WINCE3::~OSystem_WINCE3() {
      delete _fsFactory;
      delete _mixer;
}

00452 FilesystemFactory *OSystem_WINCE3::getFilesystemFactory() {
      return _fsFactory;
}

void OSystem_WINCE3::swap_sound_master() {
      _soundMaster = !_soundMaster;

      //WINCESdlGraphicsManager _graphicsManager

      if (((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.activeName() == NAME_MAIN_PANEL)
            ((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.forceRedraw(); // redraw sound icon
}


00466 void OSystem_WINCE3::engineInit() {
      check_mappings(); // called here to initialize virtual keys handling

      //update_game_settings();
      // finalize mixer init
      _mixerManager->init();
}

void OSystem_WINCE3::check_mappings() {
      CEActionsPocket *instance;

      Common::String gameid(ConfMan.get("gameid"));

      if (gameid.empty() || GUI_Actions::Instance()->initialized())
            return;

      GUI_Actions::Instance()->initInstanceGame();
      instance = (CEActionsPocket *)GUI_Actions::Instance();

      // Some games need to map the right click button, signal it here if it wasn't done
      if (instance->needsRightClickMapping()) {
            GUI::KeysDialog *keysDialog = new GUI::KeysDialog(_("Map right click action"));
            while (!instance->getMapping(POCKET_ACTION_RIGHTCLICK)) {
                  keysDialog->runModal();
                  if (!instance->getMapping(POCKET_ACTION_RIGHTCLICK)) {
                        GUI::MessageDialog alert(_("You must map a key to the 'Right Click' action to play this game"));
                        alert.runModal();
                  }
            }
            delete keysDialog;
      }

      // Map the "hide toolbar" action if needed
      if (instance->needsHideToolbarMapping()) {
            GUI::KeysDialog *keysDialog = new GUI::KeysDialog(_("Map hide toolbar action"));
            while (!instance->getMapping(POCKET_ACTION_HIDE)) {
                  keysDialog->runModal();
                  if (!instance->getMapping(POCKET_ACTION_HIDE)) {
                        GUI::MessageDialog alert(_("You must map a key to the 'Hide toolbar' action to play this game"));
                        alert.runModal();
                  }
            }
            delete keysDialog;
      }

      // Map the "zoom" actions if needed
      if (instance->needsZoomMapping()) {
            GUI::KeysDialog *keysDialog = new GUI::KeysDialog(_("Map Zoom Up action (optional)"));
            keysDialog->runModal();
            delete keysDialog;
            keysDialog = new GUI::KeysDialog(_("Map Zoom Down action (optional)"));
            keysDialog->runModal();
            delete keysDialog;
      }

      // Extra warning for Zak Mc Kracken
      if (strncmp(gameid.c_str(), "zak", 3) == 0 &&
              !GUI_Actions::Instance()->getMapping(POCKET_ACTION_HIDE)) {
            GUI::MessageDialog alert(_("Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory"));
            alert.runModal();
      }

}

void OSystem_WINCE3::setGraphicsModeIntern() {
      // Scalers have been pre-selected for the desired mode.
      // No further tuning required.
}

00535 void OSystem_WINCE3::initSDL() {
      // Check if SDL has not been initialized
      if (!_initedSDL) {
            uint32 sdlFlags = SDL_INIT_EVENTTHREAD;
            if (ConfMan.hasKey("disable_sdl_parachute"))
                  sdlFlags |= SDL_INIT_NOPARACHUTE;

            if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) {
                  SDL_VideoInit("windib", 0);
                  sdlFlags ^= SDL_INIT_VIDEO;
            }

            // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers)
            if (SDL_Init(sdlFlags) == -1)
                  error("Could not initialize SDL: %s", SDL_GetError());

            // Enable unicode support if possible
            SDL_EnableUNICODE(1);

            _initedSDL = true;
      }
}

00558 void OSystem_WINCE3::quit() {
      fclose(stdout_file);
      fclose(stderr_file);
      if (gDebugLevel <= 0) {
            DeleteFile(ASCIItoUnicode(stdout_fname));
            DeleteFile(ASCIItoUnicode(stderr_fname));
      }
      CEDevice::end();
      OSystem_SDL::quit();
}

00569 void OSystem_WINCE3::getTimeAndDate(TimeDate &t) const {
      SYSTEMTIME systime;

      GetLocalTime(&systime);
      t.tm_year   = systime.wYear - 1900;
      t.tm_mon    = systime.wMonth - 1;
      t.tm_mday   = systime.wDay;
      t.tm_hour   = systime.wHour;
      t.tm_min    = systime.wMinute;
      t.tm_sec    = systime.wSecond;
}

int OSystem_WINCE3::_platformScreenWidth;
int OSystem_WINCE3::_platformScreenHeight;
bool OSystem_WINCE3::_isOzone;

Generated by  Doxygen 1.6.0   Back to index