sync with scummvm dated 03 july 2011

This commit is contained in:
Pawel Kolodziejski 2011-07-20 06:58:19 +02:00
parent 60611723ff
commit 5bf4f9316b
112 changed files with 3581 additions and 1675 deletions

10
.gitignore vendored
View file

@ -23,9 +23,12 @@ lib*.a
/.project /.project
/.cproject /.cproject
/.settings /.settings
/.autotools
/Icon.* /Icon.*
/build /build
/staging
/dists/codeblocks/*.cbp /dists/codeblocks/*.cbp
/dists/codeblocks/*.depend /dists/codeblocks/*.depend
/dists/codeblocks/*.layout /dists/codeblocks/*.layout
@ -43,6 +46,7 @@ project.xcworkspace
/dists/msvc*/[Dd]ebug*/ /dists/msvc*/[Dd]ebug*/
/dists/msvc*/[Rr]elease*/ /dists/msvc*/[Rr]elease*/
/dists/msvc*/[Aa]nalysis*/
/dists/msvc*/*.lib /dists/msvc*/*.lib
/dists/msvc*/*.SAV /dists/msvc*/*.SAV
/dists/msvc*/*.dat /dists/msvc*/*.dat
@ -87,3 +91,9 @@ ipch/
#Ignore default Visual Studio build folders #Ignore default Visual Studio build folders
[Dd]ebug*/ [Dd]ebug*/
[Rr]elease*/ [Rr]elease*/
#Ignore Qt Creator project files
Residual.config
Residual.creator
Residual.files
Residual.includes

View file

@ -219,8 +219,6 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
} }
} }
reslt = 0;
// If the selected driver did not match the flags setting, // If the selected driver did not match the flags setting,
// we try to determine a suitable and "optimal" music driver. // we try to determine a suitable and "optimal" music driver.
const MusicPlugin::List p = MusicMan.getPlugins(); const MusicPlugin::List p = MusicMan.getPlugins();
@ -231,7 +229,7 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
if ((flags & MDT_MIDI) && !skipMidi) { if ((flags & MDT_MIDI) && !skipMidi) {
// If a preferred MT32 or GM device has been selected that device gets returned if available. // If a preferred MT32 or GM device has been selected that device gets returned if available.
Common::String devStr; Common::String devStr;
if (flags & MDT_PREFER_MT32) if (flags & MDT_PREFER_MT32)
devStr = ConfMan.get("mt32_device"); devStr = ConfMan.get("mt32_device");
else if (flags & MDT_PREFER_GM) else if (flags & MDT_PREFER_GM)
devStr = ConfMan.get("gm_device"); devStr = ConfMan.get("gm_device");
@ -263,12 +261,11 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
// If the preferred (expressly requested) device cannot be used we display a warning and continue. // If the preferred (expressly requested) device cannot be used we display a warning and continue.
// Don't warn about the failing device if we did already (this becomes relevant if the failing // Don't warn about the failing device if we did already (this becomes relevant if the failing
// device is selected as preferred device and also as GM or MT-32 device). // device is selected as preferred device and also as GM or MT-32 device).
if (failedDevStr != getDeviceString(hdl, MidiDriver::kDeviceName)) { if (failedDevStr != getDeviceString(hdl, MidiDriver::kDeviceName)) {
Common::String warningMsg = Common::String::format(_("The preferred audio device '%s' cannot be used. See log file for more information. Attempting to fall back to the next available device..."), getDeviceString(hdl, MidiDriver::kDeviceName).c_str()); Common::String warningMsg = Common::String::format(_("The preferred audio device '%s' cannot be used. See log file for more information. Attempting to fall back to the next available device..."), getDeviceString(hdl, MidiDriver::kDeviceName).c_str());
GUI::MessageDialog dialog(warningMsg); GUI::MessageDialog dialog(warningMsg);
dialog.runModal(); dialog.runModal();
} }
hdl = 0;
} }
} }
@ -283,15 +280,12 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
hdl = d->getHandle(); hdl = d->getHandle();
if (checkDevice(hdl)) if (checkDevice(hdl))
return hdl; return hdl;
else
// No warning here, since the user hasn't expressly requested anything.
hdl = 0;
} }
} }
} }
} }
// Now we default to the first available device with music type 'MT_GM' if not // Now we default to the first available device with music type 'MT_GM' if not
// MT-32 is preferred or if MT-32 is preferred but all other devices have failed. // MT-32 is preferred or if MT-32 is preferred but all other devices have failed.
if (!(flags & MDT_PREFER_MT32) || flags == (MDT_PREFER_MT32 | MDT_MIDI)) { if (!(flags & MDT_PREFER_MT32) || flags == (MDT_PREFER_MT32 | MDT_MIDI)) {
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) { for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
@ -301,9 +295,6 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
hdl = d->getHandle(); hdl = d->getHandle();
if (checkDevice(hdl)) if (checkDevice(hdl))
return hdl; return hdl;
else
// No warning here, since the user hasn't expressly requested anything.
hdl = 0;
} }
} }
} }
@ -357,15 +348,12 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
hdl = d->getHandle(); hdl = d->getHandle();
if (checkDevice(hdl)) if (checkDevice(hdl))
return hdl; return hdl;
else
// No warning here, since the user hasn't expressly requested anything.
hdl = 0;
} }
} }
} }
} }
return reslt; return 0;
} }
MidiDriver *MidiDriver::createMidi(MidiDriver::DeviceHandle handle) { MidiDriver *MidiDriver::createMidi(MidiDriver::DeviceHandle handle) {

View file

@ -93,6 +93,13 @@ public:
*/ */
void setVolume(const byte volume); void setVolume(const byte volume);
/**
* Gets the channel's own volume.
*
* @return volume
*/
byte getVolume();
/** /**
* Sets the channel's balance setting. * Sets the channel's balance setting.
* *
@ -100,6 +107,13 @@ public:
*/ */
void setBalance(const int8 balance); void setBalance(const int8 balance);
/**
* Gets the channel's balance setting.
*
* @return balance
*/
int8 getBalance();
/** /**
* Notifies the channel that the global sound type * Notifies the channel that the global sound type
* volume settings changed. * volume settings changed.
@ -342,6 +356,14 @@ void MixerImpl::setChannelVolume(SoundHandle handle, byte volume) {
_channels[index]->setVolume(volume); _channels[index]->setVolume(volume);
} }
byte MixerImpl::getChannelVolume(SoundHandle handle) {
const int index = handle._val % NUM_CHANNELS;
if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
return 0;
return _channels[index]->getVolume();
}
void MixerImpl::setChannelBalance(SoundHandle handle, int8 balance) { void MixerImpl::setChannelBalance(SoundHandle handle, int8 balance) {
Common::StackLock lock(_mutex); Common::StackLock lock(_mutex);
@ -352,6 +374,14 @@ void MixerImpl::setChannelBalance(SoundHandle handle, int8 balance) {
_channels[index]->setBalance(balance); _channels[index]->setBalance(balance);
} }
int8 MixerImpl::getChannelBalance(SoundHandle handle) {
const int index = handle._val % NUM_CHANNELS;
if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
return 0;
return _channels[index]->getBalance();
}
uint32 MixerImpl::getSoundElapsedTime(SoundHandle handle) { uint32 MixerImpl::getSoundElapsedTime(SoundHandle handle) {
return getElapsedTime(handle).msecs(); return getElapsedTime(handle).msecs();
} }
@ -482,11 +512,19 @@ void Channel::setVolume(const byte volume) {
updateChannelVolumes(); updateChannelVolumes();
} }
byte Channel::getVolume() {
return _volume;
}
void Channel::setBalance(const int8 balance) { void Channel::setBalance(const int8 balance) {
_balance = balance; _balance = balance;
updateChannelVolumes(); updateChannelVolumes();
} }
int8 Channel::getBalance() {
return _balance;
}
void Channel::updateChannelVolumes() { void Channel::updateChannelVolumes() {
// From the channel balance/volume and the global volume, we compute // From the channel balance/volume and the global volume, we compute
// the effective volume for the left and right channel. Note the // the effective volume for the left and right channel. Note the

View file

@ -210,6 +210,14 @@ public:
*/ */
virtual void setChannelVolume(SoundHandle handle, byte volume) = 0; virtual void setChannelVolume(SoundHandle handle, byte volume) = 0;
/**
* Get the channel volume for the given handle.
*
* @param handle the sound to affect
* @return channel volume
*/
virtual byte getChannelVolume(SoundHandle handle) = 0;
/** /**
* Set the channel balance for the given handle. * Set the channel balance for the given handle.
* *
@ -219,6 +227,14 @@ public:
*/ */
virtual void setChannelBalance(SoundHandle handle, int8 balance) = 0; virtual void setChannelBalance(SoundHandle handle, int8 balance) = 0;
/**
* Get the channel balance for the given handle.
*
* @param handle the sound to affect
* @return channel balance
*/
virtual int8 getChannelBalance(SoundHandle handle) = 0;
/** /**
* Get approximation of for how long the channel has been playing. * Get approximation of for how long the channel has been playing.
*/ */

View file

@ -105,7 +105,9 @@ public:
virtual bool isSoundTypeMuted(SoundType type) const; virtual bool isSoundTypeMuted(SoundType type) const;
virtual void setChannelVolume(SoundHandle handle, byte volume); virtual void setChannelVolume(SoundHandle handle, byte volume);
virtual byte getChannelVolume(SoundHandle handle);
virtual void setChannelBalance(SoundHandle handle, int8 balance); virtual void setChannelBalance(SoundHandle handle, int8 balance);
virtual int8 getChannelBalance(SoundHandle handle);
virtual uint32 getSoundElapsedTime(SoundHandle handle); virtual uint32 getSoundElapsedTime(SoundHandle handle);
virtual Timestamp getElapsedTime(SoundHandle handle); virtual Timestamp getElapsedTime(SoundHandle handle);

View file

@ -33,7 +33,10 @@ void MidiChannel_MPU401::init(MidiDriver *owner, byte channel) {
bool MidiChannel_MPU401::allocate() { bool MidiChannel_MPU401::allocate() {
if (_allocated) if (_allocated)
return false; return false;
return (_allocated = true);
_allocated = true;
return true;
} }
MidiDriver *MidiChannel_MPU401::device() { MidiDriver *MidiChannel_MPU401::device() {

View file

@ -298,6 +298,9 @@ public:
_bufferSize = osamp; _bufferSize = osamp;
} }
if (!_buffer)
error("[CopyRateConverter::flow] Cannot allocate memory for temp buffer");
// Read up to 'osamp' samples into our temporary buffer // Read up to 'osamp' samples into our temporary buffer
len = input.readBuffer(_buffer, osamp); len = input.readBuffer(_buffer, osamp);

View file

@ -44,6 +44,7 @@
#include "graphics/fontman.h" #include "graphics/fontman.h"
#include "graphics/surface.h" #include "graphics/surface.h"
#include "graphics/pixelformat.h" #include "graphics/pixelformat.h"
//#include "graphics/palette.h"
#include "graphics/font.h" #include "graphics/font.h"
class MidiChannel_MT32 : public MidiChannel_MPU401 { class MidiChannel_MT32 : public MidiChannel_MPU401 {
@ -570,8 +571,8 @@ bool MT32EmuMusicPlugin::checkDevice(MidiDriver::DeviceHandle) const {
warning("The MT-32 emulator requires one of the two following file sets (not bundled with ScummVM):\n Either 'MT32_CONTROL.ROM' and 'MT32_PCM.ROM' or 'CM32L_CONTROL.ROM' and 'CM32L_PCM.ROM'"); warning("The MT-32 emulator requires one of the two following file sets (not bundled with ScummVM):\n Either 'MT32_CONTROL.ROM' and 'MT32_PCM.ROM' or 'CM32L_CONTROL.ROM' and 'CM32L_PCM.ROM'");
return false; return false;
} }
return true; return true;
} }
Common::Error MT32EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { Common::Error MT32EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {

View file

@ -725,6 +725,8 @@ static int OPLOpenTable(void) {
ENV_CURVE = (int *)malloc(sizeof(int) * (2*EG_ENT+1)); ENV_CURVE = (int *)malloc(sizeof(int) * (2*EG_ENT+1));
if (!ENV_CURVE)
error("[OPLOpenTable] Cannot allocate memory");
/* envelope counter -> envelope output table */ /* envelope counter -> envelope output table */
for (i=0; i < EG_ENT; i++) { for (i=0; i < EG_ENT; i++) {

View file

@ -113,7 +113,7 @@ public:
* @return true if the CD drive was inited succesfully * @return true if the CD drive was inited succesfully
*/ */
virtual bool openCD(int drive) = 0; virtual bool openCD(int drive) = 0;
/** /**
* Poll CD status. * Poll CD status.
* @return true if CD audio is playing * @return true if CD audio is playing

51
backends/base-backend.cpp Normal file
View file

@ -0,0 +1,51 @@
/* 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$
*
*/
#include "backends/base-backend.h"
#ifndef DISABLE_DEFAULT_EVENT_MANAGER
#include "backends/events/default/default-events.h"
#endif
#ifndef DISABLE_DEFAULT_AUDIOCD_MANAGER
#include "backends/audiocd/default/default-audiocd.h"
#endif
void BaseBackend::initBackend() {
// Init Event manager
#ifndef DISABLE_DEFAULT_EVENT_MANAGER
if (!_eventManager)
_eventManager = new DefaultEventManager(getDefaultEventSource());
#endif
// Init audio CD manager
#ifndef DISABLE_DEFAULT_AUDIOCD_MANAGER
if (!_audiocdManager)
_audiocdManager = new DefaultAudioCDManager();
#endif
OSystem::initBackend();
}

43
backends/base-backend.h Normal file
View file

@ -0,0 +1,43 @@
/* 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.
*
*/
#ifndef BACKENDS_BASE_BACKEND_H
#define BACKENDS_BASE_BACKEND_H
#include "common/system.h"
#include "common/events.h"
class BaseBackend : public OSystem {
protected:
virtual Common::EventSource *getDefaultEventSource() = 0;
public:
virtual void initBackend();
};
class EventsBaseBackend : public BaseBackend, Common::EventSource {
protected:
virtual Common::EventSource *getDefaultEventSource() { return this; }
public:
};
#endif

View file

@ -26,6 +26,7 @@
#include "common/system.h" #include "common/system.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/translation.h"
#include "backends/events/default/default-events.h" #include "backends/events/default/default-events.h"
#include "backends/keymapper/keymapper.h" #include "backends/keymapper/keymapper.h"
#include "backends/keymapper/remap-dialog.h" #include "backends/keymapper/remap-dialog.h"
@ -218,7 +219,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
if (ConfMan.getBool("confirm_exit")) { if (ConfMan.getBool("confirm_exit")) {
if (g_engine) if (g_engine)
g_engine->pauseEngine(true); g_engine->pauseEngine(true);
GUI::MessageDialog alert("Do you really want to return to the Launcher?", "Launcher", "Cancel"); GUI::MessageDialog alert(_("Do you really want to return to the Launcher?"), _("Launcher"), _("Cancel"));
result = _shouldRTL = (alert.runModal() == GUI::kMessageOK); result = _shouldRTL = (alert.runModal() == GUI::kMessageOK);
if (g_engine) if (g_engine)
g_engine->pauseEngine(false); g_engine->pauseEngine(false);
@ -240,7 +241,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_confirmExitDialogActive = true; _confirmExitDialogActive = true;
if (g_engine) if (g_engine)
g_engine->pauseEngine(true); g_engine->pauseEngine(true);
GUI::MessageDialog alert("Do you really want to quit?", "Quit", "Cancel"); GUI::MessageDialog alert(_("Do you really want to quit?"), _("Quit"), _("Cancel"));
result = _shouldQuit = (alert.runModal() == GUI::kMessageOK); result = _shouldQuit = (alert.runModal() == GUI::kMessageOK);
if (g_engine) if (g_engine)
g_engine->pauseEngine(false); g_engine->pauseEngine(false);

View file

@ -208,7 +208,6 @@ bool SdlEventSource::pollEvent(Common::Event &event) {
}*/ }*/
SDL_Event ev; SDL_Event ev;
ev.type = SDL_NOEVENT;
while (SDL_PollEvent(&ev)) { while (SDL_PollEvent(&ev)) {
preprocessEvents(&ev); preprocessEvents(&ev);
if (dispatchSDLEvent(ev, event)) if (dispatchSDLEvent(ev, event))
@ -306,7 +305,7 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
event.type = Common::EVENT_KEYDOWN; event.type = Common::EVENT_KEYDOWN;
event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, (Uint16)ev.key.keysym.unicode);
return true; return true;
} }
@ -350,7 +349,7 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
event.type = Common::EVENT_KEYUP; event.type = Common::EVENT_KEYUP;
event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, (Uint16)ev.key.keysym.unicode);
// Ctrl-Alt-<key> will change the GFX mode // Ctrl-Alt-<key> will change the GFX mode
SDLModToOSystemKeyFlags(mod, event); SDLModToOSystemKeyFlags(mod, event);
@ -420,19 +419,19 @@ bool SdlEventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
switch (ev.jbutton.button) { switch (ev.jbutton.button) {
case JOY_BUT_ESCAPE: case JOY_BUT_ESCAPE:
event.kbd.keycode = Common::KEYCODE_ESCAPE; event.kbd.keycode = Common::KEYCODE_ESCAPE;
event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_ESCAPE, (SDLMod)ev.key.keysym.mod, 0);
break; break;
case JOY_BUT_PERIOD: case JOY_BUT_PERIOD:
event.kbd.keycode = Common::KEYCODE_PERIOD; event.kbd.keycode = Common::KEYCODE_PERIOD;
event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_PERIOD, (SDLMod)ev.key.keysym.mod, 0);
break; break;
case JOY_BUT_SPACE: case JOY_BUT_SPACE:
event.kbd.keycode = Common::KEYCODE_SPACE; event.kbd.keycode = Common::KEYCODE_SPACE;
event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_SPACE, (SDLMod)ev.key.keysym.mod, 0);
break; break;
case JOY_BUT_F5: case JOY_BUT_F5:
event.kbd.keycode = Common::KEYCODE_F5; event.kbd.keycode = Common::KEYCODE_F5;
event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_F5, (SDLMod)ev.key.keysym.mod, 0);
break; break;
} }
} }
@ -451,19 +450,19 @@ bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
switch (ev.jbutton.button) { switch (ev.jbutton.button) {
case JOY_BUT_ESCAPE: case JOY_BUT_ESCAPE:
event.kbd.keycode = Common::KEYCODE_ESCAPE; event.kbd.keycode = Common::KEYCODE_ESCAPE;
event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_ESCAPE, (SDLMod)ev.key.keysym.mod, 0);
break; break;
case JOY_BUT_PERIOD: case JOY_BUT_PERIOD:
event.kbd.keycode = Common::KEYCODE_PERIOD; event.kbd.keycode = Common::KEYCODE_PERIOD;
event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_PERIOD, (SDLMod)ev.key.keysym.mod, 0);
break; break;
case JOY_BUT_SPACE: case JOY_BUT_SPACE:
event.kbd.keycode = Common::KEYCODE_SPACE; event.kbd.keycode = Common::KEYCODE_SPACE;
event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_SPACE, (SDLMod)ev.key.keysym.mod, 0);
break; break;
case JOY_BUT_F5: case JOY_BUT_F5:
event.kbd.keycode = Common::KEYCODE_F5; event.kbd.keycode = Common::KEYCODE_F5;
event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(SDLK_F5, (SDLMod)ev.key.keysym.mod, 0);
break; break;
} }
} }

View file

@ -20,19 +20,19 @@
* *
*/ */
#if !defined(BACKEND_EVENTS_SDL_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER) #ifndef BACKEND_EVENTS_SDL_H
#define BACKEND_EVENTS_SDL_H #define BACKEND_EVENTS_SDL_H
#include "backends/events/default/default-events.h"
#include "backends/platform/sdl/sdl-sys.h" #include "backends/platform/sdl/sdl-sys.h"
#include "common/events.h"
/** /**
* The SDL event source. * The SDL event source.
*/ */
class SdlEventSource : public Common::EventSource { class SdlEventSource : public Common::EventSource {
public: public:
SdlEventSource(); SdlEventSource();
virtual ~SdlEventSource(); virtual ~SdlEventSource();
@ -69,7 +69,7 @@ protected:
/** Scroll lock state - since SDL doesn't track it */ /** Scroll lock state - since SDL doesn't track it */
bool _scrollLock; bool _scrollLock;
/** Joystick */ /** Joystick */
SDL_Joystick *_joystick; SDL_Joystick *_joystick;

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#if defined(POSIX) #if defined(POSIX) || defined(PLAYSTATION3)
// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h. // Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
// Also with clock() in sys/time.h in some Mac OS X SDKs. // Also with clock() in sys/time.h in some Mac OS X SDKs.

View file

@ -30,6 +30,7 @@
* Parts of this class are documented in the base interface class, FilesystemFactory. * Parts of this class are documented in the base interface class, FilesystemFactory.
*/ */
class POSIXFilesystemFactory : public FilesystemFactory { class POSIXFilesystemFactory : public FilesystemFactory {
protected:
virtual AbstractFSNode *makeRootFileNode() const; virtual AbstractFSNode *makeRootFileNode() const;
virtual AbstractFSNode *makeCurrentDirectoryFileNode() const; virtual AbstractFSNode *makeCurrentDirectoryFileNode() const;
virtual AbstractFSNode *makeFileNodePath(const Common::String &path) const; virtual AbstractFSNode *makeFileNodePath(const Common::String &path) const;

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#if defined(POSIX) #if defined(POSIX) || defined(PLAYSTATION3)
// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h. // Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
// Also with clock() in sys/time.h in some Mac OS X SDKs. // Also with clock() in sys/time.h in some Mac OS X SDKs.

View file

@ -54,7 +54,7 @@ bool WindowsFilesystemNode::isWritable() const {
return _access(_path.c_str(), W_OK) == 0; return _access(_path.c_str(), W_OK) == 0;
} }
void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, WIN32_FIND_DATA* find_data) { void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, bool hidden, WIN32_FIND_DATA* find_data) {
WindowsFilesystemNode entry; WindowsFilesystemNode entry;
char *asciiName = toAscii(find_data->cFileName); char *asciiName = toAscii(find_data->cFileName);
bool isDirectory; bool isDirectory;
@ -63,6 +63,10 @@ void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const c
if (!strcmp(asciiName, ".") || !strcmp(asciiName, "..")) if (!strcmp(asciiName, ".") || !strcmp(asciiName, ".."))
return; return;
// Skip hidden files if asked
if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) && !hidden)
return;
isDirectory = (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? true : false); isDirectory = (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? true : false);
if ((!isDirectory && mode == Common::FSNode::kListDirectoriesOnly) || if ((!isDirectory && mode == Common::FSNode::kListDirectoriesOnly) ||
@ -163,8 +167,6 @@ AbstractFSNode *WindowsFilesystemNode::getChild(const Common::String &n) const {
bool WindowsFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { bool WindowsFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
assert(_isDirectory); assert(_isDirectory);
//TODO: honor the hidden flag
if (_isPseudoRoot) { if (_isPseudoRoot) {
#ifndef _WIN32_WCE #ifndef _WIN32_WCE
// Drives enumeration // Drives enumeration
@ -200,10 +202,10 @@ bool WindowsFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
return false; return false;
addFile(myList, mode, _path.c_str(), &desc); addFile(myList, mode, _path.c_str(), hidden, &desc);
while (FindNextFile(handle, &desc)) while (FindNextFile(handle, &desc))
addFile(myList, mode, _path.c_str(), &desc); addFile(myList, mode, _path.c_str(), hidden, &desc);
FindClose(handle); FindClose(handle);
} }

View file

@ -37,7 +37,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <tchar.h> #include <tchar.h>
#undef ARRAYSIZE
/** /**
* Implementation of the ScummVM file system API based on Windows API. * Implementation of the ScummVM file system API based on Windows API.
@ -94,12 +93,13 @@ private:
* Adds a single WindowsFilesystemNode to a given list. * Adds a single WindowsFilesystemNode to a given list.
* This method is used by getChildren() to populate the directory entries list. * This method is used by getChildren() to populate the directory entries list.
* *
* @param list List to put the file entry node in. * @param list List to put the file entry node in.
* @param mode Mode to use while adding the file entry to the list. * @param mode Mode to use while adding the file entry to the list.
* @param base Common::String with the directory being listed. * @param base Common::String with the directory being listed.
* @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find. * @param hidden true if hidden files should be added, false otherwise
* @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find.
*/ */
static void addFile(AbstractFSList &list, ListMode mode, const char *base, WIN32_FIND_DATA* find_data); static void addFile(AbstractFSList &list, ListMode mode, const char *base, bool hidden, WIN32_FIND_DATA* find_data);
/** /**
* Converts a Unicode string to Ascii format. * Converts a Unicode string to Ascii format.

View file

@ -27,6 +27,8 @@
#include "common/noncopyable.h" #include "common/noncopyable.h"
#include "common/keyboard.h" #include "common/keyboard.h"
//#include "graphics/palette.h"
/** /**
* Abstract class for graphics manager. Subclasses * Abstract class for graphics manager. Subclasses
* implement the real functionality. * implement the real functionality.

View file

@ -24,7 +24,7 @@
#if defined(SDL_BACKEND) #if defined(SDL_BACKEND)
#include "backends/graphics/sdl/sdl-graphics.h" #include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
#include "backends/events/sdl/sdl-events.h" #include "backends/events/sdl/sdl-events.h"
#include "backends/platform/sdl/sdl.h" #include "backends/platform/sdl/sdl.h"
#include "common/config-manager.h" #include "common/config-manager.h"
@ -40,7 +40,7 @@
#include "graphics/scaler.h" #include "graphics/scaler.h"
#include "graphics/surface.h" #include "graphics/surface.h"
SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *sdlEventSource) SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource)
: :
_sdlEventSource(sdlEventSource), _sdlEventSource(sdlEventSource),
_screen(0), _screen(0),
@ -69,18 +69,18 @@ SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *sdlEventSource)
#endif #endif
} }
SdlGraphicsManager::~SdlGraphicsManager() { SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() {
// Unregister the event observer // Unregister the event observer
if (g_system->getEventManager()->getEventDispatcher() != NULL) if (g_system->getEventManager()->getEventDispatcher() != NULL)
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
} }
void SdlGraphicsManager::initEventObserver() { void SurfaceSdlGraphicsManager::initEventObserver() {
// Register the graphics manager as a event observer // Register the graphics manager as a event observer
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
} }
bool SdlGraphicsManager::hasFeature(OSystem::Feature f) { bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) {
return return
#ifdef USE_OPENGL #ifdef USE_OPENGL
(f == OSystem::kFeatureOpenGL); (f == OSystem::kFeatureOpenGL);
@ -89,19 +89,19 @@ bool SdlGraphicsManager::hasFeature(OSystem::Feature f) {
#endif #endif
} }
void SdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { void SurfaceSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
} }
bool SdlGraphicsManager::getFeatureState(OSystem::Feature f) { bool SurfaceSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
return false; return false;
} }
void SdlGraphicsManager::launcherInitSize(uint w, uint h) { void SurfaceSdlGraphicsManager::launcherInitSize(uint w, uint h) {
closeOverlay(); closeOverlay();
setupScreen(w, h, false, false); setupScreen(w, h, false, false);
} }
byte *SdlGraphicsManager::setupScreen(int screenW, int screenH, bool fullscreen, bool accel3d) { byte *SurfaceSdlGraphicsManager::setupScreen(int screenW, int screenH, bool fullscreen, bool accel3d) {
uint32 sdlflags; uint32 sdlflags;
int bpp; int bpp;
@ -220,7 +220,7 @@ byte *SdlGraphicsManager::setupScreen(int screenW, int screenH, bool fullscreen,
#define BITMAP_TEXTURE_SIZE 256 #define BITMAP_TEXTURE_SIZE 256
void SdlGraphicsManager::updateScreen() { void SurfaceSdlGraphicsManager::updateScreen() {
#ifdef USE_OPENGL #ifdef USE_OPENGL
if (_opengl) { if (_opengl) {
if (_overlayVisible) { if (_overlayVisible) {
@ -324,11 +324,11 @@ void SdlGraphicsManager::updateScreen() {
} }
} }
int16 SdlGraphicsManager::getHeight() { int16 SurfaceSdlGraphicsManager::getHeight() {
return _screen->h; return _screen->h;
} }
int16 SdlGraphicsManager::getWidth() { int16 SurfaceSdlGraphicsManager::getWidth() {
return _screen->w; return _screen->w;
} }
@ -337,7 +337,7 @@ int16 SdlGraphicsManager::getWidth() {
#pragma mark --- Overlays --- #pragma mark --- Overlays ---
#pragma mark - #pragma mark -
void SdlGraphicsManager::showOverlay() { void SurfaceSdlGraphicsManager::showOverlay() {
if (_overlayVisible) if (_overlayVisible)
return; return;
@ -346,7 +346,7 @@ void SdlGraphicsManager::showOverlay() {
clearOverlay(); clearOverlay();
} }
void SdlGraphicsManager::hideOverlay() { void SurfaceSdlGraphicsManager::hideOverlay() {
if (!_overlayVisible) if (!_overlayVisible)
return; return;
@ -356,7 +356,7 @@ void SdlGraphicsManager::hideOverlay() {
clearOverlay(); clearOverlay();
} }
void SdlGraphicsManager::clearOverlay() { void SurfaceSdlGraphicsManager::clearOverlay() {
if (!_overlayVisible) if (!_overlayVisible)
return; return;
@ -385,7 +385,7 @@ void SdlGraphicsManager::clearOverlay() {
_overlayDirty = true; _overlayDirty = true;
} }
void SdlGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) { void SurfaceSdlGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) {
if (_overlayscreen == NULL) if (_overlayscreen == NULL)
return; return;
@ -403,7 +403,7 @@ void SdlGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) {
SDL_UnlockSurface(_overlayscreen); SDL_UnlockSurface(_overlayscreen);
} }
void SdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { void SurfaceSdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
if (_overlayscreen == NULL) if (_overlayscreen == NULL)
return; return;
@ -444,7 +444,7 @@ void SdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, i
SDL_UnlockSurface(_overlayscreen); SDL_UnlockSurface(_overlayscreen);
} }
void SdlGraphicsManager::closeOverlay() { void SurfaceSdlGraphicsManager::closeOverlay() {
if (_overlayscreen) { if (_overlayscreen) {
SDL_FreeSurface(_overlayscreen); SDL_FreeSurface(_overlayscreen);
_overlayscreen = NULL; _overlayscreen = NULL;
@ -462,16 +462,16 @@ void SdlGraphicsManager::closeOverlay() {
#pragma mark --- Mouse --- #pragma mark --- Mouse ---
#pragma mark - #pragma mark -
bool SdlGraphicsManager::showMouse(bool visible) { bool SurfaceSdlGraphicsManager::showMouse(bool visible) {
SDL_ShowCursor(visible); SDL_ShowCursor(visible);
return true; return true;
} }
void SdlGraphicsManager::warpMouse(int x, int y) { void SurfaceSdlGraphicsManager::warpMouse(int x, int y) {
SDL_WarpMouse(x, y); SDL_WarpMouse(x, y);
} }
bool SdlGraphicsManager::notifyEvent(const Common::Event &event) { bool SurfaceSdlGraphicsManager::notifyEvent(const Common::Event &event) {
return false; return false;
} }

View file

@ -42,10 +42,10 @@
/** /**
* SDL graphics manager * SDL graphics manager
*/ */
class SdlGraphicsManager : public GraphicsManager, public Common::EventObserver { class SurfaceSdlGraphicsManager : public GraphicsManager, public Common::EventObserver {
public: public:
SdlGraphicsManager(SdlEventSource *sdlEventSource); SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource);
virtual ~SdlGraphicsManager(); virtual ~SurfaceSdlGraphicsManager();
virtual void initEventObserver(); virtual void initEventObserver();

View file

@ -28,7 +28,7 @@ DoubleBufferSDLMixerManager::DoubleBufferSDLMixerManager()
: :
_soundMutex(0), _soundCond(0), _soundThread(0), _soundMutex(0), _soundCond(0), _soundThread(0),
_soundThreadIsRunning(false), _soundThreadShouldQuit(false) { _soundThreadIsRunning(false), _soundThreadShouldQuit(false) {
} }
DoubleBufferSDLMixerManager::~DoubleBufferSDLMixerManager() { DoubleBufferSDLMixerManager::~DoubleBufferSDLMixerManager() {
@ -45,7 +45,7 @@ void DoubleBufferSDLMixerManager::startAudio() {
// Create two sound buffers // Create two sound buffers
_activeSoundBuf = 0; _activeSoundBuf = 0;
uint bufSize = _obtainedRate.samples * 4; uint bufSize = _obtained.samples * 4;
_soundBufSize = bufSize; _soundBufSize = bufSize;
_soundBuffers[0] = (byte *)calloc(1, bufSize); _soundBuffers[0] = (byte *)calloc(1, bufSize);
_soundBuffers[1] = (byte *)calloc(1, bufSize); _soundBuffers[1] = (byte *)calloc(1, bufSize);

View file

@ -61,18 +61,38 @@ void SdlMixerManager::init() {
// Get the desired audio specs // Get the desired audio specs
SDL_AudioSpec desired = getAudioSpec(SAMPLES_PER_SEC); SDL_AudioSpec desired = getAudioSpec(SAMPLES_PER_SEC);
// Needed as SDL_OpenAudio as of SDL-1.2.14 mutates fields in
// "desired" if used directly.
SDL_AudioSpec fmt = desired;
// Start SDL audio with the desired specs // Start SDL audio with the desired specs
if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) { if (SDL_OpenAudio(&fmt, &_obtained) != 0) {
warning("Could not open audio device: %s", SDL_GetError()); warning("Could not open audio device: %s", SDL_GetError());
_mixer = new Audio::MixerImpl(g_system, desired.freq); _mixer = new Audio::MixerImpl(g_system, desired.freq);
assert(_mixer); assert(_mixer);
_mixer->setReady(false); _mixer->setReady(false);
} else { } else {
debug(1, "Output sample rate: %d Hz", _obtainedRate.freq); debug(1, "Output sample rate: %d Hz", _obtained.freq);
if (_obtained.freq != desired.freq)
warning("SDL mixer output sample rate: %d differs from desired: %d", _obtained.freq, desired.freq);
_mixer = new Audio::MixerImpl(g_system, _obtainedRate.freq); debug(1, "Output buffer size: %d samples", _obtained.samples);
assert(_mixer); if (_obtained.samples != desired.samples)
warning("SDL mixer output buffer size: %d differs from desired: %d", _obtained.samples, desired.samples);
if (_obtained.format != desired.format)
warning("SDL mixer sound format: %d differs from desired: %d", _obtained.format, desired.format);
#ifndef __SYMBIAN32__
// The SymbianSdlMixerManager does stereo->mono downmixing,
// but otherwise we require stereo output.
if (_obtained.channels != 2)
error("SDL mixer output requires stereo output device");
#endif
_mixer = new Audio::MixerImpl(g_system, _obtained.freq);
assert(_mixer);
_mixer->setReady(true); _mixer->setReady(true);
startAudio(); startAudio();
@ -133,7 +153,7 @@ void SdlMixerManager::suspendAudio() {
int SdlMixerManager::resumeAudio() { int SdlMixerManager::resumeAudio() {
if (!_audioSuspended) if (!_audioSuspended)
return -2; return -2;
if (SDL_OpenAudio(&_obtainedRate, NULL) < 0){ if (SDL_OpenAudio(&_obtained, NULL) < 0){
return -1; return -1;
} }
SDL_PauseAudio(0); SDL_PauseAudio(0);

View file

@ -67,13 +67,13 @@ protected:
* The obtained audio specification after opening the * The obtained audio specification after opening the
* audio system. * audio system.
*/ */
SDL_AudioSpec _obtainedRate; SDL_AudioSpec _obtained;
/** State of the audio system */ /** State of the audio system */
bool _audioSuspended; bool _audioSuspended;
/** /**
* Returns the desired audio specification * Returns the desired audio specification
*/ */
virtual SDL_AudioSpec getAudioSpec(uint32 rate); virtual SDL_AudioSpec getAudioSpec(uint32 rate);

View file

@ -23,28 +23,28 @@
#ifndef BACKENDS_MODULAR_BACKEND_H #ifndef BACKENDS_MODULAR_BACKEND_H
#define BACKENDS_MODULAR_BACKEND_H #define BACKENDS_MODULAR_BACKEND_H
#include "common/system.h" #include "backends/base-backend.h"
class GraphicsManager; class GraphicsManager;
class MutexManager; class MutexManager;
/** /**
* Base class for modular backends. * Base class for modular backends.
* *
* It wraps most functions to their manager equivalent, but not * It wraps most functions to their manager equivalent, but not
* all OSystem functions are implemented here. * all OSystem functions are implemented here.
* *
* A backend derivated from this class, will need to implement * A backend derivated from this class, will need to implement
* these functions on its own: * these functions on its own:
* OSystem::pollEvent() * OSystem::pollEvent()
* OSystem::getMillis() * OSystem::getMillis()
* OSystem::delayMillis() * OSystem::delayMillis()
* OSystem::getTimeAndDate() * OSystem::getTimeAndDate()
* *
* And, it should also initialize all the managers variables * And, it should also initialize all the managers variables
* declared in this class, or override their related functions. * declared in this class, or override their related functions.
*/ */
class ModularBackend : public OSystem { class ModularBackend : public BaseBackend {
public: public:
ModularBackend(); ModularBackend();
virtual ~ModularBackend(); virtual ~ModularBackend();
@ -86,11 +86,11 @@ public:
/** @name Events and Time */ /** @name Events and Time */
//@{ //@{
virtual Common::HardwareKeySet *getHardwareKeySet() { return 0; } virtual Common::HardwareKeySet *getHardwareKeySet() { return 0; }
//@} //@}
/** @name Mutex handling */ /** @name Mutex handling */
//@{ //@{

View file

@ -1,6 +1,7 @@
MODULE := backends MODULE := backends
MODULE_OBJS := \ MODULE_OBJS := \
base-backend.o \
modular-backend.o \ modular-backend.o \
audiocd/default/default-audiocd.o \ audiocd/default/default-audiocd.o \
events/default/default-events.o \ events/default/default-events.o \
@ -51,14 +52,19 @@ endif
# derive from the SDL backend, and they all need the following files. # derive from the SDL backend, and they all need the following files.
ifdef SDL_BACKEND ifdef SDL_BACKEND
MODULE_OBJS += \ MODULE_OBJS += \
audiocd/sdl/sdl-audiocd.o \
events/sdl/sdl-events.o \ events/sdl/sdl-events.o \
graphics/sdl/sdl-graphics.o \ graphics/surfacesdl/surfacesdl-graphics.o \
mixer/doublebuffersdl/doublebuffersdl-mixer.o \ mixer/doublebuffersdl/doublebuffersdl-mixer.o \
mixer/sdl/sdl-mixer.o \ mixer/sdl/sdl-mixer.o \
mutex/sdl/sdl-mutex.o \ mutex/sdl/sdl-mutex.o \
plugins/sdl/sdl-provider.o \ plugins/sdl/sdl-provider.o \
timer/sdl/sdl-timer.o timer/sdl/sdl-timer.o
# SDL 1.3 removed audio CD support
ifndef USE_SDL13
MODULE_OBJS += \
audiocd/sdl/sdl-audiocd.o
endif
endif endif
ifdef POSIX ifdef POSIX
@ -66,7 +72,8 @@ MODULE_OBJS += \
fs/posix/posix-fs.o \ fs/posix/posix-fs.o \
fs/posix/posix-fs-factory.o \ fs/posix/posix-fs-factory.o \
plugins/posix/posix-provider.o \ plugins/posix/posix-provider.o \
saves/posix/posix-saves.o saves/posix/posix-saves.o \
taskbar/unity/unity-taskbar.o
endif endif
ifdef MACOSX ifdef MACOSX
@ -80,7 +87,8 @@ MODULE_OBJS += \
fs/windows/windows-fs.o \ fs/windows/windows-fs.o \
fs/windows/windows-fs-factory.o \ fs/windows/windows-fs-factory.o \
midi/windows.o \ midi/windows.o \
plugins/win32/win32-provider.o plugins/win32/win32-provider.o \
taskbar/win32/win32-taskbar.o
endif endif
ifdef AMIGAOS ifdef AMIGAOS
@ -90,6 +98,15 @@ MODULE_OBJS += \
midi/camd.o midi/camd.o
endif endif
ifdef PLAYSTATION3
MODULE_OBJS += \
fs/posix/posix-fs.o \
fs/posix/posix-fs-factory.o \
fs/ps3/ps3-fs-factory.o \
events/ps3sdl/ps3sdl-events.o \
mixer/sdl13/sdl13-mixer.o
endif
ifeq ($(BACKEND),ds) ifeq ($(BACKEND),ds)
MODULE_OBJS += \ MODULE_OBJS += \
fs/ds/ds-fs.o \ fs/ds/ds-fs.o \
@ -109,14 +126,6 @@ MODULE_OBJS += \
graphics/gph/gph-graphics.o graphics/gph/gph-graphics.o
endif endif
# TODO/FIXME: The gp2xsdl files are only compiled if GP2X_OLD is defined,
# which currently is never the case (unless the user manually requests it).
# ifeq ($(BACKEND),gp2x)
# MODULE_OBJS += \
# events/gp2xsdl/gp2xsdl-events.o \
# graphics/gp2xsdl/gp2xsdl-graphics.o
# endif
ifeq ($(BACKEND),linuxmoto) ifeq ($(BACKEND),linuxmoto)
MODULE_OBJS += \ MODULE_OBJS += \
events/linuxmotosdl/linuxmotosdl-events.o \ events/linuxmotosdl/linuxmotosdl-events.o \

View file

@ -74,7 +74,7 @@ void OSystem_MacOSX::addSysArchivesToSearchSet(Common::SearchSet &s, int priorit
} }
void OSystem_MacOSX::setupIcon() { void OSystem_MacOSX::setupIcon() {
// Don't set icon on OS X, as we use a nicer external icon there. // Don't set icon on OS X, as we use a nicer external icon there.
} }
bool OSystem_MacOSX::hasFeature(Feature f) { bool OSystem_MacOSX::hasFeature(Feature f) {

View file

@ -34,6 +34,7 @@
!defined(CAANOO) && \ !defined(CAANOO) && \
!defined(LINUXMOTO) && \ !defined(LINUXMOTO) && \
!defined(SAMSUNGTV) && \ !defined(SAMSUNGTV) && \
!defined(PLAYSTATION3) && \
!defined(OPENPANDORA) !defined(OPENPANDORA)
#include "backends/platform/sdl/sdl.h" #include "backends/platform/sdl/sdl.h"

View file

@ -29,6 +29,12 @@ MODULE_OBJS += \
amigaos/amigaos.o amigaos/amigaos.o
endif endif
ifdef PLAYSTATION3
MODULE_OBJS += \
ps3/ps3-main.o \
ps3/ps3.o
endif
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
OBJS := $(MODULE_OBJS) $(OBJS) OBJS := $(MODULE_OBJS) $(OBJS)

View file

@ -22,7 +22,7 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) #if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3)
#include "backends/platform/sdl/posix/posix.h" #include "backends/platform/sdl/posix/posix.h"
#include "backends/plugins/sdl/sdl-provider.h" #include "backends/plugins/sdl/sdl-provider.h"

View file

@ -33,6 +33,7 @@
#include "backends/platform/sdl/posix/posix.h" #include "backends/platform/sdl/posix/posix.h"
#include "backends/saves/posix/posix-saves.h" #include "backends/saves/posix/posix-saves.h"
#include "backends/fs/posix/posix-fs-factory.h" #include "backends/fs/posix/posix-fs-factory.h"
#include "backends/taskbar/unity/unity-taskbar.h"
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -49,6 +50,11 @@ void OSystem_POSIX::init() {
// Initialze File System Factory // Initialze File System Factory
_fsFactory = new POSIXFilesystemFactory(); _fsFactory = new POSIXFilesystemFactory();
#if defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
// Initialize taskbar manager
_taskbarManager = new UnityTaskbarManager();
#endif
// Invoke parent implementation of this method // Invoke parent implementation of this method
OSystem_SDL::init(); OSystem_SDL::init();
} }
@ -60,6 +66,11 @@ void OSystem_POSIX::initBackend() {
// Invoke parent implementation of this method // Invoke parent implementation of this method
OSystem_SDL::initBackend(); OSystem_SDL::initBackend();
#if defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
// Register the taskbar manager as an event source (this is necessary for the glib event loop to be run)
_eventManager->getEventDispatcher()->registerSource((UnityTaskbarManager *)_taskbarManager, false);
#endif
} }
bool OSystem_POSIX::hasFeature(Feature f) { bool OSystem_POSIX::hasFeature(Feature f) {

View file

@ -27,7 +27,7 @@
// fashion, even on the Symbian port. // fashion, even on the Symbian port.
// Moreover, it contains a workaround for the fact that SDL_rwops.h uses // Moreover, it contains a workaround for the fact that SDL_rwops.h uses
// a FILE pointer in one place, which conflicts with common/forbidden.h. // a FILE pointer in one place, which conflicts with common/forbidden.h.
// The SDL 1.3 headers also include strings.h
#include "common/scummsys.h" #include "common/scummsys.h"
@ -39,6 +39,16 @@ typedef struct { int FAKE; } FAKE_FILE;
#define FILE FAKE_FILE #define FILE FAKE_FILE
#endif #endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_strcasecmp)
#undef strcasecmp
#define strcasecmp FAKE_strcasecmp
#endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_strncasecmp)
#undef strncasecmp
#define strncasecmp FAKE_strncasecmp
#endif
#if defined(__SYMBIAN32__) #if defined(__SYMBIAN32__)
#include <esdl\SDL.h> #include <esdl\SDL.h>
#else #else
@ -47,8 +57,19 @@ typedef struct { int FAKE; } FAKE_FILE;
// Finally forbid FILE again (if it was forbidden to start with) // Finally forbid FILE again (if it was forbidden to start with)
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_FILE) #if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_FILE)
#undef FILE #undef FILE
#define FILE FORBIDDEN_SYMBOL_REPLACEMENT #define FILE FORBIDDEN_SYMBOL_REPLACEMENT
#endif #endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_strcasecmp)
#undef strcasecmp
#define strcasecmp FORBIDDEN_SYMBOL_REPLACEMENT
#endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_strncasecmp)
#undef strncasecmp
#define strncasecmp FORBIDDEN_SYMBOL_REPLACEMENT
#endif
#endif #endif

View file

@ -31,14 +31,22 @@
#include "backends/platform/sdl/sdl.h" #include "backends/platform/sdl/sdl.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/EventRecorder.h" #include "common/EventRecorder.h"
#include "common/taskbar.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "backends/saves/default/default-saves.h" #include "backends/saves/default/default-saves.h"
// Audio CD support was removed with SDL 1.3
#if SDL_VERSION_ATLEAST(1, 3, 0)
#include "backends/audiocd/default/default-audiocd.h"
#else
#include "backends/audiocd/sdl/sdl-audiocd.h" #include "backends/audiocd/sdl/sdl-audiocd.h"
#endif
#include "backends/events/sdl/sdl-events.h" #include "backends/events/sdl/sdl-events.h"
#include "backends/mutex/sdl/sdl-mutex.h" #include "backends/mutex/sdl/sdl-mutex.h"
#include "backends/timer/sdl/sdl-timer.h" #include "backends/timer/sdl/sdl-timer.h"
#include "backends/graphics/sdl/sdl-graphics.h" #include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
#include "icons/residual.xpm" #include "icons/residual.xpm"
@ -111,6 +119,11 @@ void OSystem_SDL::init() {
if (_timerManager == 0) if (_timerManager == 0)
_timerManager = new SdlTimerManager(); _timerManager = new SdlTimerManager();
#if defined(USE_TASKBAR)
if (_taskbarManager == 0)
_taskbarManager = new Common::TaskbarManager();
#endif
} }
void OSystem_SDL::initBackend() { void OSystem_SDL::initBackend() {
@ -126,23 +139,11 @@ void OSystem_SDL::initBackend() {
if (_graphicsManager == 0) { if (_graphicsManager == 0) {
if (_graphicsManager == 0) { if (_graphicsManager == 0) {
_graphicsManager = new SdlGraphicsManager(_eventSource); _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource);
graphicsManagerType = 0; graphicsManagerType = 0;
} }
} }
// Creates the backend managers, if they don't exist yet (we check
// for this to allow subclasses to provide their own).
if (_eventManager == 0)
_eventManager = new DefaultEventManager(_eventSource);
// We have to initialize the graphics manager before the event manager
// so the virtual keyboard can be initialized, but we have to add the
// graphics manager as an event observer after initializing the event
// manager.
if (graphicsManagerType == 0)
((SdlGraphicsManager *)_graphicsManager)->initEventObserver();
if (_savefileManager == 0) if (_savefileManager == 0)
_savefileManager = new DefaultSaveFileManager(); _savefileManager = new DefaultSaveFileManager();
@ -153,8 +154,15 @@ void OSystem_SDL::initBackend() {
_mixerManager->init(); _mixerManager->init();
} }
if (_audiocdManager == 0) if (_audiocdManager == 0) {
// Audio CD support was removed with SDL 1.3
#if SDL_VERSION_ATLEAST(1, 3, 0)
_audiocdManager = new DefaultAudioCDManager();
#else
_audiocdManager = new SdlAudioCDManager(); _audiocdManager = new SdlAudioCDManager();
#endif
}
// Setup a custom program icon. // Setup a custom program icon.
setupIcon(); setupIcon();
@ -162,8 +170,30 @@ void OSystem_SDL::initBackend() {
_inited = true; _inited = true;
ModularBackend::initBackend(); ModularBackend::initBackend();
// We have to initialize the graphics manager before the event manager
// so the virtual keyboard can be initialized, but we have to add the
// graphics manager as an event observer after initializing the event
// manager.
if (graphicsManagerType == 0)
((SurfaceSdlGraphicsManager *)_graphicsManager)->initEventObserver();
} }
#if defined(USE_TASKBAR)
void OSystem_SDL::engineInit() {
// Add the started engine to the list of recent tasks
_taskbarManager->addRecent(ConfMan.getActiveDomainName(), ConfMan.get("description"));
// Set the overlay icon the current running engine
_taskbarManager->setOverlayIcon(ConfMan.getActiveDomainName(), ConfMan.get("description"));
}
void OSystem_SDL::engineDone() {
// Remove overlay icon
_taskbarManager->setOverlayIcon("", "");
}
#endif
void OSystem_SDL::initSDL() { void OSystem_SDL::initSDL() {
// Check if SDL has not been initialized // Check if SDL has not been initialized
if (!_initedSDL) { if (!_initedSDL) {
@ -230,10 +260,22 @@ void OSystem_SDL::fatalError() {
void OSystem_SDL::logMessage(LogMessageType::Type type, const char *message) { void OSystem_SDL::logMessage(LogMessageType::Type type, const char *message) {
ModularBackend::logMessage(type, message); // First log to stdout/stderr
FILE *output = 0;
if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
output = stdout;
else
output = stderr;
fputs(message, output);
fflush(output);
// Then log into file (via the logger)
if (_logger) if (_logger)
_logger->print(message); _logger->print(message);
// Finally, some Windows / WinCE specific logging code.
#if defined( USE_WINDBG ) #if defined( USE_WINDBG )
#if defined( _WIN32_WCE ) #if defined( _WIN32_WCE )
TCHAR buf_unicode[1024]; TCHAR buf_unicode[1024];
@ -256,7 +298,7 @@ void OSystem_SDL::logMessage(LogMessageType::Type type, const char *message) {
} }
Common::String OSystem_SDL::getSystemLanguage() const { Common::String OSystem_SDL::getSystemLanguage() const {
#ifdef USE_DETECTLANG #if defined(USE_DETECTLANG) && !defined(_WIN32_WCE)
#ifdef WIN32 #ifdef WIN32
// We can not use "setlocale" (at least not for MSVC builds), since it // We can not use "setlocale" (at least not for MSVC builds), since it
// will return locales like: "English_USA.1252", thus we need a special // will return locales like: "English_USA.1252", thus we need a special
@ -323,7 +365,7 @@ void OSystem_SDL::setupIcon() {
if (sscanf(residual_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes) != 4) { if (sscanf(residual_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes) != 4) {
warning("Wrong format of residual_icon[0] (%s)", residual_icon[0]); warning("Wrong format of residual_icon[0] (%s)", residual_icon[0]);
return; return;
} }
if ((w > 512) || (h > 512) || (ncols > 255) || (nbytes > 1)) { if ((w > 512) || (h > 512) || (ncols > 255) || (nbytes > 1)) {
@ -339,6 +381,7 @@ void OSystem_SDL::setupIcon() {
for (i = 0; i < ncols; i++) { for (i = 0; i < ncols; i++) {
unsigned char code; unsigned char code;
char color[32]; char color[32];
memset(color, 0, sizeof(color));
unsigned int col; unsigned int col;
if (sscanf(residual_icon[1 + i], "%c c %s", &code, color) != 2) { if (sscanf(residual_icon[1 + i], "%c c %s", &code, color) != 2) {
warning("Wrong format of residual_icon[%d] (%s)", 1 + i, residual_icon[1 + i]); warning("Wrong format of residual_icon[%d] (%s)", 1 + i, residual_icon[1 + i]);

View file

@ -34,7 +34,7 @@
#include "backends/events/sdl/sdl-events.h" #include "backends/events/sdl/sdl-events.h"
#include "backends/log/log.h" #include "backends/log/log.h"
/** /**
* Base OSystem class for all SDL ports. * Base OSystem class for all SDL ports.
*/ */
class OSystem_SDL : public ModularBackend { class OSystem_SDL : public ModularBackend {
@ -42,7 +42,7 @@ public:
OSystem_SDL(); OSystem_SDL();
virtual ~OSystem_SDL(); virtual ~OSystem_SDL();
/** /**
* Pre-initialize backend. It should be called after * Pre-initialize backend. It should be called after
* instantiating the backend. Early needed managers are * instantiating the backend. Early needed managers are
* created here. * created here.
@ -58,6 +58,10 @@ public:
// Override functions from ModularBackend and OSystem // Override functions from ModularBackend and OSystem
virtual void initBackend(); virtual void initBackend();
#if defined(USE_TASKBAR)
virtual void engineInit();
virtual void engineDone();
#endif
virtual Common::HardwareKeySet *getHardwareKeySet(); virtual Common::HardwareKeySet *getHardwareKeySet();
virtual void quit(); virtual void quit();
virtual void fatalError(); virtual void fatalError();

View file

@ -24,6 +24,7 @@
#define FORBIDDEN_SYMBOL_ALLOW_ALL #define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "common/scummsys.h" #include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/error.h" #include "common/error.h"
#include "common/textconsole.h" #include "common/textconsole.h"
@ -34,60 +35,49 @@
#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one... #undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one...
#include <shellapi.h> #include <shellapi.h>
#include <SDL_syswm.h> // For setting the icon
#include "backends/platform/sdl/win32/win32.h" #include "backends/platform/sdl/win32/win32.h"
#include "backends/fs/windows/windows-fs-factory.h" #include "backends/fs/windows/windows-fs-factory.h"
#include "backends/taskbar/win32/win32-taskbar.h"
#include "common/memstream.h" #include "common/memstream.h"
#define DEFAULT_CONFIG_FILE "residual.ini" #define DEFAULT_CONFIG_FILE "residual.ini"
//#define HIDE_CONSOLE
#ifdef HIDE_CONSOLE
struct SdlConsoleHidingWin32 {
DWORD myPid;
DWORD myTid;
HWND consoleHandle;
};
// console hiding for win32
static BOOL CALLBACK initBackendFindConsoleWin32Proc(HWND hWnd, LPARAM lParam) {
DWORD pid, tid;
SdlConsoleHidingWin32 *variables = (SdlConsoleHidingWin32 *)lParam;
tid = GetWindowThreadProcessId(hWnd, &pid);
if ((tid == variables->myTid) && (pid == variables->myPid)) {
variables->consoleHandle = hWnd;
return FALSE;
}
return TRUE;
}
#endif
void OSystem_Win32::init() { void OSystem_Win32::init() {
#ifdef HIDE_CONSOLE // Initialize File System Factory
// console hiding for win32
SdlConsoleHidingWin32 consoleHidingWin32;
consoleHidingWin32.consoleHandle = 0;
consoleHidingWin32.myPid = GetCurrentProcessId();
consoleHidingWin32.myTid = GetCurrentThreadId();
EnumWindows (initBackendFindConsoleWin32Proc, (LPARAM)&consoleHidingWin32);
if (!ConfMan.getBool("show_console")) {
if (consoleHidingWin32.consoleHandle) {
// We won't find a window with our TID/PID in case we were started from command-line
ShowWindow(consoleHidingWin32.consoleHandle, SW_HIDE);
}
}
#endif
// Initialze File System Factory
_fsFactory = new WindowsFilesystemFactory(); _fsFactory = new WindowsFilesystemFactory();
#if defined(USE_TASKBAR)
// Initialize taskbar manager
_taskbarManager = new Win32TaskbarManager();
#endif
// Invoke parent implementation of this method // Invoke parent implementation of this method
OSystem_SDL::init(); OSystem_SDL::init();
} }
void OSystem_Win32::initBackend() {
// Console window is enabled by default on Windows
ConfMan.registerDefault("console", true);
// Enable or disable the window console window
if (ConfMan.getBool("console")) {
if (AllocConsole()) {
freopen("CONIN$","r",stdin);
freopen("CONOUT$","w",stdout);
freopen("CONOUT$","w",stderr);
}
SetConsoleTitle("Residual Status Window");
} else {
FreeConsole();
}
// Invoke parent implementation of this method
OSystem_SDL::initBackend();
}
bool OSystem_Win32::hasFeature(Feature f) { bool OSystem_Win32::hasFeature(Feature f) {
if (f == kFeatureDisplayLogFile) if (f == kFeatureDisplayLogFile)
@ -131,6 +121,28 @@ bool OSystem_Win32::displayLogFile() {
return false; return false;
} }
void OSystem_Win32::setupIcon() {
HMODULE handle = GetModuleHandle(NULL);
HICON ico = LoadIcon(handle, MAKEINTRESOURCE(1001 /* IDI_ICON */));
if (ico) {
SDL_SysWMinfo wminfo;
SDL_VERSION(&wminfo.version);
if (SDL_GetWMInfo(&wminfo)) {
// Replace the handle to the icon associated with the window class by our custom icon
SetClassLongPtr(wminfo.window, GCLP_HICON, (ULONG_PTR)ico);
// Since there wasn't any default icon, we can't use the return value from SetClassLong
// to check for errors (it would be 0 in both cases: error or no previous value for the
// icon handle). Instead we check for the last-error code value.
if (GetLastError() == ERROR_SUCCESS)
return;
}
}
// If no icon has been set, fallback to default path
OSystem_SDL::setupIcon();
}
Common::String OSystem_Win32::getDefaultConfigFileName() { Common::String OSystem_Win32::getDefaultConfigFileName() {
char configFile[MAXPATHLEN]; char configFile[MAXPATHLEN];
@ -149,18 +161,31 @@ Common::String OSystem_Win32::getDefaultConfigFileName() {
error("Unable to access user profile directory"); error("Unable to access user profile directory");
strcat(configFile, "\\Application Data"); strcat(configFile, "\\Application Data");
CreateDirectory(configFile, NULL);
// If the directory already exists (as it should in most cases),
// we don't want to fail, but we need to stop on other errors (such as ERROR_PATH_NOT_FOUND)
if (!CreateDirectory(configFile, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS)
error("Cannot create Application data folder");
}
} }
strcat(configFile, "\\Residual"); strcat(configFile, "\\Residual");
CreateDirectory(configFile, NULL); if (!CreateDirectory(configFile, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS)
error("Cannot create Residual application data folder");
}
strcat(configFile, "\\" DEFAULT_CONFIG_FILE); strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
FILE *tmp = NULL; FILE *tmp = NULL;
if ((tmp = fopen(configFile, "r")) == NULL) { if ((tmp = fopen(configFile, "r")) == NULL) {
// Check windows directory // Check windows directory
char oldConfigFile[MAXPATHLEN]; char oldConfigFile[MAXPATHLEN];
GetWindowsDirectory(oldConfigFile, MAXPATHLEN); uint ret = GetWindowsDirectory(oldConfigFile, MAXPATHLEN);
if (ret == 0 || ret > MAXPATHLEN)
error("Cannot retrieve the path of the Windows directory");
strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE); strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE);
if ((tmp = fopen(oldConfigFile, "r"))) { if ((tmp = fopen(oldConfigFile, "r"))) {
strcpy(configFile, oldConfigFile); strcpy(configFile, oldConfigFile);
@ -172,7 +197,10 @@ Common::String OSystem_Win32::getDefaultConfigFileName() {
} }
} else { } else {
// Check windows directory // Check windows directory
GetWindowsDirectory(configFile, MAXPATHLEN); uint ret = GetWindowsDirectory(configFile, MAXPATHLEN);
if (ret == 0 || ret > MAXPATHLEN)
error("Cannot retrieve the path of the Windows directory");
strcat(configFile, "\\" DEFAULT_CONFIG_FILE); strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
} }
@ -300,7 +328,7 @@ Common::SeekableReadStream *Win32ResourceArchive::createReadStreamForMember(cons
} // End of anonymous namespace } // End of anonymous namespace
void OSystem_Win32::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { void OSystem_Win32::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
s.add("Win32Res", new Win32ResourceArchive()); s.add("Win32Res", new Win32ResourceArchive(), priority);
OSystem_SDL::addSysArchivesToSearchSet(s, priority); OSystem_SDL::addSysArchivesToSearchSet(s, priority);
} }

View file

@ -28,6 +28,7 @@
class OSystem_Win32 : public OSystem_SDL { class OSystem_Win32 : public OSystem_SDL {
public: public:
virtual void init(); virtual void init();
virtual void initBackend();
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
@ -46,6 +47,7 @@ protected:
*/ */
Common::String _logFilePath; Common::String _logFilePath;
virtual void setupIcon();
virtual Common::String getDefaultConfigFileName(); virtual Common::String getDefaultConfigFileName();
virtual Common::WriteStream *createLogFile(); virtual Common::WriteStream *createLogFile();
}; };

View file

@ -31,7 +31,6 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one...
class Win32Plugin : public DynamicPlugin { class Win32Plugin : public DynamicPlugin {

View file

@ -0,0 +1,114 @@
/* 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$
*
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
#include "common/scummsys.h"
#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
#include "backends/taskbar/unity/unity-taskbar.h"
#include "common/textconsole.h"
#include <unity.h>
UnityTaskbarManager::UnityTaskbarManager() {
g_type_init();
_loop = g_main_loop_new(NULL, FALSE);
_launcher = unity_launcher_entry_get_for_desktop_id("scummvm.desktop");
}
UnityTaskbarManager::~UnityTaskbarManager() {
g_main_loop_unref(_loop);
_loop = NULL;
}
void UnityTaskbarManager::setProgressValue(int completed, int total) {
if (_launcher == NULL)
return;
double percentage = (double)completed / (double)total;
unity_launcher_entry_set_progress(_launcher, percentage);
unity_launcher_entry_set_progress_visible(_launcher, TRUE);
}
void UnityTaskbarManager::setProgressState(TaskbarProgressState state) {
if (_launcher == NULL)
return;
switch (state) {
default:
warning("[UnityTaskbarManager::setProgressState] Unknown state / Not implemented (%d)", state);
// fallback to noprogress state
case kTaskbarNoProgress:
unity_launcher_entry_set_progress_visible(_launcher, FALSE);
break;
// Unity only support two progress states as of 3.0: visible or not visible
// We show progress in all of those states
case kTaskbarIndeterminate:
case kTaskbarNormal:
case kTaskbarError:
case kTaskbarPaused:
unity_launcher_entry_set_progress_visible(_launcher, TRUE);
break;
}
}
void UnityTaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
warning("[UnityTaskbarManager::addRecent] Not implemented");
}
void UnityTaskbarManager::setCount(int count) {
if (_launcher == NULL)
return;
unity_launcher_entry_set_count(_launcher, count);
unity_launcher_entry_set_count_visible(_launcher, (count == 0) ? FALSE : TRUE);
}
// Unity requires the glib event loop to the run to function properly
// as events are sent asynchronously
bool UnityTaskbarManager::pollEvent(Common::Event &event) {
if (!_loop)
return false;
// Get context
GMainContext *context = g_main_loop_get_context(_loop);
if (!context)
return false;
// Dispatch events
g_main_context_iteration(context, FALSE);
return false;
}
#endif

View file

@ -0,0 +1,58 @@
/* 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$
*
*/
#ifndef BACKEND_UNITY_TASKBAR_H
#define BACKEND_UNITY_TASKBAR_H
#if defined(POSIX) && defined(USE_TASKBAR) && defined(USE_TASKBAR_UNITY)
#include "common/events.h"
#include "common/str.h"
#include "common/taskbar.h"
typedef struct _GMainLoop GMainLoop;
typedef struct _UnityLauncherEntry UnityLauncherEntry;
class UnityTaskbarManager : public Common::TaskbarManager, public Common::EventSource {
public:
UnityTaskbarManager();
virtual ~UnityTaskbarManager();
virtual void setProgressValue(int completed, int total);
virtual void setProgressState(TaskbarProgressState state);
virtual void addRecent(const Common::String &name, const Common::String &description);
virtual void setCount(int count);
// Implementation of the EventSource interface
virtual bool pollEvent(Common::Event &event);
private:
GMainLoop *_loop;
UnityLauncherEntry *_launcher;
};
#endif
#endif // BACKEND_UNITY_TASKBAR_H

View file

@ -0,0 +1,154 @@
/* 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$
*
*/
// TODO: Remove header when the latest changes to the Windows SDK have been integrated into MingW
// For reference, the interface definitions here are imported the SDK headers and from the
// EcWin7 project (https://code.google.com/p/dukto/)
#ifndef BACKEND_WIN32_TASKBAR_MINGW_H
#define BACKEND_WIN32_TASKBAR_MINGW_H
#if defined(WIN32)
#if defined(__GNUC__)
#ifdef __MINGW32__
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <commctrl.h>
#include <initguid.h>
#include <shlwapi.h>
#include <shlguid.h>
#define CMIC_MASK_ASYNCOK SEE_MASK_ASYNCOK
extern const GUID CLSID_ShellLink;
// Shard enumeration value
#define SHARD_LINK 0x00000006
// Taskbar GUID definitions
DEFINE_GUID(CLSID_TaskbarList,0x56fdf344,0xfd6d,0x11d0,0x95,0x8a,0x0,0x60,0x97,0xc9,0xa0,0x90);
DEFINE_GUID(IID_ITaskbarList3,0xea1afb91,0x9e28,0x4b86,0x90,0xE9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf);
DEFINE_GUID(IID_IPropertyStore,0x886d8eeb,0x8cf2,0x4446,0x8d,0x02,0xcd,0xba,0x1d,0xbd,0xcf,0x99);
// Property key
typedef struct _tagpropertykey {
GUID fmtid;
DWORD pid;
} PROPERTYKEY;
#define REFPROPERTYKEY const PROPERTYKEY &
typedef struct tagPROPVARIANT PROPVARIANT;
#define REFPROPVARIANT const PROPVARIANT &
// Property store
DECLARE_INTERFACE_(IPropertyStore, IUnknown) {
STDMETHOD (GetCount) (DWORD *cProps) PURE;
STDMETHOD (GetAt) (DWORD iProp, PROPERTYKEY *pkey) PURE;
STDMETHOD (GetValue) (REFPROPERTYKEY key, PROPVARIANT *pv) PURE;
STDMETHOD (SetValue) (REFPROPERTYKEY key, REFPROPVARIANT propvar) PURE;
STDMETHOD (Commit) (void) PURE;
private:
~IPropertyStore();
};
typedef IPropertyStore *LPIPropertyStore;
// Mingw-specific defines for taskbar integration
typedef enum THUMBBUTTONMASK {
THB_BITMAP = 0x1,
THB_ICON = 0x2,
THB_TOOLTIP = 0x4,
THB_FLAGS = 0x8
} THUMBBUTTONMASK;
typedef enum THUMBBUTTONFLAGS {
THBF_ENABLED = 0,
THBF_DISABLED = 0x1,
THBF_DISMISSONCLICK = 0x2,
THBF_NOBACKGROUND = 0x4,
THBF_HIDDEN = 0x8,
THBF_NONINTERACTIVE = 0x10
} THUMBBUTTONFLAGS;
typedef struct THUMBBUTTON {
THUMBBUTTONMASK dwMask;
UINT iId;
UINT iBitmap;
HICON hIcon;
WCHAR szTip[260];
THUMBBUTTONFLAGS dwFlags;
} THUMBBUTTON;
typedef struct THUMBBUTTON *LPTHUMBBUTTON;
typedef enum TBPFLAG {
TBPF_NOPROGRESS = 0,
TBPF_INDETERMINATE = 0x1,
TBPF_NORMAL = 0x2,
TBPF_ERROR = 0x4,
TBPF_PAUSED = 0x8
} TBPFLAG;
// Taskbar interface
DECLARE_INTERFACE_(ITaskbarList3, IUnknown) {
// IUnknown
STDMETHOD(QueryInterface) (THIS_ REFIID riid, void **ppv) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// ITaskbarList
STDMETHOD(HrInit) (THIS) PURE;
STDMETHOD(AddTab) (THIS_ HWND hwnd) PURE;
STDMETHOD(DeleteTab) (THIS_ HWND hwnd) PURE;
STDMETHOD(ActivateTab) (THIS_ HWND hwnd) PURE;
STDMETHOD(SetActiveAlt) (THIS_ HWND hwnd) PURE;
STDMETHOD (MarkFullscreenWindow) (THIS_ HWND hwnd, int fFullscreen) PURE;
// ITaskbarList3
STDMETHOD (SetProgressValue) (THIS_ HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) PURE;
STDMETHOD (SetProgressState) (THIS_ HWND hwnd, TBPFLAG tbpFlags) PURE;
STDMETHOD (RegisterTab) (THIS_ HWND hwndTab, HWND hwndMDI) PURE;
STDMETHOD (UnregisterTab) (THIS_ HWND hwndTab) PURE;
STDMETHOD (SetTabOrder) (THIS_ HWND hwndTab, HWND hwndInsertBefore) PURE;
STDMETHOD (SetTabActive) (THIS_ HWND hwndTab, HWND hwndMDI, DWORD dwReserved) PURE;
STDMETHOD (ThumbBarAddButtons) (THIS_ HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) PURE;
STDMETHOD (ThumbBarUpdateButtons) (THIS_ HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) PURE;
STDMETHOD (ThumbBarSetImageList) (THIS_ HWND hwnd, HIMAGELIST himl) PURE;
STDMETHOD (SetOverlayIcon) (THIS_ HWND hwnd, HICON hIcon, LPCWSTR pszDescription) PURE;
STDMETHOD (SetThumbnailTooltip) (THIS_ HWND hwnd, LPCWSTR pszTip) PURE;
STDMETHOD (SetThumbnailClip) (THIS_ HWND hwnd, RECT *prcClip) PURE;
private:
~ITaskbarList3();
};
typedef ITaskbarList3 *LPITaskbarList3;
#endif // __MINGW32__
#endif // __GNUC__
#endif // WIN32
#endif // BACKEND_WIN32_TASKBAR_MINGW_H

View file

@ -0,0 +1,414 @@
/* 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$
*
*/
// We cannot use common/scummsys.h directly as it will include
// windows.h and we need to do it by hand to allow excluded functions
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#if defined(WIN32) && defined(USE_TASKBAR)
// Needed for taskbar functions
#if defined(__GNUC__)
#ifdef __MINGW32__
#include "backends/taskbar/win32/mingw-compat.h"
#else
#error Only compilation with MingW is supported
#endif
#else
// We need certain functions that are excluded by default
#undef NONLS
#undef NOICONS
#include <windows.h>
#if defined(ARRAYSIZE)
#undef ARRAYSIZE
#endif
// Default MSVC headers for ITaskbarList3 and IShellLink
#include <SDKDDKVer.h>
#endif
#include <shlobj.h>
// For HWND
#include <SDL_syswm.h>
#include "common/scummsys.h"
#include "backends/taskbar/win32/win32-taskbar.h"
#include "common/config-manager.h"
#include "common/textconsole.h"
#include "common/file.h"
// System.Title property key, values taken from http://msdn.microsoft.com/en-us/library/bb787584.aspx
const PROPERTYKEY PKEY_Title = { /* fmtid = */ { 0xF29F85E0, 0x4FF9, 0x1068, { 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 } }, /* propID = */ 2 };
Win32TaskbarManager::Win32TaskbarManager() : _taskbar(NULL), _count(0), _icon(NULL) {
// Do nothing if not running on Windows 7 or later
if (!isWin7OrLater())
return;
CoInitialize(NULL);
// Try creating instance (on fail, _taskbar will contain NULL)
HRESULT hr = CoCreateInstance(CLSID_TaskbarList,
0,
CLSCTX_INPROC_SERVER,
IID_ITaskbarList3,
reinterpret_cast<void**> (&(_taskbar)));
if (SUCCEEDED(hr)) {
// Initialize taskbar object
if (FAILED(_taskbar->HrInit())) {
_taskbar->Release();
_taskbar = NULL;
}
} else {
warning("[Win32TaskbarManager::init] Cannot create taskbar instance");
}
}
Win32TaskbarManager::~Win32TaskbarManager() {
if (_taskbar)
_taskbar->Release();
_taskbar = NULL;
if (_icon)
DestroyIcon(_icon);
CoUninitialize();
}
void Win32TaskbarManager::setOverlayIcon(const Common::String &name, const Common::String &description) {
//warning("[Win32TaskbarManager::setOverlayIcon] Setting overlay icon to: %s (%s)", name.c_str(), description.c_str());
if (_taskbar == NULL)
return;
if (name.empty()) {
_taskbar->SetOverlayIcon(getHwnd(), NULL, L"");
return;
}
// Compute full icon path
Common::String path = getIconPath(name);
if (path.empty())
return;
HICON pIcon = (HICON)::LoadImage(NULL, path.c_str(), IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
if (!pIcon) {
warning("[Win32TaskbarManager::setOverlayIcon] Cannot load icon!");
return;
}
// Sets the overlay icon
LPWSTR desc = ansiToUnicode(description.c_str());
_taskbar->SetOverlayIcon(getHwnd(), pIcon, desc);
DestroyIcon(pIcon);
delete[] desc;
}
void Win32TaskbarManager::setProgressValue(int completed, int total) {
if (_taskbar == NULL)
return;
_taskbar->SetProgressValue(getHwnd(), completed, total);
}
void Win32TaskbarManager::setProgressState(TaskbarProgressState state) {
if (_taskbar == NULL)
return;
_taskbar->SetProgressState(getHwnd(), (TBPFLAG)state);
}
void Win32TaskbarManager::setCount(int count) {
if (_taskbar == NULL)
return;
if (count == 0) {
_taskbar->SetOverlayIcon(getHwnd(), NULL, L"");
return;
}
// FIXME: This isn't really nice and could use a cleanup.
// The only good thing is that it doesn't use GDI+
// and thus does not have a dependancy on it,
// with the downside of being a lot more ugly.
// Maybe replace it by a Graphic::Surface, use
// ScummVM font drawing and extract the contents at
// the end?
if (_count != count || _icon == NULL) {
// Cleanup previous icon
_count = count;
if (_icon)
DestroyIcon(_icon);
Common::String countString = (count < 100 ? Common::String::format("%d", count) : "9+");
// Create transparent background
BITMAPV5HEADER bi;
ZeroMemory(&bi, sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = 16;
bi.bV5Height = 16;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_RGB;
// Set 32 BPP alpha format
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
// Get DC
HDC hdc;
hdc = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hdc);
ReleaseDC(NULL, hdc);
// Create a bitmap mask
HBITMAP hBitmapMask = CreateBitmap(16, 16, 1, 1, NULL);
// Create the DIB section with an alpha channel
void *lpBits;
HBITMAP hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, 0);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
// Load the icon background
HICON hIconBackground = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(1002 /* IDI_COUNT */));
DrawIconEx(hMemDC, 0, 0, hIconBackground, 16, 16, 0, 0, DI_NORMAL);
DeleteObject(hIconBackground);
// Draw the count
LOGFONT lFont;
memset(&lFont, 0, sizeof(LOGFONT));
lFont.lfHeight = 10;
lFont.lfWeight = FW_BOLD;
lFont.lfItalic = 1;
strcpy(lFont.lfFaceName, "Arial");
HFONT hFont = CreateFontIndirect(&lFont);
SelectObject(hMemDC, hFont);
RECT rect;
SetRect(&rect, 4, 4, 12, 12);
SetTextColor(hMemDC, RGB(48, 48, 48));
SetBkMode(hMemDC, TRANSPARENT);
DrawText(hMemDC, countString.c_str(), -1, &rect, DT_NOCLIP|DT_CENTER);
// Set the text alpha to fully opaque (we consider the data inside the text rect)
DWORD *lpdwPixel = (DWORD *)lpBits;
for (int x = 3; x < 12; x++) {
for(int y = 3; y < 12; y++) {
unsigned char *p = (unsigned char *)(lpdwPixel + x * 16 + y);
if (p[0] != 0 && p[1] != 0 && p[2] != 0)
p[3] = 255;
}
}
// Cleanup DC
DeleteObject(hFont);
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
// Prepare our new icon
ICONINFO ii;
ii.fIcon = FALSE;
ii.xHotspot = 0;
ii.yHotspot = 0;
ii.hbmMask = hBitmapMask;
ii.hbmColor = hBitmap;
_icon = CreateIconIndirect(&ii);
DeleteObject(hBitmap);
DeleteObject(hBitmapMask);
if (!_icon) {
warning("[Win32TaskbarManager::setCount] Cannot create icon for count");
return;
}
}
// Sets the overlay icon
LPWSTR desc = ansiToUnicode(Common::String::format("Found games: %d", count).c_str());
_taskbar->SetOverlayIcon(getHwnd(), _icon, desc);
delete[] desc;
}
void Win32TaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
//warning("[Win32TaskbarManager::addRecent] Adding recent list entry: %s (%s)", name.c_str(), description.c_str());
if (_taskbar == NULL)
return;
// ANSI version doesn't seem to work correctly with Win7 jump lists, so explicitly use Unicode interface.
IShellLinkW *link;
// Get the ScummVM executable path.
WCHAR path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
// Create a shell link.
if (SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC, IID_IShellLinkW, reinterpret_cast<void**> (&link)))) {
// Convert game name and description to Unicode.
LPWSTR game = ansiToUnicode(name.c_str());
LPWSTR desc = ansiToUnicode(description.c_str());
// Set link properties.
link->SetPath(path);
link->SetArguments(game);
Common::String iconPath = getIconPath(name);
if (iconPath.empty()) {
link->SetIconLocation(path, 0); // No game-specific icon available
} else {
LPWSTR icon = ansiToUnicode(iconPath.c_str());
link->SetIconLocation(icon, 0);
delete[] icon;
}
// The link's display name must be set via property store.
IPropertyStore* propStore;
HRESULT hr = link->QueryInterface(IID_IPropertyStore, reinterpret_cast<void**> (&(propStore)));
if (SUCCEEDED(hr)) {
PROPVARIANT pv;
pv.vt = VT_LPWSTR;
pv.pwszVal = desc;
hr = propStore->SetValue(PKEY_Title, pv);
propStore->Commit();
propStore->Release();
}
// SHAddToRecentDocs will cause the games to be added to the Recent list, allowing the user to pin them.
SHAddToRecentDocs(SHARD_LINK, link);
link->Release();
delete[] game;
delete[] desc;
}
}
Common::String Win32TaskbarManager::getIconPath(Common::String target) {
// We first try to look for a iconspath configuration variable then
// fallback to the extra path
//
// Icons can be either in a subfolder named "icons" or directly in the path
Common::String iconsPath = ConfMan.get("iconspath");
Common::String extraPath = ConfMan.get("extrapath");
#define TRY_ICON_PATH(path) { \
Common::FSNode node((path)); \
if (node.exists()) \
return (path); \
}
if (!iconsPath.empty()) {
TRY_ICON_PATH(iconsPath + "/" + target + ".ico");
TRY_ICON_PATH(iconsPath + "/" + ConfMan.get("gameid") + ".ico");
TRY_ICON_PATH(iconsPath + "/icons/" + target + ".ico");
TRY_ICON_PATH(iconsPath + "/icons/" + ConfMan.get("gameid") + ".ico");
}
if (!extraPath.empty()) {
TRY_ICON_PATH(extraPath + "/" + target + ".ico");
TRY_ICON_PATH(extraPath + "/" + ConfMan.get("gameid") + ".ico");
TRY_ICON_PATH(extraPath + "/icons/" + target + ".ico");
TRY_ICON_PATH(extraPath + "/icons/" + ConfMan.get("gameid") + ".ico");
}
return "";
}
// VerSetConditionMask and VerifyVersionInfo didn't appear until Windows 2000,
// so we need to check for them at runtime
LONGLONG VerSetConditionMaskFunc(ULONGLONG dwlConditionMask, DWORD dwTypeMask, BYTE dwConditionMask) {
typedef BOOL (WINAPI *VerSetConditionMaskFunction)(ULONGLONG conditionMask, DWORD typeMask, BYTE conditionOperator);
VerSetConditionMaskFunction verSetConditionMask = (VerSetConditionMaskFunction)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VerSetConditionMask");
if (verSetConditionMask == NULL)
return 0;
return verSetConditionMask(dwlConditionMask, dwTypeMask, dwConditionMask);
}
BOOL VerifyVersionInfoFunc(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask) {
typedef BOOL (WINAPI *VerifyVersionInfoFunction)(LPOSVERSIONINFOEXA versionInformation, DWORD typeMask, DWORDLONG conditionMask);
VerifyVersionInfoFunction verifyVersionInfo = (VerifyVersionInfoFunction)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VerifyVersionInfoA");
if (verifyVersionInfo == NULL)
return FALSE;
return verifyVersionInfo(lpVersionInformation, dwTypeMask, dwlConditionMask);
}
bool Win32TaskbarManager::isWin7OrLater() {
OSVERSIONINFOEX versionInfo;
DWORDLONG conditionMask = 0;
ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
versionInfo.dwMajorVersion = 6;
versionInfo.dwMinorVersion = 1;
conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
return VerifyVersionInfoFunc(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask);
}
LPWSTR Win32TaskbarManager::ansiToUnicode(const char *s) {
DWORD size = MultiByteToWideChar(0, 0, s, -1, NULL, 0);
if (size > 0) {
LPWSTR result = new WCHAR[size];
if (MultiByteToWideChar(0, 0, s, -1, result, size) != 0)
return result;
}
return NULL;
}
HWND Win32TaskbarManager::getHwnd() {
SDL_SysWMinfo wmi;
SDL_VERSION(&wmi.version);
if(!SDL_GetWMInfo(&wmi))
return NULL;
return wmi.window;
}
#endif

View file

@ -0,0 +1,71 @@
/* 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$
*
*/
#ifndef BACKEND_WIN32_TASKBAR_H
#define BACKEND_WIN32_TASKBAR_H
#if defined(WIN32) && defined(USE_TASKBAR)
#include "common/str.h"
#include "common/taskbar.h"
struct ITaskbarList3;
class Win32TaskbarManager : public Common::TaskbarManager {
public:
Win32TaskbarManager();
virtual ~Win32TaskbarManager();
virtual void setOverlayIcon(const Common::String &name, const Common::String &description);
virtual void setProgressValue(int completed, int total);
virtual void setProgressState(TaskbarProgressState state);
virtual void setCount(int count);
virtual void addRecent(const Common::String &name, const Common::String &description);
private:
ITaskbarList3 *_taskbar;
// Count handling
HICON _icon;
int _count;
/**
* Get the path to an icon for the game
*
* @param target The game target
*
* @return The icon path (or "" if no icon was found)
*/
Common::String getIconPath(Common::String target);
// Helper functions
bool isWin7OrLater();
LPWSTR ansiToUnicode(const char *s);
HWND getHwnd();
};
#endif
#endif // BACKEND_WIN32_TASKBAR_H

View file

@ -205,6 +205,9 @@ bool VirtualKeyboardParser::parserCallback_event(ParserNode *node) {
evt->type = VirtualKeyboard::kVKEventModifier; evt->type = VirtualKeyboard::kVKEventModifier;
byte *flags = (byte*) malloc(sizeof(byte)); byte *flags = (byte*) malloc(sizeof(byte));
if (!flags)
error("[VirtualKeyboardParser::parserCallback_event] Cannot allocate memory");
*(flags) = parseFlags(node->values["modifiers"]); *(flags) = parseFlags(node->values["modifiers"]);
evt->data = flags; evt->data = flags;
@ -217,6 +220,9 @@ bool VirtualKeyboardParser::parserCallback_event(ParserNode *node) {
evt->type = VirtualKeyboard::kVKEventSwitchMode; evt->type = VirtualKeyboard::kVKEventSwitchMode;
String& mode = node->values["mode"]; String& mode = node->values["mode"];
char *str = (char*) malloc(sizeof(char) * mode.size() + 1); char *str = (char*) malloc(sizeof(char) * mode.size() + 1);
if (!str)
error("[VirtualKeyboardParser::parserCallback_event] Cannot allocate memory");
memcpy(str, mode.c_str(), sizeof(char) * mode.size()); memcpy(str, mode.c_str(), sizeof(char) * mode.size());
str[mode.size()] = 0; str[mode.size()] = 0;
evt->data = str; evt->data = str;

View file

@ -25,6 +25,8 @@
#define FORBIDDEN_SYMBOL_EXCEPTION_exit #define FORBIDDEN_SYMBOL_EXCEPTION_exit
#include <limits.h>
#include "engines/metaengine.h" #include "engines/metaengine.h"
#include "base/commandLine.h" #include "base/commandLine.h"
#include "base/plugins.h" #include "base/plugins.h"
@ -162,13 +164,6 @@ void registerDefaults() {
ConfMan.registerDefault("record_temp_file_name", "record.tmp"); ConfMan.registerDefault("record_temp_file_name", "record.tmp");
ConfMan.registerDefault("record_time_file_name", "record.time"); ConfMan.registerDefault("record_time_file_name", "record.time");
#if 0
// NEW CODE TO HIDE CONSOLE FOR WIN32
#ifdef WIN32
// console hiding for win32
ConfMan.registerDefault("show_console", false);
#endif
#endif
} }
// //
@ -197,17 +192,19 @@ void registerDefaults() {
if (!option) usage("Option '%s' requires an argument", argv[isLongCmd ? i : i-1]); if (!option) usage("Option '%s' requires an argument", argv[isLongCmd ? i : i-1]);
// Use this for options which have a required integer value // Use this for options which have a required integer value
// (we don't check ERANGE because WinCE doesn't support errno, so we're stuck just rejecting LONG_MAX/LONG_MIN..)
#define DO_OPTION_INT(shortCmd, longCmd) \ #define DO_OPTION_INT(shortCmd, longCmd) \
DO_OPTION(shortCmd, longCmd) \ DO_OPTION(shortCmd, longCmd) \
char *endptr = 0; \ char *endptr; \
strtol(option, &endptr, 0); \ long int retval = strtol(option, &endptr, 0); \
if (endptr == NULL || *endptr != 0) usage("--%s: Invalid number '%s'", longCmd, option); if (*endptr != '\0' || retval == LONG_MAX || retval == LONG_MIN) \
usage("--%s: Invalid number '%s'", longCmd, option);
// Use this for boolean options; this distinguishes between "-x" and "-X", // Use this for boolean options; this distinguishes between "-x" and "-X",
// resp. between "--some-option" and "--no-some-option". // resp. between "--some-option" and "--no-some-option".
#define DO_OPTION_BOOL(shortCmd, longCmd) \ #define DO_OPTION_BOOL(shortCmd, longCmd) \
if (isLongCmd ? (!strcmp(s+2, longCmd) || !strcmp(s+2, "no-"longCmd)) : (tolower(s[1]) == shortCmd)) { \ if (isLongCmd ? (!strcmp(s+2, longCmd) || !strcmp(s+2, "no-"longCmd)) : (tolower(s[1]) == shortCmd)) { \
bool boolValue = (islower(s[1]) != 0); \ bool boolValue = (islower(static_cast<unsigned char>(s[1])) != 0); \
s += 2; \ s += 2; \
if (isLongCmd) { \ if (isLongCmd) { \
boolValue = !strcmp(s, longCmd); \ boolValue = !strcmp(s, longCmd); \
@ -460,14 +457,11 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
END_OPTION END_OPTION
#endif #endif
#if 0 #if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
// NEW CODE TO HIDE CONSOLE FOR WIN32 // Optional console window on Windows (default: enabled)
#ifdef WIN32 DO_LONG_OPTION_BOOL("console")
// console hiding for win32
DO_LONG_OPTION_BOOL("show-console")
END_OPTION END_OPTION
#endif #endif
#endif
unknownOption: unknownOption:
// If we get till here, the option is unhandled and hence unknown. // If we get till here, the option is unhandled and hence unknown.
@ -575,7 +569,7 @@ static Common::Error listSaves(const char *target) {
" ---- ------------------------------------------------------\n"); " ---- ------------------------------------------------------\n");
for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) { for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) {
printf(" %-4s %s\n", x->save_slot().c_str(), x->description().c_str()); printf(" %-4d %s\n", x->getSaveSlot(), x->getDescription().c_str());
// TODO: Could also iterate over the full hashmap, printing all key-value pairs // TODO: Could also iterate over the full hashmap, printing all key-value pairs
} }
} else { } else {

View file

@ -322,7 +322,7 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
PluginManager::instance().init(); PluginManager::instance().init();
PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager
// If we received an invalid music parameter via command line we check this here. // If we received an invalid music parameter via command line we check this here.
// We can't check this before loading the music plugins. // We can't check this before loading the music plugins.
// On the other hand we cannot load the plugins before we know the file paths (in case of external plugins). // On the other hand we cannot load the plugins before we know the file paths (in case of external plugins).
@ -355,7 +355,7 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
system.getAudioCDManager(); system.getAudioCDManager();
MusicManager::instance(); MusicManager::instance();
Common::DebugManager::instance(); Common::DebugManager::instance();
// Init the event manager. As the virtual keyboard is loaded here, it must // Init the event manager. As the virtual keyboard is loaded here, it must
// take place after the backend is initiated and the screen has been setup // take place after the backend is initiated and the screen has been setup
system.getEventManager()->init(); system.getEventManager()->init();
@ -394,10 +394,10 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
// reallocate the config manager to get rid of any fragmentation // reallocate the config manager to get rid of any fragmentation
ConfMan.defragment(); ConfMan.defragment();
#endif #endif
// Did an error occur ? // Did an error occur ?
if (result.getCode() != Common::kNoError) { if (result.getCode() != Common::kNoError && result.getCode() != Common::kUserCanceled) {
// Shows an informative error dialog if starting the selected game failed. // Shows an informative error dialog if starting the selected game failed.
GUI::displayErrorDialog(result, _("Error running game:")); GUI::displayErrorDialog(result, _("Error running game:"));
} }

View file

@ -220,7 +220,7 @@ PluginManager &PluginManager::instance() {
if (_instance) if (_instance)
return *_instance; return *_instance;
#if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES) #if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES)
_instance = new PluginManagerUncached(); _instance = new PluginManagerUncached();
#else #else
_instance = new PluginManager(); _instance = new PluginManager();
@ -255,7 +255,7 @@ void PluginManager::addPluginProvider(PluginProvider *pp) {
void PluginManagerUncached::init() { void PluginManagerUncached::init() {
unloadAllPlugins(); unloadAllPlugins();
_allEnginePlugins.clear(); _allEnginePlugins.clear();
// Resize our pluginsInMem list to prevent fragmentation // Resize our pluginsInMem list to prevent fragmentation
_pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2); _pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2);
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); // empty the engine plugins unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); // empty the engine plugins
@ -264,7 +264,7 @@ void PluginManagerUncached::init() {
pp != _providers.end(); pp != _providers.end();
++pp) { ++pp) {
PluginList pl((*pp)->getPlugins()); PluginList pl((*pp)->getPlugins());
for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) { for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
// This is a 'hack' based on the assumption that we have no sound // This is a 'hack' based on the assumption that we have no sound
// file plugins. Currently this is the case. If it changes, we // file plugins. Currently this is the case. If it changes, we
@ -272,15 +272,15 @@ void PluginManagerUncached::init() {
// music or an engine plugin. // music or an engine plugin.
if ((*pp)->isFilePluginProvider()) { if ((*pp)->isFilePluginProvider()) {
_allEnginePlugins.push_back(*p); _allEnginePlugins.push_back(*p);
} else if ((*p)->loadPlugin()) { // and this is the proper method } else if ((*p)->loadPlugin()) { // and this is the proper method
if ((*p)->getType() == PLUGIN_TYPE_ENGINE) { if ((*p)->getType() == PLUGIN_TYPE_ENGINE) {
(*p)->unloadPlugin(); (*p)->unloadPlugin();
_allEnginePlugins.push_back(*p); _allEnginePlugins.push_back(*p);
} else { // add non-engine plugins to the 'in-memory' list } else { // add non-engine plugins to the 'in-memory' list
// these won't ever get unloaded // these won't ever get unloaded
addToPluginsInMemList(*p); addToPluginsInMemList(*p);
} }
} }
} }
} }
} }
@ -310,7 +310,7 @@ bool PluginManagerUncached::loadPluginFromGameId(const Common::String &gameId) {
bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename) { bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename) {
if (filename.empty()) if (filename.empty())
return false; return false;
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
PluginList::iterator i; PluginList::iterator i;
@ -324,7 +324,7 @@ bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename)
return false; return false;
} }
/** /**
* Update the config manager with a plugin file name that we found can handle * Update the config manager with a plugin file name that we found can handle
* the game. * the game.
**/ **/
@ -342,7 +342,7 @@ void PluginManagerUncached::updateConfigWithFileName(const Common::String &gameI
} }
} }
void PluginManagerUncached::loadFirstPlugin() { void PluginManagerUncached::loadFirstPlugin() {
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
// let's try to find one we can load // let's try to find one we can load
@ -424,7 +424,7 @@ void PluginManager::addToPluginsInMemList(Plugin *plugin) {
bool found = false; bool found = false;
// The plugin is valid, see if it provides the same module as an // The plugin is valid, see if it provides the same module as an
// already loaded one and should replace it. // already loaded one and should replace it.
PluginList::iterator pl = _pluginsInMem[plugin->getType()].begin(); PluginList::iterator pl = _pluginsInMem[plugin->getType()].begin();
while (!found && pl != _pluginsInMem[plugin->getType()].end()) { while (!found && pl != _pluginsInMem[plugin->getType()].end()) {
if (!strcmp(plugin->getName(), (*pl)->getName())) { if (!strcmp(plugin->getName(), (*pl)->getName())) {
@ -447,9 +447,11 @@ void PluginManager::addToPluginsInMemList(Plugin *plugin) {
#include "engines/metaengine.h" #include "engines/metaengine.h"
namespace Common {
DECLARE_SINGLETON(EngineManager); DECLARE_SINGLETON(EngineManager);
}
/** /**
* This function works for both cached and uncached PluginManagers. * This function works for both cached and uncached PluginManagers.
* For the cached version, most of the logic here will short circuit. * For the cached version, most of the logic here will short circuit.
* *
@ -461,24 +463,24 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng
// First look for the game using the plugins in memory. This is critical // First look for the game using the plugins in memory. This is critical
// for calls coming from inside games // for calls coming from inside games
result = findGameInLoadedPlugins(gameName, plugin); result = findGameInLoadedPlugins(gameName, plugin);
if (!result.gameid().empty()) { if (!result.gameid().empty()) {
return result; return result;
} }
// Now look for the game using the gameId. This is much faster than scanning plugin // Now look for the game using the gameId. This is much faster than scanning plugin
// by plugin // by plugin
if (PluginMan.loadPluginFromGameId(gameName)) { if (PluginMan.loadPluginFromGameId(gameName)) {
result = findGameInLoadedPlugins(gameName, plugin); result = findGameInLoadedPlugins(gameName, plugin);
if (!result.gameid().empty()) { if (!result.gameid().empty()) {
return result; return result;
} }
} }
// We failed to find it using the gameid. Scan the list of plugins // We failed to find it using the gameid. Scan the list of plugins
PluginMan.loadFirstPlugin(); PluginMan.loadFirstPlugin();
do { do {
result = findGameInLoadedPlugins(gameName, plugin); result = findGameInLoadedPlugins(gameName, plugin);
if (!result.gameid().empty()) { if (!result.gameid().empty()) {
// Update with new plugin file name // Update with new plugin file name
PluginMan.updateConfigWithFileName(gameName); PluginMan.updateConfigWithFileName(gameName);
@ -489,7 +491,7 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng
return result; return result;
} }
/** /**
* Find the game within the plugins loaded in memory * Find the game within the plugins loaded in memory
**/ **/
GameDescriptor EngineManager::findGameInLoadedPlugins(const Common::String &gameName, const EnginePlugin **plugin) const { GameDescriptor EngineManager::findGameInLoadedPlugins(const Common::String &gameName, const EnginePlugin **plugin) const {
@ -501,7 +503,7 @@ GameDescriptor EngineManager::findGameInLoadedPlugins(const Common::String &game
*plugin = 0; *plugin = 0;
EnginePlugin::List::const_iterator iter; EnginePlugin::List::const_iterator iter;
for (iter = plugins.begin(); iter != plugins.end(); ++iter) { for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
result = (**iter)->findGame(gameName.c_str()); result = (**iter)->findGame(gameName.c_str());
if (!result.gameid().empty()) { if (!result.gameid().empty()) {
@ -538,7 +540,9 @@ const EnginePlugin::List &EngineManager::getPlugins() const {
#include "audio/musicplugin.h" #include "audio/musicplugin.h"
namespace Common {
DECLARE_SINGLETON(MusicManager); DECLARE_SINGLETON(MusicManager);
}
const MusicPlugin::List &MusicManager::getPlugins() const { const MusicPlugin::List &MusicManager::getPlugins() const {
return (const MusicPlugin::List &)PluginManager::instance().getPlugins(PLUGIN_TYPE_MUSIC); return (const MusicPlugin::List &)PluginManager::instance().getPlugins(PLUGIN_TYPE_MUSIC);

View file

@ -143,7 +143,7 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
// Abstract plugins // Abstract plugins
/** /**
* Abstract base class for the plugin objects which handle plugins * Abstract base class for the plugin objects which handle plugins
* instantiation. Subclasses for this may be used for engine plugins and other * instantiation. Subclasses for this may be used for engine plugins and other
* types of plugins. An existing PluginObject refers to an executable file * types of plugins. An existing PluginObject refers to an executable file
* loaded in memory and ready to run. The plugin, on the other hand, is just * loaded in memory and ready to run. The plugin, on the other hand, is just
@ -310,7 +310,7 @@ protected:
bool tryLoadPlugin(Plugin *plugin); bool tryLoadPlugin(Plugin *plugin);
void addToPluginsInMemList(Plugin *plugin); void addToPluginsInMemList(Plugin *plugin);
static PluginManager *_instance; static PluginManager *_instance;
PluginManager(); PluginManager();
@ -326,9 +326,9 @@ public:
virtual void init() {} virtual void init() {}
virtual void loadFirstPlugin() {} virtual void loadFirstPlugin() {}
virtual bool loadNextPlugin() { return false; } virtual bool loadNextPlugin() { return false; }
virtual bool loadPluginFromGameId(const Common::String &gameId) { return false; } virtual bool loadPluginFromGameId(const Common::String &gameId) { return false; }
virtual void updateConfigWithFileName(const Common::String &gameId) {} virtual void updateConfigWithFileName(const Common::String &gameId) {}
// Functions used only by the cached PluginManager // Functions used only by the cached PluginManager
virtual void loadAllPlugins(); virtual void loadAllPlugins();
void unloadAllPlugins(); void unloadAllPlugins();
@ -338,7 +338,7 @@ public:
const PluginList &getPlugins(PluginType t) { return _pluginsInMem[t]; } const PluginList &getPlugins(PluginType t) { return _pluginsInMem[t]; }
}; };
/** /**
* Uncached version of plugin manager * Uncached version of plugin manager
* Keeps only one dynamic plugin in memory at a time * Keeps only one dynamic plugin in memory at a time
**/ **/
@ -349,15 +349,15 @@ protected:
PluginList::iterator _currentPlugin; PluginList::iterator _currentPlugin;
PluginManagerUncached() {} PluginManagerUncached() {}
bool loadPluginByFileName(const Common::String &filename); bool loadPluginByFileName(const Common::String &filename);
public: public:
virtual void init(); virtual void init();
virtual void loadFirstPlugin(); virtual void loadFirstPlugin();
virtual bool loadNextPlugin(); virtual bool loadNextPlugin();
virtual bool loadPluginFromGameId(const Common::String &gameId); virtual bool loadPluginFromGameId(const Common::String &gameId);
virtual void updateConfigWithFileName(const Common::String &gameId); virtual void updateConfigWithFileName(const Common::String &gameId);
virtual void loadAllPlugins() {} // we don't allow this virtual void loadAllPlugins() {} // we don't allow this
}; };

View file

@ -60,6 +60,11 @@ const char *gResidualBuildDate = __DATE__ " " __TIME__;
const char *gResidualVersionDate = RESIDUAL_VERSION " (" __DATE__ " " __TIME__ ")"; const char *gResidualVersionDate = RESIDUAL_VERSION " (" __DATE__ " " __TIME__ ")";
const char *gResidualFullVersion = "Residual " RESIDUAL_VERSION " (" __DATE__ " " __TIME__ ")"; const char *gResidualFullVersion = "Residual " RESIDUAL_VERSION " (" __DATE__ " " __TIME__ ")";
const char *gResidualFeatures = "" const char *gResidualFeatures = ""
#ifdef TAINTED_BUILD
// TAINTED means the build contains engines/subengines not enabled by default
"TAINTED "
#endif
#ifdef USE_TREMOR #ifdef USE_TREMOR
#ifdef USE_TREMOLO #ifdef USE_TREMOLO
// libTremolo is used on WinCE for better ogg performance // libTremolo is used on WinCE for better ogg performance

View file

@ -27,10 +27,10 @@
#include "common/savefile.h" #include "common/savefile.h"
#include "common/textconsole.h" #include "common/textconsole.h"
DECLARE_SINGLETON(Common::EventRecorder);
namespace Common { namespace Common {
DECLARE_SINGLETON(EventRecorder);
#define RECORD_SIGNATURE 0x54455354 #define RECORD_SIGNATURE 0x54455354
#define RECORD_VERSION 1 #define RECORD_VERSION 1

View file

@ -285,7 +285,7 @@ void SearchManager::clear() {
addDirectory(".", ".", -2); addDirectory(".", ".", -2);
} }
DECLARE_SINGLETON(SearchManager);
} // namespace Common } // namespace Common
DECLARE_SINGLETON(Common::SearchManager);

View file

@ -143,7 +143,7 @@ class SearchSet : public Archive {
ArchiveNodeList::iterator find(const String &name); ArchiveNodeList::iterator find(const String &name);
ArchiveNodeList::const_iterator find(const String &name) const; ArchiveNodeList::const_iterator find(const String &name) const;
// Add an archive keeping the list sorted by ascending priorities. // Add an archive keeping the list sorted by descending priority.
void insert(const Node& node); void insert(const Node& node);
public: public:

View file

@ -252,6 +252,13 @@ public:
_size = newSize; _size = newSize;
} }
void assign(const_iterator first, const_iterator last) {
resize(distance(first, last)); // FIXME: ineffective?
T *dst = _storage;
while (first != last)
*dst++ = *first++;
}
protected: protected:
static uint roundUpCapacity(uint capacity) { static uint roundUpCapacity(uint capacity) {
// Round up capacity to the next power of 2; // Round up capacity to the next power of 2;

View file

@ -38,7 +38,7 @@ namespace Common {
*/ */
bool ConfigFile::isValidName(const Common::String &name) { bool ConfigFile::isValidName(const Common::String &name) {
const char *p = name.c_str(); const char *p = name.c_str();
while (*p && (isalnum(*p) || *p == '-' || *p == '_' || *p == '.')) while (*p && (isalnum(static_cast<unsigned char>(*p)) || *p == '-' || *p == '_' || *p == '.'))
p++; p++;
return *p == 0; return *p == 0;
} }
@ -116,7 +116,7 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
// is, verify that it only consists of alphanumerics, // is, verify that it only consists of alphanumerics,
// periods, dashes and underscores). Mohawk Living Books games // periods, dashes and underscores). Mohawk Living Books games
// can have periods in their section names. // can have periods in their section names.
while (*p && (isalnum(*p) || *p == '-' || *p == '_' || *p == '.')) while (*p && (isalnum(static_cast<unsigned char>(*p)) || *p == '-' || *p == '_' || *p == '.'))
p++; p++;
if (*p == '\0') if (*p == '\0')
@ -139,7 +139,7 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
// Skip leading whitespaces // Skip leading whitespaces
const char *t = line.c_str(); const char *t = line.c_str();
while (isspace(*t)) while (isspace(static_cast<unsigned char>(*t)))
t++; t++;
// Skip empty lines / lines with only whitespace // Skip empty lines / lines with only whitespace

View file

@ -27,17 +27,17 @@
#include "common/system.h" #include "common/system.h"
#include "common/textconsole.h" #include "common/textconsole.h"
DECLARE_SINGLETON(Common::ConfigManager);
static bool isValidDomainName(const Common::String &domName) { static bool isValidDomainName(const Common::String &domName) {
const char *p = domName.c_str(); const char *p = domName.c_str();
while (*p && (isalnum(*p) || *p == '-' || *p == '_')) while (*p && (isalnum(static_cast<unsigned char>(*p)) || *p == '-' || *p == '_'))
p++; p++;
return *p == 0; return *p == 0;
} }
namespace Common { namespace Common {
DECLARE_SINGLETON(ConfigManager);
const char *ConfigManager::kApplicationDomain = "residual"; const char *ConfigManager::kApplicationDomain = "residual";
const char *ConfigManager::kTransientDomain = "__TRANSIENT"; const char *ConfigManager::kTransientDomain = "__TRANSIENT";
@ -187,7 +187,7 @@ void ConfigManager::loadFromStream(SeekableReadStream &stream) {
// Get the domain name, and check whether it's valid (that // Get the domain name, and check whether it's valid (that
// is, verify that it only consists of alphanumerics, // is, verify that it only consists of alphanumerics,
// dashes and underscores). // dashes and underscores).
while (*p && (isalnum(*p) || *p == '-' || *p == '_')) while (*p && (isalnum(static_cast<unsigned char>(*p)) || *p == '-' || *p == '_'))
p++; p++;
if (*p == '\0') if (*p == '\0')
@ -205,7 +205,7 @@ void ConfigManager::loadFromStream(SeekableReadStream &stream) {
// Skip leading whitespaces // Skip leading whitespaces
const char *t = line.c_str(); const char *t = line.c_str();
while (isspace(*t)) while (isspace(static_cast<unsigned char>(*t)))
t++; t++;
// Skip empty lines / lines with only whitespace // Skip empty lines / lines with only whitespace
@ -491,11 +491,9 @@ int ConfigManager::getInt(const String &key, const String &domName) const {
bool ConfigManager::getBool(const String &key, const String &domName) const { bool ConfigManager::getBool(const String &key, const String &domName) const {
String value(get(key, domName)); String value(get(key, domName));
bool val;
if ((value == "true") || (value == "yes") || (value == "1")) if (Common::parseBool(value, val))
return true; return val;
if ((value == "false") || (value == "no") || (value == "0"))
return false;
error("ConfigManager::getBool(%s,%s): '%s' is not a valid bool", error("ConfigManager::getBool(%s,%s): '%s' is not a valid bool",
key.c_str(), domName.c_str(), value.c_str()); key.c_str(), domName.c_str(), value.c_str());

View file

@ -147,7 +147,7 @@ public:
static void defragment(); // move in memory to reduce fragmentation static void defragment(); // move in memory to reduce fragmentation
void copyFrom(ConfigManager &source); void copyFrom(ConfigManager &source);
private: private:
friend class Singleton<SingletonBaseType>; friend class Singleton<SingletonBaseType>;
ConfigManager(); ConfigManager();

View file

@ -23,16 +23,17 @@
#include "common/debug-channels.h" #include "common/debug-channels.h"
#include "common/system.h" #include "common/system.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "common/algorithm.h"
#include <stdarg.h> // For va_list etc. #include <stdarg.h> // For va_list etc.
// TODO: Move gDebugLevel into namespace Common. // TODO: Move gDebugLevel into namespace Common.
int gDebugLevel = -1; int gDebugLevel = -1;
DECLARE_SINGLETON(Common::DebugManager);
namespace Common { namespace Common {
DECLARE_SINGLETON(DebugManager);
namespace { namespace {
struct DebugLevelComperator { struct DebugLevelComperator {
@ -107,18 +108,13 @@ bool DebugManager::isDebugChannelEnabled(uint32 channel) {
#ifndef DISABLE_TEXT_CONSOLE #ifndef DISABLE_TEXT_CONSOLE
static void debugHelper(const char *s, va_list va, bool caret = true) { static void debugHelper(const char *s, va_list va, bool caret = true) {
char buf[STRINGBUFLEN]; Common::String buf = Common::String::vformat(s, va);
vsnprintf(buf, STRINGBUFLEN, s, va); if (caret)
buf[STRINGBUFLEN-1] = '\0'; buf += '\n';
if (caret) {
buf[STRINGBUFLEN-2] = '\0';
strcat(buf, "\n");
}
if (g_system) if (g_system)
g_system->logMessage(LogMessageType::kDebug, buf); g_system->logMessage(LogMessageType::kDebug, buf.c_str());
// TODO: Think of a good fallback in case we do not have // TODO: Think of a good fallback in case we do not have
// any OSystem yet. // any OSystem yet.
} }

View file

@ -67,6 +67,9 @@ static String errorToString(ErrorCode errorCode) {
case kEnginePluginNotSupportSaves: case kEnginePluginNotSupportSaves:
return _s("Engine plugin does not support save states"); return _s("Engine plugin does not support save states");
case kUserCanceled:
return _s("User canceled");
case kUnknownError: case kUnknownError:
default: default:
return _s("Unknown error"); return _s("Unknown error");

View file

@ -62,6 +62,8 @@ enum ErrorCode {
kEnginePluginNotFound, ///< Failed to find plugin to handle target kEnginePluginNotFound, ///< Failed to find plugin to handle target
kEnginePluginNotSupportSaves, ///< Failed if plugin does not support listing save states kEnginePluginNotSupportSaves, ///< Failed if plugin does not support listing save states
kUserCanceled, ///< User has canceled the launching of the game
kUnknownError ///< Catch-all error, used if no other error code matches kUnknownError ///< Catch-all error, used if no other error code matches
}; };

View file

@ -29,7 +29,7 @@
* infrastructure code do not make use of certain "forbidden" APIs, such * infrastructure code do not make use of certain "forbidden" APIs, such
* as fopen(), setjmp(), etc. * as fopen(), setjmp(), etc.
* This is achieved by re-#defining various symbols to a "garbage" * This is achieved by re-#defining various symbols to a "garbage"
* string which then trigers a compiler error. * string which then triggers a compiler error.
* *
* Backend files may #define FORBIDDEN_SYMBOL_ALLOW_ALL if they * Backend files may #define FORBIDDEN_SYMBOL_ALLOW_ALL if they
* have to access functions like fopen, fread etc. * have to access functions like fopen, fread etc.
@ -203,6 +203,11 @@
#define exit(a) FORBIDDEN_SYMBOL_REPLACEMENT #define exit(a) FORBIDDEN_SYMBOL_REPLACEMENT
#endif #endif
#ifndef FORBIDDEN_SYMBOL_EXCEPTION_abort
#undef abort
#define abort() FORBIDDEN_SYMBOL_REPLACEMENT
#endif
#ifndef FORBIDDEN_SYMBOL_EXCEPTION_getenv #ifndef FORBIDDEN_SYMBOL_EXCEPTION_getenv
#undef getenv #undef getenv
#define getenv(a) FORBIDDEN_SYMBOL_REPLACEMENT #define getenv(a) FORBIDDEN_SYMBOL_REPLACEMENT

View file

@ -106,8 +106,9 @@ private:
HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR
}; };
#ifdef USE_HASHMAP_MEMORY_POOL
ObjectPool<Node, HASHMAP_MEMORYPOOL_SIZE> _nodePool; ObjectPool<Node, HASHMAP_MEMORYPOOL_SIZE> _nodePool;
#endif
Node **_storage; ///< hashtable of size arrsize. Node **_storage; ///< hashtable of size arrsize.
uint _mask; ///< Capacity of the HashMap minus one; must be a power of two of minus one uint _mask; ///< Capacity of the HashMap minus one; must be a power of two of minus one
@ -128,12 +129,20 @@ private:
#endif #endif
Node *allocNode(const Key &key) { Node *allocNode(const Key &key) {
#ifdef USE_HASHMAP_MEMORY_POOL
return new (_nodePool) Node(key); return new (_nodePool) Node(key);
#else
return new Node(key);
#endif
} }
void freeNode(Node *node) { void freeNode(Node *node) {
if (node && node != HASHMAP_DUMMY_NODE) if (node && node != HASHMAP_DUMMY_NODE)
#ifdef USE_HASHMAP_MEMORY_POOL
_nodePool.deleteChunk(node); _nodePool.deleteChunk(node);
#else
delete node;
#endif
} }
void assign(const HM_t &map); void assign(const HM_t &map);

View file

@ -107,14 +107,17 @@ bool MacResManager::open(String filename) {
#ifdef MACOSX #ifdef MACOSX
// Check the actual fork on a Mac computer // Check the actual fork on a Mac computer
String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc"; String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc";
SeekableReadStream *macResForkRawStream = FSNode(fullPath).createReadStream();; FSNode resFsNode = FSNode(fullPath);
if (resFsNode.exists()) {
SeekableReadStream *macResForkRawStream = resFsNode.createReadStream();;
if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) { if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) {
_baseFileName = filename; _baseFileName = filename;
return true; return true;
}
delete macResForkRawStream;
} }
delete macResForkRawStream;
#endif #endif
File *file = new File(); File *file = new File();
@ -167,14 +170,17 @@ bool MacResManager::open(FSNode path, String filename) {
#ifdef MACOSX #ifdef MACOSX
// Check the actual fork on a Mac computer // Check the actual fork on a Mac computer
String fullPath = path.getPath() + "/" + filename + "/..namedfork/rsrc"; String fullPath = path.getPath() + "/" + filename + "/..namedfork/rsrc";
SeekableReadStream *macResForkRawStream = FSNode(fullPath).createReadStream(); FSNode resFsNode = FSNode(fullPath);
if (resFsNode.exists()) {
SeekableReadStream *macResForkRawStream = resFsNode.createReadStream();;
if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) { if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) {
_baseFileName = filename; _baseFileName = filename;
return true; return true;
}
delete macResForkRawStream;
} }
delete macResForkRawStream;
#endif #endif
// First, let's try to see if the Mac converted name exists // First, let's try to see if the Mac converted name exists

View file

@ -240,7 +240,7 @@ public:
operator bool() const { return _pointer != 0; } operator bool() const { return _pointer != 0; }
~ScopedPtr() { ~ScopedPtr() {
delete _pointer; delete _pointer;
} }
/** /**

View file

@ -306,6 +306,19 @@
#define MAXPATHLEN 256 #define MAXPATHLEN 256
#endif #endif
#ifndef scumm_va_copy
#if defined(va_copy)
#define scumm_va_copy va_copy
#elif defined(__va_copy)
#define scumm_va_copy __va_copy
#elif defined(_MSC_VER)
#define scumm_va_copy(dst, src) ((dst) = (src))
#else
#error scumm_va_copy undefined for this port
#endif
#endif
// //
// Typedef our system types unless they have already been defined by config.h, // Typedef our system types unless they have already been defined by config.h,

View file

@ -89,15 +89,13 @@ protected:
}; };
/** /**
* Note that you need to use this macro from the global namespace. * Note that you need to use this macro from the Common namespace.
* *
* This is because C++ requires initial explicit specialization * This is because C++ requires initial explicit specialization
* to be placed in the same namespace as the template. * to be placed in the same namespace as the template.
* It has to be put in the global namespace to assure the correct
* namespace Common is referenced.
*/ */
#define DECLARE_SINGLETON(T) \ #define DECLARE_SINGLETON(T) \
template<> T *Common::Singleton<T>::_singleton = 0 template<> T *Singleton<T>::_singleton = 0
} // End of namespace Common } // End of namespace Common

View file

@ -25,8 +25,6 @@
#include "common/str.h" #include "common/str.h"
#include "common/util.h" #include "common/util.h"
#include <stdarg.h>
namespace Common { namespace Common {
MemoryPool *g_refCountPool = 0; // FIXME: This is never freed right now MemoryPool *g_refCountPool = 0; // FIXME: This is never freed right now
@ -407,7 +405,7 @@ void String::trim() {
makeUnique(); makeUnique();
// Trim trailing whitespace // Trim trailing whitespace
while (_size >= 1 && isspace(_str[_size - 1])) while (_size >= 1 && isspace(static_cast<unsigned char>(_str[_size - 1])))
--_size; --_size;
_str[_size] = 0; _str[_size] = 0;
@ -429,10 +427,22 @@ uint String::hash() const {
// static // static
String String::format(const char *fmt, ...) { String String::format(const char *fmt, ...) {
String output; String output;
assert(output.isStorageIntern());
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
output = String::vformat(fmt, va);
va_end(va);
return output;
}
// static
String String::vformat(const char *fmt, va_list args) {
String output;
assert(output.isStorageIntern());
va_list va;
scumm_va_copy(va, args);
int len = vsnprintf(output._str, _builtinCapacity, fmt, va); int len = vsnprintf(output._str, _builtinCapacity, fmt, va);
va_end(va); va_end(va);
@ -457,7 +467,7 @@ String String::format(const char *fmt, ...) {
assert(!output.isStorageIntern()); assert(!output.isStorageIntern());
size = output._extern._capacity; size = output._extern._capacity;
va_start(va, fmt); scumm_va_copy(va, args);
len = vsnprintf(output._str, size, fmt, va); len = vsnprintf(output._str, size, fmt, va);
va_end(va); va_end(va);
} while (len == -1 || len >= size - 1); } while (len == -1 || len >= size - 1);
@ -468,7 +478,7 @@ String String::format(const char *fmt, ...) {
} else { } else {
// vsnprintf didn't have enough space, so grow buffer // vsnprintf didn't have enough space, so grow buffer
output.ensureCapacity(len, false); output.ensureCapacity(len, false);
va_start(va, fmt); scumm_va_copy(va, args);
int len2 = vsnprintf(output._str, len+1, fmt, va); int len2 = vsnprintf(output._str, len+1, fmt, va);
va_end(va); va_end(va);
assert(len == len2); assert(len == len2);
@ -596,14 +606,14 @@ String operator+(const String &x, char y) {
} }
char *ltrim(char *t) { char *ltrim(char *t) {
while (isspace(*t)) while (isspace(static_cast<unsigned char>(*t)))
t++; t++;
return t; return t;
} }
char *rtrim(char *t) { char *rtrim(char *t) {
int l = strlen(t) - 1; int l = strlen(t) - 1;
while (l >= 0 && isspace(t[l])) while (l >= 0 && isspace(static_cast<unsigned char>(t[l])))
t[l--] = 0; t[l--] = 0;
return t; return t;
} }

View file

@ -24,6 +24,8 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#include <stdarg.h>
namespace Common { namespace Common {
/** /**
@ -213,10 +215,19 @@ public:
uint hash() const; uint hash() const;
/** /**
* Printf-like function. Returns a formatted String. * Print formatted data into a String object. Similar to sprintf,
* except that it stores the result in (variably sized) String
* instead of a fixed size buffer.
*/ */
static Common::String format(const char *fmt, ...) GCC_PRINTF(1,2); static Common::String format(const char *fmt, ...) GCC_PRINTF(1,2);
/**
* Print formatted data into a String object. Similar to vsprintf,
* except that it stores the result in (variably sized) String
* instead of a fixed size buffer.
*/
static Common::String vformat(const char *fmt, va_list args);
public: public:
typedef char * iterator; typedef char * iterator;
typedef const char * const_iterator; typedef const char * const_iterator;

View file

@ -21,17 +21,13 @@
*/ */
#define FORBIDDEN_SYMBOL_EXCEPTION_exit #define FORBIDDEN_SYMBOL_EXCEPTION_exit
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
#define FORBIDDEN_SYMBOL_EXCEPTION_fputs
#define FORBIDDEN_SYMBOL_EXCEPTION_fflush
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
#include "common/system.h" #include "common/system.h"
#include "common/events.h" #include "common/events.h"
#include "common/fs.h" #include "common/fs.h"
#include "common/savefile.h" #include "common/savefile.h"
#include "common/str.h" #include "common/str.h"
#include "common/taskbar.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "backends/audiocd/default/default-audiocd.h" #include "backends/audiocd/default/default-audiocd.h"
@ -45,6 +41,9 @@ OSystem::OSystem() {
_eventManager = 0; _eventManager = 0;
_timerManager = 0; _timerManager = 0;
_savefileManager = 0; _savefileManager = 0;
#if defined(USE_TASKBAR)
_taskbarManager = 0;
#endif
_fsFactory = 0; _fsFactory = 0;
} }
@ -58,6 +57,11 @@ OSystem::~OSystem() {
delete _timerManager; delete _timerManager;
_timerManager = 0; _timerManager = 0;
#if defined(USE_TASKBAR)
delete _taskbarManager;
_taskbarManager = 0;
#endif
delete _savefileManager; delete _savefileManager;
_savefileManager = 0; _savefileManager = 0;
@ -115,20 +119,6 @@ Common::String OSystem::getDefaultConfigFileName() {
return "residual.ini"; return "residual.ini";
} }
void OSystem::logMessage(LogMessageType::Type type, const char *message) {
#if !defined(__PLAYSTATION2__) && !defined(__DS__)
FILE *output = 0;
if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
output = stdout;
else
output = stderr;
fputs(message, output);
fflush(output);
#endif
}
Common::String OSystem::getSystemLanguage() const { Common::String OSystem::getSystemLanguage() const {
return "en_US"; return "en_US";
} }

View file

@ -42,6 +42,9 @@ struct Rect;
class SaveFileManager; class SaveFileManager;
class SearchSet; class SearchSet;
class String; class String;
#if defined(USE_TASKBAR)
class TaskbarManager;
#endif
class TimerManager; class TimerManager;
class SeekableReadStream; class SeekableReadStream;
class WriteStream; class WriteStream;
@ -149,6 +152,15 @@ protected:
*/ */
Common::SaveFileManager *_savefileManager; Common::SaveFileManager *_savefileManager;
#if defined(USE_TASKBAR)
/**
* No default value is provided for _savefileManager by OSystem.
*
* @note _savefileManager is deleted by the OSystem destructor.
*/
Common::TaskbarManager *_taskbarManager;
#endif
/** /**
* No default value is provided for _fsFactory by OSystem. * No default value is provided for _fsFactory by OSystem.
* *
@ -622,6 +634,18 @@ public:
return _savefileManager; return _savefileManager;
} }
#if defined(USE_TASKBAR)
/**
* Returns the TaskbarManager, used to handle progress bars,
* icon overlay, tasks and recent items list on the taskbar.
*
* @return the TaskbarManager for the current architecture
*/
virtual Common::TaskbarManager *getTaskbarManager() {
return _taskbarManager;
}
#endif
/** /**
* Returns the FilesystemFactory object, depending on the current architecture. * Returns the FilesystemFactory object, depending on the current architecture.
* *
@ -676,7 +700,7 @@ public:
* @param type the type of the message * @param type the type of the message
* @param message the message itself * @param message the message itself
*/ */
virtual void logMessage(LogMessageType::Type type, const char *message); virtual void logMessage(LogMessageType::Type type, const char *message) = 0;
/** /**
* Open the log file in a way that allows the user to review it, * Open the log file in a way that allows the user to review it,
@ -727,7 +751,7 @@ public:
}; };
/** The global OSystem instance. Initialised in main(). */ /** The global OSystem instance. Initialized in main(). */
extern OSystem *g_system; extern OSystem *g_system;
#endif #endif

133
common/taskbar.h Normal file
View file

@ -0,0 +1,133 @@
/* 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$
*/
#ifndef COMMON_TASKBAR_MANAGER_H
#define COMMON_TASKBAR_MANAGER_H
#include "common/scummsys.h"
#include "common/str.h"
#if defined(USE_TASKBAR)
namespace Common {
/**
* The TaskbarManager allows interaction with the ScummVM application icon:
* - in the taskbar on Windows 7 and later
* - in the launcher for Unity
* - in the dock on MacOSX
* - ...
*
* This allows GUI code and engines to display a progress bar, an overlay icon and/or count
* associated with the ScummVM icon as well as add the started engine to the recent items
* list (so that the user can start the engine directly in one click).
*
* Examples of use:
* - Track search progress and found engines when running the Mass Add dialog
* - Add an entry to the recent items when starting an engine
* - Show the current running engine icon as an overlay
*
* @note functionality will vary between supported platforms (due to API limitations)
* and some of the methods will just be no-ops or approximate the functionality
* as best as possible
*/
class TaskbarManager {
public:
/**
* Values representing the taskbar progress state
*/
enum TaskbarProgressState {
kTaskbarNoProgress = 0,
kTaskbarIndeterminate = 1,
kTaskbarNormal = 2,
kTaskbarError = 4,
kTaskbarPaused = 8
};
TaskbarManager() {}
virtual ~TaskbarManager() {}
/**
* Sets an overlay icon on the taskbar icon
*
* When an empty name is given, no icon is shown
* and the current overlay icon (if any) is removed
*
* @param name Path to the icon
* @param description The description
*
* @note on Windows, the icon should be an ICO file
*/
virtual void setOverlayIcon(const String &name, const String &description) {}
/**
* Sets a progress value on the taskbar icon
*
* @param completed The current progress value.
* @param total The maximum progress value.
*/
virtual void setProgressValue(int completed, int total) {}
/**
* Sets the progress state on the taskbar icon
*
* State can be any of the following:
* - NoProgress: disable display of progress state
* - Indeterminate
* - Normal
* - Error
* - Paused
*
* @param state The progress state
*/
virtual void setProgressState(TaskbarProgressState state) {}
/**
* Sets the count number associated with the icon as an overlay
*
* @param count The count
*
* @note Setting a count of 0 will hide the count
*/
virtual void setCount(int count) {}
/**
* Adds an engine to the recent items list
*
* Path is automatically set to the current executable path,
* an icon name is generated (with fallback to default icon)
* and the command line is set to start the engine on click.
*
* @param name The target name.
* @param description The description.
*/
virtual void addRecent(const String &name, const String &description) {}
};
} // End of namespace Common
#endif
#endif // COMMON_TASKBAR_MANAGER_H

View file

@ -46,14 +46,14 @@ void setErrorHandler(ErrorHandler handler) {
#ifndef DISABLE_TEXT_CONSOLE #ifndef DISABLE_TEXT_CONSOLE
void warning(const char *s, ...) { void warning(const char *s, ...) {
char buf[STRINGBUFLEN]; Common::String output;
va_list va; va_list va;
va_start(va, s); va_start(va, s);
vsnprintf(buf, STRINGBUFLEN, s, va); output = Common::String::vformat(s, va);
va_end(va); va_end(va);
Common::String output = Common::String::format("WARNING: %s!\n", buf); output = "WARNING: " + output + "!\n";
if (g_system) if (g_system)
g_system->logMessage(LogMessageType::kWarning, output.c_str()); g_system->logMessage(LogMessageType::kWarning, output.c_str());
@ -64,6 +64,9 @@ void warning(const char *s, ...) {
#endif #endif
void NORETURN_PRE error(const char *s, ...) { void NORETURN_PRE error(const char *s, ...) {
// We don't use String::vformat here, as that require
// using the heap, and that might be impossible at this
// point, e.g. if the error was an "out-of-memory" error.
char buf_input[STRINGBUFLEN]; char buf_input[STRINGBUFLEN];
char buf_output[STRINGBUFLEN]; char buf_output[STRINGBUFLEN];
va_list va; va_list va;

View file

@ -37,10 +37,10 @@
#ifdef USE_TRANSLATION #ifdef USE_TRANSLATION
DECLARE_SINGLETON(Common::TranslationManager);
namespace Common { namespace Common {
DECLARE_SINGLETON(TranslationManager);
bool operator<(const TLanguage &l, const TLanguage &r) { bool operator<(const TLanguage &l, const TLanguage &r) {
return strcmp(l.name, r.name) < 0; return strcmp(l.name, r.name) < 0;
} }
@ -223,13 +223,21 @@ String TranslationManager::getLangById(int id) const {
} }
bool TranslationManager::openTranslationsFile(File& inFile) { bool TranslationManager::openTranslationsFile(File& inFile) {
// First try to open it directly (i.e. using the SearchMan). // First look in the Themepath if we can find the file.
if (inFile.open("translations.dat")) if (ConfMan.hasKey("themepath") && openTranslationsFile(FSNode(ConfMan.get("themepath")), inFile))
return true; return true;
// Then look in the Themepath if we can find the file. // Then try to open it using the SearchMan.
if (ConfMan.hasKey("themepath")) ArchiveMemberList fileList;
return openTranslationsFile(FSNode(ConfMan.get("themepath")), inFile); SearchMan.listMatchingMembers(fileList, "translations.dat");
for (ArchiveMemberList::iterator it = fileList.begin(); it != fileList.end(); ++it) {
SeekableReadStream *stream = it->get()->createReadStream();
if (stream && inFile.open(stream, it->get()->getName())) {
if (checkHeader(inFile))
return true;
inFile.close();
}
}
return false; return false;
} }
@ -243,8 +251,11 @@ bool TranslationManager::openTranslationsFile(const FSNode &node, File& inFile,
// necessary to make them here. But it avoid printing warnings. // necessary to make them here. But it avoid printing warnings.
FSNode fileNode = node.getChild("translations.dat"); FSNode fileNode = node.getChild("translations.dat");
if (fileNode.exists() && fileNode.isReadable() && !fileNode.isDirectory()) { if (fileNode.exists() && fileNode.isReadable() && !fileNode.isDirectory()) {
if (inFile.open(fileNode)) if (inFile.open(fileNode)) {
return true; if (checkHeader(inFile))
return true;
inFile.close();
}
} }
// Check if we exceeded the given recursion depth // Check if we exceeded the given recursion depth
@ -268,13 +279,10 @@ bool TranslationManager::openTranslationsFile(const FSNode &node, File& inFile,
void TranslationManager::loadTranslationsInfoDat() { void TranslationManager::loadTranslationsInfoDat() {
File in; File in;
if (!openTranslationsFile(in)) { if (!openTranslationsFile(in)) {
warning("You are missing the 'translations.dat' file. GUI translation will not be available"); warning("You are missing a valid 'translations.dat' file. GUI translation will not be available");
return; return;
} }
if (!checkHeader(in))
return;
char buf[256]; char buf[256];
int len; int len;
@ -302,8 +310,13 @@ void TranslationManager::loadTranslationsInfoDat() {
_messageIds.resize(numMessages); _messageIds.resize(numMessages);
for (int i = 0; i < numMessages; ++i) { for (int i = 0; i < numMessages; ++i) {
len = in.readUint16BE(); len = in.readUint16BE();
in.read(buf, len); String msg;
_messageIds[i] = String(buf, len - 1); while (len > 0) {
in.read(buf, len > 256 ? 256 : len);
msg += String(buf, len > 256 ? 256 : len - 1);
len -= 256;
}
_messageIds[i] = msg;
} }
} }
@ -321,9 +334,6 @@ void TranslationManager::loadLanguageDat(int index) {
if (!openTranslationsFile(in)) if (!openTranslationsFile(in))
return; return;
if (!checkHeader(in))
return;
char buf[1024]; char buf[1024];
int len; int len;
@ -357,8 +367,13 @@ void TranslationManager::loadLanguageDat(int index) {
for (int i = 0; i < nbMessages; ++i) { for (int i = 0; i < nbMessages; ++i) {
_currentTranslationMessages[i].msgid = in.readUint16BE(); _currentTranslationMessages[i].msgid = in.readUint16BE();
len = in.readUint16BE(); len = in.readUint16BE();
in.read(buf, len); String msg;
_currentTranslationMessages[i].msgstr = String(buf, len - 1); while (len > 0) {
in.read(buf, len > 256 ? 256 : len);
msg += String(buf, len > 256 ? 256 : len - 1);
len -= 256;
}
_currentTranslationMessages[i].msgstr = msg;
len = in.readUint16BE(); len = in.readUint16BE();
if (len > 0) { if (len > 0) {
in.read(buf, len); in.read(buf, len);
@ -376,7 +391,7 @@ bool TranslationManager::checkHeader(File &in) {
// Check header // Check header
if (strcmp(buf, "TRANSLATIONS")) { if (strcmp(buf, "TRANSLATIONS")) {
warning("Your 'translations.dat' file is corrupt. GUI translation will not be available"); warning("File '%s' is not a valid translations data file. Skipping this file", in.getName());
return false; return false;
} }
@ -384,7 +399,7 @@ bool TranslationManager::checkHeader(File &in) {
ver = in.readByte(); ver = in.readByte();
if (ver != TRANSLATIONS_DAT_VER) { if (ver != TRANSLATIONS_DAT_VER) {
warning("Your 'translations.dat' file has a mismatching version, expected was %d but you got %d. GUI translation will not be available", TRANSLATIONS_DAT_VER, ver); warning("File '%s' has a mismatching version, expected was %d but you got %d. Skipping this file", in.getName(), TRANSLATIONS_DAT_VER, ver);
return false; return false;
} }

View file

@ -213,11 +213,6 @@ enum RenderMode {
kRenderAmiga = 5 kRenderAmiga = 5
}; };
enum HerculesDimensions {
kHercW = 720,
kHercH = 350
};
struct RenderModeDescription { struct RenderModeDescription {
const char *code; const char *code;
const char *description; const char *description;

View file

@ -263,7 +263,7 @@ bool XMLParser::vparseIntegerKey(const char *key, int count, va_list args) {
int *num_ptr; int *num_ptr;
while (count--) { while (count--) {
while (isspace(*key)) while (isspace(static_cast<unsigned char>(*key)))
key++; key++;
num_ptr = va_arg(args, int*); num_ptr = va_arg(args, int*);
@ -271,7 +271,7 @@ bool XMLParser::vparseIntegerKey(const char *key, int count, va_list args) {
key = parseEnd; key = parseEnd;
while (isspace(*key)) while (isspace(static_cast<unsigned char>(*key)))
key++; key++;
if (count && *key++ != ',') if (count && *key++ != ',')
@ -463,10 +463,10 @@ bool XMLParser::parse() {
} }
bool XMLParser::skipSpaces() { bool XMLParser::skipSpaces() {
if (!isspace(_char)) if (!isspace(static_cast<unsigned char>(_char)))
return false; return false;
while (_char && isspace(_char)) while (_char && isspace(static_cast<unsigned char>(_char)))
_char = _stream->readByte(); _char = _stream->readByte();
return true; return true;
@ -516,7 +516,7 @@ bool XMLParser::parseToken() {
_char = _stream->readByte(); _char = _stream->readByte();
} }
return isspace(_char) != 0 || _char == '>' || _char == '=' || _char == '/'; return isspace(static_cast<unsigned char>(_char)) != 0 || _char == '>' || _char == '=' || _char == '/';
} }
} // End of namespace Common } // End of namespace Common

View file

@ -31,6 +31,7 @@
#include "common/hashmap.h" #include "common/hashmap.h"
#include "common/hash-str.h" #include "common/hash-str.h"
#include "common/stack.h" #include "common/stack.h"
#include "common/memorypool.h"
namespace Common { namespace Common {
@ -294,7 +295,7 @@ protected:
* in their name. * in their name.
*/ */
virtual inline bool isValidNameChar(char c) { virtual inline bool isValidNameChar(char c) {
return isalnum(c) || c == '_'; return isalnum(static_cast<unsigned char>(c)) || c == '_';
} }
/** /**

239
configure vendored
View file

@ -65,8 +65,12 @@ get_var() {
# Add an engine: id name build subengines # Add an engine: id name build subengines
add_engine() { add_engine() {
_engines="${_engines} ${1}" _engines="${_engines} ${1}"
if test "${3}" = "no" ; then
set_var _wip_engines "${_wip_engines} ${1}"
fi
set_var _engine_${1}_name "${2}" set_var _engine_${1}_name "${2}"
set_var _engine_${1}_build "${3}" set_var _engine_${1}_build "${3}"
set_var _engine_${1}_build_default "${3}"
set_var _engine_${1}_subengines "${4}" set_var _engine_${1}_subengines "${4}"
for sub in ${4}; do for sub in ${4}; do
set_var _engine_${sub}_sub "yes" set_var _engine_${sub}_sub "yes"
@ -94,6 +98,8 @@ _fluidsynth=auto
_opengl=auto _opengl=auto
_opengles=no _opengles=no
_readline=auto _readline=auto
_taskbar=yes
_libunity=auto
# Default option behaviour yes/no # Default option behaviour yes/no
_debug_build=auto _debug_build=auto
_release_build=auto _release_build=auto
@ -122,6 +128,7 @@ _strip=strip
_ar="ar cru" _ar="ar cru"
_as="as" _as="as"
_windres=windres _windres=windres
_stagingpath="staging"
_win32path="C:/residual" _win32path="C:/residual"
_aos4path="Games:Residual" _aos4path="Games:Residual"
_staticlibpath=/sw _staticlibpath=/sw
@ -130,6 +137,7 @@ _sdlpath="$PATH"
_nasmpath="$PATH" _nasmpath="$PATH"
NASMFLAGS="" NASMFLAGS=""
NASM="" NASM=""
_tainted_build=no
# The following variables are automatically detected, and should not # The following variables are automatically detected, and should not
# be modified otherwise. Consider them read-only. # be modified otherwise. Consider them read-only.
_posix=no _posix=no
@ -377,6 +385,11 @@ get_engine_build() {
get_var _engine_$1_build get_var _engine_$1_build
} }
# Was this engine set to be built by default?
get_engine_build_default() {
get_var _engine_$1_build_default
}
# Get the subengines # Get the subengines
get_engine_subengines() { get_engine_subengines() {
get_var _engine_$1_subengines get_var _engine_$1_subengines
@ -496,12 +509,19 @@ prepare_engine_build_strings() {
if test -n "$string" ; then if test -n "$string" ; then
_engines_skipped="${_engines_skipped}#$string@" _engines_skipped="${_engines_skipped}#$string@"
fi fi
string=`get_engine_build_string $1 wip`
if test -n "$string" ; then
_engines_built_wip="${_engines_built_wip}#$string@"
fi
} }
# Get the string about building an engine # Get the string about building an engine
get_engine_build_string() { get_engine_build_string() {
engine_string="" engine_string=""
engine_build=`get_engine_build $1` engine_build=`get_engine_build $1`
engine_build_default=`get_engine_build_default $1`
show=no show=no
# Check if the current engine should be shown for the current status # Check if the current engine should be shown for the current status
@ -517,6 +537,14 @@ get_engine_build_string() {
fi fi
done done
fi fi
# Test for enabled wip sub-engines
if test $2 = wip ; then
for subeng in `get_engine_subengines $1` ; do
if test `get_engine_build $subeng` != no -a `get_engine_build_default $subeng` = no ; then
show=yes
fi
done
fi
fi fi
# Convert static/dynamic to yes to ease the check of subengines # Convert static/dynamic to yes to ease the check of subengines
@ -524,13 +552,18 @@ get_engine_build_string() {
engine_build=yes engine_build=yes
fi fi
# Check if it is a wip engine
if test "$2" = "wip" -a "$engine_build" != "no" -a "$engine_build_default" = no; then
show=yes
fi
# The engine should be shown, build the string # The engine should be shown, build the string
if test $show = yes ; then if test $show = yes ; then
build_string_func=get_${1}_build_string build_string_func=get_${1}_build_string
if ( type $build_string_func | grep function ) 2> /dev/null > /dev/null ; then if ( type $build_string_func | grep function ) 2> /dev/null > /dev/null ; then
engine_string=`$build_string_func $1 $engine_build` engine_string=`$build_string_func $1 $engine_build $2`
else else
engine_string=`get_subengines_build_string $1 $engine_build` engine_string=`get_subengines_build_string $1 $engine_build "" $2`
fi fi
engine_string="`get_engine_name $1` $engine_string" engine_string="`get_engine_name $1` $engine_string"
@ -542,14 +575,29 @@ get_engine_build_string() {
# Get the string about building subengines # Get the string about building subengines
get_subengines_build_string() { get_subengines_build_string() {
all=yes all=yes
parent_engine=$1
subengine_string=$3 subengine_string=$3
for subeng in `get_engine_subengines $1` ; do parent_status=$4
if test `get_engine_build $subeng` = $2 ; then parent_engine_build_default=`get_engine_build_default $parent_engine`
for subeng in `get_engine_subengines $parent_engine` ; do
subengine_build=`get_engine_build $subeng`
subengine_build_default=`get_engine_build_default $subeng`
if test \( $subengine_build = $2 -a "$parent_status" != wip \) -o \( "$parent_status" = wip -a $subengine_build != no -a "$subengine_build_default" = no \) ; then
subengine_string="$subengine_string [`get_engine_name $subeng`]" subengine_string="$subengine_string [`get_engine_name $subeng`]"
else else
all=no all=no
fi fi
# handle engines that are on by default and have a single subengine that is off by default
if test "$parent_status" = wip ; then
if test $parent_engine_build_default = yes -a subengine ; then
all=no
fi
fi
done done
if test $2 != no ; then if test $2 != no ; then
if test -n "$subengine_string" ; then if test -n "$subengine_string" ; then
if test $all = yes ; then if test $all = yes ; then
@ -633,6 +681,7 @@ Optional Features:
--default-dynamic make plugins dynamic by default --default-dynamic make plugins dynamic by default
--disable-mt32emu don't enable the integrated MT-32 emulator --disable-mt32emu don't enable the integrated MT-32 emulator
--disable-translation don't build support for translated messages --disable-translation don't build support for translated messages
--disable-taskbar don't build support for taskbar and launcher integration
--enable-text-console use text console instead of graphical console --enable-text-console use text console instead of graphical console
--enable-verbose-build enable regular echoing of commands during build --enable-verbose-build enable regular echoing of commands during build
process process
@ -674,6 +723,9 @@ Optional Libraries:
--with-readline-prefix=DIR Prefix where readline is installed (optional) --with-readline-prefix=DIR Prefix where readline is installed (optional)
--disable-readline disable readline support in text console [autodetect] --disable-readline disable readline support in text console [autodetect]
--with-libunity-prefix=DIR Prefix where libunity is installed (optional)
--disable-libunity disable Unity launcher integration [autodetect]
Some influential environment variables: Some influential environment variables:
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir> nonstandard directory <lib dir>
@ -711,6 +763,10 @@ for ac_option in $@; do
--disable-fluidsynth) _fluidsynth=no ;; --disable-fluidsynth) _fluidsynth=no ;;
--enable-readline) _readline=yes ;; --enable-readline) _readline=yes ;;
--disable-readline) _readline=no ;; --disable-readline) _readline=no ;;
--enable-taskbar) _taskbar=yes ;;
--disable-taskbar) _taskbar=no ;;
--enable-libunity) _libunity=yes ;;
--disable-libunity) _libunity=no ;;
--enable-opengl) _opengl=yes ;; --enable-opengl) _opengl=yes ;;
--disable-opengl) _opengl=no ;; --disable-opengl) _opengl=no ;;
--enable-verbose-build) _verbose_build=yes ;; --enable-verbose-build) _verbose_build=yes ;;
@ -871,15 +927,6 @@ caanoo)
_host_os=gph-linux _host_os=gph-linux
_host_cpu=arm _host_cpu=arm
_host_alias=arm-none-linux-gnueabi _host_alias=arm-none-linux-gnueabi
if test "$_debug_build" = auto; then
# If you want to debug on the Caanoo use '--disable-release --enable-debug'
_debug_build=no
fi
if test "$_release_build" = auto; then
# Enable release build by default.
_release_build=yes
fi
;; ;;
dingux) dingux)
_host_os=linux _host_os=linux
@ -959,6 +1006,22 @@ ps2)
_host_cpu=mips64r5900el _host_cpu=mips64r5900el
_host_alias=ee _host_alias=ee
;; ;;
ps3)
_host_os=ps3
_host_cpu=ppc
_host_alias=powerpc64-ps3-elf
# The prefix is always the same on PS3 so we hardcode the default
# here. It is still possible to define a custom prefix which is
# needed when packaging the app with a user-specific app ID.
test "x$prefix" = xNONE && prefix=/dev_hdd0/game/SCUM12000/USRDIR
# PS3 apps are installed into app-specific directories. The
# default directory structure of ScummVM makes no sense here so we
# hardcode PS3 specific directories here.
datarootdir='${prefix}/data'
datadir='${datarootdir}'
docdir='${prefix}/doc'
;;
psp) psp)
_host_os=psp _host_os=psp
_host_cpu=mipsallegrexel _host_cpu=mipsallegrexel
@ -1100,6 +1163,12 @@ ps2)
exit 1 exit 1
fi fi
;; ;;
ps3)
if test -z "$PS3DEV"; then
echo "Please set PS3DEV in your environment. export PS3DEV=<path to ps3 toolchain>"
exit 1
fi
;;
psp) psp)
if test -z "$PSPDEV"; then if test -z "$PSPDEV"; then
PSPDEV=`psp-config --pspdev-path` PSPDEV=`psp-config --pspdev-path`
@ -1292,7 +1361,7 @@ if test "$have_gcc" = yes ; then
case $_host_os in case $_host_os in
# newlib-based system include files suppress non-C89 function # newlib-based system include files suppress non-C89 function
# declarations under __STRICT_ANSI__ # declarations under __STRICT_ANSI__
amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | wii | wince ) amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | wii | wince )
;; ;;
*) *)
CXXFLAGS="$CXXFLAGS -ansi" CXXFLAGS="$CXXFLAGS -ansi"
@ -1697,7 +1766,8 @@ case $_host_os in
mingw*) mingw*)
DEFINES="$DEFINES -DWIN32" DEFINES="$DEFINES -DWIN32"
DEFINES="$DEFINES -D__USE_MINGW_ANSI_STDIO=0" DEFINES="$DEFINES -D__USE_MINGW_ANSI_STDIO=0"
LIBS="$LIBS -lmingw32 -lwinmm" LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++"
LIBS="$LIBS -lmingw32 -lwinmm -lgdi32"
OBJS="$OBJS residualwinres.o" OBJS="$OBJS residualwinres.o"
add_line_to_config_mk 'WIN32 = 1' add_line_to_config_mk 'WIN32 = 1'
;; ;;
@ -1721,6 +1791,16 @@ case $_host_os in
DEFINES="$DEFINES -D_EE" DEFINES="$DEFINES -D_EE"
DEFINES="$DEFINES -D__PLAYSTATION2__" DEFINES="$DEFINES -D__PLAYSTATION2__"
;; ;;
ps3)
# Force use of SDL from the ps3 toolchain
_sdlpath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
DEFINES="$DEFINES -DPLAYSTATION3"
CXXFLAGS="$CXXFLAGS -mcpu=cell -mminimal-toc -I$PS3DEV/psl1ght/ppu/include -I$PS3DEV/portlibs/ppu/include"
LDFLAGS="$LDFLAGS -L$PS3DEV/psl1ght/ppu/lib -L$PS3DEV/portlibs/ppu/lib"
add_line_to_config_mk 'PLAYSTATION3 = 1'
add_line_to_config_h "#define PREFIX \"${prefix}\""
;;
psp) psp)
if test -d "$PSPDEV/psp/lib"; then if test -d "$PSPDEV/psp/lib"; then
LDFLAGS="$LDFLAGS -L$PSPDEV/psp/lib" LDFLAGS="$LDFLAGS -L$PSPDEV/psp/lib"
@ -2078,6 +2158,11 @@ if test -n "$_host"; then
CXXFLAGS="$CXXFLAGS -s" CXXFLAGS="$CXXFLAGS -s"
fi fi
;; ;;
ps3)
_mt32emu=no
_timidity=no
_vkeybd=yes
;;
psp) psp)
_backend="psp" _backend="psp"
_build_scalers=no _build_scalers=no
@ -2120,6 +2205,7 @@ if test -n "$_host"; then
LDFLAGS="$LDFLAGS -Wl,--stack,65536" LDFLAGS="$LDFLAGS -Wl,--stack,65536"
_tremolo=yes _tremolo=yes
_backend="wince" _backend="wince"
_detectlang=yes
_mt32emu=no _mt32emu=no
_port_mk="backends/platform/wince/wince.mk" _port_mk="backends/platform/wince/wince.mk"
;; ;;
@ -2134,16 +2220,9 @@ fi
# #
case $_backend in case $_backend in
android) android)
# ssp at this point so the cxxtests link DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
if test "$_debug_build" = yes; then
CXXFLAGS="$CXXFLAGS -fstack-protector"
else
CXXFLAGS="$CXXFLAGS -fno-stack-protector"
fi
CXXFLAGS="$CXXFLAGS -Wa,--noexecstack" CXXFLAGS="$CXXFLAGS -Wa,--noexecstack"
LDFLAGS="$LDFLAGS -Wl,-z,noexecstack" LDFLAGS="$LDFLAGS -Wl,-z,noexecstack"
DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
;; ;;
dc) dc)
INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc' INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc'
@ -2267,6 +2346,15 @@ case $_backend in
LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`" LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`"
DEFINES="$DEFINES -DSDL_BACKEND" DEFINES="$DEFINES -DSDL_BACKEND"
add_line_to_config_mk "SDL_BACKEND = 1" add_line_to_config_mk "SDL_BACKEND = 1"
_sdlversion=`$_sdlconfig --version`
case $_sdlversion in
1.3.*)
add_line_to_config_mk "USE_SDL13 = 1"
;;
*)
;;
esac
;; ;;
esac esac
@ -2298,7 +2386,7 @@ esac
# #
echo_n "Checking if host is POSIX compliant... " echo_n "Checking if host is POSIX compliant... "
case $_host_os in case $_host_os in
amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | psp | wii | wince) amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince)
_posix=no _posix=no
;; ;;
android | beos* | bsd* | darwin* | freebsd* | gph-linux | haiku* | hpux* | iphone | irix* | linux* | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos) android | beos* | bsd* | darwin* | freebsd* | gph-linux | haiku* | hpux* | iphone | irix* | linux* | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos)
@ -2824,6 +2912,43 @@ define_in_config_h_if_yes "$_readline" 'USE_READLINE'
define_in_config_h_if_yes "$_text_console" 'USE_TEXT_CONSOLE_FOR_DEBUGGER' define_in_config_h_if_yes "$_text_console" 'USE_TEXT_CONSOLE_FOR_DEBUGGER'
#
# Check for Unity if taskbar integration is enabled
#
echocheck "libunity"
if test "$_unix" = no || test "$_taskbar" = no; then
_libunity=no
else
if test "$_libunity" = auto ; then
case $_host_os in
mingw*)
# pkgconfig and unity are not supported on mingw
_libunity=no
;;
*)
# Unity has a lots of dependencies, update the libs and cflags var with them
LIBUNITY_LIBS="$LIBUNITY_LIBS $(pkg-config --libs unity = 3.8.4 2>> "$TMPLOG")"
LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS $(pkg-config --cflags unity = 3.8.4 2>> "$TMPLOG")"
_libunity=no
cat > $TMPC << EOF
#include <unity.h>
int main(void) {
unity_launcher_entry_get_for_desktop_id("scummvm.desktop");
return 0;
}
EOF
cc_check $LIBUNITY_CFLAGS $LIBUNITY_LIBS && _libunity=yes
;;
esac
fi
if test "$_libunity" = yes ; then
LIBS="$LIBS $LIBUNITY_LIBS"
INCLUDES="$INCLUDES $LIBUNITY_CFLAGS"
fi
define_in_config_h_if_yes "$_libunity" 'USE_TASKBAR_UNITY'
fi
echo "$_libunity"
# #
# Check for OpenGL (ES) # Check for OpenGL (ES)
# #
@ -2977,12 +3102,14 @@ if test "$_translation" = no ; then
else else
echo_n "yes (" echo_n "yes ("
cat > $TMPC << EOF if test "$_detectlang" != yes ; then
cat > $TMPC << EOF
#include <locale.h> #include <locale.h>
int main(void) { setlocale(LC_ALL, ""); return 0; } int main(void) { setlocale(LC_ALL, ""); return 0; }
EOF EOF
_detectlang=no _detectlang=no
cc_check $LDFLAGS $CXXFLAGS && _detectlang=yes cc_check $LDFLAGS $CXXFLAGS && _detectlang=yes
fi
define_in_config_h_if_yes $_detectlang 'USE_DETECTLANG' define_in_config_h_if_yes $_detectlang 'USE_DETECTLANG'
if test "$_detectlang" = yes ; then if test "$_detectlang" = yes ; then
@ -2992,6 +3119,29 @@ EOF
fi fi
fi fi
#
# Check whether to build taskbar integration support
#
echo_n "Building taskbar integration support... "
define_in_config_if_yes $_taskbar 'USE_TASKBAR'
if test "$_taskbar" = yes; then
case $_host_os in
mingw*)
LIBS="$LIBS -lole32 -luuid"
echo "win32"
;;
*)
if test "$_libunity" = yes; then
echo "unity"
else
echo "$_taskbar"
fi
;;
esac
else
echo "$_taskbar"
fi
# #
# Figure out installation directories # Figure out installation directories
# #
@ -3028,6 +3178,10 @@ fi
echo_n "Backend... " echo_n "Backend... "
echo_n "$_backend" echo_n "$_backend"
if test "$_backend" = "sdl" -a -n "$_sdlversion"; then
echo_n " ($_sdlversion)"
fi
if test "$_nasm" = yes ; then if test "$_nasm" = yes ; then
echo_n ", assembly routines" echo_n ", assembly routines"
fi fi
@ -3055,6 +3209,13 @@ fi
# #
case $_backend in case $_backend in
android) android)
# ssp at this point so the cxxtests link
if test "$_debug_build" = yes; then
CXXFLAGS="$CXXFLAGS -fstack-protector"
else
CXXFLAGS="$CXXFLAGS -fno-stack-protector"
fi
static_libs='' static_libs=''
system_libs='' system_libs=''
for lib in $LIBS; do for lib in $LIBS; do
@ -3135,6 +3296,23 @@ for engine in $_engines; do
fi fi
done done
#
# Detection of WIP/unstable engines
#
for engine in $_engines; do
engine_build=`get_engine_build $engine`
engine_build_default=`get_engine_build_default $engine`
engine_wip=false
if test $engine_build != no -a $engine_build_default = no ; then
engine_wip=true
set_var _tainted_build "yes"
fi
engine_wip_defname="ENGINE_WIP_`echo $engine | tr '[a-z]' '[A-Z]'`"
add_line_to_config_h "#define $engine_wip_defname $engine_wip"
done
add_to_config_h_if_yes `get_var _tainted_build` '#define TAINTED_BUILD'
# #
# Show which engines ("frontends") are to be built # Show which engines ("frontends") are to be built
# #
@ -3160,6 +3338,12 @@ if test -n "$_engines_skipped" ; then
s/#/ /g' s/#/ /g'
fi fi
if test -n "$_engines_built_wip" ; then
echo "WARNING: This Residual build contains the following UNSTABLE engines:"
echo $_engines_built_wip | sed 's/@/\
/g
s/#/ /g'
fi
echo echo
echo "Creating config.h" echo "Creating config.h"
@ -3215,6 +3399,7 @@ AS := $_as
ASFLAGS := $ASFLAGS ASFLAGS := $ASFLAGS
WINDRES := $_windres WINDRES := $_windres
WINDRESFLAGS := $WINDRESFLAGS WINDRESFLAGS := $WINDRESFLAGS
STAGINGPATH=$_stagingpath
WIN32PATH=$_win32path WIN32PATH=$_win32path
AOS4PATH=$_aos4path AOS4PATH=$_aos4path
STATICLIBPATH=$_staticlibpath STATICLIBPATH=$_staticlibpath

View file

@ -364,6 +364,11 @@ int main(int argc, char *argv[]) {
provider = new CreateProjectTool::CodeBlocksProvider(globalWarnings, projectWarnings); provider = new CreateProjectTool::CodeBlocksProvider(globalWarnings, projectWarnings);
// Those libraries are automatically added by MSVC, but we need to add them manually with mingw
setup.libraries.push_back("ole32");
setup.libraries.push_back("uuid");
break; break;
case kProjectMSVC: case kProjectMSVC:
@ -774,7 +779,7 @@ const Feature s_features[] = {
{ "mt32emu", "USE_MT32EMU", "", true, "integrated MT-32 emulator" }, { "mt32emu", "USE_MT32EMU", "", true, "integrated MT-32 emulator" },
{ "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling. { "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling.
{ "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" }, { "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" },
{ "indeo3", "USE_INDEO3", "", true, "Indeo3 codec support"}, { "taskbar", "USE_TASKBAR", "", true, "Taskbar integration support" },
{ "translation", "USE_TRANSLATION", "", false, "Translation support" }, { "translation", "USE_TRANSLATION", "", false, "Translation support" },
{ "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"}, { "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"},
{ "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there { "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there

View file

@ -72,10 +72,9 @@ Sub CreateInstaller()
' Build command line ' Build command line
Dim commandLine : commandLine = """" & nsisPath & "\makensis.exe"" /V2" & _ Dim commandLine : commandLine = """" & nsisPath & "\makensis.exe"" /V2" & _
" /Dtop_srcdir=""" & rootFolder & """" & _ " /Dtop_srcdir=""" & rootFolder & """" & _
" /Dbuild_dir=""" & targetFolder & """" & _ " /Dstaging_dir=""" & targetFolder & """" & _
" /Dtext_dir=""" & rootFolder & """" & _
" /DARCH=""" & arch & """" & _ " /DARCH=""" & arch & """" & _
" """ & rootFolder & "\dists\nsis\scummvm.nsi""" " """ & rootFolder & "\dists\win32\residual.nsi"""
Dim oExec: Set oExec = WshShell.Exec(commandline) Dim oExec: Set oExec = WshShell.Exec(commandline)
If Err.Number <> 0 Then If Err.Number <> 0 Then

View file

@ -32,112 +32,7 @@
#include "common/translation.h" #include "common/translation.h"
#include "engines/advancedDetector.h" #include "engines/advancedDetector.h"
#include "engines/obsolete.h"
/**
* A list of pointers to ADGameDescription structs (or subclasses thereof).
*/
typedef Common::Array<const ADGameDescription*> ADGameDescList;
/**
* Detect games in specified directory.
* Parameters language and platform are used to pass on values
* specified by the user. I.e. this is used to restrict search scope.
*
* @param fslist FSList to scan or NULL for scanning all specified
* default directories.
* @param params a ADParams struct containing various parameters
* @param language restrict results to specified language only
* @param platform restrict results to specified platform only
* @return list of ADGameDescription (or subclass) pointers corresponding to matched games
*/
static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &params, Common::Language language, Common::Platform platform, const Common::String &extra);
/**
* Returns list of targets supported by the engine.
* Distinguishes engines with single ID
*/
static GameList gameIDList(const ADParams &params) {
if (params.singleid != NULL) {
GameList gl;
const PlainGameDescriptor *g = params.list;
while (g->gameid) {
if (0 == scumm_stricmp(params.singleid, g->gameid)) {
gl.push_back(GameDescriptor(g->gameid, g->description));
return gl;
}
g++;
}
error("Engine %s doesn't have its singleid specified in ids list", params.singleid);
}
return GameList(params.list);
}
static void upgradeTargetIfNecessary(const ADParams &params) {
if (params.obsoleteList == 0)
return;
Common::String gameid = ConfMan.get("gameid");
for (const ADObsoleteGameID *o = params.obsoleteList; o->from; ++o) {
if (gameid.equalsIgnoreCase(o->from)) {
gameid = o->to;
ConfMan.set("gameid", gameid);
if (o->platform != Common::kPlatformUnknown)
ConfMan.set("platform", Common::getPlatformCode(o->platform));
warning("Target upgraded from %s to %s", o->from, o->to);
// WORKAROUND: Fix for bug #1719463: "DETECTOR: Launching
// undefined target adds launcher entry"
if (ConfMan.hasKey("id_came_from_command_line")) {
warning("Target came from command line. Skipping save");
} else {
ConfMan.flushToDisk();
}
break;
}
}
}
namespace AdvancedDetector {
GameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *list,
const ADObsoleteGameID *obsoleteList
) {
// First search the list of supported game IDs for a match.
const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, list);
if (g)
return GameDescriptor(*g);
// If we didn't find the gameid in the main list, check if it
// is an obsolete game id.
if (obsoleteList != 0) {
const ADObsoleteGameID *o = obsoleteList;
while (o->from) {
if (0 == scumm_stricmp(gameid, o->from)) {
g = findPlainGameDescriptor(o->to, list);
if (g && g->description)
return GameDescriptor(gameid, "Obsolete game ID (" + Common::String(g->description) + ")");
else
return GameDescriptor(gameid, "Obsolete game ID");
}
o++;
}
}
// No match found
return GameDescriptor();
}
} // End of namespace AdvancedDetector
static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGameDescriptor *sg) { static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGameDescriptor *sg) {
const char *title = 0; const char *title = 0;
@ -156,7 +51,13 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa
extra = g.extra; extra = g.extra;
} }
GameDescriptor gd(g.gameid, title, g.language, g.platform); GameSupportLevel gsl = kStableGame;
if (g.flags & ADGF_UNSTABLE)
gsl = kUnstableGame;
else if (g.flags & ADGF_TESTING)
gsl = kTestingGame;
GameDescriptor gd(g.gameid, title, g.language, g.platform, 0, gsl);
gd.updateDesc(extra); gd.updateDesc(extra);
return gd; return gd;
} }
@ -189,10 +90,10 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD
return res; return res;
} }
static void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc, const ADParams &params) { void AdvancedMetaEngine::updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const {
if (params.singleid != NULL) { if (_singleid != NULL) {
desc["preferredtarget"] = desc["gameid"]; desc["preferredtarget"] = desc["gameid"];
desc["gameid"] = params.singleid; desc["gameid"] = _singleid;
} }
if (!desc.contains("preferredtarget")) if (!desc.contains("preferredtarget"))
@ -200,10 +101,10 @@ static void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *
desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc); desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc);
if (params.flags & kADFlagUseExtraAsHint) if (_flags & kADFlagUseExtraAsHint)
desc["extra"] = realDesc->extra; desc["extra"] = realDesc->extra;
desc.setGUIOptions(realDesc->guioptions | params.guioptions); desc.setGUIOptions(realDesc->guioptions | _guioptions);
desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language)); desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language));
if (realDesc->flags & ADGF_ADDENGLISH) if (realDesc->flags & ADGF_ADDENGLISH)
@ -211,7 +112,7 @@ static void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *
} }
bool cleanupPirated(ADGameDescList &matched) { bool cleanupPirated(ADGameDescList &matched) {
// OKay, now let's sense presense of pirated games // OKay, now let's sense presence of pirated games
if (!matched.empty()) { if (!matched.empty()) {
for (uint j = 0; j < matched.size();) { for (uint j = 0; j < matched.size();) {
if (matched[j]->flags & ADGF_PIRATED) if (matched[j]->flags & ADGF_PIRATED)
@ -222,9 +123,7 @@ bool cleanupPirated(ADGameDescList &matched) {
// We ruled out all variants and now have nothing // We ruled out all variants and now have nothing
if (matched.empty()) { if (matched.empty()) {
warning("Illegitimate game copy detected. We give no support in such cases %d", matched.size()); warning("Illegitimate game copy detected. We give no support in such cases %d", matched.size());
return true; return true;
} }
} }
@ -234,25 +133,33 @@ bool cleanupPirated(ADGameDescList &matched) {
GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const { GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
ADGameDescList matches = detectGame(fslist, params, Common::UNK_LANG, Common::kPlatformUnknown, ""); ADGameDescList matches;
GameList detectedGames; GameList detectedGames;
FileMap allFiles;
if (cleanupPirated(matches)) if (fslist.empty())
return detectedGames; return detectedGames;
// Compose a hashmap of all files in fslist.
composeFileHashMap(allFiles, fslist, (_maxScanDepth == 0 ? 1 : _maxScanDepth));
// Run the detector on this
matches = detectGame(fslist.begin()->getParent(), allFiles, Common::UNK_LANG, Common::kPlatformUnknown, "");
if (matches.empty()) { if (matches.empty()) {
// Use fallback detector if there were no matches by other means // Use fallback detector if there were no matches by other means
const ADGameDescription *fallbackDesc = fallbackDetect(fslist); const ADGameDescription *fallbackDesc = fallbackDetect(allFiles, fslist);
if (fallbackDesc != 0) { if (fallbackDesc != 0) {
GameDescriptor desc(toGameDescriptor(*fallbackDesc, params.list)); GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameids));
updateGameDescriptor(desc, fallbackDesc, params); updateGameDescriptor(desc, fallbackDesc);
detectedGames.push_back(desc); detectedGames.push_back(desc);
} }
} else { } else {
// Otherwise use the found matches // Otherwise use the found matches
cleanupPirated(matches);
for (uint i = 0; i < matches.size(); i++) { for (uint i = 0; i < matches.size(); i++) {
GameDescriptor desc(toGameDescriptor(*matches[i], params.list)); GameDescriptor desc(toGameDescriptor(*matches[i], _gameids));
updateGameDescriptor(desc, matches[i], params); updateGameDescriptor(desc, matches[i]);
detectedGames.push_back(desc); detectedGames.push_back(desc);
} }
} }
@ -262,7 +169,6 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const { Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
assert(engine); assert(engine);
upgradeTargetIfNecessary(params);
const ADGameDescription *agdDesc = 0; const ADGameDescription *agdDesc = 0;
Common::Language language = Common::UNK_LANG; Common::Language language = Common::UNK_LANG;
@ -273,9 +179,10 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
language = Common::parseLanguage(ConfMan.get("language")); language = Common::parseLanguage(ConfMan.get("language"));
if (ConfMan.hasKey("platform")) if (ConfMan.hasKey("platform"))
platform = Common::parsePlatform(ConfMan.get("platform")); platform = Common::parsePlatform(ConfMan.get("platform"));
if (params.flags & kADFlagUseExtraAsHint) if (_flags & kADFlagUseExtraAsHint) {
if (ConfMan.hasKey("extra")) if (ConfMan.hasKey("extra"))
extra = ConfMan.get("extra"); extra = ConfMan.get("extra");
}
Common::String gameid = ConfMan.get("gameid"); Common::String gameid = ConfMan.get("gameid");
@ -305,12 +212,21 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
return Common::kNoGameDataFoundError; return Common::kNoGameDataFoundError;
} }
ADGameDescList matches = detectGame(files, params, language, platform, extra); if (files.empty())
return Common::kNoGameDataFoundError;
// Compose a hashmap of all files in fslist.
FileMap allFiles;
composeFileHashMap(allFiles, files, (_maxScanDepth == 0 ? 1 : _maxScanDepth));
// Run the detector on this
ADGameDescList matches = detectGame(files.begin()->getParent(), allFiles, language, platform, extra);
if (cleanupPirated(matches)) if (cleanupPirated(matches))
return Common::kNoGameDataFoundError; return Common::kNoGameDataFoundError;
if (params.singleid == NULL) { if (_singleid == NULL) {
// Find the first match with correct gameid.
for (uint i = 0; i < matches.size(); i++) { for (uint i = 0; i < matches.size(); i++) {
if (matches[i]->gameid == gameid) { if (matches[i]->gameid == gameid) {
agdDesc = matches[i]; agdDesc = matches[i];
@ -323,11 +239,11 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
if (agdDesc == 0) { if (agdDesc == 0) {
// Use fallback detector if there were no matches by other means // Use fallback detector if there were no matches by other means
agdDesc = fallbackDetect(files); agdDesc = fallbackDetect(allFiles, files);
if (agdDesc != 0) { if (agdDesc != 0) {
// Seems we found a fallback match. But first perform a basic // Seems we found a fallback match. But first perform a basic
// sanity check: the gameid must match. // sanity check: the gameid must match.
if (params.singleid == NULL && agdDesc->gameid != gameid) if (_singleid == NULL && agdDesc->gameid != gameid)
agdDesc = 0; agdDesc = 0;
} }
} }
@ -341,10 +257,23 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
if (agdDesc->flags & ADGF_ADDENGLISH) if (agdDesc->flags & ADGF_ADDENGLISH)
lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY); lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY);
Common::updateGameGUIOptions(agdDesc->guioptions | params.guioptions, lang); Common::updateGameGUIOptions(agdDesc->guioptions | _guioptions, lang);
GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameids);
debug(2, "Running %s", toGameDescriptor(*agdDesc, params.list).description().c_str()); bool showTestingWarning = false;
#ifdef RELEASE_BUILD
showTestingWarning = true;
#endif
if (((gameDescriptor.getSupportLevel() == kUnstableGame
|| (gameDescriptor.getSupportLevel() == kTestingGame
&& showTestingWarning)))
&& !Engine::warnUserAboutUnsupportedGame())
return Common::kUserCanceled;
debug(2, "Running %s", gameDescriptor.description().c_str());
if (!createInstance(syst, engine, agdDesc)) if (!createInstance(syst, engine, agdDesc))
return Common::kNoGameDataFoundError; return Common::kNoGameDataFoundError;
else else
@ -357,7 +286,6 @@ struct SizeMD5 {
}; };
typedef Common::HashMap<Common::String, SizeMD5, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SizeMD5Map; typedef Common::HashMap<Common::String, SizeMD5, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SizeMD5Map;
typedef Common::HashMap<Common::String, Common::FSNode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSizeMD5) { static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSizeMD5) {
// TODO: This message should be cleaned up / made more specific. // TODO: This message should be cleaned up / made more specific.
@ -379,26 +307,22 @@ static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSiz
g_system->logMessage(LogMessageType::kInfo, report.c_str()); g_system->logMessage(LogMessageType::kInfo, report.c_str());
} }
static ADGameDescList detectGameFilebased(const FileMap &allFiles, const ADParams &params); void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth) const {
static void composeFileHashMap(const Common::FSList &fslist, FileMap &allFiles, int depth, const char * const *directoryGlobs) {
if (depth <= 0) if (depth <= 0)
return; return;
if (fslist.empty()) if (fslist.empty())
return; return;
// First we compose a hashmap of all files in fslist.
// Includes nifty stuff like removing trailing dots and ignoring case.
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory()) { if (file->isDirectory()) {
Common::FSList files; Common::FSList files;
if (!directoryGlobs) if (!_directoryGlobs)
continue; continue;
bool matched = false; bool matched = false;
for (const char * const *glob = directoryGlobs; *glob; glob++) for (const char * const *glob = _directoryGlobs; *glob; glob++)
if (file->getName().matchString(*glob, true)) { if (file->getName().matchString(*glob, true)) {
matched = true; matched = true;
break; break;
@ -410,7 +334,7 @@ static void composeFileHashMap(const Common::FSList &fslist, FileMap &allFiles,
if (!file->getChildren(files, Common::FSNode::kListAll)) if (!file->getChildren(files, Common::FSNode::kListAll))
continue; continue;
composeFileHashMap(files, allFiles, depth - 1, directoryGlobs); composeFileHashMap(allFiles, files, depth - 1);
} }
Common::String tstr = file->getName(); Common::String tstr = file->getName();
@ -423,26 +347,18 @@ static void composeFileHashMap(const Common::FSList &fslist, FileMap &allFiles,
} }
} }
static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &params, Common::Language language, Common::Platform platform, const Common::String &extra) { ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
FileMap allFiles;
SizeMD5Map filesSizeMD5; SizeMD5Map filesSizeMD5;
const ADGameFileDescription *fileDesc; const ADGameFileDescription *fileDesc;
const ADGameDescription *g; const ADGameDescription *g;
const byte *descPtr; const byte *descPtr;
if (fslist.empty())
return ADGameDescList();
Common::FSNode parent = fslist.begin()->getParent();
debug(3, "Starting detection in dir '%s'", parent.getPath().c_str()); debug(3, "Starting detection in dir '%s'", parent.getPath().c_str());
// First we compose a hashmap of all files in fslist. // Check which files are included in some ADGameDescription *and* are present.
// Includes nifty stuff like removing trailing dots and ignoring case. // Compute MD5s and file sizes for these files.
composeFileHashMap(fslist, allFiles, (params.depth == 0 ? 1 : params.depth), params.directoryGlobs); for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize) {
// Check which files are included in some ADGameDescription *and* present
// in fslist. Compute MD5s and file sizes for these files.
for (descPtr = params.descs; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += params.descItemSize) {
g = (const ADGameDescription *)descPtr; g = (const ADGameDescription *)descPtr;
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) { for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
@ -456,16 +372,14 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
// file and as one with resource fork. // file and as one with resource fork.
if (g->flags & ADGF_MACRESFORK) { if (g->flags & ADGF_MACRESFORK) {
Common::MacResManager *macResMan = new Common::MacResManager(); Common::MacResManager macResMan;
if (macResMan->open(parent, fname)) { if (macResMan.open(parent, fname)) {
tmp.md5 = macResMan->computeResForkMD5AsString(params.md5Bytes); tmp.md5 = macResMan.computeResForkMD5AsString(_md5Bytes);
tmp.size = macResMan->getResForkDataSize(); tmp.size = macResMan.getResForkDataSize();
debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str()); debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str());
filesSizeMD5[fname] = tmp; filesSizeMD5[fname] = tmp;
} }
delete macResMan;
} else { } else {
if (allFiles.contains(fname)) { if (allFiles.contains(fname)) {
debug(3, "+ %s", fname.c_str()); debug(3, "+ %s", fname.c_str());
@ -474,7 +388,7 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
if (testFile.open(allFiles[fname])) { if (testFile.open(allFiles[fname])) {
tmp.size = (int32)testFile.size(); tmp.size = (int32)testFile.size();
tmp.md5 = Common::computeStreamMD5AsString(testFile, params.md5Bytes); tmp.md5 = Common::computeStreamMD5AsString(testFile, _md5Bytes);
} else { } else {
tmp.size = -1; tmp.size = -1;
} }
@ -492,7 +406,7 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
// MD5 based matching // MD5 based matching
uint i; uint i;
for (i = 0, descPtr = params.descs; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += params.descItemSize, ++i) { for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize, ++i) {
g = (const ADGameDescription *)descPtr; g = (const ADGameDescription *)descPtr;
bool fileMissing = false; bool fileMissing = false;
@ -504,7 +418,7 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
continue; continue;
} }
if ((params.flags & kADFlagUseExtraAsHint) && !extra.empty() && g->extra != extra) if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && g->extra != extra)
continue; continue;
bool allFilesPresent = true; bool allFilesPresent = true;
@ -577,28 +491,20 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
} }
// Filename based fallback // Filename based fallback
if (params.fileBasedFallback != 0)
matched = detectGameFilebased(allFiles, params);
} }
return matched; return matched;
} }
/** const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const {
* Check for each ADFileBasedFallback record whether all files listed
* in it are present. If multiple pass this test, we pick the one with
* the maximal number of matching files. In case of a tie, the entry
* coming first in the list is chosen.
*/
static ADGameDescList detectGameFilebased(const FileMap &allFiles, const ADParams &params) {
const ADFileBasedFallback *ptr; const ADFileBasedFallback *ptr;
const char* const* filenames; const char* const* filenames;
int maxNumMatchedFiles = 0; int maxNumMatchedFiles = 0;
const ADGameDescription *matchedDesc = 0; const ADGameDescription *matchedDesc = 0;
for (ptr = params.fileBasedFallback; ptr->desc; ++ptr) { for (ptr = fileBasedFallback; ptr->desc; ++ptr) {
const ADGameDescription *agdesc = (const ADGameDescription *)ptr->desc; const ADGameDescription *agdesc = ptr->desc;
int numMatchedFiles = 0; int numMatchedFiles = 0;
bool fileMissing = false; bool fileMissing = false;
@ -624,28 +530,45 @@ static ADGameDescList detectGameFilebased(const FileMap &allFiles, const ADParam
} }
} }
ADGameDescList matched; return matchedDesc;
if (matchedDesc) { // We got a match
matched.push_back(matchedDesc);
if (params.flags & kADFlagPrintWarningOnFileBasedFallback) {
Common::String report = Common::String::format(_("Your game version has been detected using "
"filename matching as a variant of %s."), matchedDesc->gameid);
report += "\n";
report += _("If this is an original and unmodified version, please report any");
report += "\n";
report += _("information previously printed by Residual to the team.");
report += "\n";
g_system->logMessage(LogMessageType::kInfo, report.c_str());
}
}
return matched;
} }
GameList AdvancedMetaEngine::getSupportedGames() const { GameList AdvancedMetaEngine::getSupportedGames() const {
return gameIDList(params); if (_singleid != NULL) {
GameList gl;
const PlainGameDescriptor *g = _gameids;
while (g->gameid) {
if (0 == scumm_stricmp(_singleid, g->gameid)) {
gl.push_back(GameDescriptor(g->gameid, g->description));
return gl;
}
g++;
}
error("Engine %s doesn't have its singleid specified in ids list", _singleid);
}
return GameList(_gameids);
} }
GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const { GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const {
return AdvancedDetector::findGameID(gameid, params.list, params.obsoleteList); // First search the list of supported gameids for a match.
const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, _gameids);
if (g)
return GameDescriptor(*g);
// No match found
return GameDescriptor();
}
AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids)
: _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameids(gameids) {
_md5Bytes = 5000;
_singleid = NULL;
_flags = 0;
_guioptions = Common::GUIO_NONE;
_maxScanDepth = 1;
_directoryGlobs = NULL;
} }

View file

@ -19,38 +19,59 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* *
*/ */
#ifndef ENGINES_ADVANCED_DETECTOR_H #ifndef ENGINES_ADVANCED_DETECTOR_H
#define ENGINES_ADVANCED_DETECTOR_H #define ENGINES_ADVANCED_DETECTOR_H
#include "engines/metaengine.h" #include "engines/metaengine.h"
#include "engines/engine.h"
namespace Common { namespace Common {
class Error; class Error;
class FSList; class FSList;
} }
/**
* A record describing a file to be matched for detecting a specific game
* variant. A list of such records is used inside every ADGameDescription to
* enable detection.
*/
struct ADGameFileDescription { struct ADGameFileDescription {
const char *fileName; const char *fileName; ///< Name of described file.
uint16 fileType; // Optional. Not used during detection, only by engines. uint16 fileType; ///< Optional. Not used during detection, only by engines.
const char *md5; // Optional. May be NULL. const char *md5; ///< MD5 of (the beginning of) the described file. Optional. Set to NULL to ignore.
int32 fileSize; // Optional. Set to -1 to ignore. int32 fileSize; ///< Size of the described file. Set to -1 to ignore.
}; };
/**
* A shortcut to produce an empty ADGameFileDescription record. Used to mark
* the end of a list of these.
*/
#define AD_LISTEND {NULL, 0, NULL, 0} #define AD_LISTEND {NULL, 0, NULL, 0}
/**
* A shortcut to produce a list of ADGameFileDescription records with only one
* record that contains just a filename with an MD5, and no file size.
*/
#define AD_ENTRY1(f, x) {{ f, 0, x, -1}, AD_LISTEND} #define AD_ENTRY1(f, x) {{ f, 0, x, -1}, AD_LISTEND}
/**
* A shortcut to produce a list of ADGameFileDescription records with only one
* record that contains just a filename with an MD5, plus a file size.
*/
#define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, AD_LISTEND} #define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, AD_LISTEND}
enum ADGameFlags { enum ADGameFlags {
ADGF_NO_FLAGS = 0, ADGF_NO_FLAGS = 0,
ADGF_PIRATED = (1 << 23), // flag to designate well known pirated versions with cracks ADGF_UNSTABLE = (1 << 21), // flag to designate not yet officially-supported games that are not fit for public testing
ADGF_ADDENGLISH = (1 << 24), // always add English as language option ADGF_TESTING = (1 << 22), // flag to designate not yet officially-supported games that are fit for public testing
ADGF_MACRESFORK = (1 << 25), // the md5 for this entry will be calculated from the resource fork ADGF_PIRATED = (1 << 23), ///< flag to designate well known pirated versions with cracks
ADGF_USEEXTRAASTITLE = (1 << 26), // Extra field value will be used as main game title, not gameid ADGF_ADDENGLISH = (1 << 24), ///< always add English as language option
ADGF_DROPLANGUAGE = (1 << 28), // don't add language to gameid ADGF_MACRESFORK = (1 << 25), ///< the md5 for this entry will be calculated from the resource fork
ADGF_CD = (1 << 29), // add "-cd" to gameid ADGF_USEEXTRAASTITLE = (1 << 26), ///< Extra field value will be used as main game title, not gameid
ADGF_DEMO = (1 << 30) // add "-demo" to gameid ADGF_DROPLANGUAGE = (1 << 28), ///< don't add language to gameid
ADGF_CD = (1 << 29), ///< add "-cd" to gameid
ADGF_DEMO = (1 << 30) ///< add "-demo" to gameid
}; };
struct ADGameDescription { struct ADGameDescription {
@ -70,6 +91,11 @@ struct ADGameDescription {
uint32 guioptions; uint32 guioptions;
}; };
/**
* A list of pointers to ADGameDescription structs (or subclasses thereof).
*/
typedef Common::Array<const ADGameDescription *> ADGameDescList;
/** /**
* End marker for a table of ADGameDescription structs. Use this to * End marker for a table of ADGameDescription structs. Use this to
* terminate a list to be passed to the AdvancedDetector API. * terminate a list to be passed to the AdvancedDetector API.
@ -77,19 +103,12 @@ struct ADGameDescription {
#define AD_TABLE_END_MARKER \ #define AD_TABLE_END_MARKER \
{ NULL, NULL, { { NULL, 0, NULL, 0 } }, Common::UNK_LANG, Common::kPlatformUnknown, ADGF_NO_FLAGS, Common::GUIO_NONE } { NULL, NULL, { { NULL, 0, NULL, 0 } }, Common::UNK_LANG, Common::kPlatformUnknown, ADGF_NO_FLAGS, Common::GUIO_NONE }
struct ADObsoleteGameID {
const char *from;
const char *to;
Common::Platform platform;
};
struct ADFileBasedFallback { struct ADFileBasedFallback {
/** /**
* Pointer to an ADGameDescription or subclass thereof which will get * Pointer to an ADGameDescription or subclass thereof which will get
* returned if there's a detection match. * returned if there's a detection match.
*/ */
const void *desc; const ADGameDescription *desc;
/** /**
* A zero-terminated list of filenames used for matching. All files in * A zero-terminated list of filenames used for matching. All files in
@ -100,39 +119,42 @@ struct ADFileBasedFallback {
enum ADFlags { enum ADFlags {
/**
* Warn user about new variant if his version was detected with fallback
*/
kADFlagPrintWarningOnFileBasedFallback = (1 << 1),
/** /**
* Store value of extra field in config file, and use it as a hint * Store value of extra field in config file, and use it as a hint
* on subsequent runs. Could be used when there is no way to autodetect * on subsequent runs. Could be used when there is no way to autodetect
* game (when more than one game sits in same directory), and user picks * game (when more than one game sits in same directory), and user picks
* up a variant manually. * up a variant manually.
* In addition, this is useful if two variants of a game sharing the same
* gameid are contained in a single directory.
*/ */
kADFlagUseExtraAsHint = (1 << 2) kADFlagUseExtraAsHint = (1 << 0)
}; };
/** /**
* A structure containing all parameters for the AdvancedDetector. * A MetaEngine implementation based around the advanced detector code.
* Typically, an engine will have a single instance of this which is
* used by its AdvancedMetaEngine subclass as a parameter to the
* primary AdvancedMetaEngine constructor.
*/ */
struct ADParams { class AdvancedMetaEngine : public MetaEngine {
protected:
/** /**
* Pointer to an array of objects which are either ADGameDescription * Pointer to an array of objects which are either ADGameDescription
* or superset structures (i.e. start with an ADGameDescription member. * or superset structures (i.e. start with an ADGameDescription member.
* The list is terminated by an entry with a gameid equal to 0 * The list is terminated by an entry with a gameid equal to 0
* (see AD_TABLE_END_MARKER). * (see AD_TABLE_END_MARKER).
*/ */
const byte *descs; const byte *_gameDescriptors;
/** /**
* The size of a single entry of the above descs array. Always * The size of a single entry of the above descs array. Always
* must be >= sizeof(ADGameDescription). * must be >= sizeof(ADGameDescription).
*/ */
uint descItemSize; const uint _descItemSize;
/**
* A list of all gameids (and their corresponding descriptions) supported
* by this engine.
*/
const PlainGameDescriptor *_gameids;
/** /**
* The number of bytes to compute MD5 sum for. The AdvancedDetector * The number of bytes to compute MD5 sum for. The AdvancedDetector
@ -140,110 +162,109 @@ struct ADParams {
* Since doing that for large files can be slow, it can be restricted * Since doing that for large files can be slow, it can be restricted
* to a subset of all files. * to a subset of all files.
* Typically this will be set to something between 5 and 50 kilobyte, * Typically this will be set to something between 5 and 50 kilobyte,
* but arbitrary non-zero values are possible. * but arbitrary non-zero values are possible. The default is 5000.
*/ */
uint md5Bytes; uint _md5Bytes;
/**
* A list of all gameids (and their corresponding descriptions) supported
* by this engine.
*/
const PlainGameDescriptor *list;
/**
* Structure for autoupgrading obsolete targets (optional).
*
* @todo Properly explain this.
*/
const ADObsoleteGameID *obsoleteList;
/** /**
* Name of single gameid (optional). * Name of single gameid (optional).
* *
* @todo Properly explain this -- what does it do? * @todo Properly explain this -- what does it do?
*/ */
const char *singleid; const char *_singleid;
/**
* List of files for file-based fallback detection (optional).
* This is used if the regular MD5 based detection failed to
* detect anything.
* As usual this list is terminated by an all-zero entry.
*
* @todo Properly explain this
*/
const ADFileBasedFallback *fileBasedFallback;
/** /**
* A bitmask of flags which can be used to configure the behavior * A bitmask of flags which can be used to configure the behavior
* of the AdvancedDetector. Refer to ADFlags for a list of flags * of the AdvancedDetector. Refer to ADFlags for a list of flags
* that can be ORed together and passed here. * that can be ORed together and passed here.
*/ */
uint32 flags; uint32 _flags;
/** /**
* A bitmask of game GUI options which will be added to each * A bitmask of game GUI options which will be added to each
* entry in addition to per-game options. Refer to GameGUIOption * entry in addition to per-game options. Refer to GameGUIOption
* enum for the list. * enum for the list.
*/ */
uint32 guioptions; uint32 _guioptions;
/** /**
* Maximum depth of directories to look up * Maximum depth of directories to look up.
* If set to 0, the depth is 1 level * If set to 0, the depth is 1 level
*/ */
uint32 depth; uint32 _maxScanDepth;
/** /**
* Case-insensitive list of directory globs which could be used for * Case-insensitive list of directory globs which could be used for
* going deeper int directory structure. * going deeper into the directory structure.
* @see String::matchString() method for format description. * @see String::matchString() method for format description.
* *
* @note Last item must be 0 * @note Last item must be 0
*/ */
const char * const *directoryGlobs; const char * const *_directoryGlobs;
};
namespace AdvancedDetector {
/**
* Scan through the game descriptors specified in params and search for
* 'gameid' in there. If a match is found, returns a GameDescriptor
* with gameid and description set.
*/
GameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *list,
const ADObsoleteGameID *obsoleteList = 0
);
} // End of namespace AdvancedDetector
/**
* A MetaEngine implementation based around the advanced detector code.
*/
class AdvancedMetaEngine : public MetaEngine {
const ADParams &params;
public: public:
AdvancedMetaEngine(const ADParams &dp) : params(dp) {} AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids);
/**
* Returns list of targets supported by the engine.
* Distinguishes engines with single ID
*/
virtual GameList getSupportedGames() const; virtual GameList getSupportedGames() const;
virtual GameDescriptor findGame(const char *gameid) const; virtual GameDescriptor findGame(const char *gameid) const;
virtual GameList detectGames(const Common::FSList &fslist) const; virtual GameList detectGames(const Common::FSList &fslist) const;
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const; virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
// To be provided by subclasses protected:
// To be implemented by subclasses
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const = 0; virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const = 0;
typedef Common::HashMap<Common::String, Common::FSNode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
/** /**
* An (optional) generic fallback detect function which is invoked * An (optional) generic fallback detect function which is invoked
* if both the regular MD5 based detection as well as the file * if the regular MD5 based detection failed to detect anything.
* based fallback failed to detect anything.
*/ */
virtual const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const { virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
return 0; return 0;
} }
protected:
/**
* Detect games in specified directory.
* Parameters language and platform are used to pass on values
* specified by the user. This is used to restrict search scope.
*
* @param allFiles list of all present files, as computed by composeFileHashMap
* @param language restrict results to specified language
* @param platform restrict results to specified platform
* @param extra restrict results to specified extra string (only if kADFlagUseExtraAsHint is set)
* @return list of ADGameDescription pointers corresponding to matched games
*/
ADGameDescList detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const;
/**
* Iterates over all ADFileBasedFallback records inside fileBasedFallback.
* This then returns the record (or rather, the ADGameDescription
* contained in it) for which all files described by it are present, and
* among those the one with the maximal number of matching files.
* In case of a tie, the entry coming first in the list is chosen.
*
* @param allFiles a map describing all present files
* @param fileBasedFallback a list of ADFileBasedFallback records, zero-terminated
*/
const ADGameDescription *detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const;
// TODO
void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const;
/**
* Compose a hashmap of all files in fslist.
* Includes nifty stuff like removing trailing dots and ignoring case.
*/
void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth) const;
}; };
#endif #endif

View file

@ -143,9 +143,9 @@ void MainMenuDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint3
break; break;
case kHelpCmd: { case kHelpCmd: {
GUI::MessageDialog dialog( GUI::MessageDialog dialog(
"Sorry, this engine does not currently provide in-game help. " _("Sorry, this engine does not currently provide in-game help. "
"Please consult the README for basic information, and for " "Please consult the README for basic information, and for "
"instructions on how to obtain further assistance."); "instructions on how to obtain further assistance."));
dialog.runModal(); dialog.runModal();
} }
break; break;
@ -173,7 +173,7 @@ void MainMenuDialog::reflowLayout() {
_loadButton->setEnabled(_engine->canLoadGameStateCurrently()); _loadButton->setEnabled(_engine->canLoadGameStateCurrently());
if (_engine->hasFeature(Engine::kSupportsSavingDuringRuntime)) if (_engine->hasFeature(Engine::kSupportsSavingDuringRuntime))
_saveButton->setEnabled(_engine->canSaveGameStateCurrently()); _saveButton->setEnabled(_engine->canSaveGameStateCurrently());
// Overlay size might have changed since the construction of the dialog. // Overlay size might have changed since the construction of the dialog.
// Update labels when it might be needed // Update labels when it might be needed
// FIXME: it might be better to declare GUI::StaticTextWidget::setLabel() virtual // FIXME: it might be better to declare GUI::StaticTextWidget::setLabel() virtual
@ -246,14 +246,10 @@ void MainMenuDialog::load() {
int slot = _loadDialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); int slot = _loadDialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
if (slot >= 0) { _engine->setGameToLoadSlot(slot);
// FIXME: For now we just ignore the return
// value, which is quite bad since it could if (slot >= 0)
// be a fatal loading error, which renders
// the engine unusable.
_engine->loadGameState(slot);
close(); close();
}
} }
enum { enum {

View file

@ -42,6 +42,7 @@
#include "common/list_intern.h" #include "common/list_intern.h"
#include "common/scummsys.h" #include "common/scummsys.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "common/translation.h"
#include "gui/debugger.h" #include "gui/debugger.h"
#include "gui/dialog.h" #include "gui/dialog.h"
@ -95,6 +96,7 @@ Engine::Engine(OSystem *syst)
_targetName(ConfMan.getActiveDomainName()), _targetName(ConfMan.getActiveDomainName()),
_pauseLevel(0), _pauseLevel(0),
_pauseStartTime(0), _pauseStartTime(0),
_saveSlotToLoad(-1),
_engineStartTime(_system->getMillis()), _engineStartTime(_system->getMillis()),
_mainMenuDialog(NULL) { _mainMenuDialog(NULL) {
@ -112,6 +114,19 @@ Engine::Engine(OSystem *syst)
// there still would be problems with many games... // there still would be problems with many games...
if (!_mixer->isReady()) if (!_mixer->isReady())
warning("Sound initialization failed. This may cause severe problems in some games"); warning("Sound initialization failed. This may cause severe problems in some games");
// Setup a dummy cursor and palette, so that all engines can use
// CursorMan.replace without having any headaches about memory leaks.
//
// If an engine only used CursorMan.replaceCursor and no cursor has
// been setup before, then replaceCursor just uses pushCursor. This
// means that that the engine's cursor is never again removed from
// CursorMan. Hence we setup a fake cursor here and remove it again
// in the destructor.
CursorMan.pushCursor(NULL, 0, 0, 0, 0, 0);
// Note: Using this dummy palette will actually disable cursor
// palettes till the user enables it again.
CursorMan.pushCursorPalette(NULL, 0, 0);
} }
Engine::~Engine() { Engine::~Engine() {
@ -178,22 +193,22 @@ void Engine::checkCD() {
if (GetDriveType(buffer) == DRIVE_CDROM) { if (GetDriveType(buffer) == DRIVE_CDROM) {
GUI::MessageDialog dialog( GUI::MessageDialog dialog(
"You appear to be playing this game directly\n" _("You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n" "from the CD. This is known to cause problems,\n"
"and it is therefore recommended that you copy\n" "and it is therefore recommended that you copy\n"
"the data files to your hard disk instead.\n" "the data files to your hard disk instead.\n"
"See the README file for details.", "OK"); "See the README file for details."), _("OK"));
dialog.runModal(); dialog.runModal();
} else { } else {
// If we reached here, the game has audio tracks, // If we reached here, the game has audio tracks,
// it's not ran from the CD and the tracks have not // it's not ran from the CD and the tracks have not
// been ripped. // been ripped.
GUI::MessageDialog dialog( GUI::MessageDialog dialog(
"This game has audio tracks in its disk. These\n" _("This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n" "tracks need to be ripped from the disk using\n"
"an appropriate CD audio extracting tool in\n" "an appropriate CD audio extracting tool in\n"
"order to listen to the game's music.\n" "order to listen to the game's music.\n"
"See the README file for details.", "OK"); "See the README file for details."), _("OK"));
dialog.runModal(); dialog.runModal();
} }
#endif #endif
@ -235,10 +250,36 @@ void Engine::pauseEngineIntern(bool pause) {
void Engine::openMainMenuDialog() { void Engine::openMainMenuDialog() {
if (!_mainMenuDialog) if (!_mainMenuDialog)
_mainMenuDialog = new MainMenuDialog(this); _mainMenuDialog = new MainMenuDialog(this);
setGameToLoadSlot(-1);
runDialog(*_mainMenuDialog); runDialog(*_mainMenuDialog);
// Load savegame after main menu execution
// (not from inside the menu loop to avoid
// mouse cursor glitches and simliar bugs,
// e.g. #2822778).
// FIXME: For now we just ignore the return
// value, which is quite bad since it could
// be a fatal loading error, which renders
// the engine unusable.
if (_saveSlotToLoad >= 0)
loadGameState(_saveSlotToLoad);
syncSoundSettings(); syncSoundSettings();
} }
bool Engine::warnUserAboutUnsupportedGame() {
if (ConfMan.getBool("enable_unsupported_game_warning")) {
GUI::MessageDialog alert(_("WARNING: The game you are about to start is"
" not yet fully supported by Residual. As such, it is likely to be"
" unstable, and any saves you make might not work in future"
" versions of Residual."), _("Start anyway"), _("Cancel"));
return alert.runModal() == GUI::kMessageOK;
}
return true;
}
uint32 Engine::getTotalPlayTime() const { uint32 Engine::getTotalPlayTime() const {
if (!_pauseLevel) if (!_pauseLevel)
return _system->getMillis() - _engineStartTime; return _system->getMillis() - _engineStartTime;
@ -265,6 +306,10 @@ int Engine::runDialog(GUI::Dialog &dialog) {
return result; return result;
} }
void Engine::setGameToLoadSlot(int slot) {
_saveSlotToLoad = slot;
}
void Engine::syncSoundSettings() { void Engine::syncSoundSettings() {
// Sync the engine with the config manager // Sync the engine with the config manager
int soundVolumeMusic = ConfMan.getInt("music_volume"); int soundVolumeMusic = ConfMan.getInt("music_volume");

View file

@ -82,6 +82,13 @@ private:
*/ */
int32 _engineStartTime; int32 _engineStartTime;
/**
* Save slot selected via global main menu.
* This slot will be loaded after main menu execution (not from inside
* the menu loop, to avoid bugs like #2822778).
*/
int _saveSlotToLoad;
public: public:
@ -185,6 +192,15 @@ public:
*/ */
virtual Common::Error loadGameState(int slot); virtual Common::Error loadGameState(int slot);
/**
* Sets the game slot for a savegame to be loaded after global
* main menu execution. This is to avoid loading a savegame from
* inside the menu loop which causes bugs like #2822778.
*
* @param slot the slot from which a savestate should be loaded.
*/
void setGameToLoadSlot(int slot);
/** /**
* Indicates whether a game state can be loaded. * Indicates whether a game state can be loaded.
*/ */
@ -251,6 +267,13 @@ public:
*/ */
void openMainMenuDialog(); void openMainMenuDialog();
/**
* Display a warning to the user that the game is not fully supported.
*
* @return true if the user chose to start anyway, false otherwise
*/
static bool warnUserAboutUnsupportedGame();
/** /**
* Get the total play time. * Get the total play time.
* *

View file

@ -38,20 +38,15 @@ GameDescriptor::GameDescriptor() {
setVal("description", ""); setVal("description", "");
} }
GameDescriptor::GameDescriptor(const PlainGameDescriptor &pgd) { GameDescriptor::GameDescriptor(const PlainGameDescriptor &pgd, uint32 guioptions) {
setVal("gameid", pgd.gameid);
setVal("description", pgd.description);
}
GameDescriptor::GameDescriptor(const PlainGameDescriptorGUIOpts &pgd) {
setVal("gameid", pgd.gameid); setVal("gameid", pgd.gameid);
setVal("description", pgd.description); setVal("description", pgd.description);
if (pgd.guioptions != 0) if (guioptions != 0)
setVal("guioptions", Common::getGameGUIOptionsDescription(pgd.guioptions)); setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
} }
GameDescriptor::GameDescriptor(const Common::String &g, const Common::String &d, Common::Language l, Common::Platform p, uint32 guioptions) { GameDescriptor::GameDescriptor(const Common::String &g, const Common::String &d, Common::Language l, Common::Platform p, uint32 guioptions, GameSupportLevel gsl) {
setVal("gameid", g); setVal("gameid", g);
setVal("description", d); setVal("description", d);
if (l != Common::UNK_LANG) if (l != Common::UNK_LANG)
@ -60,6 +55,8 @@ GameDescriptor::GameDescriptor(const Common::String &g, const Common::String &d,
setVal("platform", Common::getPlatformCode(p)); setVal("platform", Common::getPlatformCode(p));
if (guioptions != 0) if (guioptions != 0)
setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions)); setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
setSupportLevel(gsl);
} }
void GameDescriptor::setGUIOptions(uint32 guioptions) { void GameDescriptor::setGUIOptions(uint32 guioptions) {
@ -74,9 +71,6 @@ void GameDescriptor::appendGUIOptions(const Common::String &str) {
} }
void GameDescriptor::updateDesc(const char *extra) { void GameDescriptor::updateDesc(const char *extra) {
// TODO: The format used here (LANG/PLATFORM/EXTRA) is not set in stone.
// We may want to change the order (PLATFORM/EXTRA/LANG, anybody?), or
// the seperator (instead of '/' use ', ' or ' ').
const bool hasCustomLanguage = (language() != Common::UNK_LANG); const bool hasCustomLanguage = (language() != Common::UNK_LANG);
const bool hasCustomPlatform = (platform() != Common::kPlatformUnknown); const bool hasCustomPlatform = (platform() != Common::kPlatformUnknown);
const bool hasExtraDesc = (extra && extra[0]); const bool hasExtraDesc = (extra && extra[0]);
@ -102,3 +96,30 @@ void GameDescriptor::updateDesc(const char *extra) {
setVal("description", descr); setVal("description", descr);
} }
} }
GameSupportLevel GameDescriptor::getSupportLevel() {
GameSupportLevel gsl = kStableGame;
if (contains("gsl")) {
Common::String gslString = getVal("gsl");
if (gslString.equals("unstable"))
gsl = kUnstableGame;
else if (gslString.equals("testing"))
gsl = kTestingGame;
}
return gsl;
}
void GameDescriptor::setSupportLevel(GameSupportLevel gsl) {
switch (gsl) {
case kUnstableGame:
setVal("gsl", "unstable");
break;
case kTestingGame:
setVal("gsl", "testing");
break;
case kStableGame:
// Fall Through intended
default:
erase("gsl");
}
}

View file

@ -39,24 +39,22 @@ struct PlainGameDescriptor {
const char *description; const char *description;
}; };
/**
* Same as PlainGameDsscriptor except it adds Game GUI options parameter
* This is a plain struct to make it possible to declare NULL-terminated C arrays
* consisting of PlainGameDescriptors.
*/
struct PlainGameDescriptorGUIOpts {
const char *gameid;
const char *description;
uint32 guioptions;
};
/** /**
* Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor * Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor
* matching the given gameid. If not match is found return 0. * matching the given gameid. If not match is found return 0.
* The end of the list must marked by a PlainGameDescriptor with gameid equal to 0. * The end of the list must be marked by an entry with gameid 0.
*/ */
const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list); const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list);
/**
* Ths is an enum to describe how done a game is. This also indicates what level of support is expected.
*/
enum GameSupportLevel {
kStableGame = 0, // the game is fully supported
kTestingGame, // the game is not supposed to end up in releases yet but is ready for public testing
kUnstableGame // the game is not even ready for public testing yet
};
/** /**
* A hashmap describing details about a given game. In a sense this is a refined * A hashmap describing details about a given game. In a sense this is a refined
* version of PlainGameDescriptor, as it also contains a gameid and a description string. * version of PlainGameDescriptor, as it also contains a gameid and a description string.
@ -67,22 +65,30 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const Pla
class GameDescriptor : public Common::StringMap { class GameDescriptor : public Common::StringMap {
public: public:
GameDescriptor(); GameDescriptor();
GameDescriptor(const PlainGameDescriptor &pgd); GameDescriptor(const PlainGameDescriptor &pgd, uint32 guioptions = 0);
GameDescriptor(const PlainGameDescriptorGUIOpts &pgd);
GameDescriptor(const Common::String &gameid, GameDescriptor(const Common::String &gameid,
const Common::String &description, const Common::String &description,
Common::Language language = Common::UNK_LANG, Common::Language language = Common::UNK_LANG,
Common::Platform platform = Common::kPlatformUnknown, Common::Platform platform = Common::kPlatformUnknown,
uint32 guioptions = 0); uint32 guioptions = 0,
GameSupportLevel gsl = kStableGame);
/** /**
* Update the description string by appending (LANG/PLATFORM/EXTRA) to it. * Update the description string by appending (EXTRA/PLATFORM/LANG) to it.
* Values that are missing are omitted, so e.g. (EXTRA/LANG) would be
* added if no platform has been specified but a language and an extra string.
*/ */
void updateDesc(const char *extra = 0); void updateDesc(const char *extra = 0);
void setGUIOptions(uint32 options); void setGUIOptions(uint32 options);
void appendGUIOptions(const Common::String &str); void appendGUIOptions(const Common::String &str);
/**
* What level of support is expected of this game
*/
GameSupportLevel getSupportLevel();
void setSupportLevel(GameSupportLevel gsl);
Common::String &gameid() { return getVal("gameid"); } Common::String &gameid() { return getVal("gameid"); }
Common::String &description() { return getVal("description"); } Common::String &description() { return getVal("description"); }
const Common::String &gameid() const { return getVal("gameid"); } const Common::String &gameid() const { return getVal("gameid"); }
@ -102,7 +108,7 @@ public:
GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {} GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {}
GameList(const PlainGameDescriptor *g) { GameList(const PlainGameDescriptor *g) {
while (g->gameid) { while (g->gameid) {
push_back(GameDescriptor(g->gameid, g->description)); push_back(GameDescriptor(*g));
g++; g++;
} }
} }

View file

@ -21,6 +21,7 @@
*/ */
#include "engines/advancedDetector.h" #include "engines/advancedDetector.h"
#include "engines/obsolete.h"
#include "engines/grim/grim.h" #include "engines/grim/grim.h"
#include "engines/grim/colormap.h" #include "engines/grim/colormap.h"
@ -362,39 +363,21 @@ static const GrimGameDescription gameDescriptions[] = {
{ AD_TABLE_END_MARKER, GType_GRIM } { AD_TABLE_END_MARKER, GType_GRIM }
}; };
static const ADObsoleteGameID obsoleteGameIDsTable[] = { static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = {
{"grimdemo", "grim", Common::kPlatformWindows}, {"grimdemo", "grim", Common::kPlatformWindows},
{0, 0, Common::kPlatformUnknown} {0, 0, Common::kPlatformUnknown}
}; };
static const ADParams detectionParams = {
// Pointer to ADGameDescription or its superset structure
(const byte *)gameDescriptions,
// Size of that superset structure
sizeof(GrimGameDescription),
// Number of bytes to compute MD5 sum for
5000,
// List of all engine targets
grimGames,
// Structure for autoupgrading obsolete targets
obsoleteGameIDsTable,
// Name of single gameid (optional)
0,
// List of files for file-based fallback detection (optional)
0,
// Flags
0,
// Additional GUI options (for every game}
Common::GUIO_NOMIDI,
// Maximum directory depth
1,
// List of directory globs
0
};
class GrimMetaEngine : public AdvancedMetaEngine { class GrimMetaEngine : public AdvancedMetaEngine {
public: public:
GrimMetaEngine() : AdvancedMetaEngine(detectionParams) {} GrimMetaEngine() : AdvancedMetaEngine(Grim::gameDescriptions, sizeof(Grim::GrimGameDescription), grimGames) {
_singleid = "grim";
_guioptions = Common::GUIO_NOMIDI;
}
virtual GameDescriptor findGame(const char *gameid) const {
return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
}
virtual const char *getName() const { virtual const char *getName() const {
return "Grim Engine"; return "Grim Engine";
@ -404,9 +387,15 @@ public:
return "LucasArts GrimE Games (C) LucasArts"; return "LucasArts GrimE Games (C) LucasArts";
} }
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const {
Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable);
return AdvancedMetaEngine::createInstance(syst, engine);
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual bool hasFeature(MetaEngineFeature f) const; virtual bool hasFeature(MetaEngineFeature f) const;
virtual SaveStateList listSaves(const char *target) const; virtual SaveStateList listSaves(const char *target) const;
}; };

View file

@ -5,6 +5,7 @@ MODULE_OBJS := \
dialogs.o \ dialogs.o \
engine.o \ engine.o \
game.o \ game.o \
obsolete.o \
savestate.o savestate.o
# Include common rules # Include common rules

88
engines/obsolete.cpp Normal file
View file

@ -0,0 +1,88 @@
/* 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.
*
*/
#include "engines/obsolete.h"
#include "common/config-manager.h"
namespace Engines {
void upgradeTargetIfNecessary(const ObsoleteGameID *obsoleteList) {
if (obsoleteList == 0)
return;
Common::String gameid = ConfMan.get("gameid");
for (const ObsoleteGameID *o = obsoleteList; o->from; ++o) {
if (gameid.equalsIgnoreCase(o->from)) {
gameid = o->to;
ConfMan.set("gameid", gameid);
if (o->platform != Common::kPlatformUnknown)
ConfMan.set("platform", Common::getPlatformCode(o->platform));
warning("Target upgraded from %s to %s", o->from, o->to);
// WORKAROUND: Fix for bug #1719463: "DETECTOR: Launching
// undefined target adds launcher entry"
if (ConfMan.hasKey("id_came_from_command_line")) {
warning("Target came from command line. Skipping save");
} else {
ConfMan.flushToDisk();
}
break;
}
}
}
GameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *gameids,
const ObsoleteGameID *obsoleteList
) {
// First search the list of supported gameids for a match.
const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, gameids);
if (g)
return GameDescriptor(*g);
// If we didn't find the gameid in the main list, check if it
// is an obsolete game id.
if (obsoleteList != 0) {
const ObsoleteGameID *o = obsoleteList;
while (o->from) {
if (0 == scumm_stricmp(gameid, o->from)) {
g = findPlainGameDescriptor(o->to, gameids);
if (g && g->description)
return GameDescriptor(gameid, "Obsolete game ID (" + Common::String(g->description) + ")");
else
return GameDescriptor(gameid, "Obsolete game ID");
}
o++;
}
}
// No match found
return GameDescriptor();
}
} // End of namespace Engines

78
engines/obsolete.h Normal file
View file

@ -0,0 +1,78 @@
/* 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.
*
*/
#ifndef ENGINES_OBSOLETE_H
#define ENGINES_OBSOLETE_H
#include "engines/game.h"
namespace Engines {
/**
* Structure for autoupgrading targets using an obsolete gameid
* to the correct new gameid.
*/
struct ObsoleteGameID {
/** Name of the obsolete gameid. */
const char *from;
/** Name of the corresponding new gameid. */
const char *to;
/**
* If platform is set to a value different from Common::kPlatformUnknown,
* then upgradeTargetIfNecessary() will use this value to set the platform
* attribute of any target it updates using this ObsoleteGameID record.
* This is useful when the old gameid encoded the target platform (e.g.
* "zakTowns" for FM-TOWNS) while the new gameid does not (e.g. "zak").
*/
Common::Platform platform;
};
/**
* Check if the currently active game target has an obsolete gameid;
* if so, replace it by the correct new gameid.
* This function is typically invoked by a MetaEngine::createInstance
* implementation.
*/
void upgradeTargetIfNecessary(const ObsoleteGameID *obsoleteList);
/**
* Scan through the given list of plain game descriptors specified and search
* for 'gameid' in there. If a match is found, returns a GameDescriptor
* with gameid and description set.
*
* Optionally can take a list of obsolete game ids into account in order
* to support obsolete gameids.
*/
GameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *gameids,
const ObsoleteGameID *obsoleteList = 0
);
} // End of namespace Engines
#endif

View file

@ -24,6 +24,17 @@
#include "graphics/surface.h" #include "graphics/surface.h"
#include "common/textconsole.h" #include "common/textconsole.h"
SaveStateDescriptor::SaveStateDescriptor()
// FIXME: default to 0 (first slot) or to -1 (invalid slot) ?
: _slot(-1), _description(), _isDeletable(true), _isWriteProtected(false),
_saveDate(), _saveTime(), _playTime(), _thumbnail() {
}
SaveStateDescriptor::SaveStateDescriptor(int s, const Common::String &d)
: _slot(s), _description(d), _isDeletable(true), _isWriteProtected(false),
_saveDate(), _saveTime(), _playTime(), _thumbnail() {
}
void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) { void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) {
if (_thumbnail.get() == t) if (_thumbnail.get() == t)
return; return;
@ -31,42 +42,16 @@ void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) {
_thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter()); _thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter());
} }
bool SaveStateDescriptor::getBool(const Common::String &key) const {
if (contains(key)) {
const Common::String value = getVal(key);
bool valueAsBool;
if (Common::parseBool(value, valueAsBool))
return valueAsBool;
error("SaveStateDescriptor: %s '%s' has unknown value '%s' for boolean '%s'",
save_slot().c_str(), description().c_str(), value.c_str(), key.c_str());
}
return false;
}
void SaveStateDescriptor::setDeletableFlag(bool state) {
setVal("is_deletable", state ? "true" : "false");
}
void SaveStateDescriptor::setWriteProtectedFlag(bool state) {
setVal("is_write_protected", state ? "true" : "false");
}
void SaveStateDescriptor::setSaveDate(int year, int month, int day) { void SaveStateDescriptor::setSaveDate(int year, int month, int day) {
Common::String buffer; _saveDate = Common::String::format("%.2d.%.2d.%.4d", day, month, year);
buffer = Common::String::format("%.2d.%.2d.%.4d", day, month, year);
setVal("save_date", buffer);
} }
void SaveStateDescriptor::setSaveTime(int hour, int min) { void SaveStateDescriptor::setSaveTime(int hour, int min) {
Common::String buffer; _saveTime = Common::String::format("%.2d:%.2d", hour, min);
buffer = Common::String::format("%.2d:%.2d", hour, min);
setVal("save_time", buffer);
} }
void SaveStateDescriptor::setPlayTime(int hours, int minutes) { void SaveStateDescriptor::setPlayTime(int hours, int minutes) {
Common::String buffer; _playTime = Common::String::format("%.2d:%.2d", hours, minutes);
buffer = Common::String::format("%.2d:%.2d", hours, minutes);
setVal("play_time", buffer);
} }
void SaveStateDescriptor::setPlayTime(uint32 msecs) { void SaveStateDescriptor::setPlayTime(uint32 msecs) {

View file

@ -24,7 +24,7 @@
#define ENGINES_SAVESTATE_H #define ENGINES_SAVESTATE_H
#include "common/array.h" #include "common/array.h"
#include "common/hash-str.h" #include "common/str.h"
#include "common/ptr.h" #include "common/ptr.h"
@ -33,65 +33,60 @@ struct Surface;
} }
/** /**
* A hashmap describing details about a given save state. * Object describing a save state.
* TODO *
* Guaranteed to contain save_slot and description values. * This at least includes the save slot number and a human readable
* Additional ideas: Playtime, creation date, thumbnail, ... * description of the save state.
*
* Further possibilites are a thumbnail, play time, creation date,
* creation time, delete protected, write protection.
*/ */
class SaveStateDescriptor : public Common::StringMap { class SaveStateDescriptor {
protected:
Common::SharedPtr<Graphics::Surface> _thumbnail; // can be 0
public: public:
SaveStateDescriptor() : _thumbnail() { SaveStateDescriptor();
setVal("save_slot", "-1"); // FIXME: default to 0 (first slot) or to -1 (invalid slot) ? SaveStateDescriptor(int s, const Common::String &d);
setVal("description", "");
}
SaveStateDescriptor(int s, const Common::String &d) : _thumbnail() { /**
setVal("save_slot", Common::String::format("%d", s)); * @param slot The saveslot id, as it would be passed to the "-x" command line switch.
setVal("description", d); */
} void setSaveSlot(int slot) { _slot = slot; }
SaveStateDescriptor(const Common::String &s, const Common::String &d) : _thumbnail() { /**
setVal("save_slot", s); * @return The saveslot id, as it would be passed to the "-x" command line switch.
setVal("description", d); */
} int getSaveSlot() const { return _slot; }
/** The saveslot id, as it would be passed to the "-x" command line switch. */ /**
Common::String &save_slot() { return getVal("save_slot"); } * @param desc A human readable description of the save state.
*/
void setDescription(const Common::String &desc) { _description = desc; }
/** The saveslot id, as it would be passed to the "-x" command line switch (read-only variant). */ /**
const Common::String &save_slot() const { return getVal("save_slot"); } * @return A human readable description of the save state.
*/
/** A human readable description of the save state. */ const Common::String &getDescription() const { return _description; }
Common::String &description() { return getVal("description"); }
/** A human readable description of the save state (read-only variant). */
const Common::String &description() const { return getVal("description"); }
/** Optional entries only included when querying via MetaEngine::querySaveMetaInfo */ /** Optional entries only included when querying via MetaEngine::querySaveMetaInfo */
/** /**
* Returns the value of a given key as boolean. * Defines whether the save state is allowed to be deleted.
* It accepts 'true', 'yes' and '1' for true and
* 'false', 'no' and '0' for false.
* (FIXME:) On unknown value it errors out ScummVM.
* On unknown key it returns false as default.
*/ */
bool getBool(const Common::String &key) const; void setDeletableFlag(bool state) { _isDeletable = state; }
/** /**
* Sets the 'is_deletable' key, which indicates if the * Queries whether the save state is allowed to be deleted.
* given savestate is safe for deletion.
*/ */
void setDeletableFlag(bool state); bool getDeletableFlag() const { return _isDeletable; }
/** /**
* Sets the 'is_write_protected' key, which indicates if the * Defines whether the save state is write protected.
* given savestate can be overwritten or not
*/ */
void setWriteProtectedFlag(bool state); void setWriteProtectedFlag(bool state) { _isWriteProtected = state; }
/**
* Queries whether the save state is write protected.
*/
bool getWriteProtectedFlag() const { return _isWriteProtected; }
/** /**
* Return a thumbnail graphics surface representing the savestate visually. * Return a thumbnail graphics surface representing the savestate visually.
@ -109,24 +104,100 @@ public:
void setThumbnail(Graphics::Surface *t); void setThumbnail(Graphics::Surface *t);
/** /**
* Sets the 'save_date' key properly, based on the given values. * Sets the date the save state was created.
*
* @param year Year of creation.
* @param month Month of creation.
* @param day Day of creation.
*/ */
void setSaveDate(int year, int month, int day); void setSaveDate(int year, int month, int day);
/** /**
* Sets the 'save_time' key properly, based on the given values. * Queries a human readable description of the date the save state was created.
*
* This will return an empty string in case the value is not set.
*/
const Common::String &getSaveDate() const { return _saveDate; }
/**
* Sets the time the save state was created.
*
* @param hour Hour of creation.
* @param min Minute of creation.
*/ */
void setSaveTime(int hour, int min); void setSaveTime(int hour, int min);
/** /**
* Sets the 'play_time' key properly, based on the given values. * Queries a human readable description of the time the save state was created.
*
* This will return an empty string in case the value is not set.
*/
const Common::String &getSaveTime() const { return _saveTime; }
/**
* Sets the time the game was played before the save state was created.
*
* @param hours How many hours the user played the game so far.
* @param min How many minutes the user played the game so far.
*/ */
void setPlayTime(int hours, int minutes); void setPlayTime(int hours, int minutes);
/** /**
* Sets the 'play_time' key properly, based on the given value. * Sets the time the game was played before the save state was created.
*
* @param msecs How many milliseconds the user played the game so far.
*/ */
void setPlayTime(uint32 msecs); void setPlayTime(uint32 msecs);
/**
* Queries a human readable description of the time the game was played
* before the save state was created.
*
* This will return an empty string in case the value is not set.
*/
const Common::String &getPlayTime() const { return _playTime; }
private:
/**
* The saveslot id, as it would be passed to the "-x" command line switch.
*/
int _slot;
/**
* A human readable description of the save state.
*/
Common::String _description;
/**
* Whether the save state can be deleted.
*/
bool _isDeletable;
/**
* Whether the save state is write protected.
*/
bool _isWriteProtected;
/**
* Human readable description of the date the save state was created.
*/
Common::String _saveDate;
/**
* Human readable description of the time the save state was created.
*/
Common::String _saveTime;
/**
* Human readable description of the time the game was played till the
* save state was created.
*/
Common::String _playTime;
/**
* The thumbnail of the save state.
*/
Common::SharedPtr<Graphics::Surface> _thumbnail;
}; };
/** List of savestates. */ /** List of savestates. */

View file

@ -24,7 +24,9 @@
#include "common/system.h" #include "common/system.h"
#include "common/stack.h" #include "common/stack.h"
namespace Common {
DECLARE_SINGLETON(Graphics::CursorManager); DECLARE_SINGLETON(Graphics::CursorManager);
}
namespace Graphics { namespace Graphics {

View file

@ -19,771 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include "common/stream.h"
#include "common/file.h"
#include "common/endian.h"
#include "common/array.h"
#include "common/textconsole.h"
#include "common/util.h"
#include "graphics/font.h" #include "graphics/font.h"
#include "graphics/surface.h"
#include "common/array.h"
#include "common/util.h"
namespace Graphics { namespace Graphics {
void free_font(NewFontData *pf);
NewFont::~NewFont() {
if (_font) {
free_font(_font);
}
}
int NewFont::getCharWidth(byte chr) const {
// If no width table is specified, return the maximum width
if (!_desc.width)
return _desc.maxwidth;
// If this character is not included in the font, use the default char.
if (chr < _desc.firstchar || _desc.firstchar + _desc.size < chr) {
chr = _desc.defaultchar;
}
return _desc.width[chr - _desc.firstchar];
}
template <typename PixelType>
void drawCharIntern(byte *ptr, uint pitch, const bitmap_t *src, int h, int minX, int maxX, const PixelType color) {
const bitmap_t maxXMask = ~((1 << (16-maxX)) - 1);
while (h-- > 0) {
bitmap_t buffer = READ_UINT16(src);
src++;
buffer &= maxXMask;
buffer <<= minX;
PixelType *tmp = (PixelType *)ptr;
while (buffer != 0) {
if ((buffer & 0x8000) != 0)
*tmp = color;
tmp++;
buffer <<= 1;
}
ptr += pitch;
}
}
void NewFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const uint32 color) const {
assert(dst != 0);
assert(_desc.bits != 0 && _desc.maxwidth <= 16);
assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2);
// If this character is not included in the font, use the default char.
if (chr < _desc.firstchar || chr >= _desc.firstchar + _desc.size) {
chr = _desc.defaultchar;
}
chr -= _desc.firstchar;
int bbw, bbh, bbx, bby;
// Get the bounding box of the character
if (!_desc.bbx) {
bbw = _desc.fbbw;
bbh = _desc.fbbh;
bbx = _desc.fbbx;
bby = _desc.fbby;
} else {
bbw = _desc.bbx[chr].w;
bbh = _desc.bbx[chr].h;
bbx = _desc.bbx[chr].x;
bby = _desc.bbx[chr].y;
}
byte *ptr = (byte *)dst->getBasePtr(tx + bbx, ty + _desc.ascent - bby - bbh);
const bitmap_t *tmp = _desc.bits + (_desc.offset ? _desc.offset[chr] : (chr * _desc.fbbh));
int y = MIN(bbh, ty + _desc.ascent - bby);
tmp += bbh - y;
y -= MAX(0, ty + _desc.ascent - bby - dst->h);
if (dst->format.bytesPerPixel == 1)
drawCharIntern<byte>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
else if (dst->format.bytesPerPixel == 2)
drawCharIntern<uint16>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
}
#pragma mark -
/* BEGIN font.h*/
/* bitmap_t helper macros*/
#define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/
#define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t))
#define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8)
#define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n)))
#define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1))
#define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT)
#define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1))
/* builtin C-based proportional/fixed font structure */
/* based on The Microwindows Project http://microwindows.org */
struct NewFontData {
char * name; /* font name*/
int maxwidth; /* max width in pixels*/
int height; /* height in pixels*/
int ascent; /* ascent (baseline) height*/
int firstchar; /* first character in bitmap*/
int size; /* font size in glyphs*/
bitmap_t* bits; /* 16-bit right-padded bitmap data*/
unsigned long* offset; /* offsets into bitmap data*/
unsigned char* width; /* character widths or NULL if fixed*/
BBX* bbx; /* character bounding box or NULL if fixed */
int defaultchar; /* default char (not glyph index)*/
long bits_size; /* # words of bitmap_t bits*/
/* unused by runtime system, read in by convbdf*/
char * facename; /* facename of font*/
char * copyright; /* copyright info for loadable fonts*/
int pixel_size;
int descent;
int fbbw, fbbh, fbbx, fbby;
};
/* END font.h*/
#define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
#define strequal(s1,s2) (!strcmp(s1, s2))
#define EXTRA 300
int start_char = 0;
int limit_char = 255;
NewFontData* bdf_read_font(Common::SeekableReadStream &fp);
int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf);
int bdf_read_bitmaps(Common::SeekableReadStream &fp, NewFontData* pf);
char * bdf_getline(Common::SeekableReadStream &fp, char *buf, int len);
bitmap_t bdf_hexval(unsigned char *buf);
void free_font(NewFontData* pf) {
if (!pf)
return;
free(pf->name);
free(pf->facename);
free(pf->bits);
free(pf->offset);
free(pf->width);
free(pf->bbx);
free(pf);
}
/* build incore structure from .bdf file*/
NewFontData* bdf_read_font(Common::SeekableReadStream &fp) {
NewFontData* pf;
uint32 pos = fp.pos();
pf = (NewFontData*)calloc(1, sizeof(NewFontData));
if (!pf)
goto errout;
if (!bdf_read_header(fp, pf)) {
warning("Error reading font header");
goto errout;
}
fp.seek(pos, SEEK_SET);
if (!bdf_read_bitmaps(fp, pf)) {
warning("Error reading font bitmaps");
goto errout;
}
return pf;
errout:
free_font(pf);
return NULL;
}
/* read bdf font header information, return 0 on error*/
int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf) {
int encoding = 0;
int nchars = 0, maxwidth, maxheight;
int firstchar = 65535;
int lastchar = -1;
char buf[256];
char facename[256];
char copyright[256];
/* set certain values to errors for later error checking*/
pf->defaultchar = -1;
pf->ascent = -1;
pf->descent = -1;
for (;;) {
if (!bdf_getline(fp, buf, sizeof(buf))) {
warning("Error: EOF on file");
return 0;
}
/* note: the way sscanf is used here ensures that a terminating null
character is automatically added. Refer to:
http://pubs.opengroup.org/onlinepubs/009695399/functions/fscanf.html */
if (isprefix(buf, "FONT ")) { /* not required*/
if (sscanf(buf, "FONT %[^\n]", facename) != 1) {
warning("Error: bad 'FONT'");
return 0;
}
pf->facename = strdup(facename);
continue;
}
if (isprefix(buf, "COPYRIGHT ")) { /* not required*/
if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) {
warning("Error: bad 'COPYRIGHT'");
return 0;
}
pf->copyright = strdup(copyright);
continue;
}
if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/
if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) {
warning("Error: bad 'DEFAULT_CHAR'");
return 0;
}
}
if (isprefix(buf, "FONT_DESCENT ")) {
if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) {
warning("Error: bad 'FONT_DESCENT'");
return 0;
}
continue;
}
if (isprefix(buf, "FONT_ASCENT ")) {
if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) {
warning("Error: bad 'FONT_ASCENT'");
return 0;
}
continue;
}
if (isprefix(buf, "FONTBOUNDINGBOX ")) {
if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d",
&pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) {
warning("Error: bad 'FONTBOUNDINGBOX'");
return 0;
}
continue;
}
if (isprefix(buf, "CHARS ")) {
if (sscanf(buf, "CHARS %d", &nchars) != 1) {
warning("Error: bad 'CHARS'");
return 0;
}
continue;
}
/*
* Reading ENCODING is necessary to get firstchar/lastchar
* which is needed to pre-calculate our offset and widths
* array sizes.
*/
if (isprefix(buf, "ENCODING ")) {
if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
warning("Error: bad 'ENCODING'");
return 0;
}
if (encoding >= 0 &&
encoding <= limit_char &&
encoding >= start_char) {
if (firstchar > encoding)
firstchar = encoding;
if (lastchar < encoding)
lastchar = encoding;
}
continue;
}
if (strequal(buf, "ENDFONT"))
break;
}
/* calc font height*/
if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) {
warning("Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING");
return 0;
}
pf->height = pf->ascent + pf->descent;
/* calc default char*/
if (pf->defaultchar < 0 ||
pf->defaultchar < firstchar ||
pf->defaultchar > limit_char )
pf->defaultchar = firstchar;
/* calc font size (offset/width entries)*/
pf->firstchar = firstchar;
pf->size = lastchar - firstchar + 1;
/* use the font boundingbox to get initial maxwidth*/
/*maxwidth = pf->fbbw - pf->fbbx;*/
maxwidth = pf->fbbw;
maxheight = pf->fbbh;
/* initially use font bounding box for bits allocation*/
pf->bits_size = nchars * BITMAP_WORDS(maxwidth) * maxheight;
/* allocate bits, offset, and width arrays*/
pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t) + EXTRA);
pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long));
pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
pf->bbx = (BBX *)malloc(pf->size * sizeof(BBX));
if (!pf->bits || !pf->offset || !pf->width) {
warning("Error: no memory for font load");
return 0;
}
return 1;
}
/* read bdf font bitmaps, return 0 on error*/
int bdf_read_bitmaps(Common::SeekableReadStream &fp, NewFontData* pf) {
long ofs = 0;
int maxwidth = 0;
int i, k, encoding = 0, width = 0;
int bbw = 0, bbh = 0, bbx = 0, bby = 0;
int proportional = 0;
int need_bbx = 0;
int encodetable = 0;
long l;
char buf[256];
/* initially mark offsets as not used*/
for (i = 0; i < pf->size; ++i)
pf->offset[i] = (unsigned long)-1;
for (;;) {
if (!bdf_getline(fp, buf, sizeof(buf))) {
warning("Error: EOF on file");
return 0;
}
if (isprefix(buf, "STARTCHAR")) {
encoding = width = bbw = bbh = bbx = bby = -1;
continue;
}
if (isprefix(buf, "ENCODING ")) {
if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
warning("Error: bad 'ENCODING'");
return 0;
}
if (encoding < start_char || encoding > limit_char)
encoding = -1;
continue;
}
if (isprefix(buf, "DWIDTH ")) {
if (sscanf(buf, "DWIDTH %d", &width) != 1) {
warning("Error: bad 'DWIDTH'");
return 0;
}
/* use font boundingbox width if DWIDTH <= 0*/
if (width <= 0)
width = pf->fbbw - pf->fbbx;
continue;
}
if (isprefix(buf, "BBX ")) {
if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
warning("Error: bad 'BBX'");
return 0;
}
continue;
}
if (strequal(buf, "BITMAP")) {
bitmap_t *ch_bitmap = pf->bits + ofs;
int ch_words;
if (encoding < 0)
continue;
/* set bits offset in encode map*/
if (pf->offset[encoding-pf->firstchar] != (unsigned long)-1) {
warning("Error: duplicate encoding for character %d (0x%02x), ignoring duplicate",
encoding, encoding);
continue;
}
pf->offset[encoding-pf->firstchar] = ofs;
pf->width[encoding-pf->firstchar] = width;
pf->bbx[encoding-pf->firstchar].w = bbw;
pf->bbx[encoding-pf->firstchar].h = bbh;
pf->bbx[encoding-pf->firstchar].x = bbx;
pf->bbx[encoding-pf->firstchar].y = bby;
if (width > maxwidth)
maxwidth = width;
/* clear bitmap*/
memset(ch_bitmap, 0, BITMAP_BYTES(bbw) * bbh);
ch_words = BITMAP_WORDS(bbw);
/* read bitmaps*/
for (i = 0; i < bbh; ++i) {
if (!bdf_getline(fp, buf, sizeof(buf))) {
warning("Error: EOF reading BITMAP data");
return 0;
}
if (isprefix(buf, "ENDCHAR"))
break;
for (k = 0; k < ch_words; ++k) {
bitmap_t value;
value = bdf_hexval((unsigned char *)buf);
if (bbw > 8) {
WRITE_UINT16(ch_bitmap, value);
} else {
WRITE_UINT16(ch_bitmap, value << 8);
}
ch_bitmap++;
}
}
ofs += ch_words * bbh;
continue;
}
if (strequal(buf, "ENDFONT"))
break;
}
/* set max width*/
pf->maxwidth = maxwidth;
/* change unused offset/width values to default char values*/
for (i = 0; i < pf->size; ++i) {
int defchar = pf->defaultchar - pf->firstchar;
if (pf->offset[i] == (unsigned long)-1) {
pf->offset[i] = pf->offset[defchar];
pf->width[i] = pf->width[defchar];
pf->bbx[i].w = pf->bbx[defchar].w;
pf->bbx[i].h = pf->bbx[defchar].h;
pf->bbx[i].x = pf->bbx[defchar].x;
pf->bbx[i].y = pf->bbx[defchar].y;
}
}
/* determine whether font doesn't require encode table*/
l = 0;
for (i = 0; i < pf->size; ++i) {
if (pf->offset[i] != (unsigned long)l) {
encodetable = 1;
break;
}
l += BITMAP_WORDS(pf->bbx[i].w) * pf->bbx[i].h;
}
if (!encodetable) {
free(pf->offset);
pf->offset = NULL;
}
/* determine whether font is fixed-width*/
for (i = 0; i < pf->size; ++i) {
if (pf->width[i] != maxwidth) {
proportional = 1;
break;
}
}
if (!proportional) {
free(pf->width);
pf->width = NULL;
}
/* determine if the font needs a bbx table */
for (i = 0; i < pf->size; ++i) {
if (pf->bbx[i].w != pf->fbbw || pf->bbx[i].h != pf->fbbh || pf->bbx[i].x != pf->fbbx || pf->bbx[i].y != pf->fbby) {
need_bbx = 1;
break;
}
}
if (!need_bbx) {
free(pf->bbx);
pf->bbx = NULL;
}
/* reallocate bits array to actual bits used*/
if (ofs < pf->bits_size) {
bitmap_t *tmp = (bitmap_t *)realloc(pf->bits, ofs * sizeof(bitmap_t));
if (tmp != NULL || ofs == 0)
pf->bits = tmp;
else
error("bdf_read_bitmaps: Error while reallocating memory");
pf->bits_size = ofs;
}
else {
if (ofs > pf->bits_size) {
warning("Warning: DWIDTH spec > max FONTBOUNDINGBOX");
if (ofs > pf->bits_size+EXTRA) {
warning("Error: Not enough bits initially allocated");
return 0;
}
pf->bits_size = ofs;
}
}
return 1;
}
/* read the next non-comment line, returns buf or NULL if EOF*/
// TODO: Can we use SeekableReadStream::readLine instead?
char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len) {
int c;
char *b;
for (;;) {
b = buf;
while (!fp.eos()) {
c = fp.readByte();
if (c == '\r')
continue;
if (c == '\n')
break;
if (b - buf >= (len - 1))
break;
*b++ = c;
}
*b = '\0';
if (fp.eos() && b == buf)
return NULL;
if (b != buf && !isprefix(buf, "COMMENT"))
break;
}
return buf;
}
/* return hex value of buffer */
bitmap_t bdf_hexval(unsigned char *buf) {
bitmap_t val = 0;
for (unsigned char *ptr = buf; *ptr; ptr++) {
int c = *ptr;
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'F')
c = c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
c = c - 'a' + 10;
else
c = 0;
val = (val << 4) | c;
}
return val;
}
NewFont *NewFont::loadFont(Common::SeekableReadStream &stream) {
NewFontData *data = bdf_read_font(stream);
if (!data || stream.err()) {
free_font(data);
return 0;
}
FontDesc desc;
desc.name = data->name;
desc.maxwidth = data->maxwidth;
desc.height = data->height;
desc.fbbw = data->fbbw;
desc.fbbh = data->fbbh;
desc.fbbx = data->fbbx;
desc.fbby = data->fbby;
desc.ascent = data->ascent;
desc.firstchar = data->firstchar;
desc.size = data->size;
desc.bits = data->bits;
desc.offset = data->offset;
desc.width = data->width;
desc.bbx = data->bbx;
desc.defaultchar = data->defaultchar;
desc.bits_size = data->bits_size;
return new NewFont(desc, data);
}
bool NewFont::cacheFontData(const NewFont &font, const Common::String &filename) {
Common::DumpFile cacheFile;
if (!cacheFile.open(filename)) {
warning("Couldn't open file '%s' for writing", filename.c_str());
return false;
}
cacheFile.writeUint16BE(font._desc.maxwidth);
cacheFile.writeUint16BE(font._desc.height);
cacheFile.writeUint16BE(font._desc.fbbw);
cacheFile.writeUint16BE(font._desc.fbbh);
cacheFile.writeSint16BE(font._desc.fbbx);
cacheFile.writeSint16BE(font._desc.fbby);
cacheFile.writeUint16BE(font._desc.ascent);
cacheFile.writeUint16BE(font._desc.firstchar);
cacheFile.writeUint16BE(font._desc.size);
cacheFile.writeUint16BE(font._desc.defaultchar);
cacheFile.writeUint32BE(font._desc.bits_size);
for (long i = 0; i < font._desc.bits_size; ++i) {
cacheFile.writeUint16BE(font._desc.bits[i]);
}
if (font._desc.offset) {
cacheFile.writeByte(1);
for (int i = 0; i < font._desc.size; ++i) {
cacheFile.writeUint32BE(font._desc.offset[i]);
}
} else {
cacheFile.writeByte(0);
}
if (font._desc.width) {
cacheFile.writeByte(1);
for (int i = 0; i < font._desc.size; ++i) {
cacheFile.writeByte(font._desc.width[i]);
}
} else {
cacheFile.writeByte(0);
}
if (font._desc.bbx) {
cacheFile.writeByte(1);
for (int i = 0; i < font._desc.size; ++i) {
cacheFile.writeByte(font._desc.bbx[i].w);
cacheFile.writeByte(font._desc.bbx[i].h);
cacheFile.writeByte(font._desc.bbx[i].x);
cacheFile.writeByte(font._desc.bbx[i].y);
}
} else {
cacheFile.writeByte(0);
}
return !cacheFile.err();
}
NewFont *NewFont::loadFromCache(Common::SeekableReadStream &stream) {
NewFont *font = 0;
NewFontData *data = (NewFontData *)malloc(sizeof(NewFontData));
if (!data)
return 0;
memset(data, 0, sizeof(NewFontData));
data->maxwidth = stream.readUint16BE();
data->height = stream.readUint16BE();
data->fbbw = stream.readUint16BE();
data->fbbh = stream.readUint16BE();
data->fbbx = stream.readSint16BE();
data->fbby = stream.readSint16BE();
data->ascent = stream.readUint16BE();
data->firstchar = stream.readUint16BE();
data->size = stream.readUint16BE();
data->defaultchar = stream.readUint16BE();
data->bits_size = stream.readUint32BE();
data->bits = (bitmap_t *)malloc(sizeof(bitmap_t) * data->bits_size);
if (!data->bits) {
free(data);
return 0;
}
for (long i = 0; i < data->bits_size; ++i) {
data->bits[i] = stream.readUint16BE();
}
bool hasOffsetTable = (stream.readByte() != 0);
if (hasOffsetTable) {
data->offset = (unsigned long *)malloc(sizeof(unsigned long) * data->size);
if (!data->offset) {
free(data->bits);
free(data);
return 0;
}
for (int i = 0; i < data->size; ++i) {
data->offset[i] = stream.readUint32BE();
}
}
bool hasWidthTable = (stream.readByte() != 0);
if (hasWidthTable) {
data->width = (unsigned char *)malloc(sizeof(unsigned char) * data->size);
if (!data->width) {
free(data->bits);
free(data->offset);
free(data);
return 0;
}
for (int i = 0; i < data->size; ++i) {
data->width[i] = stream.readByte();
}
}
bool hasBBXTable = (stream.readByte() != 0);
if (hasBBXTable) {
data->bbx = (BBX *)malloc(sizeof(BBX) * data->size);
if (!data->bbx) {
free(data->bits);
free(data->offset);
free(data->width);
free(data);
return 0;
}
for (int i = 0; i < data->size; ++i) {
data->bbx[i].w = (int8)stream.readByte();
data->bbx[i].h = (int8)stream.readByte();
data->bbx[i].x = (int8)stream.readByte();
data->bbx[i].y = (int8)stream.readByte();
}
}
if (stream.err() || stream.eos()) {
free(data->bits);
free(data->offset);
free(data->width);
free(data);
return 0;
}
FontDesc desc;
desc.name = data->name;
desc.maxwidth = data->maxwidth;
desc.height = data->height;
desc.fbbw = data->fbbw;
desc.fbbh = data->fbbh;
desc.fbbx = data->fbbx;
desc.fbby = data->fbby;
desc.ascent = data->ascent;
desc.firstchar = data->firstchar;
desc.size = data->size;
desc.bits = data->bits;
desc.offset = data->offset;
desc.width = data->width;
desc.bbx = data->bbx;
desc.defaultchar = data->defaultchar;
desc.bits_size = data->bits_size;
font = new NewFont(desc, data);
if (!font) {
free(data->bits);
free(data->offset);
free(data->width);
free(data);
return 0;
}
return font;
}
#pragma mark -
int Font::getStringWidth(const Common::String &str) const { int Font::getStringWidth(const Common::String &str) const {
int space = 0; int space = 0;
@ -944,7 +186,7 @@ int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Co
if (lineWidth > 0) { if (lineWidth > 0) {
wrapper.add(line, lineWidth); wrapper.add(line, lineWidth);
// Trim left side // Trim left side
while (tmpStr.size() && isspace(tmpStr[0])) { while (tmpStr.size() && isspace(static_cast<unsigned char>(tmpStr[0]))) {
tmpWidth -= getCharWidth(tmpStr[0]); tmpWidth -= getCharWidth(tmpStr[0]);
tmpStr.deleteChar(0); tmpStr.deleteChar(0);
} }

View file

@ -25,7 +25,6 @@
#include "common/str.h" #include "common/str.h"
namespace Common { namespace Common {
class SeekableReadStream;
template<class T> class Array; template<class T> class Array;
} }
@ -114,68 +113,6 @@ public:
int wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const; int wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const;
}; };
typedef uint16 bitmap_t; /* bitmap image unit size*/
struct BBX {
int8 w;
int8 h;
int8 x;
int8 y;
};
/* builtin C-based proportional/fixed font structure */
/* based on The Microwindows Project http://microwindows.org */
struct FontDesc {
const char * name; /* font name*/
int maxwidth; /* max width in pixels*/
int height; /* height in pixels*/
int fbbw, fbbh, fbbx, fbby; /* max bounding box */
int ascent; /* ascent (baseline) height*/
int firstchar; /* first character in bitmap*/
int size; /* font size in glyphs*/
const bitmap_t* bits; /* 16-bit right-padded bitmap data*/
const unsigned long* offset; /* offsets into bitmap data*/
const unsigned char* width; /* character widths or NULL if fixed*/
const BBX* bbx; /* character bounding box or NULL if fixed */
int defaultchar; /* default char (not glyph index)*/
long bits_size; /* # words of bitmap_t bits*/
};
struct NewFontData;
class NewFont : public Font {
protected:
FontDesc _desc;
NewFontData *_font;
public:
NewFont(const FontDesc &desc, NewFontData *font = 0) : _desc(desc), _font(font) {}
~NewFont();
virtual int getFontHeight() const { return _desc.height; }
virtual int getMaxCharWidth() const { return _desc.maxwidth; }
virtual int getCharWidth(byte chr) const;
virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const;
static NewFont *loadFont(Common::SeekableReadStream &stream);
static bool cacheFontData(const NewFont &font, const Common::String &filename);
static NewFont *loadFromCache(Common::SeekableReadStream &stream);
};
#define DEFINE_FONT(n) \
const NewFont *n = 0; \
void create_##n() { \
n = new NewFont(desc); \
}
#define FORWARD_DECLARE_FONT(n) \
extern const NewFont *n; \
extern void create_##n()
#define INIT_FONT(n) \
create_##n()
} // End of namespace Graphics } // End of namespace Graphics
#endif #endif

View file

@ -19,11 +19,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include "graphics/font.h"
#include "graphics/fontman.h" #include "graphics/fontman.h"
#include "graphics/font.h"
#include "graphics/fonts/bdf.h"
#include "common/translation.h" #include "common/translation.h"
namespace Common {
DECLARE_SINGLETON(Graphics::FontManager); DECLARE_SINGLETON(Graphics::FontManager);
}
namespace Graphics { namespace Graphics {

796
graphics/fonts/bdf.cpp Normal file
View file

@ -0,0 +1,796 @@
/* 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.
*/
#include "graphics/fonts/bdf.h"
#include "common/file.h"
#include "common/endian.h"
#include "common/textconsole.h"
#include "graphics/surface.h"
namespace Graphics {
void free_font(BdfFontData *pf);
BdfFont::~BdfFont() {
if (_font) {
free_font(_font);
}
}
int BdfFont::getFontHeight() const {
return _desc.height;
}
int BdfFont::getMaxCharWidth() const {
return _desc.maxwidth;
}
int BdfFont::getCharWidth(byte chr) const {
// If no width table is specified, return the maximum width
if (!_desc.width)
return _desc.maxwidth;
// If this character is not included in the font, use the default char.
if (chr < _desc.firstchar || _desc.firstchar + _desc.size < chr) {
chr = _desc.defaultchar;
}
return _desc.width[chr - _desc.firstchar];
}
template<typename PixelType>
void drawCharIntern(byte *ptr, uint pitch, const bitmap_t *src, int h, int minX, int maxX, const PixelType color) {
const bitmap_t maxXMask = ~((1 << (16 - maxX)) - 1);
while (h-- > 0) {
bitmap_t buffer = READ_UINT16(src);
src++;
buffer &= maxXMask;
buffer <<= minX;
PixelType *tmp = (PixelType *)ptr;
while (buffer != 0) {
if ((buffer & 0x8000) != 0)
*tmp = color;
tmp++;
buffer <<= 1;
}
ptr += pitch;
}
}
void BdfFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const uint32 color) const {
assert(dst != 0);
assert(_desc.bits != 0 && _desc.maxwidth <= 16);
assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2);
// If this character is not included in the font, use the default char.
if (chr < _desc.firstchar || chr >= _desc.firstchar + _desc.size) {
chr = _desc.defaultchar;
}
chr -= _desc.firstchar;
int bbw, bbh, bbx, bby;
// Get the bounding box of the character
if (!_desc.bbx) {
bbw = _desc.fbbw;
bbh = _desc.fbbh;
bbx = _desc.fbbx;
bby = _desc.fbby;
} else {
bbw = _desc.bbx[chr].w;
bbh = _desc.bbx[chr].h;
bbx = _desc.bbx[chr].x;
bby = _desc.bbx[chr].y;
}
byte *ptr = (byte *)dst->getBasePtr(tx + bbx, ty + _desc.ascent - bby - bbh);
const bitmap_t *tmp = _desc.bits + (_desc.offset ? _desc.offset[chr] : (chr * _desc.fbbh));
int y = MIN(bbh, ty + _desc.ascent - bby);
tmp += bbh - y;
y -= MAX(0, ty + _desc.ascent - bby - dst->h);
if (dst->format.bytesPerPixel == 1)
drawCharIntern<byte>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
else if (dst->format.bytesPerPixel == 2)
drawCharIntern<uint16>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
}
#pragma mark -
/* BEGIN font.h*/
/* bitmap_t helper macros*/
#define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/
#define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t))
#define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8)
#define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n)))
#define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1))
#define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT)
#define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1))
/* builtin C-based proportional/fixed font structure */
/* based on The Microwindows Project http://microwindows.org */
struct BdfFontData {
char *name; /* font name */
int maxwidth; /* max width in pixels */
int height; /* height in pixels */
int ascent; /* ascent (baseline) height */
int firstchar; /* first character in bitmap */
int size; /* font size in glyphs */
bitmap_t *bits; /* 16-bit right-padded bitmap data */
unsigned long *offset; /* offsets into bitmap data */
unsigned char *width; /* character widths or NULL if fixed */
BBX *bbx; /* character bounding box or NULL if fixed */
int defaultchar; /* default char (not glyph index) */
long bits_size; /* # words of bitmap_t bits */
/* unused by runtime system, read in by convbdf */
char *facename; /* facename of font */
char *copyright; /* copyright info for loadable fonts */
int pixel_size;
int descent;
int fbbw, fbbh, fbbx, fbby;
};
/* END font.h */
#define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
#define strequal(s1,s2) (!strcmp(s1, s2))
#define EXTRA 300
int start_char = 0;
int limit_char = 255;
BdfFontData *bdf_read_font(Common::SeekableReadStream &fp);
int bdf_read_header(Common::SeekableReadStream &fp, BdfFontData *pf);
int bdf_read_bitmaps(Common::SeekableReadStream &fp, BdfFontData *pf);
char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len);
bitmap_t bdf_hexval(unsigned char *buf);
void free_font(BdfFontData *pf) {
if (!pf)
return;
free(pf->name);
free(pf->facename);
free(pf->copyright);
free(pf->bits);
free(pf->offset);
free(pf->width);
free(pf->bbx);
free(pf);
}
/* build incore structure from .bdf file*/
BdfFontData *bdf_read_font(Common::SeekableReadStream &fp) {
BdfFontData *pf;
uint32 pos = fp.pos();
pf = (BdfFontData *)calloc(1, sizeof(BdfFontData));
if (!pf)
goto errout;
if (!bdf_read_header(fp, pf)) {
warning("Error reading font header");
goto errout;
}
fp.seek(pos, SEEK_SET);
if (!bdf_read_bitmaps(fp, pf)) {
warning("Error reading font bitmaps");
goto errout;
}
return pf;
errout:
free_font(pf);
return NULL;
}
/* read bdf font header information, return 0 on error*/
int bdf_read_header(Common::SeekableReadStream &fp, BdfFontData *pf) {
int encoding = 0;
int nchars = 0, maxwidth, maxheight;
int firstchar = 65535;
int lastchar = -1;
char buf[256];
char facename[256];
char copyright[256];
memset(facename, 0, sizeof(facename));
memset(copyright, 0, sizeof(copyright));
/* set certain values to errors for later error checking*/
pf->defaultchar = -1;
pf->ascent = -1;
pf->descent = -1;
for (;;) {
if (!bdf_getline(fp, buf, sizeof(buf))) {
warning("Error: EOF on file");
return 0;
}
/* note: the way sscanf is used here ensures that a terminating null
character is automatically added. Refer to:
http://pubs.opengroup.org/onlinepubs/009695399/functions/fscanf.html */
if (isprefix(buf, "FONT ")) { /* not required*/
if (sscanf(buf, "FONT %[^\n]", facename) != 1) {
warning("Error: bad 'FONT'");
return 0;
}
pf->facename = strdup(facename);
continue;
}
if (isprefix(buf, "COPYRIGHT ")) { /* not required*/
if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) {
warning("Error: bad 'COPYRIGHT'");
return 0;
}
pf->copyright = strdup(copyright);
continue;
}
if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/
if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) {
warning("Error: bad 'DEFAULT_CHAR'");
return 0;
}
}
if (isprefix(buf, "FONT_DESCENT ")) {
if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) {
warning("Error: bad 'FONT_DESCENT'");
return 0;
}
continue;
}
if (isprefix(buf, "FONT_ASCENT ")) {
if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) {
warning("Error: bad 'FONT_ASCENT'");
return 0;
}
continue;
}
if (isprefix(buf, "FONTBOUNDINGBOX ")) {
if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d",
&pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) {
warning("Error: bad 'FONTBOUNDINGBOX'");
return 0;
}
continue;
}
if (isprefix(buf, "CHARS ")) {
if (sscanf(buf, "CHARS %d", &nchars) != 1) {
warning("Error: bad 'CHARS'");
return 0;
}
continue;
}
/*
* Reading ENCODING is necessary to get firstchar/lastchar
* which is needed to pre-calculate our offset and widths
* array sizes.
*/
if (isprefix(buf, "ENCODING ")) {
if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
warning("Error: bad 'ENCODING'");
return 0;
}
if (encoding >= 0 &&
encoding <= limit_char &&
encoding >= start_char) {
if (firstchar > encoding)
firstchar = encoding;
if (lastchar < encoding)
lastchar = encoding;
}
continue;
}
if (strequal(buf, "ENDFONT"))
break;
}
/* calc font height*/
if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) {
warning("Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING");
return 0;
}
pf->height = pf->ascent + pf->descent;
/* calc default char*/
if (pf->defaultchar < 0 ||
pf->defaultchar < firstchar ||
pf->defaultchar > limit_char)
pf->defaultchar = firstchar;
/* calc font size (offset/width entries)*/
pf->firstchar = firstchar;
pf->size = lastchar - firstchar + 1;
/* use the font boundingbox to get initial maxwidth*/
/*maxwidth = pf->fbbw - pf->fbbx;*/
maxwidth = pf->fbbw;
maxheight = pf->fbbh;
/* initially use font bounding box for bits allocation*/
pf->bits_size = nchars * BITMAP_WORDS(maxwidth) * maxheight;
/* allocate bits, offset, and width arrays*/
pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t) + EXTRA);
pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long));
pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
pf->bbx = (BBX *)malloc(pf->size * sizeof(BBX));
if (!pf->bits || !pf->offset || !pf->width) {
warning("Error: no memory for font load");
return 0;
}
return 1;
}
/* read bdf font bitmaps, return 0 on error*/
int bdf_read_bitmaps(Common::SeekableReadStream &fp, BdfFontData *pf) {
long ofs = 0;
int maxwidth = 0;
int i, k, encoding = 0, width = 0;
int bbw = 0, bbh = 0, bbx = 0, bby = 0;
int proportional = 0;
int need_bbx = 0;
int encodetable = 0;
long l;
char buf[256];
/* initially mark offsets as not used*/
for (i = 0; i < pf->size; ++i)
pf->offset[i] = (unsigned long)-1;
for (;;) {
if (!bdf_getline(fp, buf, sizeof(buf))) {
warning("Error: EOF on file");
return 0;
}
if (isprefix(buf, "STARTCHAR")) {
encoding = width = bbw = bbh = bbx = bby = -1;
continue;
}
if (isprefix(buf, "ENCODING ")) {
if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
warning("Error: bad 'ENCODING'");
return 0;
}
if (encoding < start_char || encoding > limit_char)
encoding = -1;
continue;
}
if (isprefix(buf, "DWIDTH ")) {
if (sscanf(buf, "DWIDTH %d", &width) != 1) {
warning("Error: bad 'DWIDTH'");
return 0;
}
/* use font boundingbox width if DWIDTH <= 0*/
if (width <= 0)
width = pf->fbbw - pf->fbbx;
continue;
}
if (isprefix(buf, "BBX ")) {
if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
warning("Error: bad 'BBX'");
return 0;
}
continue;
}
if (strequal(buf, "BITMAP")) {
bitmap_t *ch_bitmap = pf->bits + ofs;
int ch_words;
if (encoding < 0)
continue;
/* set bits offset in encode map*/
if (pf->offset[encoding - pf->firstchar] != (unsigned long)-1) {
warning("Error: duplicate encoding for character %d (0x%02x), ignoring duplicate",
encoding, encoding);
continue;
}
pf->offset[encoding - pf->firstchar] = ofs;
pf->width[encoding - pf->firstchar] = width;
pf->bbx[encoding - pf->firstchar].w = bbw;
pf->bbx[encoding - pf->firstchar].h = bbh;
pf->bbx[encoding - pf->firstchar].x = bbx;
pf->bbx[encoding - pf->firstchar].y = bby;
if (width > maxwidth)
maxwidth = width;
/* clear bitmap*/
memset(ch_bitmap, 0, BITMAP_BYTES(bbw) * bbh);
ch_words = BITMAP_WORDS(bbw);
/* read bitmaps*/
for (i = 0; i < bbh; ++i) {
if (!bdf_getline(fp, buf, sizeof(buf))) {
warning("Error: EOF reading BITMAP data");
return 0;
}
if (isprefix(buf, "ENDCHAR"))
break;
for (k = 0; k < ch_words; ++k) {
bitmap_t value;
value = bdf_hexval((unsigned char *)buf);
if (bbw > 8) {
WRITE_UINT16(ch_bitmap, value);
} else {
WRITE_UINT16(ch_bitmap, value << 8);
}
ch_bitmap++;
}
}
ofs += ch_words * bbh;
continue;
}
if (strequal(buf, "ENDFONT"))
break;
}
/* set max width*/
pf->maxwidth = maxwidth;
/* change unused offset/width values to default char values*/
for (i = 0; i < pf->size; ++i) {
int defchar = pf->defaultchar - pf->firstchar;
if (pf->offset[i] == (unsigned long)-1) {
pf->offset[i] = pf->offset[defchar];
pf->width[i] = pf->width[defchar];
pf->bbx[i].w = pf->bbx[defchar].w;
pf->bbx[i].h = pf->bbx[defchar].h;
pf->bbx[i].x = pf->bbx[defchar].x;
pf->bbx[i].y = pf->bbx[defchar].y;
}
}
/* determine whether font doesn't require encode table*/
l = 0;
for (i = 0; i < pf->size; ++i) {
if (pf->offset[i] != (unsigned long)l) {
encodetable = 1;
break;
}
l += BITMAP_WORDS(pf->bbx[i].w) * pf->bbx[i].h;
}
if (!encodetable) {
free(pf->offset);
pf->offset = NULL;
}
/* determine whether font is fixed-width*/
for (i = 0; i < pf->size; ++i) {
if (pf->width[i] != maxwidth) {
proportional = 1;
break;
}
}
if (!proportional) {
free(pf->width);
pf->width = NULL;
}
/* determine if the font needs a bbx table */
for (i = 0; i < pf->size; ++i) {
if (pf->bbx[i].w != pf->fbbw || pf->bbx[i].h != pf->fbbh || pf->bbx[i].x != pf->fbbx || pf->bbx[i].y != pf->fbby) {
need_bbx = 1;
break;
}
}
if (!need_bbx) {
free(pf->bbx);
pf->bbx = NULL;
}
/* reallocate bits array to actual bits used*/
if (ofs < pf->bits_size) {
bitmap_t *tmp = (bitmap_t *)realloc(pf->bits, ofs * sizeof(bitmap_t));
if (tmp != NULL || ofs == 0)
pf->bits = tmp;
else
error("bdf_read_bitmaps: Error while reallocating memory");
pf->bits_size = ofs;
} else {
if (ofs > pf->bits_size) {
warning("Warning: DWIDTH spec > max FONTBOUNDINGBOX");
if (ofs > pf->bits_size + EXTRA) {
warning("Error: Not enough bits initially allocated");
return 0;
}
pf->bits_size = ofs;
}
}
return 1;
}
/* read the next non-comment line, returns buf or NULL if EOF*/
// TODO: Can we use SeekableReadStream::readLine instead?
char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len) {
int c;
char *b;
for (;;) {
b = buf;
while (!fp.eos()) {
c = fp.readByte();
if (c == '\r')
continue;
if (c == '\n')
break;
if (b - buf >= (len - 1))
break;
*b++ = c;
}
*b = '\0';
if (fp.eos() && b == buf)
return NULL;
if (b != buf && !isprefix(buf, "COMMENT"))
break;
}
return buf;
}
/* return hex value of buffer */
bitmap_t bdf_hexval(unsigned char *buf) {
bitmap_t val = 0;
for (unsigned char *ptr = buf; *ptr; ptr++) {
int c = *ptr;
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'F')
c = c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
c = c - 'a' + 10;
else
c = 0;
val = (val << 4) | c;
}
return val;
}
BdfFont *BdfFont::loadFont(Common::SeekableReadStream &stream) {
BdfFontData *data = bdf_read_font(stream);
if (!data || stream.err()) {
free_font(data);
return 0;
}
BdfFontDesc desc;
desc.name = data->name;
desc.maxwidth = data->maxwidth;
desc.height = data->height;
desc.fbbw = data->fbbw;
desc.fbbh = data->fbbh;
desc.fbbx = data->fbbx;
desc.fbby = data->fbby;
desc.ascent = data->ascent;
desc.firstchar = data->firstchar;
desc.size = data->size;
desc.bits = data->bits;
desc.offset = data->offset;
desc.width = data->width;
desc.bbx = data->bbx;
desc.defaultchar = data->defaultchar;
desc.bits_size = data->bits_size;
return new BdfFont(desc, data);
}
bool BdfFont::cacheFontData(const BdfFont &font, const Common::String &filename) {
Common::DumpFile cacheFile;
if (!cacheFile.open(filename)) {
warning("Couldn't open file '%s' for writing", filename.c_str());
return false;
}
cacheFile.writeUint16BE(font._desc.maxwidth);
cacheFile.writeUint16BE(font._desc.height);
cacheFile.writeUint16BE(font._desc.fbbw);
cacheFile.writeUint16BE(font._desc.fbbh);
cacheFile.writeSint16BE(font._desc.fbbx);
cacheFile.writeSint16BE(font._desc.fbby);
cacheFile.writeUint16BE(font._desc.ascent);
cacheFile.writeUint16BE(font._desc.firstchar);
cacheFile.writeUint16BE(font._desc.size);
cacheFile.writeUint16BE(font._desc.defaultchar);
cacheFile.writeUint32BE(font._desc.bits_size);
for (long i = 0; i < font._desc.bits_size; ++i) {
cacheFile.writeUint16BE(font._desc.bits[i]);
}
if (font._desc.offset) {
cacheFile.writeByte(1);
for (int i = 0; i < font._desc.size; ++i) {
cacheFile.writeUint32BE(font._desc.offset[i]);
}
} else {
cacheFile.writeByte(0);
}
if (font._desc.width) {
cacheFile.writeByte(1);
for (int i = 0; i < font._desc.size; ++i) {
cacheFile.writeByte(font._desc.width[i]);
}
} else {
cacheFile.writeByte(0);
}
if (font._desc.bbx) {
cacheFile.writeByte(1);
for (int i = 0; i < font._desc.size; ++i) {
cacheFile.writeByte(font._desc.bbx[i].w);
cacheFile.writeByte(font._desc.bbx[i].h);
cacheFile.writeByte(font._desc.bbx[i].x);
cacheFile.writeByte(font._desc.bbx[i].y);
}
} else {
cacheFile.writeByte(0);
}
return !cacheFile.err();
}
BdfFont *BdfFont::loadFromCache(Common::SeekableReadStream &stream) {
BdfFont *font = 0;
BdfFontData *data = (BdfFontData *)malloc(sizeof(BdfFontData));
if (!data)
return 0;
memset(data, 0, sizeof(BdfFontData));
data->maxwidth = stream.readUint16BE();
data->height = stream.readUint16BE();
data->fbbw = stream.readUint16BE();
data->fbbh = stream.readUint16BE();
data->fbbx = stream.readSint16BE();
data->fbby = stream.readSint16BE();
data->ascent = stream.readUint16BE();
data->firstchar = stream.readUint16BE();
data->size = stream.readUint16BE();
data->defaultchar = stream.readUint16BE();
data->bits_size = stream.readUint32BE();
data->bits = (bitmap_t *)malloc(sizeof(bitmap_t) * data->bits_size);
if (!data->bits) {
free(data);
return 0;
}
for (long i = 0; i < data->bits_size; ++i) {
data->bits[i] = stream.readUint16BE();
}
bool hasOffsetTable = (stream.readByte() != 0);
if (hasOffsetTable) {
data->offset = (unsigned long *)malloc(sizeof(unsigned long) * data->size);
if (!data->offset) {
free(data->bits);
free(data);
return 0;
}
for (int i = 0; i < data->size; ++i) {
data->offset[i] = stream.readUint32BE();
}
}
bool hasWidthTable = (stream.readByte() != 0);
if (hasWidthTable) {
data->width = (unsigned char *)malloc(sizeof(unsigned char) * data->size);
if (!data->width) {
free(data->bits);
free(data->offset);
free(data);
return 0;
}
for (int i = 0; i < data->size; ++i) {
data->width[i] = stream.readByte();
}
}
bool hasBBXTable = (stream.readByte() != 0);
if (hasBBXTable) {
data->bbx = (BBX *)malloc(sizeof(BBX) * data->size);
if (!data->bbx) {
free(data->bits);
free(data->offset);
free(data->width);
free(data);
return 0;
}
for (int i = 0; i < data->size; ++i) {
data->bbx[i].w = (int8)stream.readByte();
data->bbx[i].h = (int8)stream.readByte();
data->bbx[i].x = (int8)stream.readByte();
data->bbx[i].y = (int8)stream.readByte();
}
}
if (stream.err() || stream.eos()) {
free(data->bits);
free(data->offset);
free(data->width);
free(data);
return 0;
}
BdfFontDesc desc;
desc.name = data->name;
desc.maxwidth = data->maxwidth;
desc.height = data->height;
desc.fbbw = data->fbbw;
desc.fbbh = data->fbbh;
desc.fbbx = data->fbbx;
desc.fbby = data->fbby;
desc.ascent = data->ascent;
desc.firstchar = data->firstchar;
desc.size = data->size;
desc.bits = data->bits;
desc.offset = data->offset;
desc.width = data->width;
desc.bbx = data->bbx;
desc.defaultchar = data->defaultchar;
desc.bits_size = data->bits_size;
font = new BdfFont(desc, data);
if (!font) {
free(data->bits);
free(data->offset);
free(data->width);
free(data);
return 0;
}
return font;
}
} // End of namespace Graphics

100
graphics/fonts/bdf.h Normal file
View file

@ -0,0 +1,100 @@
/* 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.
*/
#ifndef GRAPHICS_FONTS_BDF_H
#define GRAPHICS_FONTS_BDF_H
#include "common/system.h"
#include "graphics/font.h"
namespace Common {
class SeekableReadStream;
}
namespace Graphics {
typedef uint16 bitmap_t; /* bitmap image unit size*/
struct BBX {
int8 w;
int8 h;
int8 x;
int8 y;
};
/* builtin C-based proportional/fixed font structure */
/* based on The Microwindows Project http://microwindows.org */
struct BdfFontDesc {
const char *name; /* font name */
int maxwidth; /* max width in pixels */
int height; /* height in pixels */
int fbbw, fbbh, fbbx, fbby; /* max bounding box */
int ascent; /* ascent (baseline) height */
int firstchar; /* first character in bitmap */
int size; /* font size in glyphs */
const bitmap_t *bits; /* 16-bit right-padded bitmap data */
const unsigned long *offset; /* offsets into bitmap data */
const unsigned char *width; /* character widths or NULL if fixed */
const BBX *bbx; /* character bounding box or NULL if fixed */
int defaultchar; /* default char (not glyph index) */
long bits_size; /* # words of bitmap_t bits */
};
struct BdfFontData;
class BdfFont : public Font {
protected:
BdfFontDesc _desc;
BdfFontData *_font;
public:
BdfFont(const BdfFontDesc &desc, BdfFontData *font = 0) : _desc(desc), _font(font) {}
~BdfFont();
virtual int getFontHeight() const;
virtual int getMaxCharWidth() const;
virtual int getCharWidth(byte chr) const;
virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const;
static BdfFont *loadFont(Common::SeekableReadStream &stream);
static bool cacheFontData(const BdfFont &font, const Common::String &filename);
static BdfFont *loadFromCache(Common::SeekableReadStream &stream);
};
#define DEFINE_FONT(n) \
const BdfFont *n = 0; \
void create_##n() { \
n = new BdfFont(desc); \
}
#define FORWARD_DECLARE_FONT(n) \
extern const BdfFont *n; \
extern void create_##n()
#define INIT_FONT(n) \
create_##n()
} // End of namespace Graphics
#endif

View file

@ -1,5 +1,5 @@
/* Generated by convbdf on Sat Jun 17 01:37:46 2006. */ /* Generated by convbdf on Sat Jun 17 01:37:46 2006. */
#include "graphics/font.h" #include "graphics/fonts/bdf.h"
/* Font information: /* Font information:
name: 5x8-L1 name: 5x8-L1
@ -5635,7 +5635,7 @@ static const unsigned long _sysfont_offset[] = {
}; };
/* Exported structure definition. */ /* Exported structure definition. */
static const FontDesc desc = { static const BdfFontDesc desc = {
"5x8-L1", "5x8-L1",
5, 5,
8, 8,

View file

@ -1,5 +1,5 @@
/* Generated by convbdf on Sat Jun 17 01:34:15 2006. */ /* Generated by convbdf on Sat Jun 17 01:34:15 2006. */
#include "graphics/font.h" #include "graphics/fonts/bdf.h"
/* Font information: /* Font information:
name: clR6x12-L1 name: clR6x12-L1
@ -7419,7 +7419,7 @@ static const unsigned long _sysfont_offset[] = {
}; };
/* Exported structure definition. */ /* Exported structure definition. */
static const FontDesc desc = { static const BdfFontDesc desc = {
"clR6x12-L1", "clR6x12-L1",
6, 6,
12, 12,

Some files were not shown because too many files have changed in this diff Show more