scummvm/backends/wince/wince-sdl.cpp

2049 lines
52 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001-2006 The ScummVM project
*
* 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$
*
*/
#include "common/stdafx.h"
#include "wince-sdl.h"
#include "common/util.h"
#include "base/gameDetector.h"
#include "base/engine.h"
#include "base/main.h"
#include "base/plugins.h"
#include "common/timer.h"
#include "common/config-manager.h"
#include "scumm/scumm.h"
#include "resource.h"
#include "gui/Actions.h"
#include "CEActionsPocket.h"
#include "CEActionsSmartphone.h"
#include "ItemAction.h"
#include "gui/KeysDialog.h"
#include "gui/message.h"
#include "sound/fmopl.h"
#include "ozone.h"
#include "CEException.h"
#ifdef USE_VORBIS
#include <vorbis/vorbisfile.h>
#endif
using namespace CEGUI;
// ********************************************************************************************
// Internal GUI names
#define NAME_MAIN_PANEL "MainPanel"
#define NAME_PANEL_KEYBOARD "Keyboard"
#define NAME_ITEM_OPTIONS "Options"
#define NAME_ITEM_SKIP "Skip"
#define NAME_ITEM_SOUND "Sound"
#define NAME_ITEM_ORIENTATION "Orientation"
// Given to the true main, needed for backend adaptation
static GameDetector _gameDetector;
static FILE *stdout_file;
static FILE *stderr_file;
// Static member inits
bool OSystem_WINCE3::_soundMaster = true;
OSystem::SoundProc OSystem_WINCE3::_originalSoundProc = NULL;
bool _isSmartphone = false;
bool _hasSmartphoneResolution = false;
// Graphics mode consts
// Low end devices 240x320
static const OSystem::GraphicsMode s_supportedGraphicsModesLow[] = {
{"1x", "Normal (no scaling)", GFX_NORMAL},
{0, 0, 0}
};
// High end device 480x640
static const OSystem::GraphicsMode s_supportedGraphicsModesHigh[] = {
{"1x", "Normal (no scaling)", GFX_NORMAL},
{"2x", "2x", GFX_DOUBLESIZE},
#ifndef _MSC_VER // EVC breaks template functions, and I'm tired of fixing them :)
{"2xsai", "2xSAI", GFX_2XSAI},
{"super2xsai", "Super2xSAI", GFX_SUPER2XSAI},
{"supereagle", "SuperEagle", GFX_SUPEREAGLE},
#endif
{"advmame2x", "AdvMAME2x", GFX_ADVMAME2X},
#ifndef _MSC_VER
{"hq2x", "HQ2x", GFX_HQ2X},
{"tv2x", "TV2x", GFX_TV2X},
#endif
{"dotmatrix", "DotMatrix", GFX_DOTMATRIX},
{0, 0, 0}
};
// ********************************************************************************************
bool isSmartphone() {
//return _isSmartphone;
return _hasSmartphoneResolution;
}
// ********************************************************************************************
// MAIN
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;
}
int SDL_main(int argc, char **argv) {
CEDevice::init();
OSystem_WINCE3::initScreenInfos();
/* Sanity check */
//#ifndef WIN32_PLATFORM_WFSP
// if (CEDevice::hasSmartphoneResolution()) {
// MessageBox(NULL, TEXT("This build was not compiled with Smartphone support"), TEXT("ScummVM error"), MB_OK | MB_ICONERROR);
// return 0;
// }
//#endif
/* Avoid print problems - this file will be put in RAM anyway */
stdout_file = fopen("\\scummvm_stdout.txt", "w");
stderr_file = fopen("\\scummvm_stderr.txt", "w");
GUI::Actions::init(_gameDetector);
int rest = 0;
__try {
g_system = OSystem_WINCE3_create();
assert(g_system);
// Invoke the actual ScummVM main entry point:
res = scummvm_main(argc, argv);
g_system->quit(); // TODO: Consider removing / replacing this!
}
__except (handleException(GetExceptionInformation())) {
}
return res;
}
// ********************************************************************************************
// ********************************************************************************************
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();
}
// ********************************************************************************************
int OSystem_WINCE3::getScreenWidth() {
return _platformScreenWidth;
}
int OSystem_WINCE3::getScreenHeight() {
return _platformScreenHeight;
}
void OSystem_WINCE3::initScreenInfos() {
// Check if we're running Ozone
int result;
RawFrameBufferInfo frameBufferInfo;
HDC hdc = GetDC(NULL);
result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *)&frameBufferInfo);
ReleaseDC(NULL, hdc);
_isOzone = (result > 0);
// And obtain the real screen size
_platformScreenWidth = (result > 0 ? frameBufferInfo.cxPixels : GetSystemMetrics(SM_CXSCREEN));
_platformScreenHeight = (result > 0 ? frameBufferInfo.cyPixels : GetSystemMetrics(SM_CYSCREEN));
}
bool OSystem_WINCE3::isOzone() {
return _isOzone;
}
// ********************************************************************************************
OSystem *OSystem_WINCE3_create() {
return new OSystem_WINCE3();
}
OSystem_WINCE3::OSystem_WINCE3() : OSystem_SDL(),
_orientationLandscape(false), _newOrientation(false), _panelInitialized(false),
_panelVisible(false), _panelStateForced(false), _forceHideMouse(false),
_freeLook(false), _forcePanelInvisible(false), _toolbarHighDrawn(false), _zoomUp(false), _zoomDown(false),
_scalersChanged(false), _monkeyKeyboard(false), _lastKeyPressed(0), _tapTime(0)
{
_isSmartphone = CEDevice::isSmartphone();
_hasSmartphoneResolution = CEDevice::hasSmartphoneResolution();
memset(&_mouseCurState, 0, sizeof(_mouseCurState));
if (_isSmartphone) {
_mouseCurState.x = 20;
_mouseCurState.y = 20;
}
create_toolbar();
// Initialize global key mapping for Smartphones
GUI_Actions::Instance()->initInstanceMain(this);
GUI_Actions::Instance()->loadMapping();
if (_isSmartphone) {
loadSmartphoneConfiguration();
}
// Mouse backup (temporary code)
_mouseBackupOld = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING * 2);
}
void OSystem_WINCE3::swap_panel_visibility() {
if (!_forcePanelInvisible && !_panelStateForced) {
_panelVisible = !_panelVisible;
_toolbarHandler.setVisible(_panelVisible);
if (_screenHeight > 240)
addDirtyRect(0, 400, 640, 80);
else
addDirtyRect(0, 200, 320, 40);
internUpdateScreen();
}
}
void OSystem_WINCE3::swap_panel() {
_toolbarHighDrawn = false;
if (!_panelStateForced) {
if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD)
_toolbarHandler.setActive(NAME_MAIN_PANEL);
else
_toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
}
}
void OSystem_WINCE3::swap_sound_master() {
_soundMaster = !_soundMaster;
if (_toolbarHandler.activeName() == NAME_MAIN_PANEL)
_toolbarHandler.forceRedraw(); // redraw sound icon
}
void OSystem_WINCE3::add_right_click(bool pushed) {
int x, y;
retrieve_mouse_location(x, y);
EventsBuffer::simulateMouseRightClick(x, y, pushed);
}
void OSystem_WINCE3::swap_mouse_visibility() {
_forceHideMouse = !_forceHideMouse;
if (_forceHideMouse)
undrawMouse();
}
void OSystem_WINCE3::swap_freeLook() {
_freeLook = !_freeLook;
}
void OSystem_WINCE3::swap_zoom_up() {
if (_zoomUp) {
// restore visibility
_toolbarHandler.setVisible(_saveToolbarZoom);
// restore scaler
_scaleFactorYd = 2;
_scalerProc = PocketPCHalf;
_zoomUp = false;
}
else
{
// only active if running on a PocketPC
if (_scalerProc != PocketPCHalf && _scalerProc != PocketPCHalfZoom)
return;
if (_scalerProc == PocketPCHalf) {
_saveToolbarZoom = _toolbarHandler.visible();
_toolbarHandler.setVisible(false);
// set zoom scaler
_scaleFactorYd = 1;
_scalerProc = PocketPCHalfZoom;
}
else
_zoomDown = false;
_zoomUp = true;
}
// redraw whole screen
addDirtyRect(0, 0, 640, 480);
internUpdateScreen();
}
void OSystem_WINCE3::swap_zoom_down() {
if (_zoomDown) {
// restore visibility
_toolbarHandler.setVisible(_saveToolbarZoom);
// restore scaler
_scaleFactorYd = 2;
_scalerProc = PocketPCHalf;
_zoomDown = false;
}
else
{
// only active if running on a PocketPC
if (_scalerProc != PocketPCHalf && _scalerProc != PocketPCHalfZoom)
return;
if (_scalerProc == PocketPCHalf) {
_saveToolbarZoom = _toolbarHandler.visible();
_toolbarHandler.setVisible(false);
// set zoom scaler
_scaleFactorYd = 1;
_scalerProc = PocketPCHalfZoom;
}
else
_zoomUp = false;
_zoomDown = true;
}
// redraw whole screen
addDirtyRect(0, 0, 640, 480);
internUpdateScreen();
}
//#ifdef WIN32_PLATFORM_WFSP
// Smartphone actions
void OSystem_WINCE3::initZones() {
int i;
_currentZone = 0;
for (i=0; i<TOTAL_ZONES; i++) {
_mouseXZone[i] = (_zones[i].x + (_zones[i].width / 2)) * _scaleFactorXm / _scaleFactorXd;
_mouseYZone[i] = (_zones[i].y + (_zones[i].height / 2)) * _scaleFactorYm / _scaleFactorYd;
}
}
void OSystem_WINCE3::loadSmartphoneConfigurationElement(String element, int &value, int defaultValue) {
value = ConfMan.getInt(element, "smartphone");
if (!value) {
value = defaultValue;
ConfMan.set(element, value, "smartphone");
}
}
void OSystem_WINCE3::loadSmartphoneConfiguration() {
loadSmartphoneConfigurationElement("repeatTrigger", _keyRepeatTrigger, 200);
loadSmartphoneConfigurationElement("repeatX", _repeatX, 4);
loadSmartphoneConfigurationElement("repeatY", _repeatY, 4);
loadSmartphoneConfigurationElement("stepX1", _stepX1, 2);
loadSmartphoneConfigurationElement("stepX2", _stepX2, 10);
loadSmartphoneConfigurationElement("stepX3", _stepX3, 40);
loadSmartphoneConfigurationElement("stepY1", _stepY1, 2);
loadSmartphoneConfigurationElement("stepY2", _stepY2, 10);
loadSmartphoneConfigurationElement("stepY3", _stepY3, 20);
ConfMan.flushToDisk();
}
void OSystem_WINCE3::add_left_click(bool pushed) {
int x, y;
retrieve_mouse_location(x, y);
EventsBuffer::simulateMouseLeftClick(x, y, pushed);
}
void OSystem_WINCE3::move_cursor_up() {
int x,y;
retrieve_mouse_location(x, y);
if (_keyRepeat > _repeatY)
y -= _stepY3;
else
if (_keyRepeat)
y -= _stepY2;
else
y -= _stepY1;
if (y < 0)
y = 0;
EventsBuffer::simulateMouseMove(x, y);
}
void OSystem_WINCE3::move_cursor_down() {
int x,y;
retrieve_mouse_location(x, y);
if (_keyRepeat > _repeatY)
y += _stepY3;
else
if (_keyRepeat)
y += _stepY2;
else
y += _stepY1;
if (y > 240)
y = 240;
EventsBuffer::simulateMouseMove(x, y);
}
void OSystem_WINCE3::move_cursor_left() {
int x,y;
retrieve_mouse_location(x, y);
if (_keyRepeat > _repeatX)
x -= _stepX3;
else
if (_keyRepeat)
x -= _stepX2;
else
x -= _stepX1;
if (x < 0)
x = 0;
EventsBuffer::simulateMouseMove(x, y);
}
void OSystem_WINCE3::move_cursor_right() {
int x,y;
retrieve_mouse_location(x, y);
if (_keyRepeat > _repeatX)
x += _stepX3;
else
if (_keyRepeat)
x += _stepX2;
else
x += _stepX1;
if (x > 320)
x = 320;
EventsBuffer::simulateMouseMove(x, y);
}
void OSystem_WINCE3::switch_zone() {
int x,y;
int i;
retrieve_mouse_location(x, y);
for (i=0; i<TOTAL_ZONES; i++)
if (x >= _zones[i].x && y >= _zones[i].y &&
x <= _zones[i].x + _zones[i].width && y <= _zones[i].y + _zones[i].height
) {
_mouseXZone[i] = x;
_mouseYZone[i] = y;
break;
}
_currentZone++;
if (_currentZone >= TOTAL_ZONES)
_currentZone = 0;
EventsBuffer::simulateMouseMove(_mouseXZone[_currentZone], _mouseYZone[_currentZone]);
}
//#endif
void OSystem_WINCE3::create_toolbar() {
PanelKeyboard *keyboard;
// Add the keyboard
if (!_hasSmartphoneResolution) {
keyboard = new PanelKeyboard(PANEL_KEYBOARD);
_toolbarHandler.add(NAME_PANEL_KEYBOARD, *keyboard);
_toolbarHandler.setVisible(false);
}
}
void OSystem_WINCE3::private_sound_proc(void *param, byte *buf, int len) {
(*_originalSoundProc)(param, buf, len);
if (!_soundMaster)
memset(buf, 0, len);
}
#ifdef USE_VORBIS
bool OSystem_WINCE3::checkOggHighSampleRate() {
char trackFile[255];
FILE *testFile;
OggVorbis_File *test_ov_file = new OggVorbis_File;
sprintf(trackFile,"%sTrack1.ogg", ConfMan.get("path").c_str());
// Check if we have an OGG audio track
testFile = fopen(trackFile, "rb");
if (testFile) {
if (!ov_open(testFile, test_ov_file, NULL, 0)) {
bool highSampleRate = (ov_info(test_ov_file, -1)->rate == 22050);
ov_clear(test_ov_file);
delete test_ov_file;
return highSampleRate;
}
}
// Do not test for OGG samples - too big and too slow anyway :)
delete test_ov_file;
return false;
}
#endif
void OSystem_WINCE3::get_sample_rate() {
// Force at least medium quality FM synthesis for FOTAQ
if (_gameDetector._gameid == "queen") {
if (!((ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) ||
(ConfMan.hasKey("FM_medium_quality") && ConfMan.getBool("FM_medium_quality")))) {
ConfMan.set("FM_medium_quality", true);
ConfMan.flushToDisk();
}
}
// See if the output frequency is forced by the game
if ((_gameDetector._gameid == "ft" ||
_gameDetector._gameid == "dig" ||
_gameDetector._gameid == "comi" ||
_gameDetector._gameid == "queen" ||
strncmp(_gameDetector._gameid.c_str(), "sword", 5) == 0 ||
strncmp(_gameDetector._gameid.c_str(), "sky", 3) == 0)
_sampleRate = SAMPLES_PER_SEC_NEW;
else {
if (ConfMan.hasKey("high_sample_rate") && ConfMan.getBool("high_sample_rate"))
_sampleRate = SAMPLES_PER_SEC_NEW;
else
_sampleRate = SAMPLES_PER_SEC_OLD;
}
#ifdef USE_VORBIS
// Modify the sample rate on the fly if OGG is involved
if (_sampleRate == SAMPLES_PER_SEC_OLD)
if (checkOggHighSampleRate())
_sampleRate = SAMPLES_PER_SEC_NEW;
#endif
}
int OSystem_WINCE3::getOutputSampleRate() const {
return _sampleRate;
}
void OSystem_WINCE3::setWindowCaption(const char *caption) {
check_mappings(); // called here to initialize virtual keys handling
//update_game_settings();
get_sample_rate(); // called here to initialize mixer
}
bool OSystem_WINCE3::openCD(int drive) {
return false;
}
const OSystem::GraphicsMode *OSystem_WINCE3::getSupportedGraphicsModes() const {
if (CEDevice::hasWideResolution())
return s_supportedGraphicsModesHigh;
else
return s_supportedGraphicsModesLow;
}
bool OSystem_WINCE3::hasFeature(Feature f) {
return
(f == kFeatureAutoComputeDirtyRects || f == kFeatureVirtualKeyboard);
}
void OSystem_WINCE3::setFeatureState(Feature f, bool enable) {
switch(f) {
case kFeatureFullscreenMode:
return;
case kFeatureVirtualKeyboard:
if (_hasSmartphoneResolution)
return;
_toolbarHighDrawn = false;
if (enable) {
_panelStateForced = true;
_saveToolbarState = _toolbarHandler.visible();
_saveActiveToolbar = _toolbarHandler.activeName();
_toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
_toolbarHandler.setVisible(true);
}
else {
_panelStateForced = false;
_toolbarHandler.setActive(_saveActiveToolbar);
_toolbarHandler.setVisible(_saveToolbarState);
}
return;
default:
OSystem_SDL::setFeatureState(f, enable);
}
}
bool OSystem_WINCE3::getFeatureState(Feature f) {
switch(f) {
case kFeatureFullscreenMode:
return false;
case kFeatureVirtualKeyboard:
return (_panelStateForced);
}
return OSystem_SDL::getFeatureState(f);
}
bool OSystem_WINCE3::setSoundCallback(SoundProc proc, void *param) {
SDL_AudioSpec desired;
int thread_priority;
memset(&desired, 0, sizeof(desired));
_originalSoundProc = proc;
desired.freq = _sampleRate;
desired.format = AUDIO_S16SYS;
desired.channels = 2;
//desired.samples = 2048;
desired.samples = 128;
desired.callback = private_sound_proc;
desired.userdata = param;
// Add sound thread priority
if (!ConfMan.hasKey("sound_thread_priority")) {
#ifdef SH3
thread_priority = THREAD_PRIORITY_NORMAL;
#else
thread_priority = THREAD_PRIORITY_ABOVE_NORMAL;
#endif
}
else
thread_priority = ConfMan.getInt("sound_thread_priority");
desired.thread_priority = thread_priority;
if (SDL_OpenAudio(&desired, NULL) != 0) {
return false;
}
SDL_PauseAudio(0);
return true;
}
void OSystem_WINCE3::check_mappings() {
CEActionsPocket *instance;
if (!_gameDetector._gameid.size() || 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(_gameDetector._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::update_game_settings() {
// Finish panel initialization
if (!_panelInitialized && _gameDetector._gameid.size()) {
Panel *panel;
_panelInitialized = true;
// Add the main panel
panel = new Panel(10, 40);
panel->setBackground(IMAGE_PANEL);
// Save
panel->add(NAME_ITEM_OPTIONS, new ItemAction(ITEM_OPTIONS, POCKET_ACTION_SAVE));
// Skip
panel->add(NAME_ITEM_SKIP, new ItemAction(ITEM_SKIP, POCKET_ACTION_SKIP));
// sound
panel->add(NAME_ITEM_SOUND, new ItemSwitch(ITEM_SOUND_OFF, ITEM_SOUND_ON, &_soundMaster));
// portrait/landscape - screen dependant
// FIXME : will still display the portrait/landscape icon when using a scaler (but will be disabled)
if (_screenWidth <= 320 && (isOzone() || !CEDevice::hasDesktopResolution())) {
_newOrientation = _orientationLandscape = (ConfMan.hasKey("landscape") ? ConfMan.getBool("landscape") : false);
panel->add(NAME_ITEM_ORIENTATION, new ItemSwitch(ITEM_VIEW_LANDSCAPE, ITEM_VIEW_PORTRAIT, &_newOrientation));
}
_toolbarHandler.add(NAME_MAIN_PANEL, *panel);
_toolbarHandler.setActive(NAME_MAIN_PANEL);
_toolbarHandler.setVisible(true);
// Keyboard is active for Monkey 1 or 2 initial copy-protection
if (strncmp(_gameDetector._gameid.c_str(), "monkey", 6) == 0) {
_monkeyKeyboard = true;
_toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
}
if (_mode == GFX_NORMAL && ConfMan.hasKey("landscape") && ConfMan.getBool("landscape")) {
setGraphicsMode(GFX_NORMAL);
hotswapGFXMode();
}
if (_hasSmartphoneResolution)
panel->setVisible(false);
// Set Smush Force Redraw rate for Full Throttle
if (!ConfMan.hasKey("Smush_force_redraw")) {
ConfMan.set("Smush_force_redraw", 30);
ConfMan.flushToDisk();
}
}
get_sample_rate();
}
void OSystem_WINCE3::initSize(uint w, uint h, int overlayScale) {
if (_hasSmartphoneResolution && h == 240)
h = 200; // mainly for the launcher
switch (_transactionMode) {
case kTransactionActive:
_transactionDetails.w = w;
_transactionDetails.h = h;
_transactionDetails.overlayScale = overlayScale;
_transactionDetails.sizeChanged = true;
_transactionDetails.needUnload = true;
return;
break;
case kTransactionCommit:
break;
default:
break;
}
if (w == 320 && h == 200 && !_hasSmartphoneResolution)
h = 240; // use the extra 40 pixels height for the toolbar
if (!_hasSmartphoneResolution) {
if (h == 240)
_toolbarHandler.setOffset(200);
else
_toolbarHandler.setOffset(400);
}
if (w != _screenWidth || h != _screenHeight)
_scalersChanged = false;
//OSystem_SDL::initSize(w, h, overlayScale);
OSystem_SDL::initSize(w, h, 1);
if (_scalersChanged) {
unloadGFXMode();
loadGFXMode();
_scalersChanged = false;
}
update_game_settings();
}
int OSystem_WINCE3::getDefaultGraphicsMode() const {
return GFX_NORMAL;
}
bool OSystem_WINCE3::update_scalers() {
if (_mode != GFX_NORMAL)
return false;
if (CEDevice::hasPocketPCResolution()) {
if (!_orientationLandscape && (_screenWidth == 320 || !_screenWidth)) {
_scaleFactorXm = 3;
_scaleFactorXd = 4;
_scaleFactorYm = 1;
_scaleFactorYd = 1;
_scalerProc = PocketPCPortrait;
_modeFlags = 0;
}
if (_screenWidth == 640 && !(isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640))) {
_scaleFactorXm = 1;
_scaleFactorXd = 2;
_scaleFactorYm = 1;
_scaleFactorYd = 2;
_scalerProc = PocketPCHalf;
_modeFlags = 0;
}
if (_screenWidth == 640 && (isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640))) {
_scaleFactorXm = 1;
_scaleFactorXd = 1;
_scaleFactorYm = 1;
_scaleFactorYd = 1;
_scalerProc = Normal1x;
_modeFlags = 0;
}
return true;
}
//#ifdef WIN32_PLATFORM_WFSP
if (_hasSmartphoneResolution) {
if (_screenWidth > 320)
error("Game resolution not supported on Smartphone");
_scaleFactorXm = 2;
_scaleFactorXd = 3;
_scaleFactorYm = 7;
_scaleFactorYd = 8;
_scalerProc = SmartphoneLandscape;
_modeFlags = 0;
initZones();
return true;
}
//#endif
return false;
}
bool OSystem_WINCE3::setGraphicsMode(int mode) {
switch (_transactionMode) {
case kTransactionActive:
_transactionDetails.mode = mode;
_transactionDetails.modeChanged = true;
return true;
break;
case kTransactionCommit:
break;
default:
break;
}
Common::StackLock lock(_graphicsMutex);
int oldScaleFactorXm = _scaleFactorXm;
int oldScaleFactorXd = _scaleFactorXd;
int oldScaleFactorYm = _scaleFactorYm;
int oldScaleFactorYd = _scaleFactorYd;
_scaleFactorXm = -1;
_scaleFactorXd = -1;
_scaleFactorYm = -1;
_scaleFactorYd = -1;
_newOrientation = _orientationLandscape = (ConfMan.hasKey("landscape") ? ConfMan.getBool("landscape") : false);
update_scalers();
// FIXME
if (isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640) && mode)
_scaleFactorXm = -1;
if (CEDevice::hasPocketPCResolution() && !CEDevice::hasWideResolution() && _orientationLandscape)
_mode = GFX_NORMAL;
else
_mode = mode;
if (_scaleFactorXm < 0) {
/* Standard scalers, from the SDL backend */
switch(_mode) {
case GFX_NORMAL:
_scaleFactor = 1;
_scalerProc = Normal1x;
break;
case GFX_DOUBLESIZE:
_scaleFactor = 2;
_scalerProc = Normal2x;
break;
case GFX_TRIPLESIZE:
_scaleFactor = 3;
_scalerProc = Normal3x;
break;
case GFX_2XSAI:
_scaleFactor = 2;
_scalerProc = _2xSaI;
break;
case GFX_SUPER2XSAI:
_scaleFactor = 2;
_scalerProc = Super2xSaI;
break;
case GFX_SUPEREAGLE:
_scaleFactor = 2;
_scalerProc = SuperEagle;
break;
case GFX_ADVMAME2X:
_scaleFactor = 2;
_scalerProc = AdvMame2x;
break;
case GFX_ADVMAME3X:
_scaleFactor = 3;
_scalerProc = AdvMame3x;
break;
case GFX_HQ2X:
_scaleFactor = 2;
_scalerProc = HQ2x;
break;
case GFX_HQ3X:
_scaleFactor = 3;
_scalerProc = HQ3x;
break;
case GFX_TV2X:
_scaleFactor = 2;
_scalerProc = TV2x;
break;
case GFX_DOTMATRIX:
_scaleFactor = 2;
_scalerProc = DotMatrix;
break;
default:
error("unknown gfx mode %d", _mode);
}
}
// Check if the scaler can be accepted, if not get back to normal scaler
if (_scaleFactor && ((_scaleFactor * _screenWidth > getScreenWidth() &&
_scaleFactor * _screenWidth > getScreenHeight())
|| (_scaleFactor * _screenHeight > getScreenWidth() &&
_scaleFactor * _screenHeight > getScreenHeight()))) {
_scaleFactor = 1;
_scalerProc = Normal1x;
}
// Common scaler system was used
if (_scaleFactorXm < 0) {
_scaleFactorXm = _scaleFactor;
_scaleFactorXd = 1;
_scaleFactorYm = _scaleFactor;
_scaleFactorYd = 1;
}
_forceFull = true;
if (oldScaleFactorXm != _scaleFactorXm ||
oldScaleFactorXd != _scaleFactorXd ||
oldScaleFactorYm != _scaleFactorYm ||
oldScaleFactorYd != _scaleFactorYd) {
_scalersChanged = true;
}
else
_scalersChanged = false;
return true;
}
void OSystem_WINCE3::loadGFXMode() {
int displayWidth;
int displayHeight;
_fullscreen = true; // forced
_forceFull = true;
_modeFlags |= DF_UPDATE_EXPAND_1_PIXEL;
_tmpscreen = NULL;
// Recompute scalers if necessary
update_scalers();
//
// Create the surface that contains the 8 bit game data
_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth, _screenHeight, 8, 0, 0, 0, 0);
if (_screen == NULL)
error("_screen failed");
//
// Create the surface that contains the scaled graphics in 16 bit mode
//
// Always use full screen mode to have a "clean screen"
displayWidth = _screenWidth * _scaleFactorXm / _scaleFactorXd;
displayHeight = _screenHeight * _scaleFactorYm / _scaleFactorYd;
// FIXME
if (!(displayWidth > GetSystemMetrics(SM_CXSCREEN))) { // no rotation
displayWidth = GetSystemMetrics(SM_CXSCREEN);
displayHeight = GetSystemMetrics(SM_CYSCREEN);
}
_hwscreen = SDL_SetVideoMode(displayWidth, displayHeight, 16, SDL_FULLSCREEN | SDL_SWSURFACE);
if (_hwscreen == NULL) {
// DON'T use error(), as this tries to bring up the debug
// console, which WON'T WORK now that _hwscreen is hosed.
// FIXME: We should be able to continue the game without
// shutting down or bringing up the debug console, but at
// this point we've already screwed up all our member vars.
// We need to find a way to call SDL_VideoModeOK *before*
// that happens and revert to all the old settings if we
// can't pull off the switch to the new settings.
//
// Fingolfin says: the "easy" way to do that is not to modify
// the member vars before we are sure everything is fine. Think
// of "transactions, commit, rollback" style... we use local vars
// in place of the member vars, do everything etc. etc.. In case
// of a failure, rollback is trivial. Only if everything worked fine
// do we "commit" the changed values to the member vars.
warning("SDL_SetVideoMode says we can't switch to that mode");
quit();
}
//
// Create the surface used for the graphics in 16 bit before scaling, and also the overlay
//
// Distinguish 555 and 565 mode
if (_hwscreen->format->Rmask == 0x7C00)
InitScalers(555);
else
InitScalers(565);
initCEScaler();
// Need some extra bytes around when using 2xSaI
_tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE,
_screenWidth + 3,
_screenHeight + 3,
16,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask);
if (_tmpscreen == NULL)
error("_tmpscreen failed");
// Overlay
_overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth, _overlayHeight, 16, 0, 0, 0, 0);
if (_overlayscreen == NULL)
error("_overlayscreen failed");
_tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth + 3, _overlayHeight + 3, 16, 0, 0, 0, 0);
if (_tmpscreen2 == NULL)
error("_tmpscreen2 failed");
// Toolbar
uint16 *toolbar_screen = (uint16 *)calloc(320 * 40, sizeof(uint16));
_toolbarLow = SDL_CreateRGBSurfaceFrom(toolbar_screen,
320, 40, 16, 320 * 2,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask
);
if (_toolbarLow == NULL)
error("_toolbarLow failed");
if (_screenHeight > 240) {
uint16 *toolbar_screen = (uint16 *)calloc(640 * 80, sizeof(uint16));
_toolbarHigh = SDL_CreateRGBSurfaceFrom(toolbar_screen,
640, 80, 16, 640 * 2,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask
);
if (_toolbarHigh == NULL)
error("_toolbarHigh failed");
}
else
_toolbarHigh = NULL;
// keyboard cursor control, some other better place for it?
_km.x_max = _screenWidth * _scaleFactorXm / _scaleFactorXd - 1;
_km.y_max = _screenHeight * _scaleFactorXm / _scaleFactorXd - 1;
_km.delay_time = 25;
_km.last_time = 0;
}
void OSystem_WINCE3::unloadGFXMode() {
if (_screen) {
SDL_FreeSurface(_screen);
_screen = NULL;
}
if (_hwscreen) {
SDL_FreeSurface(_hwscreen);
_hwscreen = NULL;
}
if (_tmpscreen) {
SDL_FreeSurface(_tmpscreen);
_tmpscreen = NULL;
}
}
void OSystem_WINCE3::hotswapGFXMode() {
if (!_screen)
return;
// Keep around the old _screen & _tmpscreen so we can restore the screen data
// after the mode switch.
SDL_Surface *old_screen = _screen;
SDL_Surface *old_tmpscreen = _tmpscreen;
// Release the HW screen surface
SDL_FreeSurface(_hwscreen);
// Release toolbars
free(_toolbarLow->pixels);
SDL_FreeSurface(_toolbarLow);
if (_toolbarHigh) {
free(_toolbarHigh->pixels);
SDL_FreeSurface(_toolbarHigh);
}
// Setup the new GFX mode
loadGFXMode();
// reset palette
SDL_SetColors(_screen, _currentPalette, 0, 256);
// Restore old screen content
SDL_BlitSurface(old_screen, NULL, _screen, NULL);
SDL_BlitSurface(old_tmpscreen, NULL, _tmpscreen, NULL);
// Free the old surfaces
SDL_FreeSurface(old_screen);
SDL_FreeSurface(old_tmpscreen);
// Blit everything to the screen
internUpdateScreen();
// Make sure that an EVENT_SCREEN_CHANGED gets sent later
_modeChanged = true;
}
void OSystem_WINCE3::update_keyboard() {
// Update the forced keyboard for Monkey Island copy protection
if (_monkeyKeyboard && Scumm::g_scumm->VAR_ROOM != 0xff && Scumm::g_scumm && Scumm::g_scumm->VAR(Scumm::g_scumm->VAR_ROOM) != 108 &&
Scumm::g_scumm->VAR(Scumm::g_scumm->VAR_ROOM) != 90) {
// Switch back to the normal panel now that the keyboard is not used anymore
_monkeyKeyboard = false;
_toolbarHandler.setActive(NAME_MAIN_PANEL);
}
}
void OSystem_WINCE3::internUpdateScreen() {
SDL_Surface *srcSurf, *origSurf;
assert(_hwscreen != NULL);
update_keyboard();
// If the shake position changed, fill the dirty area with blackness
if (_currentShakePos != _newShakePos) {
SDL_Rect blackrect = {0, 0, _screenWidth * _scaleFactorXm / _scaleFactorXd, _newShakePos * _scaleFactorYm / _scaleFactorYd};
if (_adjustAspectRatio)
blackrect.h = real2Aspect(blackrect.h - 1) + 1;
SDL_FillRect(_hwscreen, &blackrect, 0);
_currentShakePos = _newShakePos;
_forceFull = true;
}
// Make sure the mouse is drawn, if it should be drawn.
drawMouse();
// Check whether the palette was changed in the meantime and update the
// screen surface accordingly.
if (_paletteDirtyEnd != 0) {
SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart,
_paletteDirtyStart,
_paletteDirtyEnd - _paletteDirtyStart);
_paletteDirtyEnd = 0;
_forceFull = true;
}
if (!_overlayVisible) {
origSurf = _screen;
srcSurf = _tmpscreen;
}
else {
origSurf = _overlayscreen;
srcSurf = _tmpscreen2;
}
// Force a full redraw if requested
if (_forceFull) {
_numDirtyRects = 1;
_dirtyRectList[0].x = 0;
if (!_zoomDown)
_dirtyRectList[0].y = 0;
else
_dirtyRectList[0].y = _screenHeight / 2;
_dirtyRectList[0].w = _screenWidth;
if (!_zoomUp && !_zoomDown)
_dirtyRectList[0].h = _screenHeight;
else
_dirtyRectList[0].h = _screenHeight / 2;
_toolbarHandler.forceRedraw();
}
//else
// undrawMouse();
// Only draw anything if necessary
if (_numDirtyRects > 0) {
SDL_Rect *r;
SDL_Rect dst;
uint32 srcPitch, dstPitch;
SDL_Rect *last_rect = _dirtyRectList + _numDirtyRects;
bool toolbarVisible = _toolbarHandler.visible();
int toolbarOffset = _toolbarHandler.getOffset();
if (_scalerProc == Normal1x && !_adjustAspectRatio && 0) {
for (r = _dirtyRectList; r != last_rect; ++r) {
dst = *r;
// Check if the toolbar is overwritten
if (!_forceFull && toolbarVisible && r->y + r->h >= toolbarOffset) {
_toolbarHandler.forceRedraw();
}
if (_overlayVisible) {
// FIXME: I don't understand why this is necessary...
dst.x--;
dst.y--;
}
dst.y += _currentShakePos;
if (SDL_BlitSurface(origSurf, r, _hwscreen, &dst) != 0)
error("SDL_BlitSurface failed: %s", SDL_GetError());
}
} else {
for (r = _dirtyRectList; r != last_rect; ++r) {
dst = *r;
dst.x++; // Shift rect by one since 2xSai needs to acces the data around
dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
error("SDL_BlitSurface failed: %s", SDL_GetError());
}
SDL_LockSurface(srcSurf);
SDL_LockSurface(_hwscreen);
srcPitch = srcSurf->pitch;
dstPitch = _hwscreen->pitch;
for (r = _dirtyRectList; r != last_rect; ++r) {
register int dst_y = r->y + _currentShakePos;
register int dst_h = 0;
register int orig_dst_y = 0;
// Check if the toolbar is overwritten
if (!_forceFull && toolbarVisible && r->y + r->h >= toolbarOffset) {
_toolbarHandler.forceRedraw();
}
if (dst_y < _screenHeight) {
dst_h = r->h;
if (dst_h > _screenHeight - dst_y)
dst_h = _screenHeight - dst_y;
dst_y *= _scaleFactorYm;
dst_y /= _scaleFactorYd;
if (_adjustAspectRatio) {
orig_dst_y = dst_y;
dst_y = real2Aspect(dst_y);
}
if (!_zoomDown)
_scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
(byte *)_hwscreen->pixels + (r->x * 2 * _scaleFactorXm / _scaleFactorXd) + dst_y * dstPitch, dstPitch, r->w, dst_h);
else {
_scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
(byte *)_hwscreen->pixels + (r->x * 2 * _scaleFactorXm / _scaleFactorXd) + (dst_y - 240) * dstPitch, dstPitch, r->w, dst_h);
}
}
r->x = r->x * _scaleFactorXm / _scaleFactorXd;
if (!_zoomDown)
r->y = dst_y;
else
r->y = dst_y - 240;
r->w = r->w * _scaleFactorXm / _scaleFactorXd;
r->h = dst_h * _scaleFactorYm / _scaleFactorYd;
/*if (_adjustAspectRatio && orig_dst_y / _scaleFactor < _screenHeight)
r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y);
*/
}
SDL_UnlockSurface(srcSurf);
SDL_UnlockSurface(_hwscreen);
}
// Readjust the dirty rect list in case we are doing a full update.
// This is necessary if shaking is active.
if (_forceFull) {
_dirtyRectList[0].y = 0;
_dirtyRectList[0].h = (_adjustAspectRatio ? 240 : (_zoomUp || _zoomDown ? _screenHeight / 2 : _screenHeight)) * _scaleFactorYm / _scaleFactorYd;
}
}
// Add the toolbar if needed
SDL_Rect toolbar_rect[1];
if (_toolbarHandler.draw(_toolbarLow, &toolbar_rect[0])) {
// It can be drawn, scale it
uint32 srcPitch, dstPitch;
SDL_Surface *toolbarSurface;
if (_screenHeight > 240) {
if (!_toolbarHighDrawn) {
// Resize the toolbar
SDL_LockSurface(_toolbarLow);
SDL_LockSurface(_toolbarHigh);
Normal2x((byte*)_toolbarLow->pixels, _toolbarLow->pitch, (byte*)_toolbarHigh->pixels, _toolbarHigh->pitch, toolbar_rect[0].w, toolbar_rect[0].h);
SDL_UnlockSurface(_toolbarHigh);
SDL_UnlockSurface(_toolbarLow);
_toolbarHighDrawn = true;
}
else
_toolbarHighDrawn = false;
toolbar_rect[0].w *= 2;
toolbar_rect[0].h *= 2;
toolbarSurface = _toolbarHigh;
}
else
toolbarSurface = _toolbarLow;
// Apply the appropriate scaler
SDL_LockSurface(toolbarSurface);
SDL_LockSurface(_hwscreen);
srcPitch = toolbarSurface->pitch;
dstPitch = _hwscreen->pitch;
_scalerProc((byte *)toolbarSurface->pixels, srcPitch, (byte *)_hwscreen->pixels + (_toolbarHandler.getOffset() * _scaleFactorYm / _scaleFactorYd * dstPitch), dstPitch, toolbar_rect[0].w, toolbar_rect[0].h);
SDL_UnlockSurface(toolbarSurface);
SDL_UnlockSurface(_hwscreen);
// And blit it
toolbar_rect[0].y = _toolbarHandler.getOffset();
toolbar_rect[0].x = toolbar_rect[0].x * _scaleFactorXm / _scaleFactorXd;
toolbar_rect[0].y = toolbar_rect[0].y * _scaleFactorYm / _scaleFactorYd;
toolbar_rect[0].w = toolbar_rect[0].w * _scaleFactorXm / _scaleFactorXd;
toolbar_rect[0].h = toolbar_rect[0].h * _scaleFactorYm / _scaleFactorYd;
SDL_UpdateRects(_hwscreen, 1, toolbar_rect);
}
//drawMouse();
// Finally, blit all our changes to the screen
if (_numDirtyRects > 0)
SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
_numDirtyRects = 0;
_forceFull = false;
}
bool OSystem_WINCE3::saveScreenshot(const char *filename) {
assert(_hwscreen != NULL);
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
SDL_SaveBMP(_hwscreen, filename);
return true;
}
// FIXME
// Reuse static or proper mapping
static int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode)
{
if (GUI::Actions::Instance()->mappingActive())
return key;
if (key >= SDLK_F1 && key <= SDLK_F9) {
return key - SDLK_F1 + 315;
} else if (key >= SDLK_KP0 && key <= SDLK_KP9) {
return key - SDLK_KP0 + '0';
} else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) {
return key;
} else if (unicode) {
return unicode;
} else if (key >= 'a' && key <= 'z' && mod & KMOD_SHIFT) {
return key & ~0x20;
} else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) {
return 0;
}
return key;
}
void OSystem_WINCE3::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
assert (_transactionMode == kTransactionNone);
if (_overlayscreen == NULL)
return;
// Clip the coordinates
if (x < 0) {
w += x;
buf -= x;
x = 0;
}
if (y < 0) {
h += y; buf -= y * pitch;
y = 0;
}
if (w > _overlayWidth - x) {
w = _overlayWidth - x;
}
if (h > _overlayHeight - y) {
h = _overlayHeight - y;
}
if (w <= 0 || h <= 0)
return;
// Mark the modified region as dirty
_cksumValid = false;
addDirtyRect(x, y, w, h);
undrawMouse();
if (SDL_LockSurface(_overlayscreen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * 2;
do {
memcpy(dst, buf, w * 2);
dst += _overlayscreen->pitch;
buf += pitch;
} while (--h);
SDL_UnlockSurface(_overlayscreen);
}
void OSystem_WINCE3::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
assert (_transactionMode == kTransactionNone);
assert(src);
if (_screen == NULL)
return;
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
if (((long)src & 3) == 0 && pitch == _screenWidth && x == 0 && y == 0 &&
w == _screenWidth && h == _screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) {
/* Special, optimized case for full screen updates.
* It tries to determine what areas were actually changed,
* and just updates those, on the actual display. */
addDirtyRgnAuto(src);
} else {
/* Clip the coordinates */
if (x < 0) {
w += x;
src -= x;
x = 0;
}
if (y < 0) {
h += y;
src -= y * pitch;
y = 0;
}
if (w > _screenWidth - x) {
w = _screenWidth - x;
}
if (h > _screenHeight - y) {
h = _screenHeight - y;
}
if (w <= 0 || h <= 0)
return;
_cksumValid = false;
addDirtyRect(x, y, w, h);
}
undrawMouse();
// Try to lock the screen surface
if (SDL_LockSurface(_screen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
byte *dst = (byte *)_screen->pixels + y * _screenWidth + x;
if (_screenWidth == pitch && pitch == w) {
memcpy(dst, src, h*w);
} else {
do {
memcpy(dst, src, w);
src += pitch;
dst += _screenWidth;
} while (--h);
}
// Unlock the screen surface
SDL_UnlockSurface(_screen);
}
void OSystem_WINCE3::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) {
undrawMouse();
assert(w <= MAX_MOUSE_W);
assert(h <= MAX_MOUSE_H);
_mouseCurState.w = w;
_mouseCurState.h = h;
_mouseHotspotX = hotspot_x;
_mouseHotspotY = hotspot_y;
_mouseKeyColor = keycolor;
free(_mouseData);
_mouseData = (byte *)malloc(w * h);
memcpy(_mouseData, buf, w * h);
}
void OSystem_WINCE3::setMousePos(int x, int y) {
if (x != _mouseCurState.x || y != _mouseCurState.y) {
undrawMouse();
_mouseCurState.x = x;
_mouseCurState.y = y;
updateScreen();
}
}
void OSystem_WINCE3::internDrawMouse() {
if (_mouseDrawn || !_mouseVisible || !_mouseData)
return;
int x = _mouseCurState.x - _mouseHotspotX;
int y = _mouseCurState.y - _mouseHotspotY;
int w = _mouseCurState.w;
int h = _mouseCurState.h;
byte color;
const byte *src = _mouseData; // Image representing the mouse
// clip the mouse rect, and addjust the src pointer accordingly
if (x < 0) {
w += x;
src -= x;
x = 0;
}
if (y < 0) {
h += y;
src -= y * _mouseCurState.w;
y = 0;
}
if (w > _screenWidth - x)
w = _screenWidth - x;
if (h > _screenHeight - y)
h = _screenHeight - y;
// Quick check to see if anything has to be drawn at all
if (w <= 0 || h <= 0)
return;
// Draw the mouse cursor; backup the covered area in "bak"
if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
// Mark as dirty
addDirtyRect(x, y, w, h);
if (!_overlayVisible) {
byte *bak = _mouseBackupOld; // Surface used to backup the area obscured by the mouse
byte *dst; // Surface we are drawing into
dst = (byte *)_screen->pixels + y * _screenWidth + x;
while (h > 0) {
int width = w;
while (width > 0) {
*bak++ = *dst;
color = *src++;
if (color != _mouseKeyColor) // transparent, don't draw
*dst = color;
dst++;
width--;
}
src += _mouseCurState.w - w;
bak += MAX_MOUSE_W - w;
dst += _screenWidth - w;
h--;
}
} else {
uint16 *bak = (uint16 *)_mouseBackupOld; // Surface used to backup the area obscured by the mouse
byte *dst; // Surface we are drawing into
dst = (byte *)_overlayscreen->pixels + (y + 1) * _overlayscreen->pitch + (x + 1) * 2;
while (h > 0) {
int width = w;
while (width > 0) {
*bak++ = *(uint16 *)dst;
color = *src++;
if (color != 0xFF) // 0xFF = transparent, don't draw
*(uint16 *)dst = RGBToColor(_currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b);
dst += 2;
width--;
}
src += _mouseCurState.w - w;
bak += MAX_MOUSE_W - w;
dst += _overlayscreen->pitch - w * 2;
h--;
}
}
SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);
// Finally, set the flag to indicate the mouse has been drawn
_mouseDrawn = true;
}
void OSystem_WINCE3::undrawMouse() {
assert (_transactionMode == kTransactionNone || _transactionMode == kTransactionCommit);
if (!_mouseDrawn)
return;
_mouseDrawn = false;
int old_mouse_x = _mouseCurState.x - _mouseHotspotX;
int old_mouse_y = _mouseCurState.y - _mouseHotspotY;
int old_mouse_w = _mouseCurState.w;
int old_mouse_h = _mouseCurState.h;
// clip the mouse rect, and addjust the src pointer accordingly
if (old_mouse_x < 0) {
old_mouse_w += old_mouse_x;
old_mouse_x = 0;
}
if (old_mouse_y < 0) {
old_mouse_h += old_mouse_y;
old_mouse_y = 0;
}
if (old_mouse_w > _screenWidth - old_mouse_x)
old_mouse_w = _screenWidth - old_mouse_x;
if (old_mouse_h > _screenHeight - old_mouse_y)
old_mouse_h = _screenHeight - old_mouse_y;
// Quick check to see if anything has to be drawn at all
if (old_mouse_w <= 0 || old_mouse_h <= 0)
return;
if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
int x, y;
if (!_overlayVisible) {
byte *dst, *bak = _mouseBackupOld;
// No need to do clipping here, since drawMouse() did that already
dst = (byte *)_screen->pixels + old_mouse_y * _screenWidth + old_mouse_x;
for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += _screenWidth) {
for (x = 0; x < old_mouse_w; ++x) {
dst[x] = bak[x];
}
}
} else {
byte *dst;
uint16 *bak = (uint16 *)_mouseBackupOld;
// No need to do clipping here, since drawMouse() did that already
dst = (byte *)_overlayscreen->pixels + (old_mouse_y + 1) * _overlayscreen->pitch + (old_mouse_x + 1) * 2;
for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += _overlayscreen->pitch) {
for (x = 0; x < old_mouse_w; ++x) {
*((uint16 *)dst + x) = bak[x];
}
}
}
addDirtyRect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h);
SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);
}
void OSystem_WINCE3::blitCursor() {
}
void OSystem_WINCE3::showOverlay() {
assert (_transactionMode == kTransactionNone);
undrawMouse();
_overlayVisible = true;
clearOverlay();
}
void OSystem_WINCE3::hideOverlay() {
assert (_transactionMode == kTransactionNone);
undrawMouse();
_overlayVisible = false;
clearOverlay();
_forceFull = true;
}
void OSystem_WINCE3::drawMouse() {
// FIXME
if (!(_toolbarHandler.visible() && _mouseCurState.y >= _toolbarHandler.getOffset()) && !_forceHideMouse)
internDrawMouse();
}
void OSystem_WINCE3::fillMouseEvent(Event &event, int x, int y) {
event.mouse.x = x;
event.mouse.y = y;
// Update the "keyboard mouse" coords
_km.x = event.mouse.x;
_km.y = event.mouse.y;
// Adjust for the screen scaling
if (_zoomDown)
event.mouse.y += 240;
event.mouse.x = event.mouse.x * _scaleFactorXd / _scaleFactorXm;
event.mouse.y = event.mouse.y * _scaleFactorYd / _scaleFactorYm;
}
void OSystem_WINCE3::retrieve_mouse_location(int &x, int &y) {
x = _mouseCurState.x;
y = _mouseCurState.y;
x = x * _scaleFactorXm / _scaleFactorXd;
y = y * _scaleFactorYm / _scaleFactorYd;
if (_zoomDown)
y -= 240;
}
void OSystem_WINCE3::warpMouse(int x, int y) {
if (_mouseCurState.x != x || _mouseCurState.y != y) {
SDL_WarpMouse(x * _scaleFactorXm / _scaleFactorXd, y * _scaleFactorYm / _scaleFactorYd);
// SDL_WarpMouse() generates a mouse movement event, so
// set_mouse_pos() would be called eventually. However, the
// cannon script in CoMI calls this function twice each time
// the cannon is reloaded. Unless we update the mouse position
// immediately the second call is ignored, causing the cannon
// to change its aim.
setMousePos(x, y);
}
}
void OSystem_WINCE3::addDirtyRect(int x, int y, int w, int h, bool mouseRect) {
// Align on boundaries
if (_scaleFactorXd > 1) {
while (x % _scaleFactorXd) {
x--;
w++;
}
while (w % _scaleFactorXd) w++;
}
if (_scaleFactorYd > 1) {
while (y % _scaleFactorYd) {
y--;
h++;
}
while (h % _scaleFactorYd) h++;
}
if (_scalerProc == PocketPCHalfZoom) {
// Restrict rect if we're zooming
if (_zoomUp) {
if (y + h >= 240) {
if (y >= 240)
return;
else
h = 240 - y;
}
}
else
if (_zoomDown) {
if (y + h >= 240) {
if (y < 240) {
h = 240 - y;
y = 240;
}
}
else
return;
}
}
OSystem_SDL::addDirtyRect(x, y, w, h, false);
}
// FIXME
// See if some SDL mapping can be useful for HPCs
bool OSystem_WINCE3::pollEvent(Event &event) {
SDL_Event ev;
byte b = 0;
Event temp_event;
DWORD currentTime;
bool keyEvent = false;
memset(&temp_event, 0, sizeof(Event));
memset(&event, 0, sizeof(Event));
handleKbdMouse();
// If the screen mode changed, send an EVENT_SCREEN_CHANGED
if (_modeChanged) {
_modeChanged = false;
event.type = EVENT_SCREEN_CHANGED;
return true;
}
CEDevice::wakeUp();
if (_isSmartphone)
currentTime = GetTickCount();
while(SDL_PollEvent(&ev)) {
switch(ev.type) {
case SDL_KEYDOWN:
// KMOD_RESERVED is used if the key has been injected by an external buffer
if (ev.key.keysym.mod != KMOD_RESERVED) {
if (_isSmartphone) {
keyEvent = true;
_lastKeyPressed = ev.key.keysym.sym;
_keyRepeatTime = currentTime;
_keyRepeat = 0;
}
if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, true))
return true;
}
event.type = EVENT_KEYDOWN;
event.kbd.keycode = ev.key.keysym.sym;
event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
if (GUI_Actions::Instance()->mappingActive())
event.kbd.flags = 0xFF;
return true;
case SDL_KEYUP:
// KMOD_RESERVED is used if the key has been injected by an external buffer
if (ev.key.keysym.mod != KMOD_RESERVED) {
if (_isSmartphone) {
keyEvent = true;
_lastKeyPressed = 0;
}
if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, false))
return true;
}
event.type = EVENT_KEYUP;
event.kbd.keycode = ev.key.keysym.sym;
event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
if (GUI_Actions::Instance()->mappingActive())
event.kbd.flags = 0xFF;
return true;
case SDL_MOUSEMOTION:
event.type = EVENT_MOUSEMOVE;
fillMouseEvent(event, ev.motion.x, ev.motion.y);
setMousePos(event.mouse.x, event.mouse.y);
return true;
case SDL_MOUSEBUTTONDOWN:
if (ev.button.button == SDL_BUTTON_LEFT)
temp_event.type = EVENT_LBUTTONDOWN;
else if (ev.button.button == SDL_BUTTON_RIGHT)
temp_event.type = EVENT_RBUTTONDOWN;
else
break;
fillMouseEvent(temp_event, ev.button.x, ev.button.y);
// Check keyboard tap zone
if (temp_event.mouse.y <= 20) {
// Already tap initiated ?
if (_tapTime) {
int deltaX;
int deltaY;
if (temp_event.mouse.x > _tapX)
deltaX = temp_event.mouse.x - _tapX;
else
deltaX = _tapX - temp_event.mouse.x;
if (temp_event.mouse.y > _tapY)
deltaY = temp_event.mouse.y - _tapY;
else
deltaY = _tapY - temp_event.mouse.y;
if (deltaX <= 5 && deltaY <= 5 && (GetTickCount() - _tapTime < 1000))
swap_panel_visibility();
_tapTime = 0;
}
else {
_tapTime = GetTickCount();
_tapX = temp_event.mouse.x;
_tapY = temp_event.mouse.y;
}
}
if (_toolbarHandler.action(temp_event.mouse.x, temp_event.mouse.y, true)) {
if (!_toolbarHandler.drawn())
internUpdateScreen();
if (_newOrientation != _orientationLandscape && _mode == GFX_NORMAL) {
_orientationLandscape = _newOrientation;
ConfMan.set("landscape", _orientationLandscape);
ConfMan.flushToDisk();
setGraphicsMode(GFX_NORMAL);
hotswapGFXMode();
}
}
else {
if (!_freeLook)
memcpy(&event, &temp_event, sizeof(Event));
}
return true;
case SDL_MOUSEBUTTONUP:
if (ev.button.button == SDL_BUTTON_LEFT)
temp_event.type = EVENT_LBUTTONUP;
else if (ev.button.button == SDL_BUTTON_RIGHT)
temp_event.type = EVENT_RBUTTONUP;
else
break;
fillMouseEvent(temp_event, ev.button.x, ev.button.y);
if (_toolbarHandler.action(temp_event.mouse.x, temp_event.mouse.y, false)) {
if (!_toolbarHandler.drawn())
internUpdateScreen();
}
else {
if (!_freeLook)
memcpy(&event, &temp_event, sizeof(Event));
}
return true;
case SDL_VIDEOEXPOSE:
_forceFull = true;
break;
case SDL_QUIT:
event.type = EVENT_QUIT;
return true;
}
}
// Simulate repeated key for Smartphones
if (!keyEvent) {
if (_isSmartphone) {
if (_lastKeyPressed) {
if (currentTime > _keyRepeatTime + _keyRepeatTrigger) {
_keyRepeatTime = currentTime;
_keyRepeat++;
GUI_Actions::Instance()->performMapped(_lastKeyPressed, true);
}
}
}
}
return false;
}
void OSystem_WINCE3::quit() {
fclose(stdout_file);
fclose(stderr_file);
if (gDebugLevel <= 0) {
DeleteFile(TEXT("\\scummvm_stdout.txt"));
DeleteFile(TEXT("\\scummvm_stderr.txt"));
}
CEDevice::end();
OSystem_SDL::quit();
}
int OSystem_WINCE3::_platformScreenWidth;
int OSystem_WINCE3::_platformScreenHeight;
bool OSystem_WINCE3::_isOzone;
OSystem_WINCE3::zoneDesc OSystem_WINCE3::_zones[TOTAL_ZONES] = {
{ 0, 0, 320, 145 },
{ 0, 145, 150, 55 },
{ 150, 145, 170, 55 }
};