synced with scummvm

This commit is contained in:
Pawel Kolodziejski 2009-10-05 08:33:46 +00:00
parent fca3a20334
commit 7aa79c880d
115 changed files with 5209 additions and 2608 deletions

View file

@ -20,21 +20,29 @@ MODULE_DIRS :=
# Load the make rules generated by configure # Load the make rules generated by configure
-include config.mk -include config.mk
ifeq "$(HAVE_GCC)" "1"
CXXFLAGS:= -Wall $(CXXFLAGS) CXXFLAGS:= -Wall $(CXXFLAGS)
# Turn off some annoying and not-so-useful warnings # Turn off some annoying and not-so-useful warnings
CXXFLAGS+= -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder -Wno-unused-parameter CXXFLAGS+= -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder
# Enable even more warnings... # Enable even more warnings...
#CXXFLAGS+= -Wpointer-arith -Wcast-qual -Wcast-align CXXFLAGS+= -Wpointer-arith -Wcast-qual -Wcast-align
#CXXFLAGS+= -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings CXXFLAGS+= -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
# Currently we disable this gcc flag, since it will also warn in cases,
# where using GCC_PRINTF (means: __attribute__((format(printf, x, y))))
# is not possible, thus it would fail compiliation with -Werror without
# being helpful.
#CXXFLAGS+= -Wmissing-format-attribute
# Disable RTTI and exceptions, and enabled checking of pointers returned by "new" # Disable RTTI and exceptions, and enabled checking of pointers returned by "new"
#CXXFLAGS+= -fno-rtti -fno-exceptions -fcheck-new CXXFLAGS+= -fno-rtti -fno-exceptions -fcheck-new
# There is a nice extra warning that flags variables that are potentially # There is a nice extra warning that flags variables that are potentially
# used before being initialized. Very handy to catch a certain kind of # used before being initialized. Very handy to catch a certain kind of
# bugs. Unfortunately, it only works when optimizations are turned on, # bugs. Unfortunately, it only works when optimizations are turned on,
# which is why we normally don't use it. # which is why we normally don't use it.
#CXXFLAGS+= -O -Wuninitialized #CXXFLAGS+= -O -Wuninitialized
endif
####################################################################### #######################################################################
# Default commands - put the necessary replacements in config.mk # # Default commands - put the necessary replacements in config.mk #
@ -62,10 +70,15 @@ config.h config.mk: $(srcdir)/configure
ifeq "$(findstring config.mk,$(MAKEFILE_LIST))" "config.mk" ifeq "$(findstring config.mk,$(MAKEFILE_LIST))" "config.mk"
@echo "Running $(srcdir)/configure with the last specified parameters" @echo "Running $(srcdir)/configure with the last specified parameters"
@sleep 2 @sleep 2
LDFLAGS="$(SAVED_LDFLAGS)" CXX="$(SAVED_CXX)" CXXFLAGS="$(SAVED_CXXFLAGS)" CPPFLAGS="$(SAVED_CPPFLAGS)" \ LDFLAGS="$(SAVED_LDFLAGS)" CXX="$(SAVED_CXX)" \
CXXFLAGS="$(SAVED_CXXFLAGS)" CPPFLAGS="$(SAVED_CPPFLAGS)" \
ASFLAGS="$(SAVED_ASFLAGS)" WINDRESFLAGS="$(SAVED_WINDRESFLAGS)" \
$(srcdir)/configure $(SAVED_CONFIGFLAGS) $(srcdir)/configure $(SAVED_CONFIGFLAGS)
else else
$(error You need to run $(srcdir)/configure before you can run make. Check $(srcdir)/configure --help for a list of parameters) $(error You need to run $(srcdir)/configure before you can run make. Check $(srcdir)/configure --help for a list of parameters)
endif endif
include $(srcdir)/ports.mk ifneq ($(origin port_mk), undefined)
include $(srcdir)/$(port_mk)
endif

View file

@ -55,6 +55,8 @@ ifneq ($(findstring $(MAKEFLAGS),s),s)
ifneq ($(VERBOSE_BUILD),1) ifneq ($(VERBOSE_BUILD),1)
ifneq ($(VERBOSE_BUILD),yes) ifneq ($(VERBOSE_BUILD),yes)
QUIET_CXX = @echo ' ' C++ ' ' $@; QUIET_CXX = @echo ' ' C++ ' ' $@;
QUIET_AS = @echo ' ' AS ' ' $@;
QUIET_NASM = @echo ' ' NASM ' ' $@;
QUIET_AR = @echo ' ' AR ' ' $@; QUIET_AR = @echo ' ' AR ' ' $@;
QUIET_RANLIB = @echo ' ' RANLIB ' ' $@; QUIET_RANLIB = @echo ' ' RANLIB ' ' $@;
QUIET_PLUGIN = @echo ' ' PLUGIN ' ' $@; QUIET_PLUGIN = @echo ' ' PLUGIN ' ' $@;
@ -75,26 +77,40 @@ clean:
$(RM_REC) $(DEPDIRS) $(RM_REC) $(DEPDIRS)
$(RM) $(OBJS) $(EXECUTABLE) $(RM) $(OBJS) $(EXECUTABLE)
ifndef HAVE_GCC3
# If you use GCC, disable the above and enable this for intelligent #
# The build rules for object files.
#
ifdef CXX_UPDATE_DEP_FLAG
# Build rule for C++ files. Makes use of CXX_UPDATE_DEP_FLAG for advanced
# dependency tracking. # dependency tracking.
%.o: %.cpp %.o: %.cpp
$(QUIET)$(MKDIR) $(*D)/$(DEPDIR) $(QUIET)$(MKDIR) $(*D)/$(DEPDIR)
$(QUIET_CXX)$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o $(QUIET_CXX)$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
$(QUIET)$(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d
$(QUIET)$(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d" # Build rule for Objective-C files. Strictly speaking, this is for OS X only.
$(QUIET)$(RM) "$(*D)/$(DEPDIR)/$(*F).d2"
else
# If you even have GCC 3.x, you can use this build rule, which is safer; the above
# rule can get you into a bad state if you Ctrl-C at the wrong moment.
# Also, with this GCC inserts additional dummy rules for the involved headers,
# which ensures a smooth compilation even if said headers become obsolete.
%.o: %.cpp
$(QUIET)$(MKDIR) $(*D)/$(DEPDIR)
$(QUIET_CXX)$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
%.o: %.m %.o: %.m
$(QUIET)$(MKDIR) $(*D)/$(DEPDIR) $(QUIET)$(MKDIR) $(*D)/$(DEPDIR)
$(QUIET_CXX)$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(OBJCFLAGS) -c $(<) -o $*.o $(QUIET_CXX)$(CXX) $(CXX_UPDATE_DEP_FLAG) $(OBJCFLAGS) -c $(<) -o $*.o
else
# Dumb compile rule, for C++ compilers that don't allow dependency tracking or
# where it is broken (such as GCC 2.95).
.cpp.o:
$(QUIET_CXX)$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
endif
%.o: %.s
$(QUIET_AS)$(AS) $(ASFLAGS) $(<) -o $*.o
ifdef HAVE_NASM
%.o: %.asm
$(QUIET_NASM)$(NASM) -O1 $(NASMFLAGS) -g -o $*.o $(<)
endif endif
# Include the dependency tracking files. # Include the dependency tracking files.
@ -134,25 +150,6 @@ CXXFLAGS+= -DRESIDUAL_SVN_REVISION=\"$(VER_SVNREV)\"
endif endif
######################################################################
# Create the files that depend on the version
######################################################################
VERSION_FILES = \
$(srcdir)/dists/iphone/Info.plist \
$(srcdir)/dists/macosx/Info.plist
$(VERSION_FILES): %: %.in
@echo "Creating $@"
@cat $< | sed \
-e "s/@VER_MAJOR@/$(VER_MAJOR)/g" \
-e "s/@VER_MINOR@/$(VER_MINOR)/g" \
-e "s/@VER_PATCH@/$(VER_PATCH)/g" \
-e "s/@VER_EXTRA@/$(VER_EXTRA)/g" \
-e "s/@VERSION@/$(VERSION)/g" \
> $@
###################################################################### ######################################################################
# Distribution settings # Distribution settings
###################################################################### ######################################################################
@ -198,10 +195,16 @@ dist-src: \
@#RPM-src? @#RPM-src?
@#DEB-src? @#DEB-src?
# Common files
DIST_FILES_DOCS:=$(addprefix $(srcdir)/,AUTHORS COPYING COPYING.LGPL COPYRIGHT NEWS README)
# Themes files # Themes files
DIST_FILES_THEMES:=$(addprefix $(srcdir)/gui/themes/,scummmodern.zip) DIST_FILES_THEMES:=$(addprefix $(srcdir)/gui/themes/,scummmodern.zip)
# Engine data files
DIST_FILES_ENGINEDATA=
DIST_FILES_ENGINEDATA:=$(addprefix $(srcdir)/dists/engine-data/,$(DIST_FILES_ENGINEDATA))
# Plugin files # Plugin files
DIST_FILES_PLUGINS:=$(addprefix $(srcdir)/,$(PLUGINS)) DIST_FILES_PLUGINS:=$(addprefix $(srcdir)/,$(PLUGINS))

View file

@ -27,10 +27,9 @@
#define BACKENDS_BASE_BACKEND_H #define BACKENDS_BASE_BACKEND_H
#include "common/system.h" #include "common/system.h"
#include "common/fs.h"
#include "backends/events/default/default-events.h" #include "backends/events/default/default-events.h"
class BaseBackend : public OSystem, EventProvider { class BaseBackend : public OSystem, Common::EventSource {
public: public:
virtual Common::EventManager *getEventManager(); virtual Common::EventManager *getEventManager();
virtual void displayMessageOnOSD(const char *msg); virtual void displayMessageOnOSD(const char *msg);

View file

@ -35,242 +35,38 @@
#include "engines/engine.h" #include "engines/engine.h"
#include "gui/message.h" #include "gui/message.h"
#define RECORD_SIGNATURE 0x54455354 DefaultEventManager::DefaultEventManager(Common::EventSource *boss) :
#define RECORD_VERSION 1
void readRecord(Common::InSaveFile *inFile, uint32 &diff, Common::Event &event) {
diff = inFile->readUint32LE();
event.type = (Common::EventType)inFile->readUint32LE();
switch(event.type) {
case Common::EVENT_KEYDOWN:
case Common::EVENT_KEYUP:
event.kbd.keycode = (Common::KeyCode)inFile->readSint32LE();
event.kbd.ascii = inFile->readUint16LE();
event.kbd.flags = inFile->readByte();
break;
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
event.mouse.x = inFile->readSint16LE();
event.mouse.y = inFile->readSint16LE();
break;
default:
break;
}
}
void writeRecord(Common::OutSaveFile *outFile, uint32 diff, Common::Event &event) {
outFile->writeUint32LE(diff);
outFile->writeUint32LE((uint32)event.type);
switch(event.type) {
case Common::EVENT_KEYDOWN:
case Common::EVENT_KEYUP:
outFile->writeSint32LE(event.kbd.keycode);
outFile->writeUint16LE(event.kbd.ascii);
outFile->writeByte(event.kbd.flags);
break;
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
outFile->writeSint16LE(event.mouse.x);
outFile->writeSint16LE(event.mouse.y);
break;
default:
break;
}
}
DefaultEventManager::DefaultEventManager(EventProvider *boss) :
_boss(boss),
_buttonState(0), _buttonState(0),
_modifierState(0), _modifierState(0),
_shouldQuit(false), _shouldQuit(false),
_shouldRTL(false), _shouldRTL(false),
_confirmExitDialogActive(false) { _confirmExitDialogActive(false) {
assert(_boss); assert(boss);
_recordFile = NULL; _dispatcher.registerSource(boss, false);
_recordTimeFile = NULL; _dispatcher.registerSource(&_artificialEventSource, false);
_playbackFile = NULL;
_playbackTimeFile = NULL;
_timeMutex = g_system->createMutex();
_recorderMutex = g_system->createMutex();
_eventCount = 0; _dispatcher.registerObserver(this, kEventManPriority, false);
_lastEventCount = 0;
_lastMillis = 0;
Common::String recordModeString = ConfMan.get("record_mode");
if (recordModeString.compareToIgnoreCase("record") == 0) {
_recordMode = kRecorderRecord;
} else {
if (recordModeString.compareToIgnoreCase("playback") == 0) {
_recordMode = kRecorderPlayback;
} else {
_recordMode = kPassthrough;
}
}
_recordFileName = ConfMan.get("record_file_name");
if (_recordFileName.empty()) {
_recordFileName = "record.bin";
}
_recordTempFileName = ConfMan.get("record_temp_file_name");
if (_recordTempFileName.empty()) {
_recordTempFileName = "record.tmp";
}
_recordTimeFileName = ConfMan.get("record_time_file_name");
if (_recordTimeFileName.empty()) {
_recordTimeFileName = "record.time";
}
// Reset key repeat // Reset key repeat
_currentKeyDown.keycode = 0; _currentKeyDown.keycode = 0;
// recorder stuff
if (_recordMode == kRecorderRecord) {
_recordCount = 0;
_recordTimeCount = 0;
_recordFile = g_system->getSavefileManager()->openForSaving(_recordTempFileName);
_recordTimeFile = g_system->getSavefileManager()->openForSaving(_recordTimeFileName);
_recordSubtitles = ConfMan.getBool("subtitles");
}
uint32 sign;
uint32 version;
uint32 randomSourceCount;
if (_recordMode == kRecorderPlayback) {
_playbackCount = 0;
_playbackTimeCount = 0;
_playbackFile = g_system->getSavefileManager()->openForLoading(_recordFileName);
_playbackTimeFile = g_system->getSavefileManager()->openForLoading(_recordTimeFileName);
if (!_playbackFile) {
warning("Cannot open playback file %s. Playback was switched off", _recordFileName.c_str());
_recordMode = kPassthrough;
}
if (!_playbackTimeFile) {
warning("Cannot open playback time file %s. Playback was switched off", _recordTimeFileName.c_str());
_recordMode = kPassthrough;
}
}
if (_recordMode == kRecorderPlayback) {
sign = _playbackFile->readUint32LE();
if (sign != RECORD_SIGNATURE) {
error("Unknown record file signature");
}
version = _playbackFile->readUint32LE();
// conf vars
ConfMan.setBool("subtitles", _playbackFile->readByte() != 0);
_recordCount = _playbackFile->readUint32LE();
_recordTimeCount = _playbackFile->readUint32LE();
randomSourceCount = _playbackFile->readUint32LE();
for (uint i = 0; i < randomSourceCount; ++i) {
RandomSourceRecord rec;
rec.name = "";
uint32 sLen = _playbackFile->readUint32LE();
for (uint j = 0; j < sLen; ++j) {
char c = _playbackFile->readSByte();
rec.name += c;
}
rec.seed = _playbackFile->readUint32LE();
_randomSourceRecords.push_back(rec);
}
_hasPlaybackEvent = false;
}
#ifdef ENABLE_VKEYBD #ifdef ENABLE_VKEYBD
_vk = new Common::VirtualKeyboard(); _vk = new Common::VirtualKeyboard();
#endif #endif
#ifdef ENABLE_KEYMAPPER #ifdef ENABLE_KEYMAPPER
_keymapper = new Common::Keymapper(this); _keymapper = new Common::Keymapper(this);
// EventDispatcher will automatically free the keymapper
_dispatcher.registerMapper(_keymapper);
_remap = false; _remap = false;
#endif #endif
} }
DefaultEventManager::~DefaultEventManager() { DefaultEventManager::~DefaultEventManager() {
#ifdef ENABLE_KEYMAPPER
delete _keymapper;
#endif
#ifdef ENABLE_VKEYBD #ifdef ENABLE_VKEYBD
delete _vk; delete _vk;
#endif #endif
g_system->lockMutex(_timeMutex);
g_system->lockMutex(_recorderMutex);
_recordMode = kPassthrough;
g_system->unlockMutex(_timeMutex);
g_system->unlockMutex(_recorderMutex);
if (!artificialEventQueue.empty())
artificialEventQueue.clear();
if (_playbackFile != NULL) {
delete _playbackFile;
}
if (_playbackTimeFile != NULL) {
delete _playbackTimeFile;
}
if (_recordFile != NULL) {
_recordFile->finalize();
delete _recordFile;
_recordTimeFile->finalize();
delete _recordTimeFile;
_playbackFile = g_system->getSavefileManager()->openForLoading(_recordTempFileName);
assert(_playbackFile);
_recordFile = g_system->getSavefileManager()->openForSaving(_recordFileName);
_recordFile->writeUint32LE(RECORD_SIGNATURE);
_recordFile->writeUint32LE(RECORD_VERSION);
// conf vars
_recordFile->writeByte(_recordSubtitles ? 1 : 0);
_recordFile->writeUint32LE(_recordCount);
_recordFile->writeUint32LE(_recordTimeCount);
_recordFile->writeUint32LE(_randomSourceRecords.size());
for (uint i = 0; i < _randomSourceRecords.size(); ++i) {
_recordFile->writeUint32LE(_randomSourceRecords[i].name.size());
_recordFile->writeString(_randomSourceRecords[i].name);
_recordFile->writeUint32LE(_randomSourceRecords[i].seed);
}
for (uint i = 0; i < _recordCount; ++i) {
uint32 tempDiff;
Common::Event tempEvent;
readRecord(_playbackFile, tempDiff, tempEvent);
writeRecord(_recordFile, tempDiff, tempEvent);
}
_recordFile->finalize();
delete _recordFile;
delete _playbackFile;
//TODO: remove recordTempFileName'ed file
}
g_system->deleteMutex(_timeMutex);
g_system->deleteMutex(_recorderMutex);
} }
void DefaultEventManager::init() { void DefaultEventManager::init() {
@ -283,145 +79,14 @@ void DefaultEventManager::init() {
#endif #endif
} }
bool DefaultEventManager::playback(Common::Event &event) {
if (!_hasPlaybackEvent) {
if (_recordCount > _playbackCount) {
readRecord(_playbackFile, const_cast<uint32&>(_playbackDiff), _playbackEvent);
_playbackCount++;
_hasPlaybackEvent = true;
}
}
if (_hasPlaybackEvent) {
if (_playbackDiff <= (_eventCount - _lastEventCount)) {
switch(_playbackEvent.type) {
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
g_system->warpMouse(_playbackEvent.mouse.x, _playbackEvent.mouse.y);
break;
default:
break;
}
event = _playbackEvent;
_hasPlaybackEvent = false;
_lastEventCount = _eventCount;
return true;
}
}
return false;
}
void DefaultEventManager::record(Common::Event &event) {
writeRecord(_recordFile, _eventCount - _lastEventCount, event);
_recordCount++;
_lastEventCount = _eventCount;
}
void DefaultEventManager::registerRandomSource(Common::RandomSource &rnd, const char *name) {
if (_recordMode == kRecorderRecord) {
RandomSourceRecord rec;
rec.name = name;
rec.seed = rnd.getSeed();
_randomSourceRecords.push_back(rec);
}
if (_recordMode == kRecorderPlayback) {
for (uint i = 0; i < _randomSourceRecords.size(); ++i) {
if (_randomSourceRecords[i].name == name) {
rnd.setSeed(_randomSourceRecords[i].seed);
_randomSourceRecords.remove_at(i);
break;
}
}
}
}
void DefaultEventManager::processMillis(uint32 &millis) {
uint32 d;
if (_recordMode == kPassthrough) {
return;
}
g_system->lockMutex(_timeMutex);
if (_recordMode == kRecorderRecord) {
//Simple RLE compression
d = millis - _lastMillis;
if (d >= 0xff) {
_recordTimeFile->writeByte(0xff);
_recordTimeFile->writeUint32LE(d);
} else {
_recordTimeFile->writeByte(d);
}
_recordTimeCount++;
}
if (_recordMode == kRecorderPlayback) {
if (_recordTimeCount > _playbackTimeCount) {
d = _playbackTimeFile->readByte();
if (d == 0xff) {
d = _playbackTimeFile->readUint32LE();
}
millis = _lastMillis + d;
_playbackTimeCount++;
}
}
_lastMillis = millis;
g_system->unlockMutex(_timeMutex);
}
bool DefaultEventManager::pollEvent(Common::Event &event) { bool DefaultEventManager::pollEvent(Common::Event &event) {
uint32 time = g_system->getMillis(); uint32 time = g_system->getMillis();
bool result; bool result = false;
if (!artificialEventQueue.empty()) { _dispatcher.dispatch();
event = artificialEventQueue.pop(); if (!_eventQueue.empty()) {
event = _eventQueue.pop();
result = true; result = true;
} else {
result = _boss->pollEvent(event);
#ifdef ENABLE_KEYMAPPER
if (result) {
// send key press events to keymapper
if (event.type == Common::EVENT_KEYDOWN) {
if (_keymapper->mapKeyDown(event.kbd)) {
result = false;
}
} else if (event.type == Common::EVENT_KEYUP) {
if (_keymapper->mapKeyUp(event.kbd)) {
result = false;
}
}
}
#endif
}
if (_recordMode != kPassthrough) {
g_system->lockMutex(_recorderMutex);
_eventCount++;
if (_recordMode == kRecorderPlayback) {
if (event.type != Common::EVENT_QUIT) {
result = playback(event);
}
} else {
if (_recordMode == kRecorderRecord) {
if (result) {
record(event);
}
}
}
g_system->unlockMutex(_recorderMutex);
} }
if (result) { if (result) {
@ -497,6 +162,16 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
} }
} }
#endif #endif
else if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) {
// WORKAROUND: Some engines incorrectly attempt to use the
// ascii value instead of the keycode to detect the backspace
// key (a non-portable behavior). This fails at least on
// Mac OS X, possibly also on other systems.
// As a workaround, we force the ascii value for backspace
// key pressed. A better fix would be for engines to stop
// making invalid assumptions about ascii values.
event.kbd.ascii = Common::KEYCODE_BACKSPACE;
}
break; break;
case Common::EVENT_KEYUP: case Common::EVENT_KEYUP:
@ -598,13 +273,12 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
} }
void DefaultEventManager::pushEvent(const Common::Event &event) { void DefaultEventManager::pushEvent(const Common::Event &event) {
// If already received an EVENT_QUIT, don't add another one // If already received an EVENT_QUIT, don't add another one
if (event.type == Common::EVENT_QUIT) { if (event.type == Common::EVENT_QUIT) {
if (!_shouldQuit) if (!_shouldQuit)
artificialEventQueue.push(event); _artificialEventSource.addEvent(event);
} else } else
artificialEventQueue.push(event); _artificialEventSource.addEvent(event);
} }
#endif // !defined(DISABLE_DEFAULT_EVENTMANAGER) #endif // !defined(DISABLE_DEFAULT_EVENTMANAGER)

View file

@ -27,8 +27,6 @@
#define BACKEND_EVENTS_DEFAULT_H #define BACKEND_EVENTS_DEFAULT_H
#include "common/events.h" #include "common/events.h"
#include "common/savefile.h"
#include "common/mutex.h"
#include "common/queue.h" #include "common/queue.h"
namespace Common { namespace Common {
@ -41,21 +39,7 @@ namespace Common {
} }
class EventProvider { class DefaultEventManager : public Common::EventManager, Common::EventObserver {
public:
virtual ~EventProvider() {}
/**
* Get the next event in the event queue.
* @param event point to an Common::Event struct, which will be filled with the event data.
* @return true if an event was retrieved.
*/
virtual bool pollEvent(Common::Event &event) = 0;
};
class DefaultEventManager : public Common::EventManager {
EventProvider *_boss;
#ifdef ENABLE_VKEYBD #ifdef ENABLE_VKEYBD
Common::VirtualKeyboard *_vk; Common::VirtualKeyboard *_vk;
#endif #endif
@ -65,7 +49,13 @@ class DefaultEventManager : public Common::EventManager {
bool _remap; bool _remap;
#endif #endif
Common::Queue<Common::Event> _artificialEventQueue; Common::ArtificialEventSource _artificialEventSource;
Common::Queue<Common::Event> _eventQueue;
bool notifyEvent(const Common::Event &ev) {
_eventQueue.push(ev);
return true;
}
Common::Point _mousePos; Common::Point _mousePos;
int _buttonState; int _buttonState;
@ -74,44 +64,6 @@ class DefaultEventManager : public Common::EventManager {
bool _shouldRTL; bool _shouldRTL;
bool _confirmExitDialogActive; bool _confirmExitDialogActive;
class RandomSourceRecord {
public:
Common::String name;
uint32 seed;
};
Common::Array<RandomSourceRecord> _randomSourceRecords;
bool _recordSubtitles;
volatile uint32 _recordCount;
volatile uint32 _lastRecordEvent;
volatile uint32 _recordTimeCount;
Common::OutSaveFile *_recordFile;
Common::OutSaveFile *_recordTimeFile;
Common::MutexRef _timeMutex;
Common::MutexRef _recorderMutex;
volatile uint32 _lastMillis;
volatile uint32 _playbackCount;
volatile uint32 _playbackDiff;
volatile bool _hasPlaybackEvent;
volatile uint32 _playbackTimeCount;
Common::Event _playbackEvent;
Common::InSaveFile *_playbackFile;
Common::InSaveFile *_playbackTimeFile;
volatile uint32 _eventCount;
volatile uint32 _lastEventCount;
enum RecordMode {
kPassthrough = 0,
kRecorderRecord = 1,
kRecorderPlayback = 2
};
volatile RecordMode _recordMode;
Common::String _recordFileName;
Common::String _recordTempFileName;
Common::String _recordTimeFileName;
// for continuous events (keyDown) // for continuous events (keyDown)
enum { enum {
kKeyRepeatInitialDelay = 400, kKeyRepeatInitialDelay = 400,
@ -124,18 +76,13 @@ class DefaultEventManager : public Common::EventManager {
int keycode; int keycode;
} _currentKeyDown; } _currentKeyDown;
uint32 _keyRepeatTime; uint32 _keyRepeatTime;
void record(Common::Event &event);
bool playback(Common::Event &event);
public: public:
DefaultEventManager(EventProvider *boss); DefaultEventManager(Common::EventSource *boss);
~DefaultEventManager(); ~DefaultEventManager();
virtual void init(); virtual void init();
virtual bool pollEvent(Common::Event &event); virtual bool pollEvent(Common::Event &event);
virtual void pushEvent(const Common::Event &event); virtual void pushEvent(const Common::Event &event);
virtual void registerRandomSource(Common::RandomSource &rnd, const char *name);
virtual void processMillis(uint32 &millis);
virtual Common::Point getMousePos() const { return _mousePos; } virtual Common::Point getMousePos() const { return _mousePos; }
virtual int getButtonState() const { return _buttonState; } virtual int getButtonState() const { return _buttonState; }
@ -143,6 +90,9 @@ public:
virtual int shouldQuit() const { return _shouldQuit; } virtual int shouldQuit() const { return _shouldQuit; }
virtual int shouldRTL() const { return _shouldRTL; } virtual int shouldRTL() const { return _shouldRTL; }
virtual void resetRTL() { _shouldRTL = false; } virtual void resetRTL() { _shouldRTL = false; }
#ifdef FORCE_RTL
virtual void resetQuit() { _shouldQuit = false; }
#endif
#ifdef ENABLE_KEYMAPPER #ifdef ENABLE_KEYMAPPER
virtual Common::Keymapper *getKeymapper() { return _keymapper; } virtual Common::Keymapper *getKeymapper() { return _keymapper; }

View file

@ -43,8 +43,6 @@
#define ENTER() /* debug(6, "Enter") */ #define ENTER() /* debug(6, "Enter") */
#define LEAVE() /* debug(6, "Leave") */ #define LEAVE() /* debug(6, "Leave") */
const uint32 kExAllBufferSize = 40960; // TODO: is this okay for sure?
/** /**
* Implementation of the ScummVM file system API. * Implementation of the ScummVM file system API.
* *
@ -57,30 +55,33 @@ protected:
Common::String _sPath; Common::String _sPath;
bool _bIsDirectory; bool _bIsDirectory;
bool _bIsValid; bool _bIsValid;
uint32 _nProt;
/** /**
* Obtain the FileInfoBlock protection value for this FSNode, * Creates a list with all the volumes present in the root node.
* as defined in the <proto/dos.h> header.
*
* @return -1 if there were errors, 0 or a positive integer otherwise.
*/ */
virtual int getFibProtection() const; virtual AbstractFSList listVolumes() const;
public: public:
/** /**
* Creates a AmigaOSFilesystemNode with the root node as path. * Creates an AmigaOSFilesystemNode with the root node as path.
*/ */
AmigaOSFilesystemNode(); AmigaOSFilesystemNode();
/** /**
* Creates a AmigaOSFilesystemNode for a given path. * Creates an AmigaOSFilesystemNode for a given path.
* *
* @param path Common::String with the path the new node should point to. * @param path Common::String with the path the new node should point to.
*/ */
AmigaOSFilesystemNode(const Common::String &p); AmigaOSFilesystemNode(const Common::String &p);
/** /**
* FIXME: document this constructor. * Creates an AmigaOSFilesystemNode given its lock and display name
*
* @param pLock BPTR to the lock.
* @param pDisplayName name to be used for display, in case not supplied the FilePart() of the filename will be used.
*
* @note This shouldn't even be public as it's only internally, at best it should have been protected if not private
*/ */
AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayName = 0); AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayName = 0);
@ -110,11 +111,6 @@ public:
virtual Common::SeekableReadStream *createReadStream(); virtual Common::SeekableReadStream *createReadStream();
virtual Common::WriteStream *createWriteStream(); virtual Common::WriteStream *createWriteStream();
/**
* Creates a list with all the volumes present in the root node.
*/
virtual AbstractFSList listVolumes() const;
}; };
/** /**
@ -149,6 +145,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode() {
_bIsDirectory = true; _bIsDirectory = true;
_sPath = ""; _sPath = "";
_pFileLock = 0; _pFileLock = 0;
_nProt = 0; // protection is ignored for the root volume
LEAVE(); LEAVE();
} }
@ -169,37 +166,27 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
_pFileLock = 0; _pFileLock = 0;
_bIsDirectory = false; _bIsDirectory = false;
struct FileInfoBlock *fib = (struct FileInfoBlock *)IDOS->AllocDosObject(DOS_FIB, NULL);
if (!fib) {
debug(6, "FileInfoBlock is NULL");
LEAVE();
return;
}
// Check whether the node exists and if it is a directory // Check whether the node exists and if it is a directory
BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK); struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_StringNameInput,_sPath.c_str(),TAG_END);
if (pLock) { if (pExd) {
if (IDOS->Examine(pLock, fib) != DOSFALSE) { _nProt = pExd->Protection;
if (FIB_IS_DRAWER(fib)) { if (EXD_IS_DIRECTORY(pExd)) {
_bIsDirectory = true; _bIsDirectory = true;
_pFileLock = IDOS->DupLock(pLock); _pFileLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);;
_bIsValid = (_pFileLock != 0); _bIsValid = (_pFileLock != 0);
// Add a trailing slash if it is needed // Add a trailing slash if it is needed
const char c = _sPath.lastChar(); const char c = _sPath.lastChar();
if (c != '/' && c != ':') if (c != '/' && c != ':')
_sPath += '/'; _sPath += '/';
} } else {
else {
//_bIsDirectory = false; //_bIsDirectory = false;
_bIsValid = true; _bIsValid = true;
} }
IDOS->FreeDosObject(DOS_EXAMINEDATA, pExd);
} }
IDOS->UnLock(pLock);
}
IDOS->FreeDosObject(DOS_FIB, fib);
LEAVE(); LEAVE();
} }
@ -232,15 +219,10 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayNam
_bIsValid = false; _bIsValid = false;
_bIsDirectory = false; _bIsDirectory = false;
struct FileInfoBlock *fib = (struct FileInfoBlock *)IDOS->AllocDosObject(DOS_FIB, NULL); struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_FileLockInput,pLock,TAG_END);
if (!fib) { if (pExd) {
debug(6, "FileInfoBlock is NULL"); _nProt = pExd->Protection;
LEAVE(); if (EXD_IS_DIRECTORY(pExd)) {
return;
}
if (IDOS->Examine(pLock, fib) != DOSFALSE) {
if (FIB_IS_DRAWER(fib)) {
_bIsDirectory = true; _bIsDirectory = true;
_pFileLock = IDOS->DupLock(pLock); _pFileLock = IDOS->DupLock(pLock);
_bIsValid = _pFileLock != 0; _bIsValid = _pFileLock != 0;
@ -248,25 +230,29 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayNam
const char c = _sPath.lastChar(); const char c = _sPath.lastChar();
if (c != '/' && c != ':') if (c != '/' && c != ':')
_sPath += '/'; _sPath += '/';
} } else {
else {
//_bIsDirectory = false; //_bIsDirectory = false;
_bIsValid = true; _bIsValid = true;
} }
IDOS->FreeDosObject(DOS_EXAMINEDATA, pExd);
} else {
debug(6, "ExamineObject() returned NULL");
} }
IDOS->FreeDosObject(DOS_FIB, fib);
LEAVE(); LEAVE();
} }
// We need the custom copy constructor because of DupLock() // We need the custom copy constructor because of DupLock()
AmigaOSFilesystemNode::AmigaOSFilesystemNode(const AmigaOSFilesystemNode& node) { AmigaOSFilesystemNode::AmigaOSFilesystemNode(const AmigaOSFilesystemNode& node)
: AbstractFSNode() {
ENTER(); ENTER();
_sDisplayName = node._sDisplayName; _sDisplayName = node._sDisplayName;
_bIsValid = node._bIsValid; _bIsValid = node._bIsValid;
_bIsDirectory = node._bIsDirectory; _bIsDirectory = node._bIsDirectory;
_sPath = node._sPath; _sPath = node._sPath;
_pFileLock = IDOS->DupLock(node._pFileLock); _pFileLock = IDOS->DupLock(node._pFileLock);
_nProt = node._nProt;
LEAVE(); LEAVE();
} }
@ -284,21 +270,29 @@ bool AmigaOSFilesystemNode::exists() const {
bool nodeExists = false; bool nodeExists = false;
struct FileInfoBlock *fib = (struct FileInfoBlock *)IDOS->AllocDosObject(DOS_FIB, NULL); // previously we were trying to examine the node in order
if (!fib) { // to determine if the node exists or not.
debug(6, "FileInfoBlock is NULL"); // I don't see the point : once you have been granted a
LEAVE(); // lock on it then it means it exists...
return false; //
} // ============================= Old code
// BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK);
BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK); // if (pLock)
// {
// if (IDOS->Examine(pLock, fib) != DOSFALSE)
// nodeExists = true;
// IDOS->UnLock(pLock);
// }
//
// IDOS->FreeDosObject(DOS_FIB, fib);
//
// ============================= New code
BPTR pLock = IDOS->Lock(_sPath.c_str(), SHARED_LOCK);
if (pLock) { if (pLock) {
if (IDOS->Examine(pLock, fib) != DOSFALSE)
nodeExists = true; nodeExists = true;
IDOS->UnLock(pLock); IDOS->UnLock(pLock);
} }
IDOS->FreeDosObject(DOS_FIB, fib);
LEAVE(); LEAVE();
return nodeExists; return nodeExists;
} }
@ -323,8 +317,10 @@ AbstractFSNode *AmigaOSFilesystemNode::getChild(const Common::String &n) const {
bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
ENTER(); ENTER();
bool ret = false;
//TODO: honor the hidden flag //TODO: honor the hidden flag
// There is nothing like a hidden flag under AmigaOS...
if (!_bIsValid) { if (!_bIsValid) {
debug(6, "Invalid node"); debug(6, "Invalid node");
@ -345,85 +341,49 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
return true; return true;
} }
struct ExAllControl *eac = (struct ExAllControl *)IDOS->AllocDosObject(DOS_EXALLCONTROL, 0); APTR context = IDOS->ObtainDirContextTags( EX_FileLockInput, _pFileLock,
if (eac) { EX_DoCurrentDir, TRUE, /* for softlinks */
struct ExAllData *data = (struct ExAllData *)IExec->AllocVec(kExAllBufferSize, MEMF_ANY); EX_DataFields, (EXF_NAME|EXF_LINK|EXF_TYPE),
if (data) { TAG_END);
BOOL bExMore; if (context) {
eac->eac_LastKey = 0; struct ExamineData * pExd = NULL; // NB: no need to free value after usage, all is dealt by the DirContext release
do {
// Examine directory
bExMore = IDOS->ExAll(_pFileLock, data, kExAllBufferSize, ED_TYPE, eac);
LONG error = IDOS->IoErr(); AmigaOSFilesystemNode *entry ;
if (!bExMore && error != ERROR_NO_MORE_ENTRIES) while ( (pExd = IDOS->ExamineDir(context)) ) {
break; // Abnormal failure if ( (EXD_IS_FILE(pExd) && ( Common::FSNode::kListFilesOnly == mode ))
|| (EXD_IS_DIRECTORY(pExd) && ( Common::FSNode::kListDirectoriesOnly == mode ))
if (eac->eac_Entries == 0) || Common::FSNode::kListAll == mode
continue; // Normal failure, no entries )
{
struct ExAllData *ead = data; BPTR pLock = IDOS->Lock( pExd->Name, SHARED_LOCK );
do {
if ((mode == Common::FSNode::kListAll) ||
(EAD_IS_DRAWER(ead) && (mode == Common::FSNode::kListDirectoriesOnly)) ||
(EAD_IS_FILE(ead) && (mode == Common::FSNode::kListFilesOnly))) {
Common::String full_path = _sPath;
full_path += (char*)ead->ed_Name;
BPTR lock = IDOS->Lock((STRPTR)full_path.c_str(), SHARED_LOCK);
if (lock) {
AmigaOSFilesystemNode *entry = new AmigaOSFilesystemNode(lock, (char *)ead->ed_Name);
if (entry) {
//FIXME: since the isValid() function is no longer part of the AbstractFSNode
// specification, the following call had to be changed:
// if (entry->isValid())
// Please verify that the logic of the code remains coherent. Also, remember
// that the isReadable() and isWritable() methods are available.
if (entry->exists())
myList.push_back(entry);
else
delete entry;
}
IDOS->UnLock(lock);
}
}
ead = ead->ed_Next;
} while (ead);
} while (bExMore);
IExec->FreeVec(data);
}
IDOS->FreeDosObject(DOS_EXALLCONTROL, eac);
}
LEAVE();
return true;
}
int AmigaOSFilesystemNode::getFibProtection() const {
ENTER();
int fibProt = -1;
struct FileInfoBlock *fib = (struct FileInfoBlock *)IDOS->AllocDosObject(DOS_FIB, NULL);
if (!fib) {
debug(6, "FileInfoBlock is NULL");
LEAVE();
return fibProt;
}
BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK);
if (pLock) { if (pLock) {
if (IDOS->Examine(pLock, fib) != DOSFALSE) { entry = new AmigaOSFilesystemNode( pLock, pExd->Name );
fibProt = fib->fib_Protection; if (entry) {
myList.push_back(entry);
} }
IDOS->UnLock(pLock); IDOS->UnLock(pLock);
} }
}
}
if (ERROR_NO_MORE_ENTRIES != IDOS->IoErr() ) {
debug(6, "An error occured during ExamineDir");
ret = false;
} else {
ret = true;
}
IDOS->ReleaseDirContext(context);
} else {
debug(6, "Unable to ObtainDirContext");
ret = false;
}
IDOS->FreeDosObject(DOS_FIB, fib);
LEAVE(); LEAVE();
return fibProt;
return ret;
} }
AbstractFSNode *AmigaOSFilesystemNode::getParent() const { AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
@ -447,8 +407,7 @@ AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
if (parentDir) { if (parentDir) {
node = new AmigaOSFilesystemNode(parentDir); node = new AmigaOSFilesystemNode(parentDir);
IDOS->UnLock(parentDir); IDOS->UnLock(parentDir);
} } else
else
node = new AmigaOSFilesystemNode(); node = new AmigaOSFilesystemNode();
LEAVE(); LEAVE();
@ -457,33 +416,19 @@ AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
} }
bool AmigaOSFilesystemNode::isReadable() const { bool AmigaOSFilesystemNode::isReadable() const {
bool readable = false; // Regular RWED protection flags are low-active or inverted, thus the negation.
int fibProt = getFibProtection(); // moreover pseudo root filesystem (null _pFileLock) is readable whatever the
// protection says
if (fibProt >= 0) { bool readable = !(_nProt & EXDF_READ) || _pFileLock == 0;
/* The fib_Protection flag is low-active or inverted, thus the negation.
*
* For more information, consult the compiler/include/dos/dos.h
* file from the AROS source (http://aros.sourceforge.net/).
*/
readable = !(fibProt & FIBF_READ);
}
return readable; return readable;
} }
bool AmigaOSFilesystemNode::isWritable() const { bool AmigaOSFilesystemNode::isWritable() const {
bool writable = false; // Regular RWED protection flags are low-active or inverted, thus the negation.
int fibProt = getFibProtection(); // moreover pseudo root filesystem (null _pFileLock) is never writable whatever
// the protection says (because of the pseudo nature)
if (fibProt >= 0) { bool writable = !(_nProt & EXDF_WRITE) && _pFileLock !=0;
/* The fib_Protection flag is low-active or inverted, thus the negation.
*
* For more information, consult the compiler/include/dos/dos.h
* file from the AROS source (http://aros.sourceforge.net/).
*/
writable = !(fibProt & FIBF_WRITE);
}
return writable; return writable;
} }
@ -508,13 +453,10 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
if (dosList->dol_Type == DLT_VOLUME && if (dosList->dol_Type == DLT_VOLUME &&
dosList->dol_Name && dosList->dol_Name &&
dosList->dol_Task) { dosList->dol_Task) {
//const char *volName = (const char *)BADDR(dosList->dol_Name)+1;
// Copy name to buffer // Copy name to buffer
IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN); IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN);
//const char *devName = (const char *)((struct Task *)dosList->dol_Task->mp_SigTask)->tc_Node.ln_Name;
// Volume name + '\0' // Volume name + '\0'
char *volName = new char [strlen(buffer) + 1]; char *volName = new char [strlen(buffer) + 1];
@ -536,15 +478,7 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
AmigaOSFilesystemNode *entry = new AmigaOSFilesystemNode(volumeLock, buffer); AmigaOSFilesystemNode *entry = new AmigaOSFilesystemNode(volumeLock, buffer);
if (entry) { if (entry) {
//FIXME: since the isValid() function is no longer part of the AbstractFSNode
// specification, the following call had to be changed:
// if (entry->isValid())
// Please verify that the logic of the code remains coherent. Also, remember
// that the isReadable() and isWritable() methods are available.
if(entry->exists())
myList.push_back(entry); myList.push_back(entry);
else
delete entry;
} }
IDOS->UnLock(volumeLock); IDOS->UnLock(volumeLock);

View file

@ -33,7 +33,14 @@ AbstractFSNode *PSPFilesystemFactory::makeRootFileNode() const {
} }
AbstractFSNode *PSPFilesystemFactory::makeCurrentDirectoryFileNode() const { AbstractFSNode *PSPFilesystemFactory::makeCurrentDirectoryFileNode() const {
return new PSPFilesystemNode(); char buf[MAXPATHLEN];
char * ret = 0;
PowerMan.beginCriticalSection();
ret = getcwd(buf, MAXPATHLEN);
PowerMan.endCriticalSection();
return (ret ? new PSPFilesystemNode(buf) : NULL);
} }
AbstractFSNode *PSPFilesystemFactory::makeFileNodePath(const Common::String &path) const { AbstractFSNode *PSPFilesystemFactory::makeFileNodePath(const Common::String &path) const {

View file

@ -26,7 +26,7 @@
#include "engines/engine.h" #include "engines/engine.h"
#include "backends/fs/abstract-fs.h" #include "backends/fs/abstract-fs.h"
#include "backends/fs/stdiostream.h" #include "backends/fs/psp/psp-stream.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@ -35,6 +35,8 @@
#define ROOT_PATH "ms0:/" #define ROOT_PATH "ms0:/"
#include "backends/platform/psp/trace.h"
/** /**
* Implementation of the ScummVM file system API based on PSPSDK API. * Implementation of the ScummVM file system API based on PSPSDK API.
* *
@ -59,15 +61,15 @@ public:
* @param path Common::String with the path the new node should point to. * @param path Common::String with the path the new node should point to.
* @param verify true if the isValid and isDirectory flags should be verified during the construction. * @param verify true if the isValid and isDirectory flags should be verified during the construction.
*/ */
PSPFilesystemNode(const Common::String &p, bool verify); PSPFilesystemNode(const Common::String &p, bool verify = true);
virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; } virtual bool exists() const;
virtual Common::String getDisplayName() const { return _displayName; } virtual Common::String getDisplayName() const { return _displayName; }
virtual Common::String getName() const { return _displayName; } virtual Common::String getName() const { return _displayName; }
virtual Common::String getPath() const { return _path; } virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; } virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } virtual bool isReadable() const;
virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } virtual bool isWritable() const;
virtual AbstractFSNode *getChild(const Common::String &n) const; virtual AbstractFSNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
@ -94,11 +96,51 @@ PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) {
if (verify) { if (verify) {
struct stat st; struct stat st;
if (PowerMan.beginCriticalSection()==PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPFilesystemNode::PSPFilesystemNode\n");
_isValid = (0 == stat(_path.c_str(), &st)); _isValid = (0 == stat(_path.c_str(), &st));
PowerMan.endCriticalSection();
_isDirectory = S_ISDIR(st.st_mode); _isDirectory = S_ISDIR(st.st_mode);
} }
} }
bool PSPFilesystemNode::exists() const {
int ret = 0;
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPFilesystemNode::exists()\n"); // Make sure to block in case of suspend
ret = access(_path.c_str(), F_OK);
PowerMan.endCriticalSection();
return ret == 0;
}
bool PSPFilesystemNode::isReadable() const {
int ret = 0;
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPFilesystemNode::isReadable()\n"); // Make sure to block in case of suspend
ret = access(_path.c_str(), R_OK);
PowerMan.endCriticalSection();
return ret == 0;
}
bool PSPFilesystemNode::isWritable() const {
int ret = 0;
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPFilesystemNode::isWritable()\n"); // Make sure to block in case of suspend
ret = access(_path.c_str(), W_OK);
PowerMan.endCriticalSection();
return ret == 0;
}
AbstractFSNode *PSPFilesystemNode::getChild(const Common::String &n) const { AbstractFSNode *PSPFilesystemNode::getChild(const Common::String &n) const {
// FIXME: Pretty lame implementation! We do no error checking to speak // FIXME: Pretty lame implementation! We do no error checking to speak
// of, do not check if this is a special node, etc. // of, do not check if this is a special node, etc.
@ -117,6 +159,11 @@ bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool
//TODO: honor the hidden flag //TODO: honor the hidden flag
bool ret = true;
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPFilesystemNode::getChildren\n"); // Make sure to block in case of suspend
int dfd = sceIoDopen(_path.c_str()); int dfd = sceIoDopen(_path.c_str());
if (dfd > 0) { if (dfd > 0) {
SceIoDirent dir; SceIoDirent dir;
@ -149,10 +196,13 @@ bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool
} }
sceIoDclose(dfd); sceIoDclose(dfd);
return true; ret = true;
} else { } else { // dfd <= 0
return false; ret = false;
} }
PowerMan.endCriticalSection();
return ret;
} }
AbstractFSNode *PSPFilesystemNode::getParent() const { AbstractFSNode *PSPFilesystemNode::getParent() const {
@ -166,11 +216,11 @@ AbstractFSNode *PSPFilesystemNode::getParent() const {
} }
Common::SeekableReadStream *PSPFilesystemNode::createReadStream() { Common::SeekableReadStream *PSPFilesystemNode::createReadStream() {
return StdioStream::makeFromPath(getPath().c_str(), false); return PSPIoStream::makeFromPath(getPath(), false);
} }
Common::WriteStream *PSPFilesystemNode::createWriteStream() { Common::WriteStream *PSPFilesystemNode::createWriteStream() {
return StdioStream::makeFromPath(getPath().c_str(), true); return PSPIoStream::makeFromPath(getPath(), true);
} }
#endif //#ifdef __PSP__ #endif //#ifdef __PSP__

View file

@ -0,0 +1,303 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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$
*
*/
#ifdef __PSP__
#include <SDL/SDL_thread.h>
#include <SDL/SDL_mutex.h>
#include "backends/platform/psp/trace.h"
#include "backends/platform/psp/powerman.h"
#include "backends/fs/psp/psp-stream.h"
#include <errno.h>
PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode)
: StdioStream((void *)1), _path(path), _writeMode(writeMode) {
assert(!path.empty());
_handle = (void *)0; // Need to do this since base class asserts not 0.
_ferror = false;
_feof = false;
_pos = 0;
#ifdef __PSP_DEBUG_SUSPEND__
_errorSuspend = 0;
_errorSource = 0;
_errorPos = 0;
_errorHandle = 0;
_suspendCount = 0;
#endif
}
PSPIoStream::~PSPIoStream() {
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPIoStream::~PSPIoStream()\n");
PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended
// Must do this before fclose() or resume() will reopen.
fclose((FILE *)_handle); // We don't need a critical section(?). Worst case, the handle gets closed on its own
PowerMan.endCriticalSection();
}
// Function to open the file pointed to by the path.
//
//
void *PSPIoStream::open() {
if (PowerMan.beginCriticalSection() == PowerManager::Blocked) {
// No need to open. Just return the _handle resume() already opened.
PSPDebugSuspend("Suspended in PSPIoStream::open\n");
}
_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); // open
PowerMan.registerSuspend(this); // Register with the powermanager to be suspended
PowerMan.endCriticalSection();
return _handle;
}
bool PSPIoStream::err() const {
if (_ferror)
PSPDebugSuspend("In PSPIoStream::err - mem_ferror=%d, source=%d, suspend error=%d, pos=%d, _errorPos=%d, _errorHandle=%p, suspendCount=%d _handle\n",
_ferror, _errorSource, _errorSuspend, _pos, _errorPos, _errorHandle, _suspendCount);
return _ferror;
}
void PSPIoStream::clearErr() {
_ferror = false; // Remove regular error bit
}
bool PSPIoStream::eos() const {
return _feof;
}
int32 PSPIoStream::pos() const {
return _pos;
}
int32 PSPIoStream::size() const {
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPIoStream::size()\n");
fseek((FILE *)_handle, 0, SEEK_END);
int32 length = ftell((FILE *)_handle);
fseek((FILE *)_handle, _pos, SEEK_SET);
if (_pos < 0 || length < 0) { // Check for errors
PSPDebugSuspend("In PSPIoStream::size(). encountered an error!\n");
_ferror = true;
length = -1; // If our oldPos is bad, we want length to be bad too to signal
clearerr((FILE *)_handle);
#ifdef __PSP_DEBUG_SUSPEND__
_errorSource = 2;
#endif
}
PowerMan.endCriticalSection();
return length;
}
bool PSPIoStream::seek(int32 offs, int whence) {
// Check if we can access the file
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPIoStream::seek()\n");
int ret = fseek((FILE *)_handle, offs, whence);
if (ret != 0) {
_ferror = true;
PSPDebugSuspend("In PSPIoStream::seek(). encountered an error!\n");
clearerr((FILE *)_handle);
_feof = feof((FILE *)_handle);
#ifdef __PSP_DEBUG_SUSPEND__
_errorSource = 3;
#endif
}
else { // everything ok
_feof = false; // Reset eof flag since we know it was ok
}
_pos = ftell((FILE *)_handle); // update pos
PowerMan.endCriticalSection();
return ret == 0;
}
uint32 PSPIoStream::read(void *ptr, uint32 len) {
// Check if we can access the file
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPIoStream::read()\n");
size_t ret = fread((byte *)ptr, 1, len, (FILE *)_handle);
_pos += ret; // Update pos
if (ret != len) { // Check for eof
_feof = feof((FILE *)_handle);
if (!_feof) { // It wasn't an eof. Must be an error
_ferror = true;
clearerr((FILE *)_handle);
_pos = ftell((FILE *)_handle); // Update our position
PSPDebugSuspend("In PSPIoStream::read(). encountered an error!\n");
#ifdef __PSP_DEBUG_SUSPEND__
_errorSource = 4;
#endif
}
}
PowerMan.endCriticalSection();
return ret;
}
uint32 PSPIoStream::write(const void *ptr, uint32 len) {
// Check if we can access the file
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPIoStream::read()\n");
size_t ret = fwrite(ptr, 1, len, (FILE *)_handle);
_pos += ret;
if (ret != len) { // Set error
_ferror = true;
clearerr((FILE *)_handle);
_pos = ftell((FILE *)_handle); // Update pos
PSPDebugTrace("In PSPIoStream::write(). encountered an error!\n");
#ifdef __PSP_DEBUG_SUSPEND__
_errorSource = 5;
#endif
}
PowerMan.endCriticalSection();
return ret;
}
bool PSPIoStream::flush() {
// Enter critical section
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPIoStream::read()\n");
int ret = fflush((FILE *)_handle);
if (ret != 0) {
_ferror = true;
clearerr((FILE *)_handle);
PSPDebugSuspend("In PSPIoStream::flush(). encountered an error!\n");
#ifdef __PSP_DEBUG_SUSPEND__
_errorSource = 6;
#endif
}
PowerMan.endCriticalSection();
return ret == 0;
}
// For the PSP, since we're building in suspend support, we moved opening
// the actual file to an open function since we need an actual PSPIoStream object to suspend.
//
PSPIoStream *PSPIoStream::makeFromPath(const Common::String &path, bool writeMode) {
PSPIoStream *stream = new PSPIoStream(path, writeMode);
if (stream->open() > 0) {
return stream;
} else {
delete stream;
return 0;
}
}
/*
* Function to suspend the IO stream (called by PowerManager)
*/
int PSPIoStream::suspend() {
#ifdef __PSP_DEBUG_SUSPEND__
_suspendCount++;
if (_handle > 0 && _pos < 0) {
_errorSuspend = SuspendError;
_errorPos = _pos;
_errorHandle = _handle;
}
#endif /* __PSP_DEBUG_SUSPEND__ */
if (_handle > 0) {
fclose((FILE *)_handle); // close our file descriptor
_handle = (void *)0xFFFFFFFF; // Set handle to non-null invalid value so makeFromPath doesn't return error
}
return 0;
}
/*
* Function to resume the IO stream (called by Power Manager)
*/
int PSPIoStream::resume() {
int ret = 0;
#ifdef __PSP_DEBUG_SUSPEND__
_suspendCount--;
#endif
// We reopen our file descriptor
_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb");
if (_handle <= 0) {
PSPDebugSuspend("PSPIoStream::resume(): Couldn't reopen file %s\n", _path.c_str());
}
// Resume our previous position
if (_handle > 0 && _pos > 0) {
ret = fseek((FILE *)_handle, _pos, SEEK_SET);
#ifdef __PSP_DEBUG_SUSPEND__
if (ret != 0) { // Check for problem
_errorSuspend = ResumeError;
_errorPos = _pos;
_errorHandle = _handle;
}
#endif
}
return ret;
}
#endif /* __PSP__ */

View file

@ -0,0 +1,86 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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 PSPSTREAM_H_
#define PSPSTREAM_H_
#include "backends/fs/stdiostream.h"
#include "backends/platform/psp/powerman.h"
#include "common/list.h"
/*
* Class to handle special suspend/resume needs of PSP IO Streams
*/
class PSPIoStream : public StdioStream, public Suspendable {
protected:
Common::String _path; /* Need to maintain for reopening after suspend */
bool _writeMode; /* "" */
int _pos; /* "" */
mutable int _ferror; /* Save file ferror */
mutable bool _feof; /* and eof */
enum {
SuspendError = 2,
ResumeError = 3
};
int _errorSuspend;
mutable int _errorSource;
#ifdef __PSP_DEBUG_SUSPEND__
int _errorPos;
void * _errorHandle;
int _suspendCount;
#endif /* __PSP_DEBUG_SUSPEND__ */
public:
/**
* Given a path, invoke fopen on that path and wrap the result in a
* PSPIoStream instance.
*/
static PSPIoStream *makeFromPath(const Common::String &path, bool writeMode);
PSPIoStream(const Common::String &path, bool writeMode);
virtual ~PSPIoStream();
void * open(); // open the file pointed to by the file path
bool err() const;
void clearErr();
bool eos() const;
virtual uint32 write(const void *dataPtr, uint32 dataSize);
virtual bool flush();
virtual int32 pos() const;
virtual int32 size() const;
virtual bool seek(int32 offs, int whence = SEEK_SET);
virtual uint32 read(void *dataPtr, uint32 dataSize);
int suspend(); /* Suspendable interface (power manager) */
int resume(); /* " " */
};
#endif /* PSPSTREAM_H_ */

View file

@ -46,17 +46,17 @@ public:
StdioStream(void *handle); StdioStream(void *handle);
virtual ~StdioStream(); virtual ~StdioStream();
bool err() const; virtual bool err() const;
void clearErr(); virtual void clearErr();
bool eos() const; virtual bool eos() const;
virtual uint32 write(const void *dataPtr, uint32 dataSize); virtual uint32 write(const void *dataPtr, uint32 dataSize);
virtual bool flush(); virtual bool flush();
virtual int32 pos() const; virtual int32 pos() const;
virtual int32 size() const; virtual int32 size() const;
bool seek(int32 offs, int whence = SEEK_SET); virtual bool seek(int32 offs, int whence = SEEK_SET);
uint32 read(void *dataPtr, uint32 dataSize); virtual uint32 read(void *dataPtr, uint32 dataSize);
}; };
#endif #endif

View file

@ -168,6 +168,15 @@ void Keymapper::popKeymap() {
_activeMaps.pop(); _activeMaps.pop();
} }
bool Keymapper::notifyEvent(const Common::Event &ev) {
if (ev.type == Common::EVENT_KEYDOWN)
return mapKeyDown(ev.kbd);
else if (ev.type == Common::EVENT_KEYUP)
return mapKeyUp(ev.kbd);
else
return false;
}
bool Keymapper::mapKeyDown(const KeyState& key) { bool Keymapper::mapKeyDown(const KeyState& key) {
return mapKey(key, true); return mapKey(key, true);
} }
@ -255,7 +264,7 @@ void Keymapper::executeAction(const Action *action, bool keyDown) {
} }
evt.mouse = _eventMan->getMousePos(); evt.mouse = _eventMan->getMousePos();
_eventMan->pushEvent(evt); addEvent(evt);
} }
} }

View file

@ -39,7 +39,7 @@
namespace Common { namespace Common {
class Keymapper { class Keymapper : public Common::EventMapper, private Common::ArtificialEventSource {
public: public:
struct MapRecord { struct MapRecord {
@ -134,6 +134,10 @@ public:
*/ */
void popKeymap(); void popKeymap();
// Implementation of the EventMapper interface
bool notifyEvent(const Common::Event &ev);
bool pollEvent(Common::Event &ev) { return Common::ArtificialEventSource::pollEvent(ev); }
/** /**
* @brief Map a key press event. * @brief Map a key press event.
* If the active keymap contains a Action mapped to the given key, then * If the active keymap contains a Action mapped to the given key, then

View file

@ -187,6 +187,8 @@ bool OSystem_SDL::pollEvent(Common::Event &event) {
} }
*/ */
while (SDL_PollEvent(&ev)) { while (SDL_PollEvent(&ev)) {
preprocessEvents(&ev);
switch (ev.type) { switch (ev.type) {
case SDL_KEYDOWN:{ case SDL_KEYDOWN:{
b = event.kbd.flags = SDLModToOSystemKeyFlags(SDL_GetModState()); b = event.kbd.flags = SDLModToOSystemKeyFlags(SDL_GetModState());

View file

@ -26,6 +26,13 @@
#include "backends/platform/sdl/sdl.h" #include "backends/platform/sdl/sdl.h"
#include "common/mutex.h" #include "common/mutex.h"
#include "common/util.h" #include "common/util.h"
#ifdef USE_RGB_COLOR
#include "common/list.h"
#endif
#include "graphics/font.h"
#include "graphics/fontman.h"
#include "graphics/scaler.h"
#include "graphics/surface.h"
@ -354,6 +361,11 @@ void OSystem_SDL::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, i
SDL_UnlockSurface(_overlayscreen); SDL_UnlockSurface(_overlayscreen);
} }
#pragma mark -
#pragma mark --- Mouse ---
#pragma mark -
bool OSystem_SDL::showMouse(bool visible) { bool OSystem_SDL::showMouse(bool visible) {
return false; return false;
} }
@ -396,7 +408,17 @@ void OSystem_SDL::warpMouse(int x, int y) {
}*/ }*/
} }
void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) { void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
#ifdef USE_RGB_COLOR
if (!format)
_cursorFormat = Graphics::PixelFormat::createFormatCLUT8();
else if (format->bytesPerPixel <= _screenFormat.bytesPerPixel)
_cursorFormat = *format;
keycolor &= (1 << (_cursorFormat.bytesPerPixel << 3)) - 1;
#else
keycolor &= 0xFF;
#endif
if (w == 0 || h == 0) if (w == 0 || h == 0)
return; return;
/* Residual doesn't support this /* Residual doesn't support this
@ -430,9 +452,13 @@ void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x,
} }
free(_mouseData); free(_mouseData);
#ifdef USE_RGB_COLOR
_mouseData = (byte *)malloc(w * h * _cursorFormat.bytesPerPixel);
memcpy(_mouseData, buf, w * h * _cursorFormat.bytesPerPixel);
#else
_mouseData = (byte *)malloc(w * h); _mouseData = (byte *)malloc(w * h);
memcpy(_mouseData, buf, w * h); memcpy(_mouseData, buf, w * h);
#endif
blitCursor();*/ blitCursor();*/
} }

View file

@ -37,7 +37,7 @@
#include "SymbianOs.h" #include "SymbianOs.h"
#endif #endif
#if !defined(__MAEMO__) && !defined(_WIN32_WCE) && !defined(GP2XWIZ) #if !defined(__MAEMO__) && !defined(_WIN32_WCE) && !defined(GP2XWIZ)&& !defined(LINUXMOTO)
#if defined (WIN32) #if defined (WIN32)
int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) { int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) {

View file

@ -33,7 +33,7 @@
#include "common/archive.h" #include "common/archive.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/events.h" #include "common/EventRecorder.h"
#include "common/util.h" #include "common/util.h"
#ifdef UNIX #ifdef UNIX
@ -215,7 +215,7 @@ OSystem_SDL::~OSystem_SDL() {
uint32 OSystem_SDL::getMillis() { uint32 OSystem_SDL::getMillis() {
uint32 millis = SDL_GetTicks(); uint32 millis = SDL_GetTicks();
getEventManager()->processMillis(millis); g_eventRec.processMillis(millis);
return millis; return millis;
} }
@ -349,13 +349,20 @@ Common::WriteStream *OSystem_SDL::createConfigWriteStream() {
} }
void OSystem_SDL::setWindowCaption(const char *caption) { void OSystem_SDL::setWindowCaption(const char *caption) {
Common::String cap(caption); Common::String cap;
byte c;
// The string caption is supposed to be in LATIN-1 encoding.
// SDL expects UTF-8. So we perform the conversion here.
while ((c = *(const byte *)caption++)) {
if (c < 0x80)
cap += c;
else {
cap += 0xC0 | (c >> 6);
cap += 0x80 | (c & 0x3F);
}
}
// Filter out any non-ASCII characters, replacing them by question marks.
// At some point, we may wish to allow LATIN 1 or UTF-8.
for (uint i = 0; i < cap.size(); ++i)
if ((byte)cap[i] > 0x7F)
cap.setChar('?', i);
SDL_WM_SetCaption(cap.c_str(), cap.c_str()); SDL_WM_SetCaption(cap.c_str(), cap.c_str());
} }
@ -585,7 +592,6 @@ void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) {
void OSystem_SDL::setupMixer() { void OSystem_SDL::setupMixer() {
SDL_AudioSpec desired; SDL_AudioSpec desired;
SDL_AudioSpec obtained;
// Determine the desired output sampling frequency. // Determine the desired output sampling frequency.
_samplesPerSec = 0; _samplesPerSec = 0;
@ -615,7 +621,7 @@ void OSystem_SDL::setupMixer() {
_mixer = new Audio::MixerImpl(this); _mixer = new Audio::MixerImpl(this);
assert(_mixer); assert(_mixer);
if (SDL_OpenAudio(&desired, &obtained) != 0) { if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) {
warning("Could not open audio device: %s", SDL_GetError()); warning("Could not open audio device: %s", SDL_GetError());
_samplesPerSec = 0; _samplesPerSec = 0;
_mixer->setReady(false); _mixer->setReady(false);
@ -623,7 +629,7 @@ void OSystem_SDL::setupMixer() {
// Note: This should be the obtained output rate, but it seems that at // Note: This should be the obtained output rate, but it seems that at
// least on some platforms SDL will lie and claim it did get the rate // least on some platforms SDL will lie and claim it did get the rate
// even if it didn't. Probably only happens for "weird" rates, though. // even if it didn't. Probably only happens for "weird" rates, though.
_samplesPerSec = obtained.freq; _samplesPerSec = _obtainedRate.freq;
debug(1, "Output sample rate: %d Hz", _samplesPerSec); debug(1, "Output sample rate: %d Hz", _samplesPerSec);
// Tell the mixer that we are ready and start the sound processing // Tell the mixer that we are ready and start the sound processing
@ -631,7 +637,7 @@ void OSystem_SDL::setupMixer() {
_mixer->setReady(true); _mixer->setReady(true);
#ifdef MIXER_DOUBLE_BUFFERING #ifdef MIXER_DOUBLE_BUFFERING
initThreadedMixer(_mixer, obtained.samples * 4); initThreadedMixer(_mixer, _obtainedRate.samples * 4);
#endif #endif
// start the sound system // start the sound system

View file

@ -77,7 +77,7 @@ public:
virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME) virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME)
// Set the bitmap that's used when drawing the cursor. // Set the bitmap that's used when drawing the cursor.
virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale); // overloaded by CE backend (FIXME) virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); // overloaded by CE backend (FIXME)
// Get the number of milliseconds since the program was started. // Get the number of milliseconds since the program was started.
uint32 getMillis(); uint32 getMillis();
@ -127,6 +127,7 @@ public:
// Overlay // Overlay
virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; } virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; }
virtual void showOverlay(); virtual void showOverlay();
virtual void hideOverlay(); virtual void hideOverlay();
virtual void clearOverlay(); virtual void clearOverlay();
@ -143,6 +144,7 @@ public:
virtual bool hasFeature(Feature f); virtual bool hasFeature(Feature f);
virtual void setFeatureState(Feature f, bool enable); virtual void setFeatureState(Feature f, bool enable);
virtual bool getFeatureState(Feature f); virtual bool getFeatureState(Feature f);
virtual void preprocessEvents(SDL_Event *event) {};
virtual Common::SaveFileManager *getSavefileManager(); virtual Common::SaveFileManager *getSavefileManager();
virtual FilesystemFactory *getFilesystemFactory(); virtual FilesystemFactory *getFilesystemFactory();
@ -153,6 +155,7 @@ public:
protected: protected:
bool _inited; bool _inited;
SDL_AudioSpec _obtainedRate;
#ifdef USE_OPENGL #ifdef USE_OPENGL

View file

@ -55,11 +55,14 @@ void DefaultSaveFileManager::checkPath(const Common::FSNode &dir) {
} }
Common::StringList DefaultSaveFileManager::listSavefiles(const Common::String &pattern) { Common::StringList DefaultSaveFileManager::listSavefiles(const Common::String &pattern) {
Common::FSNode savePath(getSavePath()); Common::String savePathName = getSavePath();
checkPath(savePath); checkPath(Common::FSNode(savePathName));
if (getError() != Common::kNoError) if (getError() != Common::kNoError)
return Common::StringList(); return Common::StringList();
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSDirectory dir(savePath); Common::FSDirectory dir(savePath);
Common::ArchiveMemberList savefiles; Common::ArchiveMemberList savefiles;
Common::StringList results; Common::StringList results;
@ -76,11 +79,14 @@ Common::StringList DefaultSaveFileManager::listSavefiles(const Common::String &p
Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) { Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) {
// Ensure that the savepath is valid. If not, generate an appropriate error. // Ensure that the savepath is valid. If not, generate an appropriate error.
Common::FSNode savePath(getSavePath()); Common::String savePathName = getSavePath();
checkPath(savePath); checkPath(Common::FSNode(savePathName));
if (getError() != Common::kNoError) if (getError() != Common::kNoError)
return 0; return 0;
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSNode file = savePath.getChild(filename); Common::FSNode file = savePath.getChild(filename);
if (!file.exists()) if (!file.exists())
return 0; return 0;
@ -93,11 +99,14 @@ Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String
Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename) { Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename) {
// Ensure that the savepath is valid. If not, generate an appropriate error. // Ensure that the savepath is valid. If not, generate an appropriate error.
Common::FSNode savePath(getSavePath()); Common::String savePathName = getSavePath();
checkPath(savePath); checkPath(Common::FSNode(savePathName));
if (getError() != Common::kNoError) if (getError() != Common::kNoError)
return 0; return 0;
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSNode file = savePath.getChild(filename); Common::FSNode file = savePath.getChild(filename);
// Open the file for saving // Open the file for saving
@ -107,13 +116,14 @@ Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String
} }
bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) { bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
clearError(); Common::String savePathName = getSavePath();
checkPath(Common::FSNode(savePathName));
Common::FSNode savePath(getSavePath());
checkPath(savePath);
if (getError() != Common::kNoError) if (getError() != Common::kNoError)
return false; return false;
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSNode file = savePath.getChild(filename); Common::FSNode file = savePath.getChild(filename);
// FIXME: remove does not exist on all systems. If your port fails to // FIXME: remove does not exist on all systems. If your port fails to

View file

@ -26,6 +26,7 @@
#ifdef __PSP__ #ifdef __PSP__
#include "backends/saves/psp/psp-saves.h" #include "backends/saves/psp/psp-saves.h"
#include "backends/platform/psp/powerman.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/savefile.h" #include "common/savefile.h"
@ -49,6 +50,8 @@ void PSPSaveFileManager::checkPath(const Common::FSNode &dir) {
const char *savePath = dir.getPath().c_str(); const char *savePath = dir.getPath().c_str();
clearError(); clearError();
PowerMan.beginCriticalSection();
//check if the save directory exists //check if the save directory exists
SceUID fd = sceIoDopen(savePath); SceUID fd = sceIoDopen(savePath);
if (fd < 0) { if (fd < 0) {
@ -58,6 +61,8 @@ void PSPSaveFileManager::checkPath(const Common::FSNode &dir) {
//it exists, so close it again. //it exists, so close it again.
sceIoDclose(fd); sceIoDclose(fd);
} }
PowerMan.endCriticalSection();
} }
#endif #endif

View file

@ -124,6 +124,12 @@ bool DefaultTimerManager::installTimerProc(TimerProc callback, int32 interval, v
slot->nextFireTimeMicro = interval % 1000; slot->nextFireTimeMicro = interval % 1000;
slot->next = 0; slot->next = 0;
// FIXME: It seems we do allow the client to add one callback multiple times over here,
// but "removeTimerProc" will remove *all* added instances. We should either prevent
// multiple additions of a timer proc OR we should change removeTimerProc to only remove
// a specific timer proc entry.
// Probably we can safely just allow a single addition of a specific function once
// and just update our Timer documentation accordingly.
insertPrioQueue(_head, slot); insertPrioQueue(_head, slot);
return true; return true;

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -31,7 +31,6 @@
#include "backends/vkeybd/virtual-keyboard-parser.h" #include "backends/vkeybd/virtual-keyboard-parser.h"
#include "backends/vkeybd/keycode-descriptions.h" #include "backends/vkeybd/keycode-descriptions.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/fs.h"
#include "common/unzip.h" #include "common/unzip.h"
#define KEY_START_CHAR ('[') #define KEY_START_CHAR ('[')
@ -77,50 +76,76 @@ void VirtualKeyboard::reset() {
_kbdGUI->reset(); _kbdGUI->reset();
} }
bool VirtualKeyboard::loadKeyboardPack(String packName) { bool VirtualKeyboard::openPack(const String &packName, const FSNode &node) {
if (node.getChild(packName + ".xml").exists()) {
_fileArchive = new FSDirectory(node, 1);
// uncompressed keyboard pack
if (!_parser->loadFile(node.getChild(packName + ".xml"))) {
delete _fileArchive;
_fileArchive = 0;
return false;
}
return true;
}
#ifdef USE_ZLIB
if (node.getChild(packName + ".zip").exists()) {
// compressed keyboard pack
_fileArchive = new ZipArchive(node.getChild(packName + ".zip"));
if (_fileArchive->hasFile(packName + ".xml")) {
if (!_parser->loadStream(_fileArchive->createReadStreamForMember(packName + ".xml"))) {
delete _fileArchive;
_fileArchive = 0;
return false;
}
} else {
warning("Could not find %s.xml file in %s.zip keyboard pack", packName.c_str(), packName.c_str());
delete _fileArchive;
_fileArchive = 0;
return false;
}
return true;
}
#endif
return false;
}
bool VirtualKeyboard::loadKeyboardPack(const String &packName) {
_kbdGUI->initSize(_system->getOverlayWidth(), _system->getOverlayHeight()); _kbdGUI->initSize(_system->getOverlayWidth(), _system->getOverlayHeight());
delete _fileArchive; delete _fileArchive;
_fileArchive = 0; _fileArchive = 0;
_loaded = false;
FSNode vkDir; bool opened = false;
if (ConfMan.hasKey("vkeybdpath")) if (ConfMan.hasKey("vkeybdpath"))
vkDir = FSNode(ConfMan.get("vkeybdpath")); opened = openPack(packName, FSNode(ConfMan.get("vkeybdpath")));
else if (ConfMan.hasKey("extrapath")) else if (ConfMan.hasKey("extrapath"))
vkDir = FSNode(ConfMan.get("extrapath")); opened = openPack(packName, FSNode(ConfMan.get("extrapath")));
else // use current directory
vkDir = FSNode(".");
if (vkDir.getChild(packName + ".xml").exists()) { // fallback to the current dir
_fileArchive = new FSDirectory(vkDir, 1); if (!opened)
opened = openPack(packName, FSNode("."));
// uncompressed keyboard pack
if (!_parser->loadFile(vkDir.getChild(packName + ".xml")))
return false;
} else if (vkDir.getChild(packName + ".zip").exists()) {
// compressed keyboard pack
#ifdef USE_ZLIB
_fileArchive = new ZipArchive(vkDir.getChild(packName + ".zip"));
if (_fileArchive->hasFile(packName + ".xml")) {
if (!_parser->loadStream(_fileArchive->createReadStreamForMember(packName + ".xml")))
return false;
} else {
warning("Could not find %s.xml file in %s.zip keyboard pack", packName.c_str(), packName.c_str());
return false;
}
#else
return false;
#endif
} else {
warning("Keyboard pack not found");
return false;
}
if (opened) {
_parser->setParseMode(VirtualKeyboardParser::kParseFull); _parser->setParseMode(VirtualKeyboardParser::kParseFull);
_loaded = _parser->parse(); _loaded = _parser->parse();
if (_loaded)
if (_loaded) {
printf("Keyboard pack '%s' loaded successfully!\n", packName.c_str()); printf("Keyboard pack '%s' loaded successfully!\n", packName.c_str());
} else {
warning("Error parsing the keyboard pack '%s'", packName.c_str());
delete _fileArchive;
_fileArchive = 0;
}
} else {
warning("Keyboard pack not found");
}
return _loaded; return _loaded;
} }

View file

@ -1,7 +1,7 @@
/* ScummVM - Graphic Adventure Engine /* Residual - A 3D game interpreter
* *
* ScummVM is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -37,6 +37,7 @@ class OSystem;
#include "common/keyboard.h" #include "common/keyboard.h"
#include "common/list.h" #include "common/list.h"
#include "common/str.h" #include "common/str.h"
#include "common/fs.h"
#include "backends/vkeybd/image-map.h" #include "backends/vkeybd/image-map.h"
#include "graphics/surface.h" #include "graphics/surface.h"
@ -190,7 +191,7 @@ public:
* searches for a compressed keyboard pack by looking for packName.zip. * searches for a compressed keyboard pack by looking for packName.zip.
* @param packName name of the keyboard pack * @param packName name of the keyboard pack
*/ */
bool loadKeyboardPack(String packName); bool loadKeyboardPack(const String &packName);
/** /**
* Shows the keyboard, starting an event loop that will intercept all * Shows the keyboard, starting an event loop that will intercept all
@ -232,6 +233,7 @@ protected:
VirtualKeyboardParser *_parser; VirtualKeyboardParser *_parser;
void reset(); void reset();
bool openPack(const String &packName, const FSNode &node);
void deleteEvents(); void deleteEvents();
bool checkModeResolutions(); bool checkModeResolutions();
void switchMode(Mode *newMode); void switchMode(Mode *newMode);

View file

@ -34,6 +34,9 @@
#include "gui/ThemeEngine.h" #include "gui/ThemeEngine.h"
#define DETECTOR_TESTING_HACK
#define UPGRADE_ALL_TARGETS_HACK
namespace Base { namespace Base {
#ifndef DISABLE_COMMAND_LINE #ifndef DISABLE_COMMAND_LINE
@ -235,6 +238,18 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_COMMAND('z', "list-games") DO_COMMAND('z', "list-games")
END_OPTION END_OPTION
#ifdef DETECTOR_TESTING_HACK
// HACK FIXME TODO: This command is intentionally *not* documented!
DO_LONG_COMMAND("test-detector")
END_OPTION
#endif
#ifdef UPGRADE_ALL_TARGETS_HACK
// HACK FIXME TODO: This command is intentionally *not* documented!
DO_LONG_COMMAND("upgrade-targets")
END_OPTION
#endif
DO_OPTION('c', "config") DO_OPTION('c', "config")
END_OPTION END_OPTION
@ -253,10 +268,13 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_OPTION_INT('m', "music-volume") DO_OPTION_INT('m', "music-volume")
END_OPTION END_OPTION
DO_OPTION('s', "sfx-volume") DO_OPTION('p', "path")
END_OPTION Common::FSNode path(option);
if (!path.exists()) {
DO_OPTION('r', "speech-volume") usage("Non-existent game path '%s'", option);
} else if (!path.isReadable()) {
usage("Non-readable game path '%s'", option);
}
END_OPTION END_OPTION
DO_OPTION('q', "language") DO_OPTION('q', "language")
@ -264,6 +282,15 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
usage("Unrecognized language '%s'", option); usage("Unrecognized language '%s'", option);
END_OPTION END_OPTION
DO_OPTION_INT('s', "sfx-volume")
END_OPTION
DO_OPTION_INT('r', "speech-volume")
END_OPTION
DO_LONG_OPTION_INT("cdrom")
END_OPTION
DO_LONG_OPTION_OPT("joystick", "0") DO_LONG_OPTION_OPT("joystick", "0")
settings["joystick_num"] = option; settings["joystick_num"] = option;
settings.erase("joystick"); settings.erase("joystick");
@ -275,24 +302,15 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_LONG_OPTION("soft-renderer") DO_LONG_OPTION("soft-renderer")
END_OPTION END_OPTION
DO_LONG_OPTION_BOOL("disable-sdl-parachute")
END_OPTION
DO_LONG_OPTION("engine-speed") DO_LONG_OPTION("engine-speed")
END_OPTION END_OPTION
DO_LONG_OPTION("gamma") DO_LONG_OPTION("gamma")
END_OPTION END_OPTION
DO_OPTION('p', "path")
Common::FSNode path(option);
if (!path.exists()) {
usage("Non-existent game path '%s'", option);
} else if (!path.isReadable()) {
usage("Non-readable game path '%s'", option);
}
END_OPTION
DO_LONG_OPTION_BOOL("disable-sdl-parachute")
END_OPTION
DO_LONG_OPTION("savepath") DO_LONG_OPTION("savepath")
Common::FSNode path(option); Common::FSNode path(option);
if (!path.exists()) { if (!path.exists()) {
@ -326,8 +344,15 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_LONG_COMMAND("list-themes") DO_LONG_COMMAND("list-themes")
END_OPTION END_OPTION
DO_LONG_OPTION("target-md5")
END_OPTION
DO_LONG_OPTION("text-speed") DO_LONG_OPTION("text-speed")
END_OPTION END_OPTION
#ifdef ENABLE_SCUMM
DO_LONG_OPTION_INT("dimuse-tempo")
END_OPTION
#endif
DO_LONG_OPTION("speech-mode") DO_LONG_OPTION("speech-mode")
END_OPTION END_OPTION
@ -414,6 +439,192 @@ static void listThemes() {
printf("%-14s %s\n", i->id.c_str(), i->name.c_str()); printf("%-14s %s\n", i->id.c_str(), i->name.c_str());
} }
#ifdef DETECTOR_TESTING_HACK
static void runDetectorTest() {
// HACK: The following code can be used to test the detection code of our
// engines. Basically, it loops over all targets, and calls the detector
// for the given path. It then prints out the result and also checks
// whether the result agrees with the settings of the target.
const Common::ConfigManager::DomainMap &domains = ConfMan.getGameDomains();
Common::ConfigManager::DomainMap::const_iterator iter = domains.begin();
int success = 0, failure = 0;
for (iter = domains.begin(); iter != domains.end(); ++iter) {
Common::String name(iter->_key);
Common::String gameid(iter->_value.get("gameid"));
Common::String path(iter->_value.get("path"));
printf("Looking at target '%s', gameid '%s', path '%s' ...\n",
name.c_str(), gameid.c_str(), path.c_str());
if (path.empty()) {
printf(" ... no path specified, skipping\n");
continue;
}
if (gameid.empty()) {
gameid = name;
}
Common::FSNode dir(path);
Common::FSList files;
if (!dir.getChildren(files, Common::FSNode::kListAll)) {
printf(" ... invalid path, skipping\n");
continue;
}
GameList candidates(EngineMan.detectGames(files));
bool gameidDiffers = false;
GameList::iterator x;
for (x = candidates.begin(); x != candidates.end(); ++x) {
gameidDiffers |= (strcasecmp(gameid.c_str(), x->gameid().c_str()) != 0);
}
if (candidates.empty()) {
printf(" FAILURE: No games detected\n");
failure++;
} else if (candidates.size() > 1) {
if (gameidDiffers) {
printf(" WARNING: Multiple games detected, some/all with wrong gameid\n");
} else {
printf(" WARNING: Multiple games detected, but all have matching gameid\n");
}
failure++;
} else if (gameidDiffers) {
printf(" FAILURE: Wrong gameid detected\n");
failure++;
} else {
printf(" SUCCESS: Game was detected correctly\n");
success++;
}
for (x = candidates.begin(); x != candidates.end(); ++x) {
printf(" gameid '%s', desc '%s', language '%s', platform '%s'\n",
x->gameid().c_str(),
x->description().c_str(),
Common::getLanguageCode(x->language()),
Common::getPlatformCode(x->platform()));
}
}
int total = domains.size();
printf("Detector test run: %d fail, %d success, %d skipped, out of %d\n",
failure, success, total - failure - success, total);
}
#endif
#ifdef UPGRADE_ALL_TARGETS_HACK
void upgradeTargets() {
// HACK: The following upgrades all your targets to the latest and
// greatest. Right now that means updating the guioptions and (optionally)
// also the game descriptions.
// Basically, it loops over all targets, and calls the detector for the
// given path. It then compares the result with the settings of the target.
// If the basics seem to match, it updates the guioptions.
printf("Upgrading all your existing targets\n");
Common::ConfigManager::DomainMap &domains = ConfMan.getGameDomains();
Common::ConfigManager::DomainMap::iterator iter = domains.begin();
for (iter = domains.begin(); iter != domains.end(); ++iter) {
Common::ConfigManager::Domain &dom = iter->_value;
Common::String name(iter->_key);
Common::String gameid(dom.get("gameid"));
Common::String path(dom.get("path"));
printf("Looking at target '%s', gameid '%s' ...\n",
name.c_str(), gameid.c_str());
if (path.empty()) {
printf(" ... no path specified, skipping\n");
continue;
}
if (gameid.empty()) {
gameid = name;
}
gameid.toLowercase(); // TODO: Is this paranoia? Maybe we should just assume all lowercase, always?
Common::FSNode dir(path);
Common::FSList files;
if (!dir.getChildren(files, Common::FSNode::kListAll)) {
printf(" ... invalid path, skipping\n");
continue;
}
Common::Language lang = Common::parseLanguage(dom.get("language"));
Common::Platform plat = Common::parsePlatform(dom.get("platform"));
Common::String desc(dom.get("description"));
GameList candidates(EngineMan.detectGames(files));
GameDescriptor *g = 0;
// We proceed as follows:
// * If detection failed to produce candidates, skip.
// * If there is a unique detector match, trust it.
// * If there are multiple match, run over them comparing gameid, language and platform.
// If we end up with a unique match, use it. Otherwise, skip.
if (candidates.size() == 0) {
printf(" ... failed to detect game, skipping\n");
continue;
}
if (candidates.size() > 1) {
// Scan over all candidates, check if there is a unique match for gameid, language and platform
GameList::iterator x;
int matchesFound = 0;
for (x = candidates.begin(); x != candidates.end(); ++x) {
if (x->gameid() == gameid && x->language() == lang && x->platform() == plat) {
matchesFound++;
g = &(*x);
}
}
if (matchesFound != 1) {
printf(" ... detected multiple games, could not establish unique match, skipping\n");
continue;
}
} else {
// Unique match -> use it
g = &candidates[0];
}
// At this point, g points to a GameDescriptor which we can use to update
// the target referred to by dom. We update several things
// Always set the gameid explicitly (in case of legacy targets)
dom["gameid"] = g->gameid();
// Always set the GUI options. The user should not modify them, and engines might
// gain more features over time, so we want to keep this list up-to-date.
if (g->contains("guioptions")) {
printf(" -> update guioptions to '%s'\n", (*g)["guioptions"].c_str());
dom["guioptions"] = (*g)["guioptions"];
} else if (dom.contains("guioptions")) {
dom.erase("guioptions");
}
// Update the language setting but only if none has been set yet.
if (lang == Common::UNK_LANG && g->language() != Common::UNK_LANG) {
printf(" -> set language to '%s'\n", Common::getLanguageCode(g->language()));
dom["language"] = (*g)["language"];
}
// Update the platform setting but only if none has been set yet.
if (plat == Common::kPlatformUnknown && g->platform() != Common::kPlatformUnknown) {
printf(" -> set platform to '%s'\n", Common::getPlatformCode(g->platform()));
dom["platform"] = (*g)["platform"];
}
// TODO: We could also update the description. But not everybody will want that.
// Esp. because for some games (e.g. the combined Zak/Loom FM-TOWNS demo etc.)
// ScummVM still generates an incorrect description string. So, the description
// should only be updated if the user explicitly requests this.
#if 0
if (desc != g->description()) {
printf(" -> update desc from '%s' to\n '%s' ?\n", desc.c_str(), g->description().c_str());
dom["description"] = (*g)["description"];
}
#endif
}
// Finally, save our changes to disk
ConfMan.flushToDisk();
}
#endif
#else // DISABLE_COMMAND_LINE #else // DISABLE_COMMAND_LINE
@ -449,6 +660,18 @@ bool processSettings(Common::String &command, Common::StringMap &settings) {
printf(HELP_STRING, s_appName); printf(HELP_STRING, s_appName);
return false; return false;
} }
#ifdef DETECTOR_TESTING_HACK
else if (command == "test-detector") {
runDetectorTest();
return false;
}
#endif
#ifdef UPGRADE_ALL_TARGETS_HACK
else if (command == "upgrade-targets") {
upgradeTargets();
return false;
}
#endif
#endif // DISABLE_COMMAND_LINE #endif // DISABLE_COMMAND_LINE

View file

@ -41,12 +41,16 @@
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/events.h" #include "common/events.h"
#include "common/EventRecorder.h"
#include "common/file.h" #include "common/file.h"
#include "common/fs.h" #include "common/fs.h"
#include "common/system.h" #include "common/system.h"
#include "gui/GuiManager.h" #include "gui/GuiManager.h"
#include "gui/message.h" #include "gui/message.h"
#include "sound/audiocd.h"
#include "backends/keymapper/keymapper.h" #include "backends/keymapper/keymapper.h"
#if defined(_WIN32_WCE) #if defined(_WIN32_WCE)
@ -168,9 +172,9 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const
// Set the window caption to the game name // Set the window caption to the game name
Common::String caption(ConfMan.get("description")); Common::String caption(ConfMan.get("description"));
Common::String desc = EngineMan.findGame(ConfMan.get("gameid")).description(); if (caption.empty()) {
if (caption.empty() && !desc.empty()) caption = EngineMan.findGame(ConfMan.get("gameid")).description();
caption = desc; }
if (caption.empty()) if (caption.empty())
caption = ConfMan.getActiveDomainName(); // Use the domain (=target) name caption = ConfMan.getActiveDomainName(); // Use the domain (=target) name
if (!caption.empty()) { if (!caption.empty()) {
@ -341,6 +345,14 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
// 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();
// Directly after initializing the event manager, we will initialize our
// event recorder.
//
// TODO: This is just to match the current behavior, when we further extend
// our event recorder, we might do this at another place. Or even change
// the whole API for that ;-).
g_eventRec.init();
// Now as the event manager is created, setup the keymapper // Now as the event manager is created, setup the keymapper
setupKeymapper(system); setupKeymapper(system);
@ -368,11 +380,15 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
} }
// Quit unless an error occurred, or Return to launcher was requested // Quit unless an error occurred, or Return to launcher was requested
#ifndef FORCE_RTL
if (result == 0 && !g_system->getEventManager()->shouldRTL()) if (result == 0 && !g_system->getEventManager()->shouldRTL())
break; break;
#endif
// Reset RTL flag in case we want to load another engine // Reset RTL flag in case we want to load another engine
g_system->getEventManager()->resetRTL(); g_system->getEventManager()->resetRTL();
#ifdef FORCE_RTL
g_system->getEventManager()->resetQuit();
#endif
// Discard any command line options. It's unlikely that the user // Discard any command line options. It's unlikely that the user
// wanted to apply them to *all* games ever launched. // wanted to apply them to *all* games ever launched.
@ -389,6 +405,15 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
warning("Could not find any engine capable of running the selected game"); warning("Could not find any engine capable of running the selected game");
} }
// We will destroy the AudioCDManager singleton here to save some memory.
// This will not make the CD audio stop, one would have to enable this:
//AudioCD.stop();
// but the engine is responsible for stopping CD playback anyway and
// this way we catch engines not doing it properly. For some more
// information about why AudioCDManager::destroy does not stop the CD
// playback read the FIXME in sound/audiocd.h
Audio::AudioCDManager::destroy();
// reset the graphics to default // reset the graphics to default
setupGraphics(system); setupGraphics(system);
launcherDialog(); launcherDialog();

View file

@ -28,6 +28,9 @@
#include "common/sys.h" #include "common/sys.h"
//
// The residual main entry point, to be invoked by ports
//
extern "C" int residual_main(int argc, const char *const argv[]); extern "C" int residual_main(int argc, const char *const argv[]);
#endif #endif

View file

@ -23,9 +23,39 @@
* *
*/ */
#include "common/sys.h"
#include "base/internal_version.h" #include "base/internal_version.h"
#include "base/version.h" #include "base/version.h"
/*
* Version string and build date string. These can be used by anything that
* wants to display this information to the user (e.g. about dialog).
*
* Note: it would be very nice if we could instead of (or in addition to) the
* build date present a date which corresponds to the date our source files
* were last changed. To understand the difference, imagine that a user
* makes a checkout on January 1, then after a week compiles it
* (e.g. after doing a 'make clean'). The build date then will say January 8
* even though the files were last changed on January 1.
*
* Another problem is that __DATE__/__TIME__ depend on the local time zone.
*
* It's clear that such a "last changed" date would be much more useful to us
* for feedback purposes. After all, when somebody files a bug report, we
* don't care about the build date, we want to know which date their checkout
* was made.
*
* So, how could we implement this? At least on unix systems, a special script
* could do it. Basically, that script could parse the output of "svn info" or
* "svnversion" to determine the revision of the checkout, and insert that
* information somehow into the build process (e.g. by generating a tiny
* header file, analog to internal_version.h, maybe called svn_rev.h or so.)
*
* Drawback: This only works on systems which can run suitable scripts as part
* of the build proces (so I guess Visual C++ would be out of the game here?
* I don't know VC enough to be sure). And of course it must be robust enough
* to properly work in exports (i.e. release tar balls etc.).
*/
const char *gResidualVersion = RESIDUAL_VERSION; const char *gResidualVersion = RESIDUAL_VERSION;
const char *gResidualBuildDate = __DATE__ " " __TIME__; const char *gResidualBuildDate = __DATE__ " " __TIME__;
const char *gResidualVersionDate = RESIDUAL_VERSION " (" __DATE__ " " __TIME__ ")"; const char *gResidualVersionDate = RESIDUAL_VERSION " (" __DATE__ " " __TIME__ ")";
@ -52,6 +82,14 @@ const char *gResidualFeatures = ""
"MP3 " "MP3 "
#endif #endif
#ifdef USE_ALSA
"ALSA "
#endif
#ifdef USE_RGB_COLOR
"RGB "
#endif
#ifdef USE_ZLIB #ifdef USE_ZLIB
"zLib " "zLib "
#endif #endif

View file

@ -3,7 +3,7 @@
* Residual is the legal property of its developers, whose names * Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS * are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution. * file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2

138
common/EventDispatcher.cpp Normal file
View file

@ -0,0 +1,138 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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 "common/events.h"
namespace Common {
EventDispatcher::EventDispatcher() : _mapper(0) {
}
EventDispatcher::~EventDispatcher() {
for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) {
if (i->autoFree)
delete i->source;
}
for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) {
if (i->autoFree)
delete i->observer;
}
delete _mapper;
_mapper = 0;
}
void EventDispatcher::dispatch() {
Common::Event event;
for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) {
const bool allowMapping = i->source->allowMapping();
while (i->source->pollEvent(event)) {
// We only try to process the events via the setup event mapper, when
// we have a setup mapper and when the event source allows mapping.
if (_mapper && allowMapping) {
if (_mapper->notifyEvent(event)) {
// We allow the event mapper to create multiple events, when
// eating an event.
while (_mapper->pollEvent(event))
dispatchEvent(event);
// Try getting another event from the current EventSource.
continue;
}
}
dispatchEvent(event);
}
}
}
void EventDispatcher::registerMapper(EventMapper *mapper) {
if (_mapper)
delete _mapper;
_mapper = mapper;
}
void EventDispatcher::registerSource(EventSource *source, bool autoFree) {
SourceEntry newEntry;
newEntry.source = source;
newEntry.autoFree = autoFree;
_sources.push_back(newEntry);
}
void EventDispatcher::unregisterSource(EventSource *source) {
for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) {
if (i->source == source) {
if (i->autoFree)
delete source;
_sources.erase(i);
return;
}
}
}
void EventDispatcher::registerObserver(EventObserver *obs, uint priority, bool autoFree) {
ObserverEntry newEntry;
newEntry.observer = obs;
newEntry.priority = priority;
newEntry.autoFree = autoFree;
for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) {
if (i->priority < priority) {
_observers.insert(i, newEntry);
return;
}
}
_observers.push_back(newEntry);
}
void EventDispatcher::unregisterObserver(EventObserver *obs) {
for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) {
if (i->observer == obs) {
if (i->autoFree)
delete obs;
_observers.erase(i);
return;
}
}
}
void EventDispatcher::dispatchEvent(const Event &event) {
for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) {
if (i->observer->notifyEvent(event))
break;
}
}
} // end of namespace Common

367
common/EventRecorder.cpp Normal file
View file

@ -0,0 +1,367 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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 "common/EventRecorder.h"
#include "common/config-manager.h"
DECLARE_SINGLETON(Common::EventRecorder);
namespace Common {
#define RECORD_SIGNATURE 0x54455354
#define RECORD_VERSION 1
void readRecord(Common::InSaveFile *inFile, uint32 &diff, Common::Event &event) {
diff = inFile->readUint32LE();
event.type = (Common::EventType)inFile->readUint32LE();
switch (event.type) {
case Common::EVENT_KEYDOWN:
case Common::EVENT_KEYUP:
event.kbd.keycode = (Common::KeyCode)inFile->readSint32LE();
event.kbd.ascii = inFile->readUint16LE();
event.kbd.flags = inFile->readByte();
break;
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
event.mouse.x = inFile->readSint16LE();
event.mouse.y = inFile->readSint16LE();
break;
default:
break;
}
}
void writeRecord(Common::OutSaveFile *outFile, uint32 diff, const Common::Event &event) {
outFile->writeUint32LE(diff);
outFile->writeUint32LE((uint32)event.type);
switch (event.type) {
case Common::EVENT_KEYDOWN:
case Common::EVENT_KEYUP:
outFile->writeSint32LE(event.kbd.keycode);
outFile->writeUint16LE(event.kbd.ascii);
outFile->writeByte(event.kbd.flags);
break;
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
outFile->writeSint16LE(event.mouse.x);
outFile->writeSint16LE(event.mouse.y);
break;
default:
break;
}
}
EventRecorder::EventRecorder() {
_recordFile = NULL;
_recordTimeFile = NULL;
_playbackFile = NULL;
_playbackTimeFile = NULL;
_timeMutex = g_system->createMutex();
_recorderMutex = g_system->createMutex();
_eventCount = 0;
_lastEventCount = 0;
_lastMillis = 0;
_recordMode = kPassthrough;
}
EventRecorder::~EventRecorder() {
deinit();
}
void EventRecorder::init() {
Common::String recordModeString = ConfMan.get("record_mode");
if (recordModeString.compareToIgnoreCase("record") == 0) {
_recordMode = kRecorderRecord;
} else {
if (recordModeString.compareToIgnoreCase("playback") == 0) {
_recordMode = kRecorderPlayback;
} else {
_recordMode = kPassthrough;
}
}
_recordFileName = ConfMan.get("record_file_name");
if (_recordFileName.empty()) {
_recordFileName = "record.bin";
}
_recordTempFileName = ConfMan.get("record_temp_file_name");
if (_recordTempFileName.empty()) {
_recordTempFileName = "record.tmp";
}
_recordTimeFileName = ConfMan.get("record_time_file_name");
if (_recordTimeFileName.empty()) {
_recordTimeFileName = "record.time";
}
// recorder stuff
if (_recordMode == kRecorderRecord) {
_recordCount = 0;
_recordTimeCount = 0;
_recordFile = g_system->getSavefileManager()->openForSaving(_recordTempFileName);
_recordTimeFile = g_system->getSavefileManager()->openForSaving(_recordTimeFileName);
_recordSubtitles = ConfMan.getBool("subtitles");
}
uint32 sign;
uint32 version;
uint32 randomSourceCount;
if (_recordMode == kRecorderPlayback) {
_playbackCount = 0;
_playbackTimeCount = 0;
_playbackFile = g_system->getSavefileManager()->openForLoading(_recordFileName);
_playbackTimeFile = g_system->getSavefileManager()->openForLoading(_recordTimeFileName);
if (!_playbackFile) {
warning("Cannot open playback file %s. Playback was switched off", _recordFileName.c_str());
_recordMode = kPassthrough;
}
if (!_playbackTimeFile) {
warning("Cannot open playback time file %s. Playback was switched off", _recordTimeFileName.c_str());
_recordMode = kPassthrough;
}
}
if (_recordMode == kRecorderPlayback) {
sign = _playbackFile->readUint32LE();
if (sign != RECORD_SIGNATURE) {
error("Unknown record file signature");
}
version = _playbackFile->readUint32LE();
// conf vars
ConfMan.setBool("subtitles", _playbackFile->readByte() != 0);
_recordCount = _playbackFile->readUint32LE();
_recordTimeCount = _playbackFile->readUint32LE();
randomSourceCount = _playbackFile->readUint32LE();
for (uint i = 0; i < randomSourceCount; ++i) {
RandomSourceRecord rec;
rec.name = "";
uint32 sLen = _playbackFile->readUint32LE();
for (uint j = 0; j < sLen; ++j) {
char c = _playbackFile->readSByte();
rec.name += c;
}
rec.seed = _playbackFile->readUint32LE();
_randomSourceRecords.push_back(rec);
}
_hasPlaybackEvent = false;
}
g_system->getEventManager()->getEventDispatcher()->registerSource(this, false);
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 1, false);
}
void EventRecorder::deinit() {
g_system->getEventManager()->getEventDispatcher()->unregisterSource(this);
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
g_system->lockMutex(_timeMutex);
g_system->lockMutex(_recorderMutex);
_recordMode = kPassthrough;
g_system->unlockMutex(_timeMutex);
g_system->unlockMutex(_recorderMutex);
if (_playbackFile != NULL) {
delete _playbackFile;
}
if (_playbackTimeFile != NULL) {
delete _playbackTimeFile;
}
if (_recordFile != NULL) {
_recordFile->finalize();
delete _recordFile;
_recordTimeFile->finalize();
delete _recordTimeFile;
_playbackFile = g_system->getSavefileManager()->openForLoading(_recordTempFileName);
assert(_playbackFile);
_recordFile = g_system->getSavefileManager()->openForSaving(_recordFileName);
_recordFile->writeUint32LE(RECORD_SIGNATURE);
_recordFile->writeUint32LE(RECORD_VERSION);
// conf vars
_recordFile->writeByte(_recordSubtitles ? 1 : 0);
_recordFile->writeUint32LE(_recordCount);
_recordFile->writeUint32LE(_recordTimeCount);
_recordFile->writeUint32LE(_randomSourceRecords.size());
for (uint i = 0; i < _randomSourceRecords.size(); ++i) {
_recordFile->writeUint32LE(_randomSourceRecords[i].name.size());
_recordFile->writeString(_randomSourceRecords[i].name);
_recordFile->writeUint32LE(_randomSourceRecords[i].seed);
}
for (uint i = 0; i < _recordCount; ++i) {
uint32 tempDiff;
Common::Event tempEvent;
readRecord(_playbackFile, tempDiff, tempEvent);
writeRecord(_recordFile, tempDiff, tempEvent);
}
_recordFile->finalize();
delete _recordFile;
delete _playbackFile;
//TODO: remove recordTempFileName'ed file
}
g_system->deleteMutex(_timeMutex);
g_system->deleteMutex(_recorderMutex);
}
void EventRecorder::registerRandomSource(Common::RandomSource &rnd, const char *name) {
if (_recordMode == kRecorderRecord) {
RandomSourceRecord rec;
rec.name = name;
rec.seed = rnd.getSeed();
_randomSourceRecords.push_back(rec);
}
if (_recordMode == kRecorderPlayback) {
for (uint i = 0; i < _randomSourceRecords.size(); ++i) {
if (_randomSourceRecords[i].name == name) {
rnd.setSeed(_randomSourceRecords[i].seed);
_randomSourceRecords.remove_at(i);
break;
}
}
}
}
void EventRecorder::processMillis(uint32 &millis) {
uint32 d;
if (_recordMode == kPassthrough) {
return;
}
g_system->lockMutex(_timeMutex);
if (_recordMode == kRecorderRecord) {
//Simple RLE compression
d = millis - _lastMillis;
if (d >= 0xff) {
_recordTimeFile->writeByte(0xff);
_recordTimeFile->writeUint32LE(d);
} else {
_recordTimeFile->writeByte(d);
}
_recordTimeCount++;
}
if (_recordMode == kRecorderPlayback) {
if (_recordTimeCount > _playbackTimeCount) {
d = _playbackTimeFile->readByte();
if (d == 0xff) {
d = _playbackTimeFile->readUint32LE();
}
millis = _lastMillis + d;
_playbackTimeCount++;
}
}
_lastMillis = millis;
g_system->unlockMutex(_timeMutex);
}
bool EventRecorder::notifyEvent(const Common::Event &ev) {
if (_recordMode != kRecorderRecord)
return false;
Common::StackLock lock(_recorderMutex);
++_eventCount;
writeRecord(_recordFile, _eventCount - _lastEventCount, ev);
_recordCount++;
_lastEventCount = _eventCount;
return false;
}
bool EventRecorder::pollEvent(Common::Event &ev) {
if (_recordMode != kRecorderPlayback)
return false;
Common::StackLock lock(_recorderMutex);
++_eventCount;
if (!_hasPlaybackEvent) {
if (_recordCount > _playbackCount) {
readRecord(_playbackFile, const_cast<uint32&>(_playbackDiff), _playbackEvent);
_playbackCount++;
_hasPlaybackEvent = true;
}
}
if (_hasPlaybackEvent) {
if (_playbackDiff <= (_eventCount - _lastEventCount)) {
switch (_playbackEvent.type) {
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
g_system->warpMouse(_playbackEvent.mouse.x, _playbackEvent.mouse.y);
break;
default:
break;
}
ev = _playbackEvent;
_hasPlaybackEvent = false;
_lastEventCount = _eventCount;
return true;
}
}
return false;
}
} // end of namespace Common

106
common/EventRecorder.h Normal file
View file

@ -0,0 +1,106 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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_EVENTRECORDER_H
#define COMMON_EVENTRECORDER_H
#include "common/sys.h"
#include "common/events.h"
#include "common/singleton.h"
#include "common/savefile.h"
#include "common/mutex.h"
#include "common/array.h"
#define g_eventRec (Common::EventRecorder::instance())
namespace Common {
/**
* Our generic event recorder.
*
* TODO: Add more documentation.
*/
class EventRecorder : private EventSource, private EventObserver, public Singleton<EventRecorder> {
friend class Common::Singleton<SingletonBaseType>;
EventRecorder();
~EventRecorder();
public:
void init();
void deinit();
/** Register random source so it can be serialized in game test purposes */
void registerRandomSource(Common::RandomSource &rnd, const char *name);
/** TODO: Add documentation, this is only used by the backend */
void processMillis(uint32 &millis);
private:
bool notifyEvent(const Common::Event &ev);
bool pollEvent(Common::Event &ev);
bool allowMapping() const { return false; }
class RandomSourceRecord {
public:
Common::String name;
uint32 seed;
};
Common::Array<RandomSourceRecord> _randomSourceRecords;
bool _recordSubtitles;
volatile uint32 _recordCount;
volatile uint32 _lastRecordEvent;
volatile uint32 _recordTimeCount;
Common::OutSaveFile *_recordFile;
Common::OutSaveFile *_recordTimeFile;
Common::MutexRef _timeMutex;
Common::MutexRef _recorderMutex;
volatile uint32 _lastMillis;
volatile uint32 _playbackCount;
volatile uint32 _playbackDiff;
volatile bool _hasPlaybackEvent;
volatile uint32 _playbackTimeCount;
Common::Event _playbackEvent;
Common::InSaveFile *_playbackFile;
Common::InSaveFile *_playbackTimeFile;
volatile uint32 _eventCount;
volatile uint32 _lastEventCount;
enum RecordMode {
kPassthrough = 0,
kRecorderRecord = 1,
kRecorderPlayback = 2
};
volatile RecordMode _recordMode;
Common::String _recordFileName;
Common::String _recordTempFileName;
Common::String _recordTimeFileName;
};
} // end of namespace Common
#endif

View file

@ -56,7 +56,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern)
ArchiveMemberList::iterator it = allNames.begin(); ArchiveMemberList::iterator it = allNames.begin();
for ( ; it != allNames.end(); ++it) { for ( ; it != allNames.end(); ++it) {
if ((*it)->getName().matchString(lowercasePattern, true)) { if ((*it)->getName().matchString(lowercasePattern, false, true)) {
list.push_back(*it); list.push_back(*it);
matches++; matches++;
} }
@ -123,6 +123,55 @@ void SearchSet::addDirectory(const String &name, const FSNode &dir, int priority
add(name, new FSDirectory(dir, depth, flat), priority); add(name, new FSDirectory(dir, depth, flat), priority);
} }
void SearchSet::addSubDirectoriesMatching(const FSNode &directory, String origPattern, bool ignoreCase, int priority) {
FSList subDirs;
if (!directory.getChildren(subDirs))
return;
String nextPattern, pattern;
String::const_iterator sep = Common::find(origPattern.begin(), origPattern.end(), '/');
if (sep != origPattern.end()) {
pattern = String(origPattern.begin(), sep);
++sep;
if (sep != origPattern.end())
nextPattern = String(sep, origPattern.end());
}
else {
pattern = origPattern;
}
// TODO: The code we have for displaying all matches, which vary only in case, might
// be a bit overhead, but as long as we want to display all useful information to the
// user we will need to keep track of all directory names added so far. We might
// want to reconsider this though.
typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> MatchList;
MatchList multipleMatches;
MatchList::iterator matchIter;
for (FSList::const_iterator i = subDirs.begin(); i != subDirs.end(); ++i) {
String name = i->getName();
if (Common::matchString(name.c_str(), pattern.c_str(), ignoreCase)) {
matchIter = multipleMatches.find(name);
if (matchIter == multipleMatches.end()) {
multipleMatches[name] = true;
} else {
if (matchIter->_value) {
warning("Clash in case for match of pattern \"%s\" found in directory \"%s\": \"%s\"", pattern.c_str(), directory.getPath().c_str(), matchIter->_key.c_str());
matchIter->_value = false;
}
warning("Clash in case for match of pattern \"%s\" found in directory \"%s\": \"%s\"", pattern.c_str(), directory.getPath().c_str(), name.c_str());
}
if (nextPattern.empty())
addDirectory(name, *i, priority);
else
addSubDirectoriesMatching(*i, nextPattern, ignoreCase, priority);
}
}
}
void SearchSet::remove(const String &name) { void SearchSet::remove(const String &name) {
ArchiveNodeList::iterator it = find(name); ArchiveNodeList::iterator it = find(name);

View file

@ -168,6 +168,52 @@ public:
*/ */
void addDirectory(const String &name, const FSNode &directory, int priority = 0, int depth = 1, bool flat = false); void addDirectory(const String &name, const FSNode &directory, int priority = 0, int depth = 1, bool flat = false);
/**
* Create and add a sub directory by name (caseless).
*
* It is also possible to add sub directories of sub directories (of any depth) with this function.
* The path seperator for this case is SLASH for *all* systems.
*
* An example would be:
*
* "game/itedata"
*
* In this example the code would first try to search for all directories matching
* "game" (case insensitive) in the path "directory" first and search through all
* of the matches for "itedata" (case insensitive too).
*
* Note that it will add *all* matches found!
*
* Even though this method is currently implemented via addSubDirectoriesMatching it is not safe
* to assume that this method is using anything other than a simple case insensitive compare.
* Thus do not use any tokens like '*' or '?' in the "caselessName" parameter of this function!
*/
void addSubDirectoryMatching(const FSNode &directory, const String &caselessName, int priority = 0) {
addSubDirectoriesMatching(directory, caselessName, true, priority);
}
/**
* Create and add sub directories by pattern.
*
* It is also possible to add sub directories of sub directories (of any depth) with this function.
* The path seperator for this case is SLASH for *all* systems.
*
* An example would be:
*
* "game/itedata"
*
* In this example the code would first try to search for all directories matching
* "game" in the path "directory" first and search through all of the matches for
* "itedata". If "ingoreCase" is set to true, the code would do a case insensitive
* match, otherwise it is doing a case sensitive match.
*
* This method works of course also with tokens. For a list of available tokens
* see the documentation for Common::matchString.
*
* @see Common::matchString
*/
void addSubDirectoriesMatching(const FSNode &directory, String origPattern, bool ignoreCase, int priority = 0);
/** /**
* Remove an archive from the searchable set. * Remove an archive from the searchable set.
*/ */

View file

@ -222,7 +222,7 @@ public:
T *old_storage = _storage; T *old_storage = _storage;
_capacity = newCapacity; _capacity = newCapacity;
_storage = new T[newCapacity](); _storage = new T[newCapacity];
assert(_storage); assert(_storage);
if (old_storage) { if (old_storage) {
@ -273,7 +273,7 @@ protected:
// If there is not enough space, allocate more and // If there is not enough space, allocate more and
// copy old elements over. // copy old elements over.
uint newCapacity = roundUpCapacity(_size + n); uint newCapacity = roundUpCapacity(_size + n);
newStorage = new T[newCapacity](); newStorage = new T[newCapacity];
assert(newStorage); assert(newStorage);
copy(_storage, _storage + idx, newStorage); copy(_storage, _storage + idx, newStorage);
pos = newStorage + idx; pos = newStorage + idx;

View file

@ -26,10 +26,8 @@
#include "common/config-file.h" #include "common/config-file.h"
#include "common/file.h" #include "common/file.h"
#include "common/savefile.h" #include "common/savefile.h"
#include "common/util.h"
#include "common/debug.h"
#include "common/system.h" #include "common/system.h"
#include "common/util.h"
#define MAXLINELEN 256 #define MAXLINELEN 256

View file

@ -132,10 +132,10 @@ public:
// //
// Some additional convenience accessors. // Some additional convenience accessors.
// //
int getInt(const String &key, const String &domName = String::emptyString) const; int getInt(const String &key, const String &domName = String()) const;
bool getBool(const String &key, const String &domName = String::emptyString) const; bool getBool(const String &key, const String &domName = String()) const;
void setInt(const String &key, int value, const String &domName = String::emptyString); void setInt(const String &key, int value, const String &domName = String());
void setBool(const String &key, bool value, const String &domName = String::emptyString); void setBool(const String &key, bool value, const String &domName = String());
void registerDefault(const String &key, const String &value); void registerDefault(const String &key, const String &value);

View file

@ -154,7 +154,14 @@ static void debugHelper(const char *s, va_list va, bool caret = true) {
char buf[STRINGBUFLEN]; char buf[STRINGBUFLEN];
vsnprintf(in_buf, STRINGBUFLEN, s, va); vsnprintf(in_buf, STRINGBUFLEN, s, va);
// Next, give the active engine (if any) a chance to augment the message,
// but only if not used from debugN.
if (g_engine && caret) {
g_engine->errorString(in_buf, buf, STRINGBUFLEN);
} else {
strncpy(buf, in_buf, STRINGBUFLEN); strncpy(buf, in_buf, STRINGBUFLEN);
}
buf[STRINGBUFLEN-1] = '\0';
if (caret) { if (caret) {
buf[STRINGBUFLEN-2] = '\0'; buf[STRINGBUFLEN-2] = '\0';

View file

@ -28,28 +28,115 @@
#include "common/sys.h" #include "common/sys.h"
// /**
// Endian conversion functions, macros etc., follow from here! * \file endian.h
// * Endian conversion and byteswap conversion functions or macros
*
* SWAP_BYTES_??(a) - inverse byte order
* SWAP_CONSTANT_??(a) - inverse byte order, implemented as macro.
* Use with compiletime-constants only, the result will be a compiletime-constant aswell.
* Unlike most other functions these can be used for eg. switch-case labels
*
* READ_UINT??(a) - read native value from pointer a
* READ_??_UINT??(a) - read LE/BE value from pointer a and convert it to native
* WRITE_??_UINT??(a, v) - write native value v to pointer a with LE/BE encoding
* TO_??_??(a) - convert native value v to LE/BE
* FROM_??_??(a) - convert LE/BE value v to native
* CONSTANT_??_??(a) - convert LE/BE value v to native, implemented as macro.
* Use with compiletime-constants only, the result will be a compiletime-constant aswell.
* Unlike most other functions these can be used for eg. switch-case labels
*/
// Sanity check
#if !defined(SYSTEM_LITTLE_ENDIAN) && !defined(SYSTEM_BIG_ENDIAN)
# error No endianness defined
#endif
#define SWAP_CONSTANT_32(a) \
((uint32)((((a) >> 24) & 0x00FF) | \
(((a) >> 8) & 0xFF00) | \
(((a) & 0xFF00) << 8) | \
(((a) & 0x00FF) << 24) ))
#define SWAP_CONSTANT_16(a) \
((uint16)((((a) >> 8) & 0x00FF) | \
(((a) << 8) & 0xFF00) ))
/** /**
* Swap the bytes in a 32 bit word in order to convert LE encoded data to BE * Swap the bytes in a 32 bit word in order to convert LE encoded data to BE
* and vice versa. * and vice versa.
*/ */
FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
return ((a >> 24) & 0x000000FF) | // machine/compiler-specific variants come first, fallback last
((a >> 8) & 0x0000FF00) |
((a << 8) & 0x00FF0000) | // Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does)
((a << 24) & 0xFF000000); #if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2))
FORCEINLINE uint32 SWAP_BYTES_32(const uint32 a) {
if (__builtin_constant_p(a)) {
return SWAP_CONSTANT_32(a);
} else {
uint32 result;
# if defined(__psp__)
// use special allegrex instruction
__asm__ ("wsbw %0,%1" : "=r" (result) : "r" (a));
# else
__asm__ ("wsbh %0,%1\n"
"rotr %0,%0,16" : "=r" (result) : "r" (a));
# endif
return result;
} }
}
// Test for GCC >= 4.3.0 as this version added the bswap builtin
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
return __builtin_bswap32(a);
}
// test for MSVC 7 or newer
#elif defined(_MSC_VER) && _MSC_VER >= 1300
FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
return _byteswap_ulong(a);
}
// generic fallback
#else
inline uint32 SWAP_BYTES_32(uint32 a) {
const uint16 low = (uint16)a, high = (uint16)(a >> 16);
return ((uint32)(uint16)((low >> 8) | (low << 8)) << 16)
| (uint16)((high >> 8) | (high << 8));
}
#endif
/** /**
* Swap the bytes in a 16 bit word in order to convert LE encoded data to BE * Swap the bytes in a 16 bit word in order to convert LE encoded data to BE
* and vice versa. * and vice versa.
*/ */
FORCEINLINE uint16 SWAP_BYTES_16(uint16 a) {
return ((a >> 8) & 0x00FF) + ((a << 8) & 0xFF00); // compilerspecific variants come first, fallback last
// Test for GCC and if the target has the MIPS rel.2 instructions (we know the psp does)
#if defined(__GNUC__) && (defined(__psp__) || defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS64R2))
FORCEINLINE uint16 SWAP_BYTES_16(const uint16 a) {
if (__builtin_constant_p(a)) {
return SWAP_CONSTANT_16(a);
} else {
uint16 result;
__asm__ ("wsbh %0,%1" : "=r" (result) : "r" (a));
return result;
} }
}
#else
inline uint16 SWAP_BYTES_16(const uint16 a) {
return (a >> 8) | (a << 8);
}
#endif
/** /**
@ -70,25 +157,119 @@ FORCEINLINE uint16 SWAP_BYTES_16(uint16 a) {
* For the latter systems we provide the INVERSE_MKID override. * For the latter systems we provide the INVERSE_MKID override.
*/ */
#if defined(INVERSE_MKID) #if defined(INVERSE_MKID)
#define MKID_BE(a) ((uint32) \ #define MKID_BE(a) SWAP_CONSTANT_32(a)
(((a) >> 24) & 0x000000FF) | \
(((a) >> 8) & 0x0000FF00) | \
(((a) << 8) & 0x00FF0000) | \
(((a) << 24) & 0xFF000000))
#else #else
# define MKID_BE(a) ((uint32)(a)) # define MKID_BE(a) ((uint32)(a))
#endif #endif
// Functions for reading/writing native Integers,
// this transparently handles the need for alignment
#if !defined(SYSTEM_NEED_ALIGNMENT)
FORCEINLINE uint16 READ_UINT16(const void *ptr) {
return *(const uint16 *)(ptr);
}
FORCEINLINE uint32 READ_UINT32(const void *ptr) {
return *(const uint32 *)(ptr);
}
FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
*(uint16 *)(ptr) = value;
}
FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
*(uint32 *)(ptr) = value;
}
// test for GCC >= 4.0. these implementations will automatically use CPU-specific
// instructions for unaligned data when they are available (eg. MIPS)
#elif defined(__GNUC__) && (__GNUC__ >= 4)
FORCEINLINE uint16 READ_UINT16(const void *ptr) {
struct Unaligned16 { uint16 val; } __attribute__ ((__packed__));
return ((const Unaligned16 *)ptr)->val;
}
FORCEINLINE uint32 READ_UINT32(const void *ptr) {
struct Unaligned32 { uint32 val; } __attribute__ ((__packed__));
return ((const Unaligned32 *)ptr)->val;
}
FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
struct Unaligned16 { uint16 val; } __attribute__ ((__packed__));
((Unaligned16 *)ptr)->val = value;
}
FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
struct Unaligned32 { uint32 val; } __attribute__ ((__packed__));
((Unaligned32 *)ptr)->val = value;
}
// use software fallback by loading each byte explicitely
#else
# if defined(SYSTEM_LITTLE_ENDIAN) # if defined(SYSTEM_LITTLE_ENDIAN)
#define READ_UINT16(a) READ_LE_UINT16(a) inline uint16 READ_UINT16(const void *ptr) {
#define READ_UINT32(a) READ_LE_UINT32(a) const uint8 *b = (const uint8 *)ptr;
return (b[1] << 8) | b[0];
}
inline uint32 READ_UINT32(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
}
inline void WRITE_UINT16(void *ptr, uint16 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 0);
b[1] = (uint8)(value >> 8);
}
inline void WRITE_UINT32(void *ptr, uint32 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 0);
b[1] = (uint8)(value >> 8);
b[2] = (uint8)(value >> 16);
b[3] = (uint8)(value >> 24);
}
#define WRITE_UINT16(a, v) WRITE_LE_UINT16(a, v) # elif defined(SYSTEM_BIG_ENDIAN)
#define WRITE_UINT32(a, v) WRITE_LE_UINT32(a, v)
inline uint16 READ_UINT16(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[0] << 8) | b[1];
}
inline uint32 READ_UINT32(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
}
inline void WRITE_UINT16(void *ptr, uint16 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 8);
b[1] = (uint8)(value >> 0);
}
inline void WRITE_UINT32(void *ptr, uint32 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 24);
b[1] = (uint8)(value >> 16);
b[2] = (uint8)(value >> 8);
b[3] = (uint8)(value >> 0);
}
# endif
#endif
// Map Funtions for reading/writing BE/LE integers depending on native endianess
#if defined(SYSTEM_LITTLE_ENDIAN)
#define READ_LE_UINT16(a) READ_UINT16(a)
#define READ_LE_UINT32(a) READ_UINT32(a)
#define WRITE_LE_UINT16(a, v) WRITE_UINT16(a, v)
#define WRITE_LE_UINT32(a, v) WRITE_UINT32(a, v)
#define FROM_LE_32(a) ((uint32)(a)) #define FROM_LE_32(a) ((uint32)(a))
#define FROM_LE_16(a) ((uint16)(a)) #define FROM_LE_16(a) ((uint16)(a))
@ -102,16 +283,61 @@ FORCEINLINE uint16 SWAP_BYTES_16(uint16 a) {
#define TO_BE_32(a) SWAP_BYTES_32(a) #define TO_BE_32(a) SWAP_BYTES_32(a)
#define TO_BE_16(a) SWAP_BYTES_16(a) #define TO_BE_16(a) SWAP_BYTES_16(a)
#define CONSTANT_LE_32(a) ((uint32)(a))
#define CONSTANT_LE_16(a) ((uint16)(a))
#define CONSTANT_BE_32(a) SWAP_CONSTANT_32(a)
#define CONSTANT_BE_16(a) SWAP_CONSTANT_16(a)
// if the unaligned load and the byteswap take alot instructions its better to directly read and invert
# if defined(SYSTEM_NEED_ALIGNMENT) && !defined(__mips__)
inline uint16 READ_BE_UINT16(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[0] << 8) | b[1];
}
inline uint32 READ_BE_UINT32(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
}
inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 8);
b[1] = (uint8)(value >> 0);
}
inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 24);
b[1] = (uint8)(value >> 16);
b[2] = (uint8)(value >> 8);
b[3] = (uint8)(value >> 0);
}
# else
inline uint16 READ_BE_UINT16(const void *ptr) {
return SWAP_BYTES_16(READ_UINT16(ptr));
}
inline uint32 READ_BE_UINT32(const void *ptr) {
return SWAP_BYTES_32(READ_UINT32(ptr));
}
inline void WRITE_BE_UINT16(void *ptr, uint16 value) {
WRITE_UINT16(ptr, SWAP_BYTES_16(value));
}
inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
WRITE_UINT32(ptr, SWAP_BYTES_32(value));
}
# endif // if defined(SYSTEM_NEED_ALIGNMENT)
#elif defined(SYSTEM_BIG_ENDIAN) #elif defined(SYSTEM_BIG_ENDIAN)
#define MKID(a) ((uint32)(a))
#define MKID_BE(a) ((uint32)(a)) #define MKID_BE(a) ((uint32)(a))
#define READ_UINT16(a) READ_BE_UINT16(a) #define READ_BE_UINT16(a) READ_UINT16(a)
#define READ_UINT32(a) READ_BE_UINT32(a) #define READ_BE_UINT32(a) READ_UINT32(a)
#define WRITE_UINT16(a, v) WRITE_BE_UINT16(a, v) #define WRITE_BE_UINT16(a, v) WRITE_UINT16(a, v)
#define WRITE_UINT32(a, v) WRITE_BE_UINT32(a, v) #define WRITE_BE_UINT32(a, v) WRITE_UINT32(a, v)
#define FROM_LE_32(a) SWAP_BYTES_32(a) #define FROM_LE_32(a) SWAP_BYTES_32(a)
#define FROM_LE_16(a) SWAP_BYTES_16(a) #define FROM_LE_16(a) SWAP_BYTES_16(a)
@ -125,95 +351,62 @@ FORCEINLINE uint16 SWAP_BYTES_16(uint16 a) {
#define TO_BE_32(a) ((uint32)(a)) #define TO_BE_32(a) ((uint32)(a))
#define TO_BE_16(a) ((uint16)(a)) #define TO_BE_16(a) ((uint16)(a))
#define CONSTANT_LE_32(a) SWAP_CONSTANT_32(a)
#define CONSTANT_LE_16(a) SWAP_CONSTANT_16(a)
#define CONSTANT_BE_32(a) ((uint32)(a))
#define CONSTANT_BE_16(a) ((uint16)(a))
// if the unaligned load and the byteswap take alot instructions its better to directly read and invert
# if defined(SYSTEM_NEED_ALIGNMENT) && !defined(__mips__)
inline uint16 READ_LE_UINT16(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[1] << 8) | b[0];
}
inline uint32 READ_LE_UINT32(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0]);
}
inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 0);
b[1] = (uint8)(value >> 8);
}
inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
uint8 *b = (uint8 *)ptr;
b[0] = (uint8)(value >> 0);
b[1] = (uint8)(value >> 8);
b[2] = (uint8)(value >> 16);
b[3] = (uint8)(value >> 24);
}
# else # else
#error No endianness defined inline uint16 READ_LE_UINT16(const void *ptr) {
return SWAP_BYTES_16(READ_UINT16(ptr));
#endif
#if defined(SYSTEM_NEED_ALIGNMENT) || !defined(SYSTEM_LITTLE_ENDIAN)
FORCEINLINE uint16 READ_LE_UINT16(const void *ptr) {
const byte *b = (const byte *)ptr;
return (b[1] << 8) + b[0];
} }
FORCEINLINE uint32 READ_LE_UINT32(const void *ptr) { inline uint32 READ_LE_UINT32(const void *ptr) {
const byte *b = (const byte *)ptr; return SWAP_BYTES_32(READ_UINT32(ptr));
return (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + (b[0]);
} }
FORCEINLINE void WRITE_LE_UINT16(void *ptr, uint16 value) { inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
byte *b = (byte *)ptr; WRITE_UINT16(ptr, SWAP_BYTES_16(value));
b[0] = (byte)(value >> 0);
b[1] = (byte)(value >> 8);
} }
FORCEINLINE void WRITE_LE_UINT32(void *ptr, uint32 value) { inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
byte *b = (byte *)ptr; WRITE_UINT32(ptr, SWAP_BYTES_32(value));
b[0] = (byte)(value >> 0);
b[1] = (byte)(value >> 8);
b[2] = (byte)(value >> 16);
b[3] = (byte)(value >> 24);
}
#else
FORCEINLINE uint16 READ_LE_UINT16(const void *ptr) {
return *(const uint16 *)(ptr);
}
FORCEINLINE uint32 READ_LE_UINT32(const void *ptr) {
return *(const uint32 *)(ptr);
}
FORCEINLINE void WRITE_LE_UINT16(void *ptr, uint16 value) {
*(uint16 *)(ptr) = value;
}
FORCEINLINE void WRITE_LE_UINT32(void *ptr, uint32 value) {
*(uint32 *)(ptr) = value;
}
#endif
#if defined(SYSTEM_NEED_ALIGNMENT) || !defined(SYSTEM_BIG_ENDIAN)
FORCEINLINE uint16 READ_BE_UINT16(const void *ptr) {
const byte *b = (const byte *)ptr;
return (b[0] << 8) + b[1];
}
FORCEINLINE uint32 READ_BE_UINT32(const void *ptr) {
const byte *b = (const byte*)ptr;
return (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + (b[3]);
}
FORCEINLINE void WRITE_BE_UINT16(void *ptr, uint16 value) {
byte *b = (byte *)ptr;
b[0] = (byte)(value >> 8);
b[1] = (byte)(value >> 0);
}
FORCEINLINE void WRITE_BE_UINT32(void *ptr, uint32 value) {
byte *b = (byte *)ptr;
b[0] = (byte)(value >> 24);
b[1] = (byte)(value >> 16);
b[2] = (byte)(value >> 8);
b[3] = (byte)(value >> 0);
}
#else
FORCEINLINE uint16 READ_BE_UINT16(const void *ptr) {
return *(const uint16 *)(ptr);
}
FORCEINLINE uint32 READ_BE_UINT32(const void *ptr) {
return *(const uint32 *)(ptr);
}
FORCEINLINE void WRITE_BE_UINT16(void *ptr, uint16 value) {
*(uint16 *)(ptr) = value;
}
FORCEINLINE void WRITE_BE_UINT32(void *ptr, uint32 value) {
*(uint32 *)(ptr) = value;
}
#endif
FORCEINLINE uint32 READ_LE_UINT24(const void *ptr) {
const byte *b = (const byte *)ptr;
return (b[2] << 16) + (b[1] << 8) + (b[0]);
} }
FORCEINLINE uint32 READ_BE_UINT24(const void *ptr) { # endif // if defined(SYSTEM_NEED_ALIGNMENT)
const byte *b = (const byte*)ptr;
return (b[0] << 16) + (b[1] << 8) + (b[2]); #endif // if defined(SYSTEM_LITTLE_ENDIAN)
inline uint32 READ_LE_UINT24(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[2] << 16) | (b[1] << 8) | (b[0]);
}
inline uint32 READ_BE_UINT24(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
return (b[0] << 16) | (b[1] << 8) | (b[2]);
} }
#if defined(SYSTEM_BIG_ENDIAN) #if defined(SYSTEM_BIG_ENDIAN)

View file

@ -48,6 +48,7 @@ enum Error {
kInvalidPathError, //!< Engine initialization: Invalid game path was passed kInvalidPathError, //!< Engine initialization: Invalid game path was passed
kNoGameDataFoundError, //!< Engine initialization: No game data was found in the specified location kNoGameDataFoundError, //!< Engine initialization: No game data was found in the specified location
kUnsupportedGameidError, //!< Engine initialization: Gameid not supported by this (Meta)Engine kUnsupportedGameidError, //!< Engine initialization: Gameid not supported by this (Meta)Engine
kUnsupportedColorMode, //!< Engine initialization: Engine does not support backend's color mode
kReadPermissionDenied, //!< Unable to read data due to missing read permission kReadPermissionDenied, //!< Unable to read data due to missing read permission

View file

@ -31,6 +31,9 @@
#include "common/rect.h" #include "common/rect.h"
#include "common/noncopyable.h" #include "common/noncopyable.h"
#include "common/list.h"
#include "common/singleton.h"
namespace Common { namespace Common {
/** /**
@ -126,6 +129,190 @@ struct Event {
Event() : type(EVENT_INVALID), synthetic(false) {} Event() : type(EVENT_INVALID), synthetic(false) {}
}; };
/**
* A source of Events.
*
* An example for this is OSystem, it provides events created by the system
* and or user.
*/
class EventSource {
public:
virtual ~EventSource() {}
/**
* Queries a event from the source.
*
* @param event a reference to the event struct, where the event should be stored.
* @return true if an event was polled, false otherwise.
*/
virtual bool pollEvent(Event &event) = 0;
/**
* Checks whether events from this source are allowed to be mapped.
*
* Possible event sources not allowing mapping are: the event recorder/player and/or
* the EventManager, which allows user events to be pushed.
*
* By default we allow mapping for every event source.
*/
virtual bool allowMapping() const { return true; }
};
/**
* An artificial event source. This is class is used as an event source, which is
* made up by client specific events.
*
* Example usage cases for this are the Keymapper or the DefaultEventManager.
*/
class ArtificialEventSource : public EventSource {
protected:
Common::Queue<Common::Event> _artificialEventQueue;
public:
void addEvent(const Common::Event &ev) {
_artificialEventQueue.push(ev);
}
bool pollEvent(Common::Event &ev) {
if (!_artificialEventQueue.empty()) {
ev = _artificialEventQueue.pop();
return true;
} else {
return false;
}
}
/**
* By default an artificial event source prevents its events
* from being mapped.
*/
virtual bool allowMapping() const { return false; }
};
/**
* Object which catches and processes Events.
*
* An example for this is the Engine object, it is catching events and processing them.
*/
class EventObserver {
public:
virtual ~EventObserver() {}
/**
* Notifies the source of an incoming event.
*
* An obeser is supposed to eat the event, with returning true, when
* it might want prevent other observers from preventing to receive
* the event. An usage example here is the keymapper:
* If it processes an Event, it should 'eat' it and create a new
* event, which the EventDispatcher will then catch.
*
* @param event the event, which is incoming.
* @return true if this observer uses this event, false otherwise.
*/
virtual bool notifyEvent(const Event &event) = 0;
};
/**
* A event mapper, which will map events to others.
*
* An example for this is the Keymapper.
*/
class EventMapper : public EventSource, public EventObserver {
public:
/** For event mappers resulting events should never be mapped */
bool allowMapping() const { return false; }
};
/**
* Dispatches events from various sources to various observers.
*
* EventDispatcher is using a priority based approach. Observers
* with higher priority will be notified before observers with
* lower priority. Because of the possibility that oberservers
* might 'eat' events, not all observers might be notified.
*
* Another speciality is the support for a event mapper, which
* will catch events and create new events out of them. This
* mapper will be processed before an event is sent to the
* observers.
*/
class EventDispatcher {
public:
EventDispatcher();
~EventDispatcher();
/**
* Tries to catch events from the registered event
* sources and dispatch them to the observers.
*
* This dispatches *all* events the sources offer.
*/
void dispatch();
/**
* Registers an event mapper with the dispatcher.
*
* The ownership of the "mapper" variable will pass
* to the EventDispatcher, thus it will be deleted
* with "delete", when EventDispatcher is destroyed.
*
* Note there is only one mapper per EventDispatcher
* possible, thus when this method is called twice,
* the former mapper will be destroied.
*/
void registerMapper(EventMapper *mapper);
/**
* Queries the setup event mapper.
*/
EventMapper *queryMapper() const { return _mapper; }
/**
* Registers a new EventSource with the Dispatcher.
*/
void registerSource(EventSource *source, bool autoFree);
/**
* Unregisters a EventSource.
*
* This takes the "autoFree" flag passed to registerSource into account.
*/
void unregisterSource(EventSource *source);
/**
* Registers a new EventObserver with the Dispatcher.
*/
void registerObserver(EventObserver *obs, uint priority, bool autoFree);
/**
* Unregisters a EventObserver.
*
* This takes the "autoFree" flag passed to registerObserver into account.
*/
void unregisterObserver(EventObserver *obs);
private:
EventMapper *_mapper;
struct Entry {
bool autoFree;
};
struct SourceEntry : public Entry {
EventSource *source;
};
Common::List<SourceEntry> _sources;
struct ObserverEntry : public Entry {
uint priority;
EventObserver *observer;
};
Common::List<ObserverEntry> _observers;
void dispatchEvent(const Event &event);
};
class Keymapper; class Keymapper;
/** /**
@ -161,11 +348,6 @@ public:
*/ */
virtual void pushEvent(const Common::Event &event) = 0; virtual void pushEvent(const Common::Event &event) = 0;
/** Register random source so it can be serialized in game test purposes **/
virtual void registerRandomSource(Common::RandomSource &rnd, const char *name) = 0;
virtual void processMillis(uint32 &millis) = 0;
/** Return the current mouse position */ /** Return the current mouse position */
virtual Common::Point getMousePos() const = 0; virtual Common::Point getMousePos() const = 0;
@ -195,7 +377,9 @@ public:
* Used when we have returned to the launcher. * Used when we have returned to the launcher.
*/ */
virtual void resetRTL() = 0; virtual void resetRTL() = 0;
#ifdef FORCE_RTL
virtual void resetQuit() = 0;
#endif
// Optional: check whether a given key is currently pressed ???? // Optional: check whether a given key is currently pressed ????
//virtual bool isKeyPressed(int keycode) = 0; //virtual bool isKeyPressed(int keycode) = 0;
@ -207,9 +391,21 @@ public:
virtual Common::Keymapper *getKeymapper() = 0; virtual Common::Keymapper *getKeymapper() = 0;
#endif #endif
protected: enum {
/**
* Priority of the event manager, for now it's lowest since it eats
* *all* events, we might to change that in the future though.
*/
kEventManPriority = 0
};
Common::Queue<Common::Event> artificialEventQueue; /**
* Returns the underlying EventDispatcher.
*/
EventDispatcher *getEventDispatcher() { return &_dispatcher; }
protected:
EventDispatcher _dispatcher;
}; };
} // End of namespace Common } // End of namespace Common

View file

@ -32,16 +32,6 @@
namespace Common { namespace Common {
void File::addDefaultDirectory(const String &directory) {
FSNode dir(directory);
addDefaultDirectory(dir);
}
void File::addDefaultDirectory(const FSNode &dir) {
if (dir.exists() && dir.isDirectory())
SearchMan.addDirectory(dir.getPath(), dir);
}
File::File() File::File()
: _handle(0) { : _handle(0) {
} }
@ -120,15 +110,6 @@ bool File::isOpen() const {
return _handle != NULL; return _handle != NULL;
} }
bool File::ioFailed() const {
return !_handle || (eos() || err());
}
void File::clearIOFailed() {
if (_handle)
_handle->clearErr();
}
bool File::err() const { bool File::err() const {
assert(_handle); assert(_handle);
return _handle->err(); return _handle->err();

View file

@ -48,10 +48,6 @@ protected:
String _name; String _name;
public: public:
static void addDefaultDirectory(const String &directory);
static void addDefaultDirectory(const FSNode &directory);
File(); File();
virtual ~File(); virtual ~File();
@ -126,19 +122,6 @@ public:
*/ */
const char *getName() const { return _name.c_str(); } const char *getName() const { return _name.c_str(); }
/**
* DEPRECATED: Use err() or eos() instead.
* Returns true if any I/O failure occurred or the end of the
* stream was reached while reading.
*/
bool ioFailed() const;
/**
* DEPRECATED: Don't use this unless you are still using ioFailed().
* Reset the I/O error status.
*/
void clearIOFailed();
bool err() const; // implement abstract Stream method bool err() const; // implement abstract Stream method
void clearErr(); // implement abstract Stream method void clearErr(); // implement abstract Stream method
bool eos() const; // implement abstract SeekableReadStream method bool eos() const; // implement abstract SeekableReadStream method

View file

@ -249,7 +249,7 @@ SeekableReadStream *FSDirectory::createReadStreamForMember(const String &name) c
} }
FSDirectory *FSDirectory::getSubDirectory(const String &name, int depth, bool flat) { FSDirectory *FSDirectory::getSubDirectory(const String &name, int depth, bool flat) {
return getSubDirectory(String::emptyString, name, depth, flat); return getSubDirectory(String(), name, depth, flat);
} }
FSDirectory *FSDirectory::getSubDirectory(const String &prefix, const String &name, int depth, bool flat) { FSDirectory *FSDirectory::getSubDirectory(const String &prefix, const String &name, int depth, bool flat) {
@ -320,7 +320,7 @@ int FSDirectory::listMatchingMembers(ArchiveMemberList &list, const String &patt
int matches = 0; int matches = 0;
NodeCache::iterator it = _fileCache.begin(); NodeCache::iterator it = _fileCache.begin();
for ( ; it != _fileCache.end(); ++it) { for ( ; it != _fileCache.end(); ++it) {
if (it->_key.matchString(lowercasePattern, true)) { if (it->_key.matchString(lowercasePattern, false, true)) {
list.push_back(ArchiveMemberPtr(new FSNode(it->_value))); list.push_back(ArchiveMemberPtr(new FSNode(it->_value)));
matches++; matches++;
} }

View file

@ -40,6 +40,12 @@
namespace Common { namespace Common {
// The sgi IRIX MIPSpro Compiler has difficulties with nested templates.
// This and the other __sgi conditionals below work around these problems.
#ifdef __sgi
template<class T> class IteratorImpl;
#endif
// Enable the following #define if you want to check how many collisions the // Enable the following #define if you want to check how many collisions the
// code produces (many collisions indicate either a bad hash function, or a // code produces (many collisions indicate either a bad hash function, or a
// hash table that is too small). // hash table that is too small).
@ -93,39 +99,41 @@ public:
ObjectPool<Node, HASHMAP_MEMORYPOOL_SIZE> _nodePool; ObjectPool<Node, HASHMAP_MEMORYPOOL_SIZE> _nodePool;
Node *allocNode(const Key &key) { Node **_storage; ///< hashtable of size arrsize.
return new (_nodePool) Node(key); uint _mask; ///< Capacity of the HashMap minus one; must be a power of two of minus one
}
void freeNode(Node *node) {
if (node && node != &_dummyNode)
_nodePool.deleteChunk(node);
}
Node **_storage; // hashtable of size arrsize.
uint _mask; /**< Capacity of the HashMap minus one; must be a power of two of minus one */
uint _size; uint _size;
uint _deleted; ///< Number of deleted elements (_dummyNodes) uint _deleted; ///< Number of deleted elements (_dummyNodes)
HashFunc _hash; HashFunc _hash;
EqualFunc _equal; EqualFunc _equal;
// Default value, returned by the const getVal. /** Default value, returned by the const getVal. */
const Val _defaultVal; const Val _defaultVal;
// Dummy node, used as marker for erased objects. /** Dummy node, used as marker for erased objects. */
Node _dummyNode; #define HASHMAP_DUMMY_NODE ((Node *)1)
#ifdef DEBUG_HASH_COLLISIONS #ifdef DEBUG_HASH_COLLISIONS
mutable int _collisions, _lookups, _dummyHits; mutable int _collisions, _lookups, _dummyHits;
#endif #endif
Node *allocNode(const Key &key) {
return new (_nodePool) Node(key);
}
void freeNode(Node *node) {
if (node && node != HASHMAP_DUMMY_NODE)
_nodePool.deleteChunk(node);
}
void assign(const HM_t &map); void assign(const HM_t &map);
int lookup(const Key &key) const; int lookup(const Key &key) const;
int lookupAndCreateIfMissing(const Key &key); int lookupAndCreateIfMissing(const Key &key);
void expandStorage(uint newCapacity); void expandStorage(uint newCapacity);
#ifndef __sgi
template<class T> friend class IteratorImpl; template<class T> friend class IteratorImpl;
#endif
/** /**
* Simple HashMap iterator implementation. * Simple HashMap iterator implementation.
@ -133,7 +141,11 @@ public:
template<class NodeType> template<class NodeType>
class IteratorImpl { class IteratorImpl {
friend class HashMap; friend class HashMap;
#ifdef __sgi
template<class T> friend class Common::IteratorImpl;
#else
template<class T> friend class IteratorImpl; template<class T> friend class IteratorImpl;
#endif
protected: protected:
typedef const HashMap hashmap_t; typedef const HashMap hashmap_t;
@ -148,6 +160,7 @@ public:
assert(_idx <= _hashmap->_mask); assert(_idx <= _hashmap->_mask);
Node *node = _hashmap->_storage[_idx]; Node *node = _hashmap->_storage[_idx];
assert(node != 0); assert(node != 0);
assert(node != HASHMAP_DUMMY_NODE);
return node; return node;
} }
@ -166,7 +179,7 @@ public:
assert(_hashmap); assert(_hashmap);
do { do {
_idx++; _idx++;
} while (_idx <= _hashmap->_mask && _hashmap->_storage[_idx] == 0); } while (_idx <= _hashmap->_mask && (_hashmap->_storage[_idx] == 0 || _hashmap->_storage[_idx] == HASHMAP_DUMMY_NODE));
if (_idx > _hashmap->_mask) if (_idx > _hashmap->_mask)
_idx = (uint)-1; _idx = (uint)-1;
@ -207,6 +220,7 @@ public:
Val &getVal(const Key &key); Val &getVal(const Key &key);
const Val &getVal(const Key &key) const; const Val &getVal(const Key &key) const;
const Val &getVal(const Key &key, const Val &defaultVal) const;
void setVal(const Key &key, const Val &val); void setVal(const Key &key, const Val &val);
void clear(bool shrinkArray = 0); void clear(bool shrinkArray = 0);
@ -218,7 +232,7 @@ public:
iterator begin() { iterator begin() {
// Find and return the first non-empty entry // Find and return the first non-empty entry
for (uint ctr = 0; ctr <= _mask; ++ctr) { for (uint ctr = 0; ctr <= _mask; ++ctr) {
if (_storage[ctr]) if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
return iterator(ctr, this); return iterator(ctr, this);
} }
return end(); return end();
@ -230,7 +244,7 @@ public:
const_iterator begin() const { const_iterator begin() const {
// Find and return the first non-empty entry // Find and return the first non-empty entry
for (uint ctr = 0; ctr <= _mask; ++ctr) { for (uint ctr = 0; ctr <= _mask; ++ctr) {
if (_storage[ctr]) if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
return const_iterator(ctr, this); return const_iterator(ctr, this);
} }
return end(); return end();
@ -274,7 +288,7 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap()
#ifdef __PLAYSTATION2__ #ifdef __PLAYSTATION2__
{ {
#else #else
: _defaultVal(), _dummyNode() { : _defaultVal() {
#endif #endif
_mask = HASHMAP_MIN_CAPACITY - 1; _mask = HASHMAP_MIN_CAPACITY - 1;
_storage = new Node *[HASHMAP_MIN_CAPACITY]; _storage = new Node *[HASHMAP_MIN_CAPACITY];
@ -298,7 +312,7 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap()
*/ */
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) : HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
_defaultVal(), _dummyNode() { _defaultVal() {
#ifdef DEBUG_HASH_COLLISIONS #ifdef DEBUG_HASH_COLLISIONS
_collisions = 0; _collisions = 0;
_lookups = 0; _lookups = 0;
@ -340,8 +354,8 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
_size = 0; _size = 0;
_deleted = 0; _deleted = 0;
for (uint ctr = 0; ctr <= _mask; ++ctr) { for (uint ctr = 0; ctr <= _mask; ++ctr) {
if (map._storage[ctr] == &map._dummyNode) { if (map._storage[ctr] == HASHMAP_DUMMY_NODE) {
_storage[ctr] = &_dummyNode; _storage[ctr] = HASHMAP_DUMMY_NODE;
_deleted++; _deleted++;
} else if (map._storage[ctr] != NULL) { } else if (map._storage[ctr] != NULL) {
_storage[ctr] = allocNode(map._storage[ctr]->_key); _storage[ctr] = allocNode(map._storage[ctr]->_key);
@ -383,7 +397,9 @@ template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) { void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
assert(newCapacity > _mask+1); assert(newCapacity > _mask+1);
#ifndef NDEBUG
const uint old_size = _size; const uint old_size = _size;
#endif
const uint old_mask = _mask; const uint old_mask = _mask;
Node **old_storage = _storage; Node **old_storage = _storage;
@ -397,7 +413,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
// rehash all the old elements // rehash all the old elements
for (uint ctr = 0; ctr <= old_mask; ++ctr) { for (uint ctr = 0; ctr <= old_mask; ++ctr) {
if (old_storage[ctr] == NULL || old_storage[ctr] == &_dummyNode) if (old_storage[ctr] == NULL || old_storage[ctr] == HASHMAP_DUMMY_NODE)
continue; continue;
// Insert the element from the old table into the new table. // Insert the element from the old table into the new table.
@ -406,7 +422,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
// don't have to call _equal(). // don't have to call _equal().
const uint hash = _hash(old_storage[ctr]->_key); const uint hash = _hash(old_storage[ctr]->_key);
uint idx = hash & _mask; uint idx = hash & _mask;
for (uint perturb = hash; _storage[idx] != NULL && _storage[idx] != &_dummyNode; perturb >>= HASHMAP_PERTURB_SHIFT) { for (uint perturb = hash; _storage[idx] != NULL && _storage[idx] != HASHMAP_DUMMY_NODE; perturb >>= HASHMAP_PERTURB_SHIFT) {
idx = (5 * idx + perturb + 1) & _mask; idx = (5 * idx + perturb + 1) & _mask;
} }
@ -430,7 +446,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) { for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
if (_storage[ctr] == NULL) if (_storage[ctr] == NULL)
break; break;
if (_storage[ctr] == &_dummyNode) { if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
#ifdef DEBUG_HASH_COLLISIONS #ifdef DEBUG_HASH_COLLISIONS
_dummyHits++; _dummyHits++;
#endif #endif
@ -464,7 +480,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &
for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) { for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
if (_storage[ctr] == NULL) if (_storage[ctr] == NULL)
break; break;
if (_storage[ctr] == &_dummyNode) { if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
#ifdef DEBUG_HASH_COLLISIONS #ifdef DEBUG_HASH_COLLISIONS
_dummyHits++; _dummyHits++;
#endif #endif
@ -540,11 +556,16 @@ Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) {
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const { const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const {
return getVal(key, _defaultVal);
}
template<class Key, class Val, class HashFunc, class EqualFunc>
const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key, const Val &defaultVal) const {
uint ctr = lookup(key); uint ctr = lookup(key);
if (_storage[ctr] != NULL) if (_storage[ctr] != NULL)
return _storage[ctr]->_value; return _storage[ctr]->_value;
else else
return _defaultVal; return defaultVal;
} }
template<class Key, class Val, class HashFunc, class EqualFunc> template<class Key, class Val, class HashFunc, class EqualFunc>
@ -563,12 +584,14 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) {
// If we remove a key, we replace it with a dummy node. // If we remove a key, we replace it with a dummy node.
freeNode(_storage[ctr]); freeNode(_storage[ctr]);
_storage[ctr] = &_dummyNode; _storage[ctr] = HASHMAP_DUMMY_NODE;
_size--; _size--;
_deleted++; _deleted++;
return; return;
} }
#undef HASHMAP_DUMMY_NODE
} // End of namespace Common } // End of namespace Common
#endif #endif

View file

@ -46,6 +46,12 @@ MemoryPool::MemoryPool(size_t chunkSize) {
} }
MemoryPool::~MemoryPool() { MemoryPool::~MemoryPool() {
#if 0
freeUnusedPages();
if (!_pages.empty())
warning("Memory leak found in pool");
#endif
for (size_t i = 0; i < _pages.size(); ++i) for (size_t i = 0; i < _pages.size(); ++i)
::free(_pages[i].start); ::free(_pages[i].start);
} }
@ -62,7 +68,7 @@ void MemoryPool::allocPage() {
_pages.push_back(page); _pages.push_back(page);
// Next time, we'll alocate a page twice as big as this one. // Next time, we'll allocate a page twice as big as this one.
_chunksPerPage *= 2; _chunksPerPage *= 2;
// Add the page to the pool of free chunk // Add the page to the pool of free chunk

View file

@ -5,6 +5,8 @@ MODULE_OBJS := \
config-file.o \ config-file.o \
config-manager.o \ config-manager.o \
debug.o \ debug.o \
EventDispatcher.o \
EventRecorder.o \
file.o \ file.o \
fs.o \ fs.o \
hashmap.o \ hashmap.o \

View file

@ -28,6 +28,8 @@
#include "common/memorypool.h" #include "common/memorypool.h"
#include <stdarg.h>
#if !defined(__SYMBIAN32__) #if !defined(__SYMBIAN32__)
#include <new> #include <new>
#endif #endif
@ -350,12 +352,12 @@ bool String::contains(char x) const {
return strchr(c_str(), x) != NULL; return strchr(c_str(), x) != NULL;
} }
bool String::matchString(const char *pat, bool pathMode) const { bool String::matchString(const char *pat, bool ignoreCase, bool pathMode) const {
return Common::matchString(c_str(), pat, pathMode); return Common::matchString(c_str(), pat, ignoreCase, pathMode);
} }
bool String::matchString(const String &pat, bool pathMode) const { bool String::matchString(const String &pat, bool ignoreCase, bool pathMode) const {
return Common::matchString(c_str(), pat.c_str(), pathMode); return Common::matchString(c_str(), pat.c_str(), ignoreCase, pathMode);
} }
void String::deleteLastChar() { void String::deleteLastChar() {
@ -435,6 +437,50 @@ uint String::hash() const {
return hashit(c_str()); return hashit(c_str());
} }
// static
String String::printf(const char *fmt, ...) {
String output;
assert(output.isStorageIntern());
va_list va;
va_start(va, fmt);
int len = vsnprintf(output._str, _builtinCapacity, fmt, va);
va_end(va);
if (len == -1) {
// MSVC doesn't return the size the full string would take up.
// Try increasing the size of the string until it fits.
// We assume MSVC failed to output the correct, null-terminated string
// if the return value is either -1 or size.
int size = _builtinCapacity;
do {
size *= 2;
output.ensureCapacity(size-1, false);
assert(!output.isStorageIntern());
size = output._extern._capacity;
va_start(va, fmt);
len = vsnprintf(output._str, size, fmt, va);
va_end(va);
} while (len == -1 || len >= size);
} else if (len < (int)_builtinCapacity) {
// vsnprintf succeeded
output._size = len;
} else {
// vsnprintf didn't have enough space, so grow buffer
output.ensureCapacity(len, false);
va_start(va, fmt);
int len2 = vsnprintf(output._str, len+1, fmt, va);
va_end(va);
assert(len == len2);
output._size = len2;
}
return output;
}
#pragma mark - #pragma mark -
bool String::operator ==(const String &x) const { bool String::operator ==(const String &x) const {
@ -635,7 +681,7 @@ Common::String normalizePath(const Common::String &path, const char sep) {
return result; return result;
} }
bool matchString(const char *str, const char *pat, bool pathMode) { bool matchString(const char *str, const char *pat, bool ignoreCase, bool pathMode) {
assert(str); assert(str);
assert(pat); assert(pat);
@ -652,7 +698,7 @@ bool matchString(const char *str, const char *pat, bool pathMode) {
switch (*pat) { switch (*pat) {
case '*': case '*':
// Record pattern / string possition for backtracking // Record pattern / string position for backtracking
p = ++pat; p = ++pat;
q = str; q = str;
// If pattern ended with * -> match // If pattern ended with * -> match
@ -661,7 +707,8 @@ bool matchString(const char *str, const char *pat, bool pathMode) {
break; break;
default: default:
if (*pat != *str) { if ((!ignoreCase && *pat != *str) ||
(ignoreCase && tolower(*pat) != tolower(*str))) {
if (p) { if (p) {
// No match, oops -> try to backtrack // No match, oops -> try to backtrack
pat = p; pat = p;

View file

@ -170,12 +170,13 @@ public:
* *
* @param str Text to be matched against the given pattern. * @param str Text to be matched against the given pattern.
* @param pat Glob pattern. * @param pat Glob pattern.
* @param ignoreCase Whether to ignore the case when doing pattern match
* @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly. * @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly.
* *
* @return true if str matches the pattern, false otherwise. * @return true if str matches the pattern, false otherwise.
*/ */
bool matchString(const char *pat, bool pathMode = false) const; bool matchString(const char *pat, bool ignoreCase = false, bool pathMode = false) const;
bool matchString(const String &pat, bool pathMode = false) const; bool matchString(const String &pat, bool ignoreCase = false, bool pathMode = false) const;
inline const char *c_str() const { return _str; } inline const char *c_str() const { return _str; }
@ -218,6 +219,11 @@ public:
uint hash() const; uint hash() const;
/**
* Printf-like function. Returns a formatted String.
*/
static Common::String printf(const char *fmt, ...) GCC_PRINTF(1,2);
public: public:
typedef char * iterator; typedef char * iterator;
typedef const char * const_iterator; typedef const char * const_iterator;
@ -311,11 +317,12 @@ Common::String normalizePath(const Common::String &path, const char sep);
* *
* @param str Text to be matched against the given pattern. * @param str Text to be matched against the given pattern.
* @param pat Glob pattern. * @param pat Glob pattern.
* @param ignoreCase Whether to ignore the case when doing pattern match
* @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly. * @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly.
* *
* @return true if str matches the pattern, false otherwise. * @return true if str matches the pattern, false otherwise.
*/ */
bool matchString(const char *str, const char *pat, bool pathMode = false); bool matchString(const char *str, const char *pat, bool ignoreCase = false, bool pathMode = false);
typedef Array<String> StringList; typedef Array<String> StringList;

View file

@ -27,6 +27,7 @@
#define COMMON_STREAM_H #define COMMON_STREAM_H
#include "common/sys.h" #include "common/sys.h"
#include "common/endian.h"
namespace Common { namespace Common {
@ -106,38 +107,38 @@ public:
} }
void writeUint16LE(uint16 value) { void writeUint16LE(uint16 value) {
writeByte((byte)(value & 0xff)); value = TO_LE_16(value);
writeByte((byte)(value >> 8)); write(&value, 2);
} }
void writeUint32LE(uint32 value) { void writeUint32LE(uint32 value) {
writeUint16LE((uint16)(value & 0xffff)); value = TO_LE_32(value);
writeUint16LE((uint16)(value >> 16)); write(&value, 4);
} }
void writeUint16BE(uint16 value) { void writeUint16BE(uint16 value) {
writeByte((byte)(value >> 8)); value = TO_BE_16(value);
writeByte((byte)(value & 0xff)); write(&value, 2);
} }
void writeUint32BE(uint32 value) { void writeUint32BE(uint32 value) {
writeUint16BE((uint16)(value >> 16)); value = TO_BE_32(value);
writeUint16BE((uint16)(value & 0xffff)); write(&value, 4);
} }
void writeSint16LE(int16 value) { FORCEINLINE void writeSint16LE(int16 value) {
writeUint16LE((uint16)value); writeUint16LE((uint16)value);
} }
void writeSint32LE(int32 value) { FORCEINLINE void writeSint32LE(int32 value) {
writeUint32LE((uint32)value); writeUint32LE((uint32)value);
} }
void writeSint16BE(int16 value) { FORCEINLINE void writeSint16BE(int16 value) {
writeUint16BE((uint16)value); writeUint16BE((uint16)value);
} }
void writeSint32BE(int32 value) { FORCEINLINE void writeSint32BE(int32 value) {
writeUint32BE((uint32)value); writeUint32BE((uint32)value);
} }
@ -179,7 +180,7 @@ public:
* DEPRECATED * DEPRECATED
* Default implementation for backward compatibility * Default implementation for backward compatibility
*/ */
virtual bool ioFailed() { return (eos() || err()); } inline bool ioFailed() { return (eos() || err()); }
/** /**
* Read an unsigned byte from the stream and return it. * Read an unsigned byte from the stream and return it.
@ -188,7 +189,7 @@ public:
* calling err() and eos() ). * calling err() and eos() ).
*/ */
byte readByte() { byte readByte() {
byte b = 0; byte b = 0; // FIXME: remove initialisation
read(&b, 1); read(&b, 1);
return b; return b;
} }
@ -199,10 +200,8 @@ public:
* if a read error occurred (for which client code can check by * if a read error occurred (for which client code can check by
* calling err() and eos() ). * calling err() and eos() ).
*/ */
int8 readSByte() { FORCEINLINE int8 readSByte() {
int8 b = 0; return (int8)readByte();
read(&b, 1);
return b;
} }
/** /**
@ -213,9 +212,9 @@ public:
* calling err() and eos() ). * calling err() and eos() ).
*/ */
uint16 readUint16LE() { uint16 readUint16LE() {
uint16 a = readByte(); uint16 val;
uint16 b = readByte(); read(&val, 2);
return a | (b << 8); return FROM_LE_16(val);
} }
/** /**
@ -226,9 +225,9 @@ public:
* calling err() and eos() ). * calling err() and eos() ).
*/ */
uint32 readUint32LE() { uint32 readUint32LE() {
uint32 a = readUint16LE(); uint32 val;
uint32 b = readUint16LE(); read(&val, 4);
return (b << 16) | a; return FROM_LE_32(val);
} }
/** /**
@ -239,9 +238,9 @@ public:
* calling err() and eos() ). * calling err() and eos() ).
*/ */
uint16 readUint16BE() { uint16 readUint16BE() {
uint16 b = readByte(); uint16 val;
uint16 a = readByte(); read(&val, 2);
return a | (b << 8); return FROM_BE_16(val);
} }
/** /**
@ -252,9 +251,9 @@ public:
* calling err() and eos() ). * calling err() and eos() ).
*/ */
uint32 readUint32BE() { uint32 readUint32BE() {
uint32 b = readUint16BE(); uint32 val;
uint32 a = readUint16BE(); read(&val, 4);
return (b << 16) | a; return FROM_BE_32(val);
} }
/** /**
@ -264,7 +263,7 @@ public:
* if a read error occurred (for which client code can check by * if a read error occurred (for which client code can check by
* calling err() and eos() ). * calling err() and eos() ).
*/ */
int16 readSint16LE() { FORCEINLINE int16 readSint16LE() {
return (int16)readUint16LE(); return (int16)readUint16LE();
} }
@ -275,7 +274,7 @@ public:
* if a read error occurred (for which client code can check by * if a read error occurred (for which client code can check by
* calling err() and eos() ). * calling err() and eos() ).
*/ */
int32 readSint32LE() { FORCEINLINE int32 readSint32LE() {
return (int32)readUint32LE(); return (int32)readUint32LE();
} }
@ -286,7 +285,7 @@ public:
* if a read error occurred (for which client code can check by * if a read error occurred (for which client code can check by
* calling err() and eos() ). * calling err() and eos() ).
*/ */
int16 readSint16BE() { FORCEINLINE int16 readSint16BE() {
return (int16)readUint16BE(); return (int16)readUint16BE();
} }
@ -297,7 +296,7 @@ public:
* if a read error occurred (for which client code can check by * if a read error occurred (for which client code can check by
* calling err() and eos() ). * calling err() and eos() ).
*/ */
int32 readSint32BE() { FORCEINLINE int32 readSint32BE() {
return (int32)readUint32BE(); return (int32)readUint32BE();
} }
@ -400,6 +399,7 @@ public:
/** /**
* SubReadStream provides access to a ReadStream restricted to the range * SubReadStream provides access to a ReadStream restricted to the range
* [currentPosition, currentPosition+end). * [currentPosition, currentPosition+end).
*
* Manipulating the parent stream directly /will/ mess up a substream. * Manipulating the parent stream directly /will/ mess up a substream.
* Likewise, manipulating two substreams of a parent stream will cause them to * Likewise, manipulating two substreams of a parent stream will cause them to
* step on each others toes. * step on each others toes.
@ -434,6 +434,9 @@ public:
* SeekableSubReadStream provides access to a SeekableReadStream restricted to * SeekableSubReadStream provides access to a SeekableReadStream restricted to
* the range [begin, end). * the range [begin, end).
* The same caveats apply to SeekableSubReadStream as do to SeekableReadStream. * The same caveats apply to SeekableSubReadStream as do to SeekableReadStream.
*
* Manipulating the parent stream directly /will/ mess up a substream.
* @see SubReadStream
*/ */
class SeekableSubReadStream : public SubReadStream, public SeekableReadStream { class SeekableSubReadStream : public SubReadStream, public SeekableReadStream {
protected: protected:
@ -451,28 +454,36 @@ public:
/** /**
* This is a wrapper around SeekableSubReadStream, but it adds non-endian * This is a wrapper around SeekableSubReadStream, but it adds non-endian
* read methods whose endianness is set on the stream creation. * read methods whose endianness is set on the stream creation.
*
* Manipulating the parent stream directly /will/ mess up a substream.
* @see SubReadStream
*/ */
class SeekableSubReadStreamEndian : public SeekableSubReadStream { class SeekableSubReadStreamEndian : public SeekableSubReadStream {
public: private:
bool _bigEndian; const bool _bigEndian;
public:
SeekableSubReadStreamEndian(SeekableReadStream *parentStream, uint32 begin, uint32 end, bool bigEndian = false, bool disposeParentStream = false) SeekableSubReadStreamEndian(SeekableReadStream *parentStream, uint32 begin, uint32 end, bool bigEndian = false, bool disposeParentStream = false)
: SeekableSubReadStream(parentStream, begin, end, disposeParentStream), _bigEndian(bigEndian) { : SeekableSubReadStream(parentStream, begin, end, disposeParentStream), _bigEndian(bigEndian) {
} }
inline uint16 readUint16() { uint16 readUint16() {
return (_bigEndian) ? readUint16BE() : readUint16LE(); uint16 val;
read(&val, 2);
return (_bigEndian) ? TO_BE_16(val) : TO_LE_16(val);
} }
inline uint32 readUint32() { uint32 readUint32() {
return (_bigEndian) ? readUint32BE() : readUint32LE(); uint32 val;
read(&val, 4);
return (_bigEndian) ? TO_BE_32(val) : TO_LE_32(val);
} }
inline int16 readSint16() { FORCEINLINE int16 readSint16() {
return (int16)readUint16(); return (int16)readUint16();
} }
inline int32 readSint32() { FORCEINLINE int32 readSint32() {
return (int32)readUint32(); return (int32)readUint32();
} }
}; };
@ -575,23 +586,28 @@ public:
*/ */
class MemoryReadStreamEndian : public Common::MemoryReadStream { class MemoryReadStreamEndian : public Common::MemoryReadStream {
private: private:
const bool _bigEndian;
public: public:
bool _bigEndian;
MemoryReadStreamEndian(const byte *buf, uint32 len, bool bigEndian = false) : MemoryReadStream(buf, len), _bigEndian(bigEndian) {} MemoryReadStreamEndian(const byte *buf, uint32 len, bool bigEndian = false) : MemoryReadStream(buf, len), _bigEndian(bigEndian) {}
inline uint16 readUint16() { uint16 readUint16() {
return (_bigEndian) ? readUint16BE() : readUint16LE(); uint16 val;
read(&val, 2);
return (_bigEndian) ? TO_BE_16(val) : TO_LE_16(val);
} }
inline uint32 readUint32() { uint32 readUint32() {
return (_bigEndian) ? readUint32BE() : readUint32LE(); uint32 val;
read(&val, 4);
return (_bigEndian) ? TO_BE_32(val) : TO_LE_32(val);
} }
inline int16 readSint16() { FORCEINLINE int16 readSint16() {
return (int16)readUint16(); return (int16)readUint16();
} }
inline int32 readSint32() { FORCEINLINE int32 readSint32() {
return (int32)readUint32(); return (int32)readUint32();
} }
}; };
@ -642,13 +658,13 @@ private:
byte *old_data = _data; byte *old_data = _data;
_capacity = new_len + 32; _capacity = new_len + 32;
_data = new byte[_capacity]; _data = (byte *)malloc(_capacity);
_ptr = _data + _pos; _ptr = _data + _pos;
if (old_data) { if (old_data) {
// Copy old data // Copy old data
memcpy(_data, old_data, _size); memcpy(_data, old_data, _size);
delete[] old_data; free(old_data);
} }
_size = new_len; _size = new_len;
@ -658,7 +674,7 @@ public:
~MemoryWriteStreamDynamic() { ~MemoryWriteStreamDynamic() {
if (_disposeMemory) if (_disposeMemory)
delete[] _data; free(_data);
} }
uint32 write(const void *dataPtr, uint32 dataSize) { uint32 write(const void *dataPtr, uint32 dataSize) {

View file

@ -125,7 +125,6 @@ public:
* like PocketPC, Palms, Symbian phones like the P800, Zaurus, etc. * like PocketPC, Palms, Symbian phones like the P800, Zaurus, etc.
*/ */
kFeatureVirtualKeyboard, kFeatureVirtualKeyboard,
kFeatureIconifyWindow,
kFeatureOpenGL, kFeatureOpenGL,
/** /**
@ -174,7 +173,6 @@ public:
* rather complicated for backend authors to fully understand and * rather complicated for backend authors to fully understand and
* implement the semantics of the OSystem interface. * implement the semantics of the OSystem interface.
*/ */
//@{ //@{
/** /**
@ -323,8 +321,10 @@ public:
* @param hotspotY vertical offset from the top side to the hotspot * @param hotspotY vertical offset from the top side to the hotspot
* @param keycolor transparency color index * @param keycolor transparency color index
* @param cursorTargetScale scale factor which cursor is designed for * @param cursorTargetScale scale factor which cursor is designed for
* @param format pointer to the pixel format which cursor graphic uses
*/ */
virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int cursorTargetScale = 1) = 0; virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL) = 0;
//@} //@}
@ -490,13 +490,11 @@ public:
/** /**
* Set a window caption or any other comparable status display to the * Set a window caption or any other comparable status display to the
* given value. The caption must be a pure ASCII string. Passing a * given value. The caption must be a pure ISO LATIN 1 string. Passing a
* non-ASCII string may lead to unexpected behavior, even crashes. * string with a different encoding may lead to unexpected behavior,
* even crashes.
* *
* In a future revision of this API, this may be changed to allowing * @param caption the window caption to use, as an ISO LATIN 1 string
* UTF-8 or UTF-16 encoded data, or maybe ISO LATIN 1.
*
* @param caption the window caption to use, as an ASCII string
*/ */
virtual void setWindowCaption(const char *caption) {} virtual void setWindowCaption(const char *caption) {}

View file

@ -24,6 +24,7 @@
#include "common/util.h" #include "common/util.h"
#include "common/system.h" #include "common/system.h"
#include "common/config-manager.h"
#include "gui/debugger.h" #include "gui/debugger.h"
#include "engines/engine.h" #include "engines/engine.h"
@ -211,6 +212,7 @@ const LanguageDescription g_languages[] = {
{"ru", "Russian", RU_RUS}, {"ru", "Russian", RU_RUS},
{"es", "Spanish", ES_ESP}, {"es", "Spanish", ES_ESP},
{"se", "Swedish", SE_SWE}, {"se", "Swedish", SE_SWE},
{"hu", "Hungarian", HU_HUN},
{0, 0, UNK_LANG} {0, 0, UNK_LANG}
}; };
@ -419,6 +421,14 @@ String getGameGUIOptionsDescription(uint32 options) {
return res; return res;
} }
void updateGameGUIOptions(const uint32 options) {
if ((options && !ConfMan.hasKey("guioptions")) ||
(ConfMan.hasKey("guioptions") && options != parseGameGUIOptions(ConfMan.get("guioptions")))) {
ConfMan.set("guioptions", getGameGUIOptionsDescription(options));
ConfMan.flushToDisk();
}
}
} // End of namespace Common } // End of namespace Common

View file

@ -26,7 +26,6 @@
#define COMMON_UTIL_H #define COMMON_UTIL_H
#include "common/sys.h" #include "common/sys.h"
#include "common/debug.h"
#include "common/str.h" #include "common/str.h"
#if defined(WIN32) #if defined(WIN32)
@ -183,6 +182,7 @@ enum Language {
RU_RUS, RU_RUS,
ES_ESP, ES_ESP,
SE_SWE, SE_SWE,
HU_HUN,
UNK_LANG = -1 // Use default language (i.e. none specified) UNK_LANG = -1 // Use default language (i.e. none specified)
}; };
@ -294,6 +294,13 @@ bool checkGameGUIOption(GameGUIOption option, const String &str);
uint32 parseGameGUIOptions(const String &str); uint32 parseGameGUIOptions(const String &str);
String getGameGUIOptionsDescription(uint32 options); String getGameGUIOptionsDescription(uint32 options);
/**
* Updates the GUI options of the current config manager
* domain, when they differ to the ones passed as
* parameter.
*/
void updateGameGUIOptions(const uint32 options);
} // End of namespace Common } // End of namespace Common

175
config.guess vendored
View file

@ -1,10 +1,10 @@
#! /bin/sh #! /bin/sh
# Attempt to guess a canonical system name. # Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
# Free Software Foundation, Inc. # Free Software Foundation, Inc.
timestamp='2009-04-27' timestamp='2009-09-18'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@ -27,16 +27,16 @@ timestamp='2009-04-27'
# the same distribution terms that you use for the rest of that program. # the same distribution terms that you use for the rest of that program.
# Originally written by Per Bothner <per@bothner.com>. # Originally written by Per Bothner. Please send patches (context
# Please send patches to <config-patches@gnu.org>. Submit a context # diff format) to <config-patches@gnu.org> and include a ChangeLog
# diff and a properly formatted ChangeLog entry. # entry.
# #
# This script attempts to guess a canonical system name similar to # This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and # config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1. # exits with 0. Otherwise, it exits with 1.
# #
# The plan is that this can be called by configure scripts if you # You can get the latest version of this script from:
# don't specify an explicit build system type. # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
me=`echo "$0" | sed -e 's,.*/,,'` me=`echo "$0" | sed -e 's,.*/,,'`
@ -170,7 +170,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax) arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep __ELF__ >/dev/null | grep -q __ELF__
then then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX? # Return netbsd for either. FIX?
@ -656,7 +656,7 @@ EOF
# => hppa64-hp-hpux11.23 # => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep __LP64__ >/dev/null grep -q __LP64__
then then
HP_ARCH="hppa2.0w" HP_ARCH="hppa2.0w"
else else
@ -822,6 +822,9 @@ EOF
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks echo i${UNAME_MACHINE}-pc-mks
exit ;; exit ;;
8664:Windows_NT:*)
echo x86_64-pc-mks
exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*) i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem? # How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@ -851,6 +854,20 @@ EOF
i*86:Minix:*:*) i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix echo ${UNAME_MACHINE}-pc-minix
exit ;; exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
PCA57) UNAME_MACHINE=alphapca56 ;;
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
exit ;;
arm*:Linux:*:*) arm*:Linux:*:*)
eval $set_cc_for_build eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
@ -873,6 +890,9 @@ EOF
frv:Linux:*:*) frv:Linux:*:*)
echo frv-unknown-linux-gnu echo frv-unknown-linux-gnu
exit ;; exit ;;
i*86:Linux:*:*)
echo ${UNAME_MACHINE}-pc-linux-gnu
exit ;;
ia64:Linux:*:*) ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;; exit ;;
@ -882,40 +902,17 @@ EOF
m68*:Linux:*:*) m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;; exit ;;
mips:Linux:*:*) mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c sed 's/^ //' << EOF >$dummy.c
#undef CPU #undef CPU
#undef mips #undef ${UNAME_MACHINE}
#undef mipsel #undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=mipsel CPU=${UNAME_MACHINE}el
#else #else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=mips CPU=${UNAME_MACHINE}
#else
CPU=
#endif
#endif
EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
/^CPU/{
s: ::g
p
}'`"
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef mips64
#undef mips64el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=mips64el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=mips64
#else #else
CPU= CPU=
#endif #endif
@ -931,29 +928,12 @@ EOF
or32:Linux:*:*) or32:Linux:*:*)
echo or32-unknown-linux-gnu echo or32-unknown-linux-gnu
exit ;; exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-gnu
exit ;;
ppc64:Linux:*:*)
echo powerpc64-unknown-linux-gnu
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
PCA57) UNAME_MACHINE=alphapca56 ;;
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
exit ;;
padre:Linux:*:*) padre:Linux:*:*)
echo sparc-unknown-linux-gnu echo sparc-unknown-linux-gnu
exit ;; exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-gnu
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*) parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level # Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
@ -962,8 +942,11 @@ EOF
*) echo hppa-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;;
esac esac
exit ;; exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*) ppc64:Linux:*:*)
echo hppa64-unknown-linux-gnu echo powerpc64-unknown-linux-gnu
exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-gnu
exit ;; exit ;;
s390:Linux:*:* | s390x:Linux:*:*) s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux echo ${UNAME_MACHINE}-ibm-linux
@ -986,66 +969,6 @@ EOF
xtensa*:Linux:*:*) xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;; exit ;;
i*86:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us. cd to the root directory to prevent
# problems with other programs or directories called `ld' in the path.
# Set LC_ALL=C to ensure ld outputs messages in English.
ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
| sed -ne '/supported targets:/!d
s/[ ][ ]*/ /g
s/.*supported targets: *//
s/ .*//
p'`
case "$ld_supported_targets" in
elf32-i386)
TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
;;
a.out-i386-linux)
echo "${UNAME_MACHINE}-pc-linux-gnuaout"
exit ;;
"")
# Either a pre-BFD a.out linker (linux-gnuoldld) or
# one that does not give us useful --help.
echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
exit ;;
esac
# Determine whether the default compiler is a.out or elf
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include <features.h>
#ifdef __ELF__
# ifdef __GLIBC__
# if __GLIBC__ >= 2
LIBC=gnu
# else
LIBC=gnulibc1
# endif
# else
LIBC=gnulibc1
# endif
#else
#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
LIBC=gnu
#else
LIBC=gnuaout
#endif
#endif
#ifdef __dietlibc__
LIBC=dietlibc
#endif
EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
/^LIBC/{
s: ::g
p
}'`"
test x"${LIBC}" != x && {
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit
}
test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
;;
i*86:DYNIX/ptx:4*:*) i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both # earlier versions are messed up and put the nodename in both
@ -1074,7 +997,7 @@ EOF
i*86:syllable:*:*) i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable echo ${UNAME_MACHINE}-pc-syllable
exit ;; exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE} echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;; exit ;;
i*86:*DOS:*:*) i*86:*DOS:*:*)
@ -1182,7 +1105,7 @@ EOF
rs6000:LynxOS:2.*:*) rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE} echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;; exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE} echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;; exit ;;
SM[BE]S:UNIX_SV:*:*) SM[BE]S:UNIX_SV:*:*)
@ -1275,6 +1198,16 @@ EOF
*:Darwin:*:*) *:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
case $UNAME_PROCESSOR in case $UNAME_PROCESSOR in
i386)
eval $set_cc_for_build
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
UNAME_PROCESSOR="x86_64"
fi
fi ;;
unknown) UNAME_PROCESSOR=powerpc ;; unknown) UNAME_PROCESSOR=powerpc ;;
esac esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}

27
config.sub vendored
View file

@ -1,10 +1,10 @@
#! /bin/sh #! /bin/sh
# Configuration validation subroutine script. # Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
# Free Software Foundation, Inc. # Free Software Foundation, Inc.
timestamp='2009-04-17' timestamp='2009-08-19'
# This file is (in principle) common to ALL GNU software. # This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software # The presence of a machine in this file suggests that SOME GNU software
@ -32,13 +32,16 @@ timestamp='2009-04-17'
# Please send patches to <config-patches@gnu.org>. Submit a context # Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry. # diff and a properly formatted GNU ChangeLog entry.
# #
# Configuration subroutine to validate and canonicalize a configuration type. # Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument. # Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1. # If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed. # Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
# This file is supposed to be the same for all GNU packages # This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases # and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software. # that are meaningful with *any* GNU software.
@ -149,10 +152,13 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis | -knuth | -cray) -apple | -axis | -knuth | -cray | -microblaze)
os= os=
basic_machine=$1 basic_machine=$1
;; ;;
-bluegene*)
os=-cnk
;;
-sim | -cisco | -oki | -wec | -winbond) -sim | -cisco | -oki | -wec | -winbond)
os= os=
basic_machine=$1 basic_machine=$1
@ -337,7 +343,7 @@ case $basic_machine in
| lm32-* \ | lm32-* \
| m32c-* | m32r-* | m32rle-* \ | m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \ | mips16-* \
| mips64-* | mips64el-* \ | mips64-* | mips64el-* \
@ -467,6 +473,10 @@ case $basic_machine in
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux os=-linux
;; ;;
bluegene*)
basic_machine=powerpc-ibm
os=-cnk
;;
c90) c90)
basic_machine=c90-cray basic_machine=c90-cray
os=-unicos os=-unicos
@ -719,6 +729,9 @@ case $basic_machine in
basic_machine=ns32k-utek basic_machine=ns32k-utek
os=-sysv os=-sysv
;; ;;
microblaze)
basic_machine=microblaze-xilinx
;;
mingw32) mingw32)
basic_machine=i386-pc basic_machine=i386-pc
os=-mingw32 os=-mingw32
@ -1260,7 +1273,7 @@ case $os in
# Each alternative MUST END IN A *, to match a version number. # Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4. # -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
| -kopensolaris* \ | -kopensolaris* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
@ -1613,7 +1626,7 @@ case $basic_machine in
-sunos*) -sunos*)
vendor=sun vendor=sun
;; ;;
-aix*) -cnk*|-aix*)
vendor=ibm vendor=ibm
;; ;;
-beos*) -beos*)

324
configure vendored
View file

@ -29,6 +29,8 @@ SAVED_LDFLAGS=$LDFLAGS
SAVED_CXX=$CXX SAVED_CXX=$CXX
SAVED_CXXFLAGS=$CXXFLAGS SAVED_CXXFLAGS=$CXXFLAGS
SAVED_CPPFLAGS=$CPPFLAGS SAVED_CPPFLAGS=$CPPFLAGS
SAVED_ASFLAGS=$ASFLAGS
SAVED_WINDRESFLAGS=$WINDRESFLAGS
# Use environment vars if set # Use environment vars if set
CXXFLAGS="$CXXFLAGS $CPPFLAGS" CXXFLAGS="$CXXFLAGS $CPPFLAGS"
@ -54,15 +56,22 @@ if test "$ac_emxsupport" != "no" -a "$ac_emxsupport" != "NO"; then
unset ac_TEMP_PATH unset ac_TEMP_PATH
fi fi
set_var() {
eval ${1}='${2}'
}
get_var() {
eval echo \$${1}
}
# Add an engine: id name build subengines # Add an engine: id name build subengines
add_engine() { add_engine() {
_engines="${_engines} ${1}" _engines="${_engines} ${1}"
eval _engine_${1}_name='${2}' set_var _engine_${1}_name "${2}"
eval _engine_${1}_build='${3}' set_var _engine_${1}_build "${3}"
eval _engine_${1}_subengines='${4}' set_var _engine_${1}_subengines "${4}"
for sub in ${4}; do for sub in ${4}; do
eval _engine_${sub}_sub=yes set_var _engine_${sub}_sub "yes"
done done
} }
@ -92,6 +101,7 @@ _plugins_default=static
_ranlib=ranlib _ranlib=ranlib
_strip=strip _strip=strip
_ar="ar cru" _ar="ar cru"
_as="as"
_windres=windres _windres=windres
_win32path="C:/residual" _win32path="C:/residual"
_aos4path="Games:Residual" _aos4path="Games:Residual"
@ -107,6 +117,7 @@ _host_os=""
_host_alias="" _host_alias=""
_srcdir=`dirname $0` _srcdir=`dirname $0`
_port_mk="ports.mk"
# Determine a tmp file name, using mktemp(1) when available. # Determine a tmp file name, using mktemp(1) when available.
if type mktemp > /dev/null 2>&1 ; then if type mktemp > /dev/null 2>&1 ; then
@ -225,7 +236,7 @@ find_sdlconfig() {
# #
get_system_exe_extension() { get_system_exe_extension() {
case $1 in case $1 in
mingw* | *os2-emx) mingw* | *os2-emx | wince)
_exeext=".exe" _exeext=".exe"
;; ;;
arm-riscos) arm-riscos)
@ -237,7 +248,7 @@ get_system_exe_extension() {
gp2x-linux) gp2x-linux)
_exeext=".gp2x" _exeext=".gp2x"
;; ;;
dreamcast | wii | gamecube | psp) dreamcast | wii | gamecube | nds | psp)
_exeext=".elf" _exeext=".elf"
;; ;;
*) *)
@ -271,22 +282,22 @@ Try \`$0 --help' for more information." >&2
# Get the name of the engine # Get the name of the engine
get_engine_name() { get_engine_name() {
eval echo \$_engine_$1_name get_var _engine_$1_name
} }
# Will this engine be built? # Will this engine be built?
get_engine_build() { get_engine_build() {
eval echo \$_engine_$1_build get_var _engine_$1_build
} }
# Get the subengines # Get the subengines
get_engine_subengines() { get_engine_subengines() {
eval echo \$_engine_$1_subengines get_var _engine_$1_subengines
} }
# Ask if this is a subengine # Ask if this is a subengine
get_engine_sub() { get_engine_sub() {
sub=`eval echo \\$_engine_$1_sub` sub=`get_var _engine_$1_sub`
if test -z "$sub" ; then if test -z "$sub" ; then
sub=no sub=no
fi fi
@ -296,14 +307,14 @@ get_engine_sub() {
# Enable *all* engines # Enable *all* engines
engine_enable_all() { engine_enable_all() {
for engine in $_engines; do for engine in $_engines; do
eval _engine_${engine}_build=yes set_var _engine_${engine}_build "yes"
done done
} }
# Disable *all* engines # Disable *all* engines
engine_disable_all() { engine_disable_all() {
for engine in $_engines; do for engine in $_engines; do
eval _engine_${engine}_build=no set_var _engine_${engine}_build "no"
done done
} }
@ -327,7 +338,7 @@ engine_enable() {
if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then
if test "`get_engine_name ${engine}`" != "" ; then if test "`get_engine_name ${engine}`" != "" ; then
eval _engine_${engine}_build=$opt set_var _engine_${engine}_build "$opt"
else else
option_error option_error
fi fi
@ -346,7 +357,7 @@ engine_disable() {
engine=`echo $1 | sed 's/-/_/g'` engine=`echo $1 | sed 's/-/_/g'`
if test "`get_engine_name ${engine}`" != "" ; then if test "`get_engine_name ${engine}`" != "" ; then
eval _engine_${engine}_build=no set_var _engine_${engine}_build "no"
else else
option_error option_error
fi fi
@ -493,7 +504,7 @@ Usage: $0 [OPTIONS]...
Configuration: Configuration:
-h, --help display this help and exit -h, --help display this help and exit
--backend=BACKEND backend to build (sdl, morphos, dc, gp2x, gp2xwiz, iphone, wii, psp, null) [sdl] --backend=BACKEND backend to build (sdl, dc, gp2x, gp2xwiz, iphone, morphos, nds, psp, wii, wince, linuxmoto, null) [sdl]
Installation directories: Installation directories:
--prefix=DIR use this prefix for installing Residual [/usr/local] --prefix=DIR use this prefix for installing Residual [/usr/local]
@ -508,20 +519,23 @@ Special configuration feature:
dreamcast for Sega Dreamcast dreamcast for Sega Dreamcast
wii for Nintendo Wii wii for Nintendo Wii
gamecube for Nintendo Gamecube gamecube for Nintendo Gamecube
nds for Nintendo DS
iphone for Apple iPhone iphone for Apple iPhone
wince for Windows CE
psp for PlayStation Portable psp for PlayStation Portable
Optional Features: Game engines:
--disable-debug disable building with debugging symbols
--enable-Werror treat warnings as errors
--enable-profiling enable building with gprof profile information
--enable-release set flags to build release binary
--enable-verbose-build enable regular echoing of commands during build process
--enable-all-engines enable all engines --enable-all-engines enable all engines
--disable-all-engines disable all engines --disable-all-engines disable all engines
$engines_help $engines_help
Optional Features:
--disable-debug disable building with debugging symbols
--enable-Werror treat warnings as errors
--enable-plugins enable the support for dynamic plugins --enable-plugins enable the support for dynamic plugins
--default-dynamic make plugins dynamic by default --default-dynamic make plugins dynamic by default
--enable-profiling enable building with gprof profile information
--enable-release set flags to build release binary
--enable-verbose-build enable regular echoing of commands during build process
Optional Libraries: Optional Libraries:
--with-ogg-prefix=DIR Prefix where libogg is installed (optional) --with-ogg-prefix=DIR Prefix where libogg is installed (optional)
@ -548,6 +562,8 @@ Some influential environment variables:
CXXFLAGS C++ compiler flags CXXFLAGS C++ compiler flags
CPPFLAGS C++ preprocessor flags, e.g. -I<include dir> if you have CPPFLAGS C++ preprocessor flags, e.g. -I<include dir> if you have
headers in a nonstandard directory <include dir> headers in a nonstandard directory <include dir>
ASFLAGS assembler flags
WINDRESFLAGS Windows resource compiler flags
EOF EOF
exit 0 exit 0
@ -566,8 +582,9 @@ for ac_option in $@; do
--disable-flac) _flac=no ;; --disable-flac) _flac=no ;;
--enable-mad) _mad=yes ;; --enable-mad) _mad=yes ;;
--disable-mad) _mad=no ;; --disable-mad) _mad=no ;;
--enable-plugins) _dynamic_modules=yes ;;
--enable-verbose-build) _verbose_build=yes ;; --enable-verbose-build) _verbose_build=yes ;;
--enable-plugins) _dynamic_modules=yes ;;
--default-dynamic) _plugins_default=dynamic ;; --default-dynamic) _plugins_default=dynamic ;;
--enable-vkeybd) _vkeybd=yes ;; --enable-vkeybd) _vkeybd=yes ;;
--disable-vkeybd) _vkeybd=no ;; --disable-vkeybd) _vkeybd=no ;;
@ -676,6 +693,16 @@ linupy)
_host_os=linux _host_os=linux
_host_cpu=arm _host_cpu=arm
;; ;;
motoezx)
_host_os=linux
_host_cpu=arm
_host_alias=arm-linux-gnu
;;
motomagx)
_host_os=linux
_host_cpu=arm
_host_alias=arm-linux-gnueabi
;;
arm-riscos) arm-riscos)
_host_os=riscos _host_os=riscos
_host_cpu=arm _host_cpu=arm
@ -703,6 +730,11 @@ iphone)
_host_cpu=arm _host_cpu=arm
_host_alias=arm-apple-darwin9 _host_alias=arm-apple-darwin9
;; ;;
wince)
_host_os=wince
_host_cpu=arm
_host_alias=arm-wince-mingw32ce
;;
neuros) neuros)
_host_os=linux _host_os=linux
_host_cpu=arm _host_cpu=arm
@ -719,17 +751,22 @@ wii)
_host_cpu=ppc _host_cpu=ppc
_host_alias=powerpc-gekko _host_alias=powerpc-gekko
;; ;;
gamecube)
_host_os=gamecube
_host_cpu=ppc
_host_alias=powerpc-gekko
;;
nds)
_host_os=nds
_host_cpu=arm
_host_alias=arm-eabi
;;
psp) psp)
_host_os=psp _host_os=psp
_host_cpu=mipsallegrexel _host_cpu=mipsallegrexel
_host_alias=psp _host_alias=psp
LDFLAGS="$LDFLAGS -L$PSPDEV/psp/sdk/lib -specs=$_srcdir/backends/platform/psp/psp.spec" LDFLAGS="$LDFLAGS -L$PSPDEV/psp/sdk/lib -specs=$_srcdir/backends/platform/psp/psp.spec"
;; ;;
gamecube)
_host_os=gamecube
_host_cpu=ppc
_host_alias=powerpc-gekko
;;
*) *)
if test -n "$_host"; then if test -n "$_host"; then
guessed_host=`$_srcdir/config.sub $_host` guessed_host=`$_srcdir/config.sub $_host`
@ -742,6 +779,13 @@ esac
if test -z "$_host_alias"; then if test -z "$_host_alias"; then
_host_alias="$_host_cpu-$_host_os" _host_alias="$_host_cpu-$_host_os"
else
# if _host_alias was set, default to the standard GNU tools
_ranlib=$_host_alias-ranlib
_strip=$_host_alias-strip
_ar="$_host_alias-ar cru"
_as="$_host_alias-as"
_windres=$_host_alias-windres
fi fi
# #
@ -766,7 +810,7 @@ esac
# Platform specific sanity checks # Platform specific sanity checks
# #
case $_host_os in case $_host_os in
wii | gamecube) wii | gamecube | nds)
if test -z "$DEVKITPRO"; then if test -z "$DEVKITPRO"; then
echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>" echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>"
exit 1 exit 1
@ -836,11 +880,29 @@ fi
# #
echocheck "compiler version" echocheck "compiler version"
have_gcc=no
cxx_version=`( $CXX -dumpversion ) 2>&1` cxx_version=`( $CXX -dumpversion ) 2>&1`
if test "$?" -gt 0; then if test "$?" -gt 0; then
# TODO: Big scary warning about unsupported Compilers
cxx_version=`( $CXX -version ) 2>&1`
if test "$?" -eq 0; then
cxx_version="`echo "${cxx_version}" | sed -ne 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/gp'`"
if test -z "${cxx_version}"; then
cxx_version="not found" cxx_version="not found"
cxx_verc_fail=yes
fi
echo non-gcc compiler version ${cxx_version}
else
cxx_version="not found"
cxx_verc_fail=yes
echo found non-gcc compiler version ${cxx_version}
fi
else
add_line_to_config_mk 'HAVE_GCC = 1'
have_gcc=yes
fi fi
if test "$have_gcc" = yes; then
case $cxx_version in case $cxx_version in
2.95.[2-9]|2.95.[2-9][-.]*|3.[0-9]|3.[0-9].[0-9]|3.[0-9].[0-9][-.]*|4.[0-9]|4.[0-9].[0-9]|4.[0-9].[0-9][-.]*) 2.95.[2-9]|2.95.[2-9][-.]*|3.[0-9]|3.[0-9].[0-9]|3.[0-9].[0-9][-.]*|4.[0-9]|4.[0-9].[0-9]|4.[0-9].[0-9][-.]*)
_cxx_major=`echo $cxx_version | cut -d '.' -f 1` _cxx_major=`echo $cxx_version | cut -d '.' -f 1`
@ -867,6 +929,30 @@ case $cxx_version in
cxx_verc_fail=yes cxx_verc_fail=yes
;; ;;
esac esac
else
case $_host_os in
irix*)
case $cxx_version in
7.4.4*)
# We just assume this is SGI MipsPRO
_cxx_major=7
_cxx_minor=4
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MDupdate "$(*D)/$(DEPDIR)/$(*F).d"'
add_line_to_config_mk '-include Makedepend'
;;
*)
cxx_version="$cxx_version, bad"
cxx_verc_fail=yes
;;
esac
;;
*)
cxx_version="$cxx_version, bad"
cxx_verc_fail=yes
;;
esac
fi
echo "$cxx_version" echo "$cxx_version"
@ -1040,7 +1126,7 @@ case $_host_os in
;; ;;
darwin*) darwin*)
DEFINES="$DEFINES -DUNIX -DMACOSX -DUSE_OPENGL" DEFINES="$DEFINES -DUNIX -DMACOSX -DUSE_OPENGL"
LIBS="$LIBS -framework QuickTime -framework AudioUnit -framework AudioToolbox -framework Carbon -Wl,-framework,OpenGL \ LIBS="$LIBS -framework QuickTime -framework AudioUnit -framework AudioToolbox -framework Carbon -framework OpenGL \
-dylib_file /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib" -dylib_file /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"
;; ;;
mingw*) mingw*)
@ -1073,17 +1159,24 @@ case $_host_os in
wii) wii)
CXXFLAGS="$CXXFLAGS -Os -mrvl -mcpu=750 -meabi -mhard-float" CXXFLAGS="$CXXFLAGS -Os -mrvl -mcpu=750 -meabi -mhard-float"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched" CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include" CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include -I$DEVKITPRO/wii/include"
LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii" LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii -L$DEVKITPRO/wii/lib"
;; ;;
gamecube) gamecube)
CXXFLAGS="$CXXFLAGS -Os -mogc -mcpu=750 -meabi -mhard-float" CXXFLAGS="$CXXFLAGS -Os -mogc -mcpu=750 -meabi -mhard-float"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched" CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include" CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include -I$DEVKITPRO/cube/include"
LDFLAGS="$LDFLAGS -mogc -mcpu=750 -L$DEVKITPRO/libogc/lib/cube" LDFLAGS="$LDFLAGS -mogc -mcpu=750 -L$DEVKITPRO/libogc/lib/cube -L$DEVKITPRO/cube/lib"
;;
nds)
# TODO nds
;; ;;
psp) psp)
CXXFLAGS="$CXXFLAGS -O2 -G0 -I$PSPDEV/psp/sdk/include -D_PSP_FW_VERSION=150" CXXFLAGS="$CXXFLAGS -O3 -G0 -I$PSPDEV/psp/sdk/include -D_PSP_FW_VERSION=150"
;;
wince)
CXXFLAGS="$CXXFLAGS -O3 -march=armv4 -mtune=xscale -D_WIN32_WCE=300 -D__ARM__ -D_ARM_ -DUNICODE -DFPM_DEFAULT -DNONSTANDARD_PORT"
CXXFLAGS="$CXXFLAGS -DWIN32 -Dcdecl= -D__cdecl__="
;; ;;
# given this is a shell script assume some type of unix # given this is a shell script assume some type of unix
*) *)
@ -1098,16 +1191,6 @@ if test -n "$_host"; then
linupy|arm-riscos) linupy|arm-riscos)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX" DEFINES="$DEFINES -DUNIX"
_endian=little
_need_memalign=yes
add_line_to_config_h "#define LINUPY"
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
;;
arm-linux|arm*-linux-gnueabi|arm-*-linux|*-angstrom-linux)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX -DUSE_ARM_SOUND_ASM"
#not true for all ARM systems, but the interesting ones are all LE. Most (if not all) BE arm devices don't have a screen #not true for all ARM systems, but the interesting ones are all LE. Most (if not all) BE arm devices don't have a screen
_endian=little _endian=little
_need_memalign=yes _need_memalign=yes
@ -1115,6 +1198,44 @@ if test -n "$_host"; then
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
;;
motoezx)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX -DMOTOEZX"
#not true for all ARM systems, but the interesting ones are all LE. Most (if not all) BE arm devices don't have a screen
ASFLAGS="$ASFLAGS -mfpu=vfp"
_endian=little
_need_memalign=yes
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
add_line_to_config_mk 'USE_ARM_GFX_ASM = 1'
add_line_to_config_mk 'USE_ARM_COSTUME_ASM = 1'
add_line_to_config_mk 'USE_ARM_SCALER_ASM = 1'
_backend="linuxmoto"
_build_hq_scalers="no"
_mt32emu="no"
_port_mk="backends/platform/linuxmoto/linuxmoto.mk"
;;
motomagx)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX -DMOTOMAGX"
#not true for all ARM systems, but the interesting ones are all LE. Most (if not all) BE arm devices don't have a screen
ASFLAGS="$ASFLAGS -mfpu=vfp"
_endian=little
_need_memalign=yes
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
_backend="linuxmoto"
_build_hq_scalers="no"
_mt32emu="no"
_port_mk="backends/platform/linuxmoto/linuxmoto.mk"
;; ;;
bfin*) bfin*)
_need_memalign=yes _need_memalign=yes
@ -1125,7 +1246,7 @@ if test -n "$_host"; then
;; ;;
gp2xwiz) gp2xwiz)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX -DGP2XWIZ -DNDEBUG -DUSE_ARM_SMUSH_ASM" DEFINES="$DEFINES -DUNIX -DGP2XWIZ -DNDEBUG"
CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s -mtune=arm926ej-s" CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s -mtune=arm926ej-s"
LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS"
_endian=little _endian=little
@ -1133,8 +1254,6 @@ if test -n "$_host"; then
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1' add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
_backend="gp2xwiz" _backend="gp2xwiz"
@ -1143,27 +1262,26 @@ if test -n "$_host"; then
;; ;;
gp2x) gp2x)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX -DGP2X -DNDEBUG -DUSE_ARM_SMUSH_ASM" DEFINES="$DEFINES -DUNIX -DGP2X -DNDEBUG"
CXXFLAGS="$CXXFLAGS -march=armv4t" CXXFLAGS="$CXXFLAGS -march=armv4t"
ASFLAGS="$ASFLAGS -mfloat-abi=soft"
LDFLAGS="$LDFLAGS -static" LDFLAGS="$LDFLAGS -static"
_endian=little _endian=little
_need_memalign=yes _need_memalign=yes
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
_backend="gp2x" _backend="gp2x"
_build_hq_scalers="no" _build_hq_scalers="no"
_mt32emu="no" _mt32emu="no"
;; ;;
neuros) neuros)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX" DEFINES="$DEFINES -DUNIX -DNEUROS"
_endian=little _endian=little
_need_memalign=yes _need_memalign=yes
add_line_to_config_h "#define NEUROS"
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
@ -1198,34 +1316,46 @@ if test -n "$_host"; then
_windres=$_host-windres _windres=$_host-windres
_ar="$_host-ar cru" _ar="$_host-ar cru"
_ranlib=$_host-ranlib _ranlib=$_host-ranlib
_strip=$_host-strip
;; ;;
iphone) iphone)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DIPHONE -DUNIX -DUSE_ARM_SOUND_ASM" DEFINES="$DEFINES -DIPHONE -DUNIX"
_endian=little _endian=little
_need_memalign=yes _need_memalign=yes
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
_backend="iphone" _backend="iphone"
_ar="$_host_alias-ar cru" ;;
_ranlib=$_host_alias-ranlib wince)
_strip=$_host_alias-strip echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
LDFLAGS="$LDFLAGS -Wl,-Map,scummvm.exe.map -Wl,--stack,65536"
_endian=little
_need_memalign=yes
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
add_line_to_config_mk 'USE_TREMOLO = 1'
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
_backend="wince"
_mt32emu="no"
_port_mk="backends/platform/wince/wince.mk"
;; ;;
dreamcast) dreamcast)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE" DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE"
CXXFLAGS="$CXXFLAGS -O3 -Wno-multichar -funroll-loops -fschedule-insns2 -fomit-frame-pointer -fdelete-null-pointer-checks -fno-exceptions" CXXFLAGS="$CXXFLAGS -O3 -funroll-loops -fschedule-insns2 -fomit-frame-pointer -fdelete-null-pointer-checks"
_endian=little _endian=little
_need_memalign=yes _need_memalign=yes
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
_backend="dc" _backend="dc"
_ar="$_host_alias-ar cru" _mad="yes"
_ranlib=$_host_alias-ranlib _zlib="yes"
add_line_to_config_mk 'include $(srcdir)/backends/platform/dc/dreamcast.mk' add_line_to_config_mk 'include $(srcdir)/backends/platform/dc/dreamcast.mk'
;; ;;
wii) wii)
@ -1235,16 +1365,14 @@ if test -n "$_host"; then
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_strip=$_host_alias-strip
_backend="wii" _backend="wii"
_port_mk="backends/platform/wii/wii.mk"
add_line_to_config_mk 'GAMECUBE = 0' add_line_to_config_mk 'GAMECUBE = 0'
add_line_to_config_mk 'include $(srcdir)/backends/platform/wii/wii.mk'
add_line_to_config_h "#define DEBUG_WII_USBGECKO" add_line_to_config_h "#define DEBUG_WII_USBGECKO"
add_line_to_config_h "/* #define DEBUG_WII_MEMSTATS */" add_line_to_config_h "/* #define DEBUG_WII_MEMSTATS */"
add_line_to_config_h "/* #define DEBUG_WII_GDB */" add_line_to_config_h "/* #define DEBUG_WII_GDB */"
add_line_to_config_h "#define USE_WII_DI" add_line_to_config_h "#define USE_WII_DI"
add_line_to_config_h "#define USE_WII_SMB"
add_line_to_config_h "#define USE_WII_KBD" add_line_to_config_h "#define USE_WII_KBD"
;; ;;
gamecube) gamecube)
@ -1254,17 +1382,36 @@ if test -n "$_host"; then
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_strip=$_host_alias-strip
_backend="wii" _backend="wii"
_port_mk="backends/platform/wii/wii.mk"
add_line_to_config_mk 'GAMECUBE = 1' add_line_to_config_mk 'GAMECUBE = 1'
add_line_to_config_mk 'include $(srcdir)/backends/platform/wii/wii.mk'
add_line_to_config_h '#define GAMECUBE' add_line_to_config_h '#define GAMECUBE'
add_line_to_config_h "/* #define DEBUG_WII_USBGECKO */" add_line_to_config_h "/* #define DEBUG_WII_USBGECKO */"
add_line_to_config_h "/* #define DEBUG_WII_MEMSTATS */" add_line_to_config_h "/* #define DEBUG_WII_MEMSTATS */"
add_line_to_config_h "/* #define DEBUG_WII_GDB */" add_line_to_config_h "/* #define DEBUG_WII_GDB */"
;; ;;
nds)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
# TODO: complete this
# TODO: Maybe rename nds -> ds (would be more consistent with other backends)
DEFINES="$DEFINES -D__DS__ -DNDS -DARM9 -DARM -DNONSTANDARD_PORT"
DEFINES="$DEFINES -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555"
DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER"
DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
DEFINES="$DEFINES -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE"
_endian=little
_need_memalign=yes
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
_backend="nds"
_build_hq_scalers="no"
_mt32emu="no"
add_line_to_config_mk 'include $(srcdir)/backends/platform/ds/ds.mk'
# TODO: Enable more ARM optimizations -- requires testing!
add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1'
add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1'
;;
psp) psp)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
_endian=little _endian=little
@ -1272,10 +1419,8 @@ if test -n "$_host"; then
type_1_byte='char' type_1_byte='char'
type_2_byte='short' type_2_byte='short'
type_4_byte='int' type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_backend="psp" _backend="psp"
add_line_to_config_mk 'include $(srcdir)/backends/platform/psp/psp.mk' _port_mk="backends/platform/psp/psp.mk"
;; ;;
*) *)
echo "Continuing with auto-detected values ... if you have problems, please add your target to configure." echo "Continuing with auto-detected values ... if you have problems, please add your target to configure."
@ -1667,6 +1812,12 @@ case $_backend in
LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`" LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`"
DEFINES="$DEFINES -DSDL_BACKEND" DEFINES="$DEFINES -DSDL_BACKEND"
;; ;;
linuxmoto)
find_sdlconfig
INCLUDES="$INCLUDES `$_sdlconfig --prefix="$_sdlpath" --cflags`"
LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`"
DEFINES="$DEFINES -DSDL_BACKEND -DLINUXMOTO"
;;
gp2x) gp2x)
find_sdlconfig find_sdlconfig
INCLUDES="$INCLUDES `$_sdlconfig --prefix="$_sdlpath" --cflags`" INCLUDES="$INCLUDES `$_sdlconfig --prefix="$_sdlpath" --cflags`"
@ -1685,6 +1836,10 @@ case $_backend in
OBJCFLAGS="$OBJCFLAGS --std=c99" OBJCFLAGS="$OBJCFLAGS --std=c99"
LIBS="$LIBS -lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES -framework QuartzCore -framework GraphicsServices -framework CoreFoundation -framework Foundation -framework AudioToolbox -framework CoreAudio" LIBS="$LIBS -lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES -framework QuartzCore -framework GraphicsServices -framework CoreFoundation -framework Foundation -framework AudioToolbox -framework CoreAudio"
;; ;;
wince)
INCLUDES="$INCLUDES "'-I$(srcdir) -I$(srcdir)/backends/platform/wince -I$(srcdir)/engines -I$(srcdir)/backends/platform/wince/missing/gcc -I$(srcdir)/backends/platform/wince/CEgui -I$(srcdir)/backends/platform/wince/CEkeys'
LIBS="$LIBS -static -lSDL"
;;
dc) dc)
INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc -isystem $(ronindir)/include' INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc -isystem $(ronindir)/include'
LDFLAGS="$LDFLAGS -Wl,-Ttext,0x8c010000 -nostartfiles "'$(ronindir)/lib/crt0.o -L$(ronindir)/lib' LDFLAGS="$LDFLAGS -Wl,-Ttext,0x8c010000 -nostartfiles "'$(ronindir)/lib/crt0.o -L$(ronindir)/lib'
@ -1694,15 +1849,18 @@ case $_backend in
DEFINES="$DEFINES -D__WII__ -DGEKKO" DEFINES="$DEFINES -D__WII__ -DGEKKO"
case $_host_os in case $_host_os in
gamecube) gamecube)
LIBS="$LIBS -lfat -logc -ldb" LIBS="$LIBS -lgxflux -lfat -logc -ldb"
;; ;;
*) *)
LIBS="$LIBS -ldi -lfat -lwiiuse -lbte -logc -lwiikeyboard -ldb" LIBS="$LIBS -lgxflux -ldi -ltinysmb -lfat -lwiiuse -lbte -logc -lwiikeyboard -ldb"
;; ;;
esac esac
;; ;;
nds)
# TODO nds
;;
psp) psp)
DEFINES="$DEFINES -D__PSP__ -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE" DEFINES="$DEFINES -D__PSP__ -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DDISABLE_DOSBOX_OPL"
INCLUDES="$INCLUDES -I$PSPDEV/psp/include/SDL" INCLUDES="$INCLUDES -I$PSPDEV/psp/include/SDL"
LIBS="$LIBS -lSDL" LIBS="$LIBS -lSDL"
;; ;;
@ -1716,11 +1874,12 @@ MODULES="$MODULES backends/platform/$_backend"
# #
# Do CXXFLAGS now we know the compiler version # Do CXXFLAGS now we know the compiler version
# #
if test "$have_gcc" = yes ; then
if test "$_cxx_major" -ge "3" ; then if test "$_cxx_major" -ge "3" ; 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__
mingw* | dreamcast | wii | gamecube | psp | amigaos*) mingw* | dreamcast | wii | gamecube | psp | wince | amigaos*)
CXXFLAGS="$CXXFLAGS -W -Wno-unused-parameter" CXXFLAGS="$CXXFLAGS -W -Wno-unused-parameter"
;; ;;
*) *)
@ -1728,6 +1887,7 @@ if test "$_cxx_major" -ge "3" ; then
;; ;;
esac esac
add_line_to_config_mk 'HAVE_GCC3 = 1' add_line_to_config_mk 'HAVE_GCC3 = 1'
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP'
fi; fi;
if test "$_cxx_major" -ge "4" && test "$_cxx_minor" -ge "3" ; then if test "$_cxx_major" -ge "4" && test "$_cxx_minor" -ge "3" ; then
@ -1735,6 +1895,7 @@ if test "$_cxx_major" -ge "4" && test "$_cxx_minor" -ge "3" ; then
else else
CXXFLAGS="$CXXFLAGS -Wconversion" CXXFLAGS="$CXXFLAGS -Wconversion"
fi; fi;
fi;
# Some platforms use certain GNU extensions in header files # Some platforms use certain GNU extensions in header files
case $_host_os in case $_host_os in
@ -1761,12 +1922,12 @@ for engine in $_engines; do
# If dynamic plugins aren't supported, mark # If dynamic plugins aren't supported, mark
# all the engines as static # all the engines as static
if test $_dynamic_modules = no ; then if test $_dynamic_modules = no ; then
eval _engine_${engine}_build=static set_var _engine_${engine}_build "static"
else else
# If it wasn't explicitly marked as static or # If it wasn't explicitly marked as static or
# dynamic, use the configured default # dynamic, use the configured default
if test `get_engine_build $engine` = yes ; then if test `get_engine_build $engine` = yes ; then
eval _engine_${engine}_build=${_plugins_default} set_var _engine_${engine}_build "${_plugins_default}"
fi fi
fi fi
@ -1774,7 +1935,7 @@ for engine in $_engines; do
if test `get_engine_build $engine` = dynamic ; then if test `get_engine_build $engine` = dynamic ; then
isbuilt=DYNAMIC_PLUGIN isbuilt=DYNAMIC_PLUGIN
else else
eval _engine_${engine}_build=static set_var _engine_${engine}_build "static"
isbuilt=STATIC_PLUGIN isbuilt=STATIC_PLUGIN
fi fi
fi fi
@ -1871,7 +2032,10 @@ LIBS += $LIBS
RANLIB := $_ranlib RANLIB := $_ranlib
STRIP := $_strip STRIP := $_strip
AR := $_ar AR := $_ar
AS := $_as
ASFLAGS := $ASFLAGS
WINDRES := $_windres WINDRES := $_windres
WINDRESFLAGS := $WINDRESFLAGS
WIN32PATH=$_win32path WIN32PATH=$_win32path
AOS4PATH=$_aos4path AOS4PATH=$_aos4path
STATICLIBPATH=$_staticlibpath STATICLIBPATH=$_staticlibpath
@ -1896,11 +2060,15 @@ LDFLAGS += $LDFLAGS
$_mak_plugins $_mak_plugins
port_mk = $_port_mk
SAVED_CONFIGFLAGS := $SAVED_CONFIGFLAGS SAVED_CONFIGFLAGS := $SAVED_CONFIGFLAGS
SAVED_LDFLAGS := $SAVED_LDFLAGS SAVED_LDFLAGS := $SAVED_LDFLAGS
SAVED_CXX := $SAVED_CXX SAVED_CXX := $SAVED_CXX
SAVED_CXXFLAGS := $SAVED_CXXFLAGS SAVED_CXXFLAGS := $SAVED_CXXFLAGS
SAVED_CPPFLAGS := $SAVED_CPPFLAGS SAVED_CPPFLAGS := $SAVED_CPPFLAGS
SAVED_ASFLAGS := $SAVED_ASFLAGS
SAVED_WINDRESFLAGS := $SAVED_WINDRESFLAGS
EOF EOF
# #

View file

@ -2,7 +2,7 @@ Source: residual
Section: games Section: games
Priority: optional Priority: optional
Maintainer: Pino Toscano <pino@kde.org> Maintainer: Pino Toscano <pino@kde.org>
Build-Depends: debhelper (>= 5.0.0), libgl1-mesa-dev, libsdl1.2-dev, libz-dev Build-Depends: debhelper (>= 5.0.0), libgl1-mesa-dev, libsdl1.2-dev, libz-dev, libmad0-dev, libvorbis-dev (>= 1.0.0-2), libflac-dev (>= 1.1.1-2), libz-dev, libfluidsynth-dev
Standards-Version: 3.8.0 Standards-Version: 3.8.0
Package: residual Package: residual

View file

@ -4,7 +4,7 @@ build: residual
residual: residual:
dh_testdir dh_testdir
./configure --enable-release --prefix=/usr --bindir=/usr/games --datadir=/usr/share/games --mandir=/usr/share/man --disable-vorbis --disable-mad --disable-tremor --disable-flac ./configure --enable-release --prefix=/usr --bindir=/usr/games --datadir=/usr/share/games --mandir=/usr/share/man
$(MAKE) $(MAKE)
clean: clean:

View file

@ -11,15 +11,12 @@ if not exist rpl.exe goto no_rpl
echo Creating MSVC9 project files from the MSVC8 ones echo Creating MSVC9 project files from the MSVC8 ones
copy /y msvc8\*.vcproj msvc9\ copy /y msvc8\*.vcproj msvc9\
copy /y msvc8\*.sln msvc9\ copy /y msvc8\*.sln msvc9\
copy /y msvc8\*.vsprops msvc9\
rpl -e -q "Version=\"8.00\"" "Version=\"9.00\"" msvc9\*.vcproj rpl -e -q "Version=\"8.00\"" "Version=\"9.00\"" msvc9\*.vcproj
rpl -e -q "Version=\"8,00\"" "Version=\"9,00\"" msvc9\*.vcproj rpl -e -q "Version=\"8,00\"" "Version=\"9,00\"" msvc9\*.vcproj
rpl -e -q "Keyword=\"Win32Proj\"" "Keyword=\"Win32Proj\"\n\tTargetFrameworkVersion=\"131072\"" msvc9\*.vcproj rpl -e -q "Keyword=\"Win32Proj\"" "Keyword=\"Win32Proj\"\n\tTargetFrameworkVersion=\"131072\"" msvc9\*.vcproj
rpl -e -q "EntryPointSymbol=\"WinMainCRTStartup\"" "EntryPointSymbol=\"WinMainCRTStartup\"\n\t\t\t\tRandomizedBaseAddress=\"1\"\n\t\t\t\tDataExecutionPrevention=\"0\"" msvc9\residual.vcproj rpl -e -q "Format Version 9.00" "Format Version 10.00" msvc9\scummvm.sln
rpl -e -q "Format Version 9.00" "Format Version 10.00" msvc9\residual.sln rpl -e -q "Format Version 9,00" "Format Version 10,00" msvc9\scummvm.sln
rpl -e -q "Format Version 9,00" "Format Version 10,00" msvc9\residual.sln
rpl -e -q "# Visual C++ Express 2005" "# Visual C++ Express 2008" msvc9\residual.sln
rpl -e -q "# Visual Studio 2005" "# Visual Studio 2008" msvc9\residual
.sln
goto the_end goto the_end
:no_rpl :no_rpl

View file

@ -240,6 +240,18 @@
RelativePath="..\..\common\error.h" RelativePath="..\..\common\error.h"
> >
</File> </File>
<File
RelativePath="..\..\common\EventDispatcher.cpp"
>
</File>
<File
RelativePath="..\..\common\EventRecorder.cpp"
>
</File>
<File
RelativePath="..\..\common\EventRecorder.h"
>
</File>
<File <File
RelativePath="..\..\common\events.h" RelativePath="..\..\common\events.h"
> >
@ -460,6 +472,14 @@
<Filter <Filter
Name="sound" Name="sound"
> >
<File
RelativePath="..\..\sound\audiocd.cpp"
>
</File>
<File
RelativePath="..\..\sound\audiocd.h"
>
</File>
<File <File
RelativePath="..\..\sound\audiostream.cpp" RelativePath="..\..\sound\audiostream.cpp"
> >
@ -468,6 +488,14 @@
RelativePath="..\..\sound\audiostream.h" RelativePath="..\..\sound\audiostream.h"
> >
</File> </File>
<File
RelativePath="..\..\sound\flac.cpp"
>
</File>
<File
RelativePath="..\..\sound\flac.h"
>
</File>
<File <File
RelativePath="..\..\sound\mixer.cpp" RelativePath="..\..\sound\mixer.cpp"
> >
@ -480,6 +508,18 @@
RelativePath="..\..\sound\mixer_intern.h" RelativePath="..\..\sound\mixer_intern.h"
> >
</File> </File>
<File
RelativePath="..\..\sound\module.mk"
>
</File>
<File
RelativePath="..\..\sound\mp3.cpp"
>
</File>
<File
RelativePath="..\..\sound\mp3.h"
>
</File>
<File <File
RelativePath="..\..\sound\rate.cpp" RelativePath="..\..\sound\rate.cpp"
> >
@ -488,6 +528,14 @@
RelativePath="..\..\sound\rate.h" RelativePath="..\..\sound\rate.h"
> >
</File> </File>
<File
RelativePath="..\..\sound\vorbis.cpp"
>
</File>
<File
RelativePath="..\..\sound\vorbis.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="rsc" Name="rsc"

View file

@ -11,15 +11,12 @@ if not exist rpl.exe goto no_rpl
echo Creating MSVC8 project files from the MSVC9 ones echo Creating MSVC8 project files from the MSVC9 ones
copy /y msvc9\*.vcproj msvc8\ copy /y msvc9\*.vcproj msvc8\
copy /y msvc9\*.sln msvc8\ copy /y msvc9\*.sln msvc8\
copy /y msvc9\*.vsprops msvc8\
rpl -e -q "Version=\"9.00\"" "Version=\"8.00\"" msvc8\*.vcproj rpl -e -q "Version=\"9.00\"" "Version=\"8.00\"" msvc8\*.vcproj
rpl -e -q "Version=\"9,00\"" "Version=\"8,00\"" msvc8\*.vcproj rpl -e -q "Version=\"9,00\"" "Version=\"8,00\"" msvc8\*.vcproj
rpl -e -q "\tTargetFrameworkVersion=\"131072\"\n" "" msvc8\*.vcproj rpl -e -q "\tTargetFrameworkVersion=\"131072\"\n" "" msvc8\*.vcproj
rpl -e -q "\t\t\t\tRandomizedBaseAddress=\"1\"\n" "" msvc8\residual.vcproj rpl -e -q "Format Version 10.00" "Format Version 9.00" msvc8\scummvm.sln
rpl -e -q "\t\t\t\tDataExecutionPrevention=\"0\"\n" "" msvc8\residual.vcproj rpl -e -q "Format Version 10,00" "Format Version 9,00" msvc8\scummvm.sln
rpl -e -q "Format Version 10.00" "Format Version 9.00" msvc8\residual.sln
rpl -e -q "Format Version 10,00" "Format Version 9,00" msvc8\residual.sln
rpl -e -q "# Visual C++ Express 2008" "# Visual C++ Express 2005" msvc8\residual.sln
rpl -e -q "# Visual Studio 2008" "# Visual Studio 2005" msvc8\residual.sln
goto the_end goto the_end
:no_rpl :no_rpl

View file

@ -291,14 +291,17 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
} }
} }
if (agdDesc == 0) { if (agdDesc == 0)
return Common::kNoGameDataFoundError; return Common::kNoGameDataFoundError;
}
// If the GUI options were updated, we catch this here and update them in the users config
// file transparently.
Common::updateGameGUIOptions(agdDesc->guioptions | params.guioptions);
debug(2, "Running %s", toGameDescriptor(*agdDesc, params.list).description().c_str()); debug(2, "Running %s", toGameDescriptor(*agdDesc, params.list).description().c_str());
if (!createInstance(syst, engine, agdDesc)) { if (!createInstance(syst, engine, agdDesc))
return Common::kNoGameDataFoundError; return Common::kNoGameDataFoundError;
} else
return Common::kNoError; return Common::kNoError;
} }

View file

@ -29,6 +29,8 @@
#include "common/system.h" #include "common/system.h"
#include "common/events.h" #include "common/events.h"
#include "graphics/scaler.h"
#include "gui/about.h" #include "gui/about.h"
#include "gui/GuiManager.h" #include "gui/GuiManager.h"
#include "gui/launcher.h" #include "gui/launcher.h"

View file

@ -221,7 +221,10 @@ void Engine::syncSoundSettings() {
} }
void Engine::flipMute() { void Engine::flipMute() {
bool mute = false; // Mute will be set to true by default here. This has two reasons:
// - if the game already has an "mute" config entry, it will be overwritten anyway.
// - if it does not have a "mute" config entry, the sound is unmuted currently and should be muted now.
bool mute = true;
if (ConfMan.hasKey("mute")) { if (ConfMan.hasKey("mute")) {
mute = !ConfMan.getBool("mute"); mute = !ConfMan.getBool("mute");

View file

@ -29,6 +29,7 @@
#include "common/error.h" #include "common/error.h"
#include "common/fs.h" #include "common/fs.h"
#include "common/str.h" #include "common/str.h"
#include "graphics/pixelformat.h"
class OSystem; class OSystem;

View file

@ -24,6 +24,7 @@
*/ */
#include "common/events.h" #include "common/events.h"
#include "common/file.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "engines/engine.h" #include "engines/engine.h"
@ -352,9 +353,6 @@ Common::Error GrimEngine::run() {
error("gfx backend doesn't support hardware rendering"); error("gfx backend doesn't support hardware rendering");
#endif #endif
if (g_grim->getGameFlags() & GF_DEMO)
Common::File::addDefaultDirectory(_gameDataDir.getChild("Movies"));
g_driver->setupScreen(640, 480, fullscreen); g_driver->setupScreen(640, 480, fullscreen);
Bitmap *splash_bm = NULL; Bitmap *splash_bm = NULL;

View file

@ -36,6 +36,10 @@
namespace Graphics { namespace Graphics {
class VectorRenderer; class VectorRenderer;
typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const Graphics::DrawStep &);
struct DrawStep { struct DrawStep {
struct Color { struct Color {
uint8 r, g, b; uint8 r, g, b;
@ -58,7 +62,10 @@ struct DrawStep {
kVectorAlignBottom, kVectorAlignBottom,
kVectorAlignTop, kVectorAlignTop,
kVectorAlignCenter kVectorAlignCenter
} xAlign, yAlign; };
VectorAlignment xAlign;
VectorAlignment yAlign;
uint8 shadow, stroke, factor, radius, bevel; /**< Misc options... */ uint8 shadow, stroke, factor, radius, bevel; /**< Misc options... */
@ -67,7 +74,7 @@ struct DrawStep {
uint32 scale; /**< scale of all the coordinates in FIXED POINT with 16 bits mantissa */ uint32 scale; /**< scale of all the coordinates in FIXED POINT with 16 bits mantissa */
void (VectorRenderer::*drawingCall)(const Common::Rect &, const DrawStep &); /** Pointer to drawing function */ DrawingFunctionCallback drawingCall; /**< Pointer to drawing function */
Graphics::Surface *blitSrc; Graphics::Surface *blitSrc;
}; };

View file

@ -365,22 +365,24 @@ applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) {
uint8 r, g, b; uint8 r, g, b;
uint lum; uint lum;
const uint32 shiftMask = (uint32)~( // Mask to clear the last bit of every color component and all unused bits
(1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) | (_format.aLoss == 8 ? 0 : (1 << _format.aShift))) >> 1; const uint32 colorMask = ~((1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) // R/G/B components
| (_format.aLoss == 8 ? 0 : (1 << _format.aShift)) // Alpha component
| ~(_alphaMask | _redMask | _greenMask | _blueMask)); // All unused bits
if (shadingStyle == GUI::ThemeEngine::kShadingDim) { if (shadingStyle == GUI::ThemeEngine::kShadingDim) {
int n = (pixels + 7) >> 3; int n = (pixels + 7) >> 3;
switch (pixels % 8) { switch (pixels % 8) {
case 0: do { case 0: do {
*ptr = (*ptr >> 1) & shiftMask; ++ptr; *ptr = (*ptr & colorMask) >> 1; ++ptr;
case 7: *ptr = (*ptr >> 1) & shiftMask; ++ptr; case 7: *ptr = (*ptr & colorMask) >> 1; ++ptr;
case 6: *ptr = (*ptr >> 1) & shiftMask; ++ptr; case 6: *ptr = (*ptr & colorMask) >> 1; ++ptr;
case 5: *ptr = (*ptr >> 1) & shiftMask; ++ptr; case 5: *ptr = (*ptr & colorMask) >> 1; ++ptr;
case 4: *ptr = (*ptr >> 1) & shiftMask; ++ptr; case 4: *ptr = (*ptr & colorMask) >> 1; ++ptr;
case 3: *ptr = (*ptr >> 1) & shiftMask; ++ptr; case 3: *ptr = (*ptr & colorMask) >> 1; ++ptr;
case 2: *ptr = (*ptr >> 1) & shiftMask; ++ptr; case 2: *ptr = (*ptr & colorMask) >> 1; ++ptr;
case 1: *ptr = (*ptr >> 1) & shiftMask; ++ptr; case 1: *ptr = (*ptr & colorMask) >> 1; ++ptr;
} while (--n > 0); } while (--n > 0);
} }
@ -423,7 +425,7 @@ calcGradient(uint32 pos, uint32 max) {
output |= ((_gradientStart & _redMask) + ((Base::_gradientBytes[0] * pos) >> 12)) & _redMask; output |= ((_gradientStart & _redMask) + ((Base::_gradientBytes[0] * pos) >> 12)) & _redMask;
output |= ((_gradientStart & _greenMask) + ((Base::_gradientBytes[1] * pos) >> 12)) & _greenMask; output |= ((_gradientStart & _greenMask) + ((Base::_gradientBytes[1] * pos) >> 12)) & _greenMask;
output |= ((_gradientStart & _blueMask) + ((Base::_gradientBytes[2] * pos) >> 12)) & _blueMask; output |= ((_gradientStart & _blueMask) + ((Base::_gradientBytes[2] * pos) >> 12)) & _blueMask;
output |= ~(_redMask | _greenMask | _blueMask); output |= _alphaMask;
return output; return output;
} }
@ -599,12 +601,12 @@ drawRoundedSquare(int x, int y, int r, int w, int h) {
w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0) w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0)
return; return;
if ((r << 1) > w || (r << 1) > h) if ((r * 2) > w || (r * 2) > h)
r = MIN(w >> 1, h >> 1); r = MIN(w /2, h / 2);
if (Base::_fillMode != kFillDisabled && Base::_shadowOffset if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
&& x + w + Base::_shadowOffset < Base::_activeSurface->w && x + w + Base::_shadowOffset + 1 < Base::_activeSurface->w
&& y + h + Base::_shadowOffset < Base::_activeSurface->h) { && y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h) {
drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset); drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset);
} }
@ -918,10 +920,12 @@ drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, P
} }
int i, j; int i, j;
x = MAX(x - bevel, 0); x = MAX(x - bevel, 0);
y = MAX(y - bevel, 0); y = MAX(y - bevel, 0);
h += bevel << 1;
w += bevel << 1; w = MIN(w + (bevel * 2), (int)_activeSurface->w);
h = MIN(h + (bevel * 2), (int)_activeSurface->h);
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);

View file

@ -237,6 +237,33 @@ struct ColorMasks<8888> {
}; };
}; };
#ifdef __WII__
/* Gamecube/Wii specific ColorMask ARGB3444 */
template<>
struct ColorMasks<3444> {
enum {
kBytesPerPixel = 2,
kAlphaBits = 3,
kRedBits = 4,
kGreenBits = 4,
kBlueBits = 4,
kBlueShift = 0,
kGreenShift = kBlueBits,
kRedShift = kGreenBits+kBlueBits,
kAlphaShift = kGreenBits+kBlueBits+kRedBits,
kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
kRedMask = ((1 << kRedBits) - 1) << kRedShift,
kGreenMask = ((1 << kGreenBits) - 1) << kGreenShift,
kBlueMask = ((1 << kBlueBits) - 1) << kBlueShift,
kRedBlueMask = kRedMask | kBlueMask
};
};
#endif
template<class T> template<class T>
uint32 RGBToColor(uint8 r, uint8 g, uint8 b) { uint32 RGBToColor(uint8 r, uint8 g, uint8 b) {
return T::kAlphaMask | return T::kAlphaMask |

View file

@ -57,14 +57,14 @@ bool CursorManager::showMouse(bool visible) {
return g_system->showMouse(visible); return g_system->showMouse(visible);
} }
void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetScale) { void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) {
Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale); Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format);
cur->_visible = isVisible(); cur->_visible = isVisible();
_cursorStack.push(cur); _cursorStack.push(cur);
if (buf) { if (buf) {
g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale); g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format);
} }
} }
@ -77,7 +77,7 @@ void CursorManager::popCursor() {
if (!_cursorStack.empty()) { if (!_cursorStack.empty()) {
cur = _cursorStack.top(); cur = _cursorStack.top();
g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_targetScale); g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_targetScale, &cur->_format);
} }
g_system->showMouse(isVisible()); g_system->showMouse(isVisible());
@ -93,15 +93,24 @@ void CursorManager::popAllCursors() {
g_system->showMouse(isVisible()); g_system->showMouse(isVisible());
} }
void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) {
void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetScale) {
if (_cursorStack.empty()) { if (_cursorStack.empty()) {
pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale); pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format);
return; return;
} }
Cursor *cur = _cursorStack.top(); Cursor *cur = _cursorStack.top();
#ifdef USE_RGB_COLOR
uint size;
if (!format)
size = w * h;
else
size = w * h * format->bytesPerPixel;
#else
uint size = w * h; uint size = w * h;
#endif
if (cur->_size < size) { if (cur->_size < size) {
delete[] cur->_data; delete[] cur->_data;
@ -118,8 +127,14 @@ void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX,
cur->_hotspotY = hotspotY; cur->_hotspotY = hotspotY;
cur->_keycolor = keycolor; cur->_keycolor = keycolor;
cur->_targetScale = targetScale; cur->_targetScale = targetScale;
#ifdef USE_RGB_COLOR
if (format)
cur->_format = *format;
else
cur->_format = Graphics::PixelFormat::createFormatCLUT8();
#endif
g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale); g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format);
} }
bool CursorManager::supportsCursorPalettes() { bool CursorManager::supportsCursorPalettes() {

View file

@ -28,6 +28,10 @@
#include "common/sys.h" #include "common/sys.h"
#include "common/stack.h" #include "common/stack.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "graphics/pixelformat.h"
#ifdef USE_RGB_COLOR
#include "common/system.h"
#endif
namespace Graphics { namespace Graphics {
@ -36,7 +40,21 @@ public:
/** Query whether the mouse cursor is visible. */ /** Query whether the mouse cursor is visible. */
bool isVisible(); bool isVisible();
/** Show or hide the mouse cursor. */ /**
* Show or hide the mouse cursor.
*
* This function does not call OSystem::updateScreen, when visible is true.
* This fact might result in a non visible mouse cursor if the caller does
* not call OSystem::updateScreen itself after a showMouse(true) call.
*
* TODO: We might want to reconsider this behavior, it might be confusing
* for the user to call OSystem::updateScreen separately, on the other
* hand OSystem::updateScreen might as well display unwanted changes on
* the screen. Another alternative would be to let the backend worry
* about this on OSystem::showMouse call.
*
* @see OSystem::showMouse.
*/
bool showMouse(bool visible); bool showMouse(bool visible);
/** /**
@ -51,12 +69,13 @@ public:
* @param hotspotY the hotspot Y coordinate * @param hotspotY the hotspot Y coordinate
* @param keycolor the index for the transparent color * @param keycolor the index for the transparent color
* @param targetScale the scale for which the cursor is designed * @param targetScale the scale for which the cursor is designed
* * @param format a pointer to the pixel format which the cursor graphic uses,
* CLUT8 will be used if this is NULL or not specified.
* @note It is ok for the buffer to be a NULL pointer. It is sometimes * @note It is ok for the buffer to be a NULL pointer. It is sometimes
* useful to push a "dummy" cursor and modify it later. The * useful to push a "dummy" cursor and modify it later. The
* cursor will be added to the stack, but not to the backend. * cursor will be added to the stack, but not to the backend.
*/ */
void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetScale = 1); void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, const Graphics::PixelFormat *format = NULL);
/** /**
* Pop a cursor from the stack, and restore the previous one to the * Pop a cursor from the stack, and restore the previous one to the
@ -76,8 +95,10 @@ public:
* @param hotspotY the hotspot Y coordinate * @param hotspotY the hotspot Y coordinate
* @param keycolor the index for the transparent color * @param keycolor the index for the transparent color
* @param targetScale the scale for which the cursor is designed * @param targetScale the scale for which the cursor is designed
* @param format a pointer to the pixel format which the cursor graphic uses,
* CLUT8 will be used if this is NULL or not specified.
*/ */
void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetScale = 1); void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, const Graphics::PixelFormat *format = NULL);
/** /**
* Pop all of the cursors and cursor palettes from their respective stacks. * Pop all of the cursors and cursor palettes from their respective stacks.
@ -152,13 +173,24 @@ private:
uint _height; uint _height;
int _hotspotX; int _hotspotX;
int _hotspotY; int _hotspotY;
byte _keycolor; uint32 _keycolor;
Graphics::PixelFormat _format;
byte _targetScale; byte _targetScale;
uint _size; uint _size;
Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, const Graphics::PixelFormat *format = NULL) {
Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetScale = 1) { #ifdef USE_RGB_COLOR
if (!format)
_format = Graphics::PixelFormat::createFormatCLUT8();
else
_format = *format;
_size = w * h * _format.bytesPerPixel;
_keycolor = keycolor & ((1 << (_format.bytesPerPixel << 3)) - 1);
#else
_format = Graphics::PixelFormat::createFormatCLUT8();
_size = w * h; _size = w * h;
_keycolor = keycolor & 0xFF;
#endif
_data = new byte[_size]; _data = new byte[_size];
if (data && _data) if (data && _data)
memcpy(_data, data, _size); memcpy(_data, data, _size);
@ -166,7 +198,6 @@ private:
_height = h; _height = h;
_hotspotX = hotspotX; _hotspotX = hotspotX;
_hotspotY = hotspotY; _hotspotY = hotspotY;
_keycolor = keycolor;
_targetScale = targetScale; _targetScale = targetScale;
} }
@ -202,7 +233,6 @@ private:
delete[] _data; delete[] _data;
} }
}; };
Common::Stack<Cursor *> _cursorStack; Common::Stack<Cursor *> _cursorStack;
Common::Stack<Palette *> _cursorPaletteStack; Common::Stack<Palette *> _cursorPaletteStack;
}; };

View file

@ -572,8 +572,10 @@ bitmap_t bdf_hexval(unsigned char *buf) {
NewFont *NewFont::loadFont(Common::SeekableReadStream &stream) { NewFont *NewFont::loadFont(Common::SeekableReadStream &stream) {
NewFontData *data = bdf_read_font(stream); NewFontData *data = bdf_read_font(stream);
if (!data) if (!data || stream.err()) {
free_font(data);
return 0; return 0;
}
FontDesc desc; FontDesc desc;
desc.name = data->name; desc.name = data->name;
@ -731,6 +733,14 @@ NewFont *NewFont::loadFromCache(Common::SeekableReadStream &stream) {
} }
} }
if (stream.err() || stream.eos()) {
free(data->bits);
free(data->offset);
free(data->width);
free(data);
return 0;
}
FontDesc desc; FontDesc desc;
desc.name = data->name; desc.name = data->name;
desc.maxwidth = data->maxwidth; desc.maxwidth = data->maxwidth;
@ -750,7 +760,7 @@ NewFont *NewFont::loadFromCache(Common::SeekableReadStream &stream) {
desc.bits_size = data->bits_size; desc.bits_size = data->bits_size;
font = new NewFont(desc, data); font = new NewFont(desc, data);
if (!font || stream.ioFailed()) { if (!font) {
free(data->bits); free(data->bits);
free(data->offset); free(data->offset);
free(data->width); free(data->width);

View file

@ -27,6 +27,7 @@
#define GRAPHICS_PIXELFORMAT_H #define GRAPHICS_PIXELFORMAT_H
#include "common/sys.h" #include "common/sys.h"
#include "common/list.h"
namespace Graphics { namespace Graphics {
@ -50,6 +51,24 @@ struct PixelFormat {
byte rLoss, gLoss, bLoss, aLoss; /**< Precision loss of each color component. */ byte rLoss, gLoss, bLoss, aLoss; /**< Precision loss of each color component. */
byte rShift, gShift, bShift, aShift; /**< Binary left shift of each color component in the pixel value. */ byte rShift, gShift, bShift, aShift; /**< Binary left shift of each color component in the pixel value. */
inline PixelFormat() {
bytesPerPixel =
rLoss = gLoss = bLoss = aLoss =
rShift = gShift = bShift = aShift = 0;
}
inline PixelFormat(byte BytesPerPixel,
byte RBits, byte GBits, byte BBits, byte ABits,
byte RShift, byte GShift, byte BShift, byte AShift) {
bytesPerPixel = BytesPerPixel;
rLoss = 8 - RBits, gLoss = 8 - GBits, bLoss = 8 - BBits, aLoss = 8 - ABits;
rShift = RShift, gShift = GShift, bShift = BShift, aShift = AShift;
}
static inline PixelFormat createFormatCLUT8() {
return PixelFormat(1, 0, 0, 0, 0, 0, 0, 0, 0);
}
inline bool operator==(const PixelFormat &fmt) const { inline bool operator==(const PixelFormat &fmt) const {
// TODO: If aLoss==8, then the value of aShift is irrelevant, and should be ignored. // TODO: If aLoss==8, then the value of aShift is irrelevant, and should be ignored.
return 0 == memcmp(this, &fmt, sizeof(PixelFormat)); return 0 == memcmp(this, &fmt, sizeof(PixelFormat));
@ -129,6 +148,26 @@ struct PixelFormat {
} }
}; };
/**
* Determines the first matching format between two lists.
*
* @param backend The higher priority list, meant to be a list of formats supported by the backend
* @param frontend The lower priority list, meant to be a list of formats supported by the engine
* @return The first item on the backend list that also occurs on the frontend list
* or PixelFormat::createFormatCLUT8() if no matching formats were found.
*/
inline PixelFormat findCompatibleFormat(Common::List<PixelFormat> backend, Common::List<PixelFormat> frontend) {
#ifdef USE_RGB_COLOR
for (Common::List<PixelFormat>::iterator i = backend.begin(); i != backend.end(); ++i) {
for (Common::List<PixelFormat>::iterator j = frontend.begin(); j != frontend.end(); ++j) {
if (*i == *j)
return *i;
}
}
#endif
return PixelFormat::createFormatCLUT8();
}
} // end of namespace Graphics } // end of namespace Graphics
#endif #endif

View file

@ -84,7 +84,7 @@ void EditTextWidget::drawWidget() {
// Draw the text // Draw the text
adjustOffset(); adjustOffset();
g_gui.theme()->drawText(Common::Rect(_x+2+ _leftPadding,_y+2, _x+_leftPadding+getEditRect().width()+2, _y+_h-2), _editString, _state, Graphics::kTextAlignLeft, false, -_editScrollOffset, false, _font); g_gui.theme()->drawText(Common::Rect(_x+2+ _leftPadding,_y+2, _x+_leftPadding+getEditRect().width()+2, _y+_h-2), _editString, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, -_editScrollOffset, false, _font);
} }
Common::Rect EditTextWidget::getEditRect() const { Common::Rect EditTextWidget::getEditRect() const {

View file

@ -72,7 +72,6 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled),
error("Failed to load any GUI theme, aborting"); error("Failed to load any GUI theme, aborting");
} }
} }
_themeChange = false;
} }
GuiManager::~GuiManager() { GuiManager::~GuiManager() {
@ -143,12 +142,20 @@ bool GuiManager::loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx)
// Enable the new theme // Enable the new theme
// //
_theme = newTheme; _theme = newTheme;
_themeChange = true; _useStdCursor = !_theme->ownCursor();
// If _stateIsSaved is set, we know that a Theme is already initialized,
// thus we initialize the new theme properly
if (_stateIsSaved) {
_theme->enable();
if (_useStdCursor)
setupCursor();
}
// refresh all dialogs // refresh all dialogs
for (int i = 0; i < _dialogStack.size(); ++i) { for (int i = 0; i < _dialogStack.size(); ++i)
_dialogStack[i]->reflowLayout(); _dialogStack[i]->reflowLayout();
}
// We need to redraw immediately. Otherwise // We need to redraw immediately. Otherwise
// some other event may cause a widget to be // some other event may cause a widget to be
@ -157,10 +164,6 @@ bool GuiManager::loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx)
redraw(); redraw();
_system->updateScreen(); _system->updateScreen();
Common::Event event;
event.type = Common::EVENT_SCREEN_CHANGED;
_system->getEventManager()->pushEvent(event);
return true; return true;
} }
@ -233,7 +236,6 @@ void GuiManager::runLoop() {
// _theme->refresh(); // _theme->refresh();
_themeChange = false;
_redrawStatus = kRedrawFull; _redrawStatus = kRedrawFull;
redraw(); redraw();
} }
@ -285,21 +287,6 @@ void GuiManager::runLoop() {
Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y);
// HACK to change the cursor to the new themes one
if (_themeChange) {
_theme->enable();
_useStdCursor = !_theme->ownCursor();
if (_useStdCursor)
setupCursor();
// _theme->refresh();
_themeChange = false;
_redrawStatus = kRedrawFull;
redraw();
}
if (lastRedraw + waitTime < _system->getMillis()) { if (lastRedraw + waitTime < _system->getMillis()) {
_theme->updateScreen(); _theme->updateScreen();
_system->updateScreen(); _system->updateScreen();

View file

@ -122,8 +122,6 @@ protected:
int _cursorAnimateTimer; int _cursorAnimateTimer;
byte _cursor[2048]; byte _cursor[2048];
bool _themeChange;
void initKeymap(); void initKeymap();
void saveState(); void saveState();

View file

@ -24,6 +24,8 @@
#include "common/system.h" #include "common/system.h"
#include "common/events.h" #include "common/events.h"
#include "common/frac.h"
#include "gui/ListWidget.h" #include "gui/ListWidget.h"
#include "gui/ScrollBarWidget.h" #include "gui/ScrollBarWidget.h"
#include "gui/dialog.h" #include "gui/dialog.h"
@ -62,6 +64,7 @@ ListWidget::ListWidget(GuiObject *boss, const String &name, uint32 cmd)
_editable = true; _editable = true;
_quickSelect = true; _quickSelect = true;
_editColor = ThemeEngine::kFontColorNormal;
} }
ListWidget::ListWidget(GuiObject *boss, int x, int y, int w, int h, uint32 cmd) ListWidget::ListWidget(GuiObject *boss, int x, int y, int w, int h, uint32 cmd)
@ -105,6 +108,22 @@ Widget *ListWidget::findWidget(int x, int y) {
} }
void ListWidget::setSelected(int item) { void ListWidget::setSelected(int item) {
// HACK/FIXME: If our _listIndex has a non zero size,
// we will need to look up, whether the user selected
// item is present in that list
if (_listIndex.size()) {
int filteredItem = -1;
for (uint i = 0; i < _listIndex.size(); ++i) {
if (_listIndex[i] == item) {
filteredItem = i;
break;
}
}
item = filteredItem;
}
assert(item >= -1 && item < (int)_list.size()); assert(item >= -1 && item < (int)_list.size());
// We only have to do something if the widget is enabled and the selection actually changes // We only have to do something if the widget is enabled and the selection actually changes
@ -123,7 +142,17 @@ void ListWidget::setSelected(int item) {
} }
} }
void ListWidget::setList(const StringList &list) { ThemeEngine::FontColor ListWidget::getSelectionColor() const {
if (_listColors.empty())
return ThemeEngine::kFontColorNormal;
if (_filter.empty())
return _listColors[_selectedItem];
else
return _listColors[_listIndex[_selectedItem]];
}
void ListWidget::setList(const StringList &list, const ColorList *colors) {
if (_editMode && _caretVisible) if (_editMode && _caretVisible)
drawCaret(true); drawCaret(true);
@ -131,6 +160,13 @@ void ListWidget::setList(const StringList &list) {
_dataList = list; _dataList = list;
_list = list; _list = list;
_filter.clear(); _filter.clear();
_listIndex.clear();
_listColors.clear();
if (colors) {
_listColors = *colors;
assert(_listColors.size() == _dataList.size());
}
int size = list.size(); int size = list.size();
if (_currentPos >= size) if (_currentPos >= size)
@ -143,7 +179,19 @@ void ListWidget::setList(const StringList &list) {
scrollBarRecalc(); scrollBarRecalc();
} }
void ListWidget::append(const String &s) { void ListWidget::append(const String &s, ThemeEngine::FontColor color) {
if (_dataList.size() == _listColors.size()) {
// If the color list has the size of the data list, we append the color.
_listColors.push_back(color);
} else if (!_listColors.size() && color != ThemeEngine::kFontColorNormal) {
// If it's the first entry to use a non default color, we will fill
// up all other entries of the color list with the default color and
// add the requested color for the new entry.
for (uint i = 0; i < _dataList.size(); ++i)
_listColors.push_back(ThemeEngine::kFontColorNormal);
_listColors.push_back(color);
}
_dataList.push_back(s); _dataList.push_back(s);
_list.push_back(s); _list.push_back(s);
@ -356,8 +404,13 @@ bool ListWidget::handleKeyUp(Common::KeyState state) {
return true; return true;
} }
void ListWidget::receivedFocusWidget() {
// Redraw the widget so the selection color will change
draw();
}
void ListWidget::lostFocusWidget() { void ListWidget::lostFocusWidget() {
// If we loose focus, we simply forget the user changes // If we lose focus, we simply forget the user changes
_editMode = false; _editMode = false;
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
drawCaret(true); drawCaret(true);
@ -387,15 +440,14 @@ void ListWidget::drawWidget() {
for (i = 0, pos = _currentPos; i < _entriesPerPage && pos < len; i++, pos++) { for (i = 0, pos = _currentPos; i < _entriesPerPage && pos < len; i++, pos++) {
const int y = _y + _topPadding + kLineHeight * i; const int y = _y + _topPadding + kLineHeight * i;
const int fontHeight = kLineHeight; const int fontHeight = kLineHeight;
bool inverted = false; ThemeEngine::TextInversionState inverted = ThemeEngine::kTextInversionNone;
// Draw the selected item inverted, on a highlighted background. // Draw the selected item inverted, on a highlighted background.
if (_selectedItem == pos) { if (_selectedItem == pos) {
if (_hasFocus) if (_hasFocus)
inverted = true; inverted = ThemeEngine::kTextInversionFocus;
else else
g_gui.theme()->drawWidgetBackground(Common::Rect(_x, y - 1, _x + _w - 1, y + fontHeight - 1), inverted = ThemeEngine::kTextInversion;
0, ThemeEngine::kWidgetBackgroundBorderSmall);
} }
Common::Rect r(getEditRect()); Common::Rect r(getEditRect());
@ -413,17 +465,27 @@ void ListWidget::drawWidget() {
int width; int width;
ThemeEngine::FontColor color = ThemeEngine::kFontColorNormal;
if (!_listColors.empty()) {
if (_filter.empty() || _selectedItem == -1)
color = _listColors[pos];
else
color = _listColors[_listIndex[pos]];
}
if (_selectedItem == pos && _editMode) { if (_selectedItem == pos && _editMode) {
buffer = _editString; buffer = _editString;
color = _editColor;
adjustOffset(); adjustOffset();
width = _w - r.left - _hlRightPadding - _leftPadding - scrollbarW; width = _w - r.left - _hlRightPadding - _leftPadding - scrollbarW;
g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state,
buffer, _state, Graphics::kTextAlignLeft, inverted, pad, true); Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
} else { } else {
buffer = _list[pos]; buffer = _list[pos];
width = _w - r.left - scrollbarW; width = _w - r.left - scrollbarW;
g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state,
buffer, _state, Graphics::kTextAlignLeft, inverted, pad, true); Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
} }
_textWidth[i] = width; _textWidth[i] = width;
@ -481,6 +543,14 @@ void ListWidget::startEditMode() {
if (_editable && !_editMode && _selectedItem >= 0) { if (_editable && !_editMode && _selectedItem >= 0) {
_editMode = true; _editMode = true;
setEditString(_list[_selectedItem]); setEditString(_list[_selectedItem]);
if (_listColors.empty()) {
_editColor = ThemeEngine::kFontColorNormal;
} else {
if (_filter.empty())
_editColor = _listColors[_selectedItem];
else
_editColor = _listColors[_listIndex[_selectedItem]];
}
draw(); draw();
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
} }
@ -522,13 +592,15 @@ void ListWidget::reflowLayout() {
// of the list. // of the list.
// We do a rough rounding on the decimal places of Entries Per Page, // We do a rough rounding on the decimal places of Entries Per Page,
// to add another entry even if it goes a tad over the padding. // to add another entry even if it goes a tad over the padding.
_entriesPerPage = ((_h - _topPadding - _bottomPadding) << 16) / kLineHeight; frac_t entriesPerPage = intToFrac(_h - _topPadding - _bottomPadding) / kLineHeight;
if ((uint)(_entriesPerPage & 0xFFFF) >= 0xF000) // Our threshold before we add another entry is 0.9375 (0xF000 with FRAC_BITS being 16).
_entriesPerPage += (1 << 16); const frac_t threshold = intToFrac(15) / 16;
_entriesPerPage >>= 16; if ((frac_t)(entriesPerPage & FRAC_LO_MASK) >= threshold)
entriesPerPage += FRAC_ONE;
_entriesPerPage = fracToInt(entriesPerPage);
assert(_entriesPerPage > 0); assert(_entriesPerPage > 0);
delete[] _textWidth; delete[] _textWidth;
@ -560,9 +632,12 @@ void ListWidget::setFilter(const String &filter, bool redraw) {
if (_filter.empty()) { if (_filter.empty()) {
// No filter -> display everything // No filter -> display everything
_list = _dataList; _list = _dataList;
_listIndex.clear();
} else { } else {
// Restrict the list to everything which contains _filter as a substring, // Restrict the list to everything which contains all words in _filter
// ignoring case. // as substrings, ignoring case.
Common::StringTokenizer tok(_filter);
String tmp; String tmp;
int n = 0; int n = 0;
@ -572,7 +647,16 @@ void ListWidget::setFilter(const String &filter, bool redraw) {
for (StringList::iterator i = _dataList.begin(); i != _dataList.end(); ++i, ++n) { for (StringList::iterator i = _dataList.begin(); i != _dataList.end(); ++i, ++n) {
tmp = *i; tmp = *i;
tmp.toLowercase(); tmp.toLowercase();
if (tmp.contains(_filter)) { bool matches = true;
tok.reset();
while (!tok.empty()) {
if (!tmp.contains(tok.nextToken())) {
matches = false;
break;
}
}
if (matches) {
_list.push_back(*i); _list.push_back(*i);
_listIndex.push_back(n); _listIndex.push_back(n);
} }

View file

@ -28,6 +28,8 @@
#include "gui/editable.h" #include "gui/editable.h"
#include "common/str.h" #include "common/str.h"
#include "gui/ThemeEngine.h"
namespace GUI { namespace GUI {
class ScrollBarWidget; class ScrollBarWidget;
@ -51,9 +53,11 @@ class ListWidget : public EditableWidget {
public: public:
typedef Common::String String; typedef Common::String String;
typedef Common::StringList StringList; typedef Common::StringList StringList;
typedef Common::Array<ThemeEngine::FontColor> ColorList;
protected: protected:
StringList _list; StringList _list;
StringList _dataList; StringList _dataList;
ColorList _listColors;
Common::Array<int> _listIndex; Common::Array<int> _listIndex;
bool _editable; bool _editable;
bool _editMode; bool _editMode;
@ -80,6 +84,8 @@ protected:
uint32 _cmd; uint32 _cmd;
ThemeEngine::FontColor _editColor;
public: public:
ListWidget(GuiObject *boss, const String &name, uint32 cmd = 0); ListWidget(GuiObject *boss, const String &name, uint32 cmd = 0);
ListWidget(GuiObject *boss, int x, int y, int w, int h, uint32 cmd = 0); ListWidget(GuiObject *boss, int x, int y, int w, int h, uint32 cmd = 0);
@ -87,20 +93,33 @@ public:
virtual Widget *findWidget(int x, int y); virtual Widget *findWidget(int x, int y);
void setList(const StringList &list); void setList(const StringList &list, const ColorList *colors = 0);
void append(const String &s);
const StringList &getList() const { return _dataList; } const StringList &getList() const { return _dataList; }
int getSelected() const { return (_filter.empty() || _selectedItem == -1) ? _selectedItem : _listIndex[_selectedItem]; }
void append(const String &s, ThemeEngine::FontColor color = ThemeEngine::kFontColorNormal);
void setSelected(int item); void setSelected(int item);
int getSelected() const { return (_filter.empty() || _selectedItem == -1) ? _selectedItem : _listIndex[_selectedItem]; }
const String &getSelectedString() const { return _list[_selectedItem]; } const String &getSelectedString() const { return _list[_selectedItem]; }
ThemeEngine::FontColor getSelectionColor() const;
void setNumberingMode(NumberingMode numberingMode) { _numberingMode = numberingMode; } void setNumberingMode(NumberingMode numberingMode) { _numberingMode = numberingMode; }
bool isEditable() const { return _editable; }
void setEditable(bool editable) { _editable = editable; }
void scrollTo(int item); void scrollTo(int item);
void scrollToEnd(); void scrollToEnd();
void enableQuickSelect(bool enable) { _quickSelect = enable; } void enableQuickSelect(bool enable) { _quickSelect = enable; }
String getQuickSelectString() const { return _quickSelectStr; } String getQuickSelectString() const { return _quickSelectStr; }
bool isEditable() const { return _editable; }
void setEditable(bool editable) { _editable = editable; }
void setEditColor(ThemeEngine::FontColor color) { _editColor = color; }
// Made startEditMode/endEditMode for SaveLoadChooser
void startEditMode();
void endEditMode();
void setFilter(const String &filter, bool redraw = true); void setFilter(const String &filter, bool redraw = true);
virtual void handleTickle(); virtual void handleTickle();
@ -115,10 +134,6 @@ public:
virtual bool wantsFocus() { return true; } virtual bool wantsFocus() { return true; }
// Made startEditMode for SCUMM's SaveLoadChooser
void startEditMode();
void endEditMode();
protected: protected:
void drawWidget(); void drawWidget();
@ -130,6 +145,7 @@ protected:
Common::Rect getEditRect() const; Common::Rect getEditRect() const;
void receivedFocusWidget();
void lostFocusWidget(); void lostFocusWidget();
void scrollToCurrent(); void scrollToCurrent();

View file

@ -345,7 +345,7 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) {
g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x+w, y+kLineHeight)); g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x+w, y+kLineHeight));
} else { } else {
g_gui.theme()->drawText(Common::Rect(x+1, y+2, x+w, y+2+kLineHeight), name, hilite ? ThemeEngine::kStateHighlight : ThemeEngine::kStateEnabled, g_gui.theme()->drawText(Common::Rect(x+1, y+2, x+w, y+2+kLineHeight), name, hilite ? ThemeEngine::kStateHighlight : ThemeEngine::kStateEnabled,
Graphics::kTextAlignLeft, false, _leftPadding); Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, _leftPadding);
} }
} }

View file

@ -63,9 +63,9 @@ void ScrollBarWidget::handleMouseDown(int x, int y, int button, int clickCount)
_currentPos++; _currentPos++;
_draggingPart = kDownArrowPart; _draggingPart = kDownArrowPart;
} else if (y < _sliderPos) { } else if (y < _sliderPos) {
_currentPos -= _entriesPerPage; _currentPos -= _entriesPerPage - 1;
} else if (y >= _sliderPos + _sliderHeight) { } else if (y >= _sliderPos + _sliderHeight) {
_currentPos += _entriesPerPage; _currentPos += _entriesPerPage - 1;
} else { } else {
_draggingPart = kSliderPart; _draggingPart = kSliderPart;
_sliderDeltaMouseDownPos = y - _sliderPos; _sliderDeltaMouseDownPos = y - _sliderPos;

View file

@ -91,7 +91,37 @@ int TabWidget::addTab(const String &title) {
int numTabs = _tabs.size(); int numTabs = _tabs.size();
// HACK: Nintendo DS uses a custom config dialog. This dialog does not work with
// our default "Globals.TabWidget.Tab.Width" setting.
//
// TODO: Add proper handling in the theme layout for such cases.
//
// There are different solutions to this problem:
// - offer a "Tab.Width" setting per tab widget and thus let the Ninteno DS
// backend set a default value for its special dialog.
//
// - change our themes to use auto width calculaction by default
//
// - change "Globals.TabWidget.Tab.Width" to be the minimal tab width setting and
// rename it accordingly.
// Actually this solution is pretty similar to our HACK for the Nintendo DS
// backend. This hack enables auto width calculation by default with the
// "Globals.TabWidget.Tab.Width" value as minimal width for the tab buttons.
//
// - we might also consider letting every tab button having its own width.
//
// - other solutions you can think of, which are hopefully less evil ;-).
//
// Of course also the Ninteno DS' dialog should be in our layouting engine, instead
// of being hard coded like it is right now.
//
// There are checks for __DS__ all over this source file to take care of the
// aforemnetioned problem.
#ifdef __DS__
if (true) {
#else
if (g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width") == 0) { if (g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width") == 0) {
#endif
if (_tabWidth == 0) if (_tabWidth == 0)
_tabWidth = 40; _tabWidth = 40;
// Determine the new tab width // Determine the new tab width
@ -217,6 +247,10 @@ void TabWidget::reflowLayout() {
if (_tabWidth == 0) { if (_tabWidth == 0) {
_tabWidth = 40; _tabWidth = 40;
#ifdef __DS__
}
if (true) {
#endif
int maxWidth = _w / _tabs.size(); int maxWidth = _w / _tabs.size();
for (uint i = 0; i < _tabs.size(); ++i) { for (uint i = 0; i < _tabs.size(); ++i) {

View file

@ -76,6 +76,10 @@ public:
*/ */
void removeTab(int tabID); void removeTab(int tabID);
int getActiveTab() {
return _activeTab;
}
/** /**
* Set the active tab by specifying a valid tab ID. * Set the active tab by specifying a valid tab ID.
* setActiveTab changes the value of _firstWidget. This means new * setActiveTab changes the value of _firstWidget. This means new

View file

@ -56,10 +56,10 @@ const char * const ThemeEngine::kImageSearch = "search.bmp";
struct TextDrawData { struct TextDrawData {
const Graphics::Font *_fontPtr; const Graphics::Font *_fontPtr;
};
struct { struct TextColorData {
uint8 r, g, b; int r, g, b;
} _color;
}; };
struct WidgetDrawData { struct WidgetDrawData {
@ -67,6 +67,7 @@ struct WidgetDrawData {
Common::List<Graphics::DrawStep> _steps; Common::List<Graphics::DrawStep> _steps;
TextData _textDataId; TextData _textDataId;
TextColor _textColorId;
Graphics::TextAlign _textAlignH; Graphics::TextAlign _textAlignH;
GUI::ThemeEngine::TextAlignVertical _textAlignV; GUI::ThemeEngine::TextAlignVertical _textAlignV;
@ -116,16 +117,17 @@ protected:
class ThemeItemTextData : public ThemeItem { class ThemeItemTextData : public ThemeItem {
public: public:
ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const Common::Rect &area, const Common::String &text, ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const TextColorData *color, const Common::Rect &area, const Common::String &text,
Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV, Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV,
bool ellipsis, bool restoreBg, int deltaX) : bool ellipsis, bool restoreBg, int deltaX) :
ThemeItem(engine, area), _data(data), _text(text), _alignH(alignH), _alignV(alignV), ThemeItem(engine, area), _data(data), _color(color), _text(text), _alignH(alignH), _alignV(alignV),
_ellipsis(ellipsis), _restoreBg(restoreBg), _deltax(deltaX) {} _ellipsis(ellipsis), _restoreBg(restoreBg), _deltax(deltaX) {}
void drawSelf(bool draw, bool restore); void drawSelf(bool draw, bool restore);
protected: protected:
const TextDrawData *_data; const TextDrawData *_data;
const TextColorData *_color;
Common::String _text; Common::String _text;
Graphics::TextAlign _alignH; Graphics::TextAlign _alignH;
GUI::ThemeEngine::TextAlignVertical _alignV; GUI::ThemeEngine::TextAlignVertical _alignV;
@ -167,6 +169,7 @@ static const DrawDataInfo kDrawDataDefaults[] = {
{kDDPlainColorBackground, "plain_bg", true, kDDNone}, {kDDPlainColorBackground, "plain_bg", true, kDDNone},
{kDDDefaultBackground, "default_bg", true, kDDNone}, {kDDDefaultBackground, "default_bg", true, kDDNone},
{kDDTextSelectionBackground, "text_selection", false, kDDNone}, {kDDTextSelectionBackground, "text_selection", false, kDDNone},
{kDDTextSelectionFocusBackground, "text_selection_focus", false, kDDNone},
{kDDWidgetBackgroundDefault, "widget_default", true, kDDNone}, {kDDWidgetBackgroundDefault, "widget_default", true, kDDNone},
{kDDWidgetBackgroundSmall, "widget_small", true, kDDNone}, {kDDWidgetBackgroundSmall, "widget_small", true, kDDNone},
@ -179,7 +182,7 @@ static const DrawDataInfo kDrawDataDefaults[] = {
{kDDSliderFull, "slider_full", false, kDDNone}, {kDDSliderFull, "slider_full", false, kDDNone},
{kDDSliderHover, "slider_hover", false, kDDNone}, {kDDSliderHover, "slider_hover", false, kDDNone},
{kDDSliderDisabled, "slider_disabled", true, kDDNone}, {kDDSliderDisabled, "slider_disabled", false, kDDNone},
{kDDCheckboxDefault, "checkbox_default", true, kDDNone}, {kDDCheckboxDefault, "checkbox_default", true, kDDNone},
{kDDCheckboxDisabled, "checkbox_disabled", true, kDDNone}, {kDDCheckboxDisabled, "checkbox_disabled", true, kDDNone},
@ -231,7 +234,7 @@ void ThemeItemTextData::drawSelf(bool draw, bool restore) {
_engine->restoreBackground(_area); _engine->restoreBackground(_area);
if (draw) { if (draw) {
_engine->renderer()->setFgColor(_data->_color.r, _data->_color.g, _data->_color.b); _engine->renderer()->setFgColor(_color->r, _color->g, _color->b);
_engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis); _engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis);
} }
@ -276,6 +279,10 @@ ThemeEngine::ThemeEngine(Common::String id, GraphicsMode mode) :
_texts[i] = 0; _texts[i] = 0;
} }
for (int i = 0; i < kTextColorMAX; ++i) {
_textColors[i] = 0;
}
// We currently allow two different ways of theme selection in our config file: // We currently allow two different ways of theme selection in our config file:
// 1) Via full path // 1) Via full path
// 2) Via a basename, which will need to be translated into a full path // 2) Via a basename, which will need to be translated into a full path
@ -531,20 +538,21 @@ void ThemeEngine::addDrawStep(const Common::String &drawDataId, const Graphics::
_widgets[id]->_steps.push_back(step); _widgets[id]->_steps.push_back(step);
} }
bool ThemeEngine::addTextData(const Common::String &drawDataId, TextData textId, Graphics::TextAlign alignH, TextAlignVertical alignV) { bool ThemeEngine::addTextData(const Common::String &drawDataId, TextData textId, TextColor colorId, Graphics::TextAlign alignH, TextAlignVertical alignV) {
DrawData id = parseDrawDataId(drawDataId); DrawData id = parseDrawDataId(drawDataId);
if (id == -1 || textId == -1 || !_widgets[id]) if (id == -1 || textId == -1 || colorId == kTextColorMAX || !_widgets[id])
return false; return false;
_widgets[id]->_textDataId = textId; _widgets[id]->_textDataId = textId;
_widgets[id]->_textColorId = colorId;
_widgets[id]->_textAlignH = alignH; _widgets[id]->_textAlignH = alignH;
_widgets[id]->_textAlignV = alignV; _widgets[id]->_textAlignV = alignV;
return true; return true;
} }
bool ThemeEngine::addFont(TextData textId, const Common::String &file, int r, int g, int b) { bool ThemeEngine::addFont(TextData textId, const Common::String &file) {
if (textId == -1) if (textId == -1)
return false; return false;
@ -568,13 +576,26 @@ bool ThemeEngine::addFont(TextData textId, const Common::String &file, int r, in
} }
} }
_texts[textId]->_color.r = r;
_texts[textId]->_color.g = g;
_texts[textId]->_color.b = b;
return true; return true;
} }
bool ThemeEngine::addTextColor(TextColor colorId, int r, int g, int b) {
if (colorId >= kTextColorMAX)
return false;
if (_textColors[colorId] != 0)
delete _textColors[colorId];
_textColors[colorId] = new TextColorData;
_textColors[colorId]->r = r;
_textColors[colorId]->g = g;
_textColors[colorId]->b = b;
return true;
}
bool ThemeEngine::addBitmap(const Common::String &filename) { bool ThemeEngine::addBitmap(const Common::String &filename) {
// Nothing has to be done if the bitmap already has been loaded. // Nothing has to be done if the bitmap already has been loaded.
Graphics::Surface *surf = _bitmaps[filename]; Graphics::Surface *surf = _bitmaps[filename];
@ -655,6 +676,11 @@ void ThemeEngine::unloadTheme() {
_texts[i] = 0; _texts[i] = 0;
} }
for (int i = 0; i < kTextColorMAX; ++i) {
delete _textColors[i];
_textColors[i] = 0;
}
_themeEval->reset(); _themeEval->reset();
_themeOk = false; _themeOk = false;
} }
@ -770,7 +796,7 @@ void ThemeEngine::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic,
} }
} }
void ThemeEngine::queueDDText(TextData type, const Common::Rect &r, const Common::String &text, bool restoreBg, void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg,
bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax) { bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax) {
if (_texts[type] == 0) if (_texts[type] == 0)
@ -779,7 +805,7 @@ void ThemeEngine::queueDDText(TextData type, const Common::Rect &r, const Common
Common::Rect area = r; Common::Rect area = r;
area.clip(_screen.w, _screen.h); area.clip(_screen.w, _screen.h);
ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], area, text, alignH, alignV, ellipsis, restoreBg, deltax); ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], _textColors[color], area, text, alignH, alignV, ellipsis, restoreBg, deltax);
if (_buffering) { if (_buffering) {
_screenQueue.push_back(q); _screenQueue.push_back(q);
@ -823,7 +849,7 @@ void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, W
dd = kDDButtonDisabled; dd = kDDButtonDisabled;
queueDD(dd, r, 0, hints & WIDGET_CLEARBG); queueDD(dd, r, 0, hints & WIDGET_CLEARBG);
queueDDText(getTextData(dd), r, str, false, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV); queueDDText(getTextData(dd), getTextColor(dd), r, str, false, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV);
} }
void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) { void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) {
@ -846,7 +872,6 @@ void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str,
if (state == kStateDisabled) if (state == kStateDisabled)
dd = kDDCheckboxDisabled; dd = kDDCheckboxDisabled;
TextData td = (state == kStateHighlight) ? kTextDataHover : getTextData(dd);
const int checkBoxSize = MIN((int)r.height(), getFontHeight()); const int checkBoxSize = MIN((int)r.height(), getFontHeight());
r2.bottom = r2.top + checkBoxSize; r2.bottom = r2.top + checkBoxSize;
@ -857,7 +882,7 @@ void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str,
r2.left = r2.right + checkBoxSize; r2.left = r2.right + checkBoxSize;
r2.right = r.right; r2.right = r.right;
queueDDText(td, r2, str, false, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV); queueDDText(getTextData(dd), getTextColor(dd), r2, str, false, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV);
} }
void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) { void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) {
@ -957,7 +982,7 @@ void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &s
if (!sel.empty()) { if (!sel.empty()) {
Common::Rect text(r.left + 3, r.top + 1, r.right - 10, r.bottom); Common::Rect text(r.left + 3, r.top + 1, r.right - 10, r.bottom);
queueDDText(getTextData(dd), text, sel, true, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV, deltax); queueDDText(getTextData(dd), getTextColor(dd), text, sel, true, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV, deltax);
} }
} }
@ -995,74 +1020,114 @@ void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, co
if (!ready()) if (!ready())
return; return;
const int tabOffset = 2;
tabWidth -= tabOffset;
queueDD(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight)); queueDD(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight));
for (int i = 0; i < (int)tabs.size(); ++i) { for (int i = 0; i < (int)tabs.size(); ++i) {
if (i == active) if (i == active)
continue; continue;
Common::Rect tabRect(r.left + i * (tabWidth + tabOffset), r.top, r.left + i * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight); Common::Rect tabRect(r.left + i * tabWidth, r.top, r.left + (i + 1) * tabWidth, r.top + tabHeight);
queueDD(kDDTabInactive, tabRect); queueDD(kDDTabInactive, tabRect);
queueDDText(getTextData(kDDTabInactive), tabRect, tabs[i], false, false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV); queueDDText(getTextData(kDDTabInactive), getTextColor(kDDTabInactive), tabRect, tabs[i], false, false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV);
} }
if (active >= 0) { if (active >= 0) {
Common::Rect tabRect(r.left + active * (tabWidth + tabOffset), r.top, r.left + active * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight); Common::Rect tabRect(r.left + active * tabWidth, r.top, r.left + (active + 1) * tabWidth, r.top + tabHeight);
const uint16 tabLeft = active * (tabWidth + tabOffset); const uint16 tabLeft = active * tabWidth;
const uint16 tabRight = MAX(r.right - tabRect.right, 0); const uint16 tabRight = MAX(r.right - tabRect.right, 0);
queueDD(kDDTabActive, tabRect, (tabLeft << 16) | (tabRight & 0xFFFF)); queueDD(kDDTabActive, tabRect, (tabLeft << 16) | (tabRight & 0xFFFF));
queueDDText(getTextData(kDDTabActive), tabRect, tabs[active], false, false, _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV); queueDDText(getTextData(kDDTabActive), getTextColor(kDDTabActive), tabRect, tabs[active], false, false, _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV);
} }
} }
void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, bool inverted, int deltax, bool useEllipsis, FontStyle font) { void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color) {
if (!ready()) if (!ready())
return; return;
TextColor colorId = kTextColorMAX;
switch (color) {
case kFontColorNormal:
if (inverted) { if (inverted) {
queueDD(kDDTextSelectionBackground, r); colorId = kTextColorNormalInverted;
queueDDText(kTextDataInverted, r, str, false, useEllipsis, align, kTextAlignVCenter, deltax); } else {
switch (state) {
case kStateDisabled:
colorId = kTextColorNormalDisabled;
break;
case kStateHighlight:
colorId = kTextColorNormalHover;
break;
case kStateEnabled:
colorId = kTextColorNormal;
break;
}
}
break;
case kFontColorAlternate:
if (inverted) {
colorId = kTextColorAlternativeInverted;
} else {
switch (state) {
case kStateDisabled:
colorId = kTextColorAlternativeDisabled;
break;
case kStateHighlight:
colorId = kTextColorAlternativeHover;
break;
case kStateEnabled:
colorId = kTextColorAlternative;
break;
}
}
break;
default:
return; return;
} }
switch (font) { TextData textId = kTextDataNone;
case kFontStyleNormal: if (font == kFontStyleNormal)
queueDDText(kTextDataNormalFont, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax); textId = kTextDataNormalFont;
return; else
textId = kTextDataDefault;
bool restore = true;
switch (inverted) {
case kTextInversion:
queueDD(kDDTextSelectionBackground, r);
restore = false;
break;
case kTextInversionFocus:
queueDD(kDDTextSelectionFocusBackground, r);
restore = false;
break;
default: default:
break; break;
} }
switch (state) { queueDDText(textId, colorId, r, str, restore, useEllipsis, align, kTextAlignVCenter, deltax);
case kStateDisabled:
queueDDText(kTextDataDisabled, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
return;
case kStateHighlight:
queueDDText(kTextDataHover, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
return;
case kStateEnabled:
queueDDText(kTextDataDefault, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
return;
}
} }
void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state) { void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) {
if (!ready()) if (!ready())
return; return;
Common::Rect charArea = r; Common::Rect charArea = r;
charArea.clip(_screen.w, _screen.h); charArea.clip(_screen.w, _screen.h);
uint32 color = _overlayFormat.RGBToColor(_texts[kTextDataDefault]->_color.r, _texts[kTextDataDefault]->_color.g, _texts[kTextDataDefault]->_color.b); uint32 rgbColor = _overlayFormat.RGBToColor(_textColors[color]->r, _textColors[color]->g, _textColors[color]->b);
restoreBackground(charArea); restoreBackground(charArea);
font->drawChar(&_screen, ch, charArea.left, charArea.top, color); font->drawChar(&_screen, ch, charArea.left, charArea.top, rgbColor);
addDirtyRect(charArea); addDirtyRect(charArea);
} }
@ -1161,6 +1226,78 @@ void ThemeEngine::openDialog(bool doBuffer, ShadingStyle style) {
} }
bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int hotspotY, int scale) { bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int hotspotY, int scale) {
return true; // Residual doesn's support cursor palette mode
// Try to locate the specified file among all loaded bitmaps
const Graphics::Surface *cursor = _bitmaps[filename];
if (!cursor)
return false;
#ifdef USE_RGB_COLOR
_cursorFormat.bytesPerPixel = 1;
_cursorFormat.rLoss = _cursorFormat.gLoss = _cursorFormat.bLoss = _cursorFormat.aLoss = 8;
_cursorFormat.rShift = _cursorFormat.gShift = _cursorFormat.bShift = _cursorFormat.aShift = 0;
#endif
// Set up the cursor parameters
_cursorHotspotX = hotspotX;
_cursorHotspotY = hotspotY;
_cursorTargetScale = scale;
_cursorWidth = cursor->w;
_cursorHeight = cursor->h;
// Allocate a new buffer for the cursor
delete[] _cursor;
_cursor = new byte[_cursorWidth * _cursorHeight];
assert(_cursor);
memset(_cursor, 0xFF, sizeof(byte) * _cursorWidth * _cursorHeight);
// the transparent color is 0xFF00FF
const int colTransparent = _overlayFormat.RGBToColor(0xFF, 0, 0xFF);
// Now, scan the bitmap. We have to convert it from 16 bit color mode
// to 8 bit mode, and have to create a suitable palette on the fly.
uint colorsFound = 0;
Common::HashMap<int, int> colorToIndex;
const OverlayColor *src = (const OverlayColor*)cursor->pixels;
for (uint y = 0; y < _cursorHeight; ++y) {
for (uint x = 0; x < _cursorWidth; ++x) {
byte r, g, b;
// Skip transparency
if (src[x] == colTransparent)
continue;
_overlayFormat.colorToRGB(src[x], r, g, b);
const int col = (r << 16) | (g << 8) | b;
// If there is no entry yet for this color in the palette: Add one
if (!colorToIndex.contains(col)) {
const int index = colorsFound++;
colorToIndex[col] = index;
_cursorPal[index * 4 + 0] = r;
_cursorPal[index * 4 + 1] = g;
_cursorPal[index * 4 + 2] = b;
_cursorPal[index * 4 + 3] = 0xFF;
if (colorsFound > MAX_CURS_COLORS) {
warning("Cursor contains too many colors (%d, but only %d are allowed)", colorsFound, MAX_CURS_COLORS);
return false;
}
}
// Copy pixel from the 16 bit source surface to the 8bit target surface
const int index = colorToIndex[col];
_cursor[y * _cursorWidth + x] = index;
}
src += _cursorWidth;
}
_useCursor = true;
_cursorPalSize = colorsFound;
return true; return true;
} }
@ -1189,6 +1326,9 @@ TextData ThemeEngine::getTextData(DrawData ddId) const {
return _widgets[ddId] ? (TextData)_widgets[ddId]->_textDataId : kTextDataNone; return _widgets[ddId] ? (TextData)_widgets[ddId]->_textDataId : kTextDataNone;
} }
TextColor ThemeEngine::getTextColor(DrawData ddId) const {
return _widgets[ddId] ? _widgets[ddId]->_textColorId : kTextColorMAX;
}
DrawData ThemeEngine::parseDrawDataId(const Common::String &name) const { DrawData ThemeEngine::parseDrawDataId(const Common::String &name) const {
for (int i = 0; i < kDrawDataMAX; ++i) for (int i = 0; i < kDrawDataMAX; ++i)
@ -1287,7 +1427,7 @@ bool ThemeEngine::themeConfigParseHeader(Common::String header, Common::String &
Common::StringTokenizer tok(header, ":"); Common::StringTokenizer tok(header, ":");
if (tok.nextToken() != SCUMMVM_THEME_VERSION_STR) if (tok.nextToken() != RESIDUAL_THEME_VERSION_STR)
return false; return false;
themeName = tok.nextToken(); themeName = tok.nextToken();
@ -1383,7 +1523,7 @@ void ThemeEngine::listUsableThemes(Common::List<ThemeDescriptor> &list) {
output.clear(); output.clear();
} }
void ThemeEngine::listUsableThemes(Common::FSNode node, Common::List<ThemeDescriptor> &list, int depth) { void ThemeEngine::listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth) {
if (!node.exists() || !node.isReadable() || !node.isDirectory()) if (!node.exists() || !node.isReadable() || !node.isDirectory())
return; return;

View file

@ -32,7 +32,7 @@
#include "graphics/surface.h" #include "graphics/surface.h"
#include "graphics/fontman.h" #include "graphics/fontman.h"
#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.5" #define RESIDUAL_THEME_VERSION_STR "RESIDUAL_STX0.8"
namespace Graphics { namespace Graphics {
struct DrawStep; struct DrawStep;
@ -45,6 +45,7 @@ struct WidgetDrawData;
struct DrawDataInfo; struct DrawDataInfo;
struct TextDataInfo; struct TextDataInfo;
struct TextDrawData; struct TextDrawData;
struct TextColorData;
class Dialog; class Dialog;
class GuiObject; class GuiObject;
class ThemeEval; class ThemeEval;
@ -62,6 +63,7 @@ enum DrawData {
kDDPlainColorBackground, kDDPlainColorBackground,
kDDDefaultBackground, kDDDefaultBackground,
kDDTextSelectionBackground, kDDTextSelectionBackground,
kDDTextSelectionFocusBackground,
kDDWidgetBackgroundDefault, kDDWidgetBackgroundDefault,
kDDWidgetBackgroundSmall, kDDWidgetBackgroundSmall,
@ -104,15 +106,26 @@ enum DrawData {
enum TextData { enum TextData {
kTextDataNone = -1, kTextDataNone = -1,
kTextDataDefault = 0, kTextDataDefault = 0,
kTextDataHover,
kTextDataDisabled,
kTextDataInverted,
kTextDataButton, kTextDataButton,
kTextDataButtonHover,
kTextDataNormalFont, kTextDataNormalFont,
kTextDataMAX kTextDataMAX
}; };
enum TextColor {
kTextColorNormal = 0,
kTextColorNormalInverted,
kTextColorNormalHover,
kTextColorNormalDisabled,
kTextColorAlternative,
kTextColorAlternativeInverted,
kTextColorAlternativeHover,
kTextColorAlternativeDisabled,
kTextColorButton,
kTextColorButtonHover,
kTextColorButtonDisabled,
kTextColorMAX
};
class ThemeEngine { class ThemeEngine {
protected: protected:
typedef Common::HashMap<Common::String, Graphics::Surface*> ImagesMap; typedef Common::HashMap<Common::String, Graphics::Surface*> ImagesMap;
@ -156,6 +169,13 @@ public:
typedef State WidgetStateInfo; typedef State WidgetStateInfo;
//! Text inversion state of the text to be draw
enum TextInversionState {
kTextInversionNone, //!< Indicates that the text should not be drawn inverted
kTextInversion, //!< Indicates that the text should be drawn inverted, but not focused
kTextInversionFocus //!< Indicates thte the test should be drawn inverted, and focused
};
enum ScrollbarState { enum ScrollbarState {
kScrollbarStateNo, kScrollbarStateNo,
kScrollbarStateUp, kScrollbarStateUp,
@ -175,6 +195,13 @@ public:
kFontStyleMax kFontStyleMax
}; };
//! Font color selector
enum FontColor {
kFontColorNormal = 0, //!< The default color of the theme
kFontColorAlternate = 1, //!< Alternative font color
kFontColorMax
};
//! Function used to process areas other than the current dialog //! Function used to process areas other than the current dialog
enum ShadingStyle { enum ShadingStyle {
kShadingNone, //!< No special post processing kShadingNone, //!< No special post processing
@ -302,9 +329,9 @@ public:
void drawDialogBackground(const Common::Rect &r, DialogBackground type, WidgetStateInfo state = kStateEnabled); void drawDialogBackground(const Common::Rect &r, DialogBackground type, WidgetStateInfo state = kStateEnabled);
void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, bool inverted = false, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold); void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, TextInversionState inverted = kTextInversionNone, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold, FontColor color = kFontColorNormal);
void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled, FontColor color = kFontColorNormal);
//@} //@}
@ -332,6 +359,7 @@ public:
DrawData parseDrawDataId(const Common::String &name) const; DrawData parseDrawDataId(const Common::String &name) const;
TextData getTextData(DrawData ddId) const; TextData getTextData(DrawData ddId) const;
TextColor getTextColor(DrawData ddId) const;
/** /**
@ -363,9 +391,16 @@ public:
* *
* @param fontName Identifier name for the font. * @param fontName Identifier name for the font.
* @param file Name of the font file. * @param file Name of the font file.
*/
bool addFont(TextData textId, const Common::String &file);
/**
* Interface for the ThemeParser class: adds a text color value.
*
* @param colorId Identifier for the color type.
* @param r, g, b Color of the font. * @param r, g, b Color of the font.
*/ */
bool addFont(TextData textId, const Common::String &file, int r, int g, int b); bool addTextColor(TextColor colorId, int r, int g, int b);
/** /**
@ -380,7 +415,7 @@ public:
* Adds a new TextStep from the ThemeParser. This will be deprecated/removed once the * Adds a new TextStep from the ThemeParser. This will be deprecated/removed once the
* new Font API is in place. FIXME: Is that so ??? * new Font API is in place. FIXME: Is that so ???
*/ */
bool addTextData(const Common::String &drawDataId, TextData textId, Graphics::TextAlign alignH, TextAlignVertical alignV); bool addTextData(const Common::String &drawDataId, TextData textId, TextColor id, Graphics::TextAlign alignH, TextAlignVertical alignV);
protected: protected:
/** /**
@ -503,7 +538,7 @@ protected:
* This function is called from all the Widget Drawing methods. * This function is called from all the Widget Drawing methods.
*/ */
void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0, bool restore = false); void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0, bool restore = false);
void queueDDText(TextData type, const Common::Rect &r, const Common::String &text, bool restoreBg, void queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg,
bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0); bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0);
void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha); void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha);
@ -529,7 +564,7 @@ private:
static Common::String getThemeFile(const Common::String &id); static Common::String getThemeFile(const Common::String &id);
static Common::String getThemeId(const Common::String &filename); static Common::String getThemeId(const Common::String &filename);
static void listUsableThemes(Common::FSNode node, Common::List<ThemeDescriptor> &list, int depth=-1); static void listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth = -1);
protected: protected:
OSystem *_system; /** Global system object. */ OSystem *_system; /** Global system object. */
@ -572,8 +607,14 @@ protected:
/** Array of all the text fonts that can be drawn. */ /** Array of all the text fonts that can be drawn. */
TextDrawData *_texts[kTextDataMAX]; TextDrawData *_texts[kTextDataMAX];
/** Array of all font colors available. */
TextColorData *_textColors[kTextColorMAX];
ImagesMap _bitmaps; ImagesMap _bitmaps;
Graphics::PixelFormat _overlayFormat; Graphics::PixelFormat _overlayFormat;
#ifdef USE_RGB_COLOR
Graphics::PixelFormat _cursorFormat;
#endif
/** List of all the dirty screens that must be blitted to the overlay. */ /** List of all the dirty screens that must be blitted to the overlay. */
Common::List<Common::Rect> _dirtyScreen; Common::List<Common::Rect> _dirtyScreen;

View file

@ -23,17 +23,11 @@
* *
*/ */
#include "common/util.h"
#include "common/system.h"
#include "common/events.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/xmlparser.h"
#include "gui/ThemeEngine.h" #include "gui/ThemeEngine.h"
#include "gui/ThemeEval.h" #include "gui/ThemeEval.h"
#include "gui/ThemeParser.h" #include "gui/ThemeParser.h"
#include "gui/GuiManager.h" #include "gui/GuiManager.h"
#include "graphics/VectorRenderer.h" #include "graphics/VectorRenderer.h"
namespace GUI { namespace GUI {
@ -45,11 +39,7 @@ struct TextDataInfo {
static const TextDataInfo kTextDataDefaults[] = { static const TextDataInfo kTextDataDefaults[] = {
{ kTextDataDefault, "text_default" }, { kTextDataDefault, "text_default" },
{kTextDataHover, "text_hover"},
{kTextDataDisabled, "text_disabled"},
{kTextDataInverted, "text_inverted"},
{ kTextDataButton, "text_button" }, { kTextDataButton, "text_button" },
{kTextDataButtonHover, "text_button_hover"},
{ kTextDataNormalFont, "text_normal" } { kTextDataNormalFont, "text_normal" }
}; };
@ -62,6 +52,33 @@ static TextData parseTextDataId(const Common::String &name) {
return kTextDataNone; return kTextDataNone;
} }
struct TextColorDataInfo {
TextColor id;
const char *name;
};
static const TextColorDataInfo kTextColorDefaults[] = {
{ kTextColorNormal, "color_normal" },
{ kTextColorNormalInverted, "color_normal_inverted" },
{ kTextColorNormalHover, "color_normal_hover" },
{ kTextColorNormalDisabled, "color_normal_disabled" },
{ kTextColorAlternative, "color_alternative" },
{ kTextColorAlternativeInverted, "color_alternative_inverted" },
{ kTextColorAlternativeHover, "color_alternative_hover" },
{ kTextColorAlternativeDisabled, "color_alternative_disabled" },
{ kTextColorButton, "color_button" },
{ kTextColorButtonHover, "color_button_hover" },
{ kTextColorButtonDisabled, "color_button_disabled" }
};
static TextColor parseTextColorId(const Common::String &name) {
for (int i = 0; i < kTextColorMAX; ++i)
if (name.compareToIgnoreCase(kTextColorDefaults[i].name) == 0)
return kTextColorDefaults[i].id;
return kTextColorMAX;
}
static Graphics::TextAlign parseTextHAlign(const Common::String &val) { static Graphics::TextAlign parseTextHAlign(const Common::String &val) {
if (val == "left") if (val == "left")
return Graphics::kTextAlignLeft; return Graphics::kTextAlignLeft;
@ -86,19 +103,6 @@ static GUI::ThemeEngine::TextAlignVertical parseTextVAlign(const Common::String
ThemeParser::ThemeParser(ThemeEngine *parent) : XMLParser() { ThemeParser::ThemeParser(ThemeEngine *parent) : XMLParser() {
_drawFunctions["circle"] = &Graphics::VectorRenderer::drawCallback_CIRCLE;
_drawFunctions["square"] = &Graphics::VectorRenderer::drawCallback_SQUARE;
_drawFunctions["roundedsq"] = &Graphics::VectorRenderer::drawCallback_ROUNDSQ;
_drawFunctions["bevelsq"] = &Graphics::VectorRenderer::drawCallback_BEVELSQ;
_drawFunctions["line"] = &Graphics::VectorRenderer::drawCallback_LINE;
_drawFunctions["triangle"] = &Graphics::VectorRenderer::drawCallback_TRIANGLE;
_drawFunctions["fill"] = &Graphics::VectorRenderer::drawCallback_FILLSURFACE;
_drawFunctions["tab"] = &Graphics::VectorRenderer::drawCallback_TAB;
_drawFunctions["void"] = &Graphics::VectorRenderer::drawCallback_VOID;
_drawFunctions["bitmap"] = &Graphics::VectorRenderer::drawCallback_BITMAP;
_drawFunctions["cross"] = &Graphics::VectorRenderer::drawCallback_CROSS;
_defaultStepGlobal = defaultDrawStep(); _defaultStepGlobal = defaultDrawStep();
_defaultStepLocal = 0; _defaultStepLocal = 0;
_theme = parent; _theme = parent;
@ -107,8 +111,6 @@ ThemeParser::ThemeParser(ThemeEngine *parent) : XMLParser() {
ThemeParser::~ThemeParser() { ThemeParser::~ThemeParser() {
delete _defaultStepGlobal; delete _defaultStepGlobal;
delete _defaultStepLocal; delete _defaultStepLocal;
_palette.clear();
_drawFunctions.clear();
} }
void ThemeParser::cleanup() { void ThemeParser::cleanup() {
@ -169,21 +171,32 @@ bool ThemeParser::parserCallback_defaults(ParserNode *node) {
} }
bool ThemeParser::parserCallback_font(ParserNode *node) { bool ThemeParser::parserCallback_font(ParserNode *node) {
int red, green, blue;
if (resolutionCheck(node->values["resolution"]) == false) { if (resolutionCheck(node->values["resolution"]) == false) {
node->ignore = true; node->ignore = true;
return true; return true;
} }
TextData textDataId = parseTextDataId(node->values["id"]);
if (!_theme->addFont(textDataId, node->values["file"]))
return parserError("Error loading Font in theme engine.");
return true;
}
bool ThemeParser::parserCallback_text_color(ParserNode *node) {
int red, green, blue;
TextColor colorId = parseTextColorId(node->values["id"]);
if (colorId == kTextColorMAX)
return parserError("Error text color is not defined.");
if (_palette.contains(node->values["color"])) if (_palette.contains(node->values["color"]))
getPaletteColor(node->values["color"], red, green, blue); getPaletteColor(node->values["color"], red, green, blue);
else if (!parseIntegerKey(node->values["color"].c_str(), 3, &red, &green, &blue)) else if (!parseIntegerKey(node->values["color"].c_str(), 3, &red, &green, &blue))
return parserError("Error parsing color value for font definition."); return parserError("Error parsing color value for text color definition.");
TextData textDataId = parseTextDataId(node->values["id"]); if (!_theme->addTextColor(colorId, red, green, blue))
if (!_theme->addFont(textDataId, node->values["file"], red, green, blue)) return parserError("Error while adding text color information.");
return parserError("Error loading Font in theme engine.");
return true; return true;
} }
@ -236,8 +249,9 @@ bool ThemeParser::parserCallback_text(ParserNode *node) {
Common::String id = getParentNode(node)->values["id"]; Common::String id = getParentNode(node)->values["id"];
TextData textDataId = parseTextDataId(node->values["font"]); TextData textDataId = parseTextDataId(node->values["font"]);
TextColor textColorId = parseTextColorId(node->values["text_color"]);
if (!_theme->addTextData(id, textDataId, alignH, alignV)) if (!_theme->addTextData(id, textDataId, textColorId, alignH, alignV))
return parserError("Error adding Text Data for '%s'.", id.c_str()); return parserError("Error adding Text Data for '%s'.", id.c_str());
return true; return true;
@ -281,15 +295,44 @@ bool ThemeParser::parserCallback_color(ParserNode *node) {
} }
static Graphics::DrawingFunctionCallback getDrawingFunctionCallback(const Common::String &name) {
if (name == "circle")
return &Graphics::VectorRenderer::drawCallback_CIRCLE;
if (name == "square")
return &Graphics::VectorRenderer::drawCallback_SQUARE;
if (name == "roundedsq")
return &Graphics::VectorRenderer::drawCallback_ROUNDSQ;
if (name == "bevelsq")
return &Graphics::VectorRenderer::drawCallback_BEVELSQ;
if (name == "line")
return &Graphics::VectorRenderer::drawCallback_LINE;
if (name == "triangle")
return &Graphics::VectorRenderer::drawCallback_TRIANGLE;
if (name == "fill")
return &Graphics::VectorRenderer::drawCallback_FILLSURFACE;
if (name == "tab")
return &Graphics::VectorRenderer::drawCallback_TAB;
if (name == "void")
return &Graphics::VectorRenderer::drawCallback_VOID;
if (name == "bitmap")
return &Graphics::VectorRenderer::drawCallback_BITMAP;
if (name == "cross")
return &Graphics::VectorRenderer::drawCallback_CROSS;
return 0;
}
bool ThemeParser::parserCallback_drawstep(ParserNode *node) { bool ThemeParser::parserCallback_drawstep(ParserNode *node) {
Graphics::DrawStep *drawstep = newDrawStep(); Graphics::DrawStep *drawstep = newDrawStep();
Common::String functionName = node->values["func"]; Common::String functionName = node->values["func"];
if (_drawFunctions.contains(functionName) == false) drawstep->drawingCall = getDrawingFunctionCallback(functionName);
return parserError("%s is not a valid drawing function name", functionName.c_str());
drawstep->drawingCall = _drawFunctions[functionName]; if (drawstep->drawingCall == 0)
return parserError("%s is not a valid drawing function name", functionName.c_str());
if (!parseDrawStep(node, drawstep, true)) if (!parseDrawStep(node, drawstep, true))
return false; return false;

View file

@ -27,7 +27,6 @@
#define THEME_PARSER_H #define THEME_PARSER_H
#include "common/sys.h" #include "common/sys.h"
#include "common/system.h"
#include "common/xmlparser.h" #include "common/xmlparser.h"
namespace GUI { namespace GUI {
@ -35,8 +34,6 @@ namespace GUI {
class ThemeEngine; class ThemeEngine;
class ThemeParser : public Common::XMLParser { class ThemeParser : public Common::XMLParser {
typedef void (Graphics::VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const Graphics::DrawStep &);
public: public:
ThemeParser(ThemeEngine *parent); ThemeParser(ThemeEngine *parent);
@ -70,9 +67,13 @@ protected:
XML_KEY(font) XML_KEY(font)
XML_PROP(id, true) XML_PROP(id, true)
XML_PROP(file, true) XML_PROP(file, true)
XML_PROP(color, true)
XML_PROP(resolution, false) XML_PROP(resolution, false)
KEY_END() KEY_END()
XML_KEY(text_color)
XML_PROP(id, true);
XML_PROP(color, true);
KEY_END()
KEY_END() KEY_END()
XML_KEY(bitmaps) XML_KEY(bitmaps)
@ -146,6 +147,7 @@ protected:
XML_KEY(text) XML_KEY(text)
XML_PROP(font, true) XML_PROP(font, true)
XML_PROP(text_color, true)
XML_PROP(vertical_align, true) XML_PROP(vertical_align, true)
XML_PROP(horizontal_align, true) XML_PROP(horizontal_align, true)
KEY_END() KEY_END()
@ -214,6 +216,7 @@ protected:
bool parserCallback_render_info(ParserNode *node); bool parserCallback_render_info(ParserNode *node);
bool parserCallback_defaults(ParserNode *node); bool parserCallback_defaults(ParserNode *node);
bool parserCallback_font(ParserNode *node); bool parserCallback_font(ParserNode *node);
bool parserCallback_text_color(ParserNode *node);
bool parserCallback_fonts(ParserNode *node); bool parserCallback_fonts(ParserNode *node);
bool parserCallback_text(ParserNode *node); bool parserCallback_text(ParserNode *node);
bool parserCallback_palette(ParserNode *node); bool parserCallback_palette(ParserNode *node);
@ -249,8 +252,6 @@ protected:
Graphics::DrawStep *_defaultStepGlobal; Graphics::DrawStep *_defaultStepGlobal;
Graphics::DrawStep *_defaultStepLocal; Graphics::DrawStep *_defaultStepLocal;
Common::HashMap<Common::String, DrawingFunctionCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _drawFunctions;
struct PaletteColor { struct PaletteColor {
uint8 r, g, b; uint8 r, g, b;
}; };

View file

@ -247,7 +247,7 @@ void AboutDialog::drawDialog() {
str++; str++;
if (*str && y > _y && y + g_gui.theme()->getFontHeight() < _y + _h) if (*str && y > _y && y + g_gui.theme()->getFontHeight() < _y + _h)
g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, false, 0, false); g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, ThemeEngine::kTextInversionNone, 0, false);
y += _lineHeight; y += _lineHeight;
} }
} }

View file

@ -43,7 +43,7 @@ enum {
*/ */
BrowserDialog::BrowserDialog(const char *title, bool dirBrowser) BrowserDialog::BrowserDialog(const char *title, bool dirBrowser)
: Dialog("browser") { : Dialog("Browser") {
_titleRef = CFStringCreateWithCString(0, title, CFStringGetSystemEncoding()); _titleRef = CFStringCreateWithCString(0, title, CFStringGetSystemEncoding());
_isDirBrowser = dirBrowser; _isDirBrowser = dirBrowser;
} }

View file

@ -112,6 +112,7 @@ void ConsoleDialog::init() {
_w = _w - _w / 20; _w = _w - _w / 20;
_h = _h * kConsoleLineHeight + 2; _h = _h * kConsoleLineHeight + 2;
_x = _w / 40;
// Set scrollbar dimensions // Set scrollbar dimensions
int scrollBarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0); int scrollBarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
@ -149,8 +150,8 @@ void ConsoleDialog::open() {
if (_w != w || _h != h) if (_w != w || _h != h)
init(); init();
_x = _w / 40;
_y = -_h; _y = -_h;
_slideTime = g_system->getMillis(); _slideTime = g_system->getMillis();
_slideMode = kDownSlideMode; _slideMode = kDownSlideMode;

View file

@ -143,7 +143,7 @@ public:
void handleKeyDown(Common::KeyState state); void handleKeyDown(Common::KeyState state);
void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
int printf(const char *format, ...); int printf(const char *format, ...) GCC_PRINTF(2, 3);
int vprintf(const char *format, va_list argptr); int vprintf(const char *format, va_list argptr);
#undef putchar #undef putchar
void putchar(int c); void putchar(int c);

View file

@ -27,10 +27,14 @@
#include "common/system.h" #include "common/system.h"
#include "gui/debugger.h" #include "gui/debugger.h"
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
#include "gui/console.h" #include "gui/console.h"
#elif defined(USE_READLINE)
#include <readline/readline.h>
#include <readline/history.h>
#endif #endif
namespace GUI { namespace GUI {
Debugger::Debugger() { Debugger::Debugger() {
@ -39,9 +43,11 @@ Debugger::Debugger() {
_isAttached = false; _isAttached = false;
_errStr = NULL; _errStr = NULL;
_firstTime = true; _firstTime = true;
_debuggerDialog = new GUI::ConsoleDialog(1.0, 0.67F); #ifndef USE_TEXT_CONSOLE
_debuggerDialog = new GUI::ConsoleDialog(1.0f, 0.67f);
_debuggerDialog->setInputCallback(debuggerInputCallback, this); _debuggerDialog->setInputCallback(debuggerInputCallback, this);
_debuggerDialog->setCompletionCallback(debuggerCompletionCallback, this); _debuggerDialog->setCompletionCallback(debuggerCompletionCallback, this);
#endif
//DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit)); //DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
DCmd_Register("exit", WRAP_METHOD(Debugger, Cmd_Exit)); DCmd_Register("exit", WRAP_METHOD(Debugger, Cmd_Exit));
@ -55,7 +61,9 @@ Debugger::Debugger() {
} }
Debugger::~Debugger() { Debugger::~Debugger() {
#ifndef USE_TEXT_CONSOLE
delete _debuggerDialog; delete _debuggerDialog;
#endif
} }
@ -65,7 +73,7 @@ int Debugger::DebugPrintf(const char *format, ...) {
va_start(argptr, format); va_start(argptr, format);
int count; int count;
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
count = _debuggerDialog->vprintf(format, argptr); count = _debuggerDialog->vprintf(format, argptr);
#else #else
count = ::vprintf(format, argptr); count = ::vprintf(format, argptr);
@ -112,9 +120,22 @@ void Debugger::onFrame() {
} }
} }
#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE)
namespace {
Debugger *g_readline_debugger;
char *readline_completionFunction(const char *text, int state) {
return g_readline_debugger->readlineComplete(text, state);
}
} // end of anonymous namespace
#endif
// Main Debugger Loop // Main Debugger Loop
void Debugger::enter() { void Debugger::enter() {
#if USE_CONSOLE // TODO: Having three I/O methods #ifdef-ed in this file is not the
// cleanest approach to this...
#ifndef USE_TEXT_CONSOLE
if (_firstTime) { if (_firstTime) {
DebugPrintf("Debugger started, type 'exit' to return to the game.\n"); DebugPrintf("Debugger started, type 'exit' to return to the game.\n");
DebugPrintf("Type 'help' to see a little list of commands and variables.\n"); DebugPrintf("Type 'help' to see a little list of commands and variables.\n");
@ -129,18 +150,28 @@ void Debugger::enter() {
_debuggerDialog->runModal(); _debuggerDialog->runModal();
#else #else
// TODO: compared to the console input, this here is very bare bone.
// For example, no support for tab completion and no history. At least
// we should re-add (optional) support for the readline library.
// Or maybe instead of choosing between a console dialog and stdio,
// we should move that choice into the ConsoleDialog class - that is,
// the console dialog code could be #ifdef'ed to not print to the dialog
// but rather to stdio. This way, we could also reuse the command history
// and tab completion of the console. It would still require a lot of
// work, but at least no dependency on a 3rd party library...
printf("Debugger entered, please switch to this console for input.\n"); printf("Debugger entered, please switch to this console for input.\n");
#ifdef USE_READLINE
// TODO: add support for saving/loading history?
g_readline_debugger = this;
rl_completion_entry_function = &readline_completionFunction;
char *line_read = 0;
do {
free(line_read);
line_read = readline("debug> ");
if (line_read && line_read[0])
add_history(line_read);
} while (line_read && parseCommand(line_read));
free(line_read);
line_read = 0;
#else
int i; int i;
char buf[256]; char buf[256];
@ -156,6 +187,7 @@ void Debugger::enter() {
if (i == 0) if (i == 0)
continue; continue;
} while (parseCommand(buf)); } while (parseCommand(buf));
#endif
#endif #endif
} }
@ -211,7 +243,7 @@ bool Debugger::parseCommand(const char *inputOrig) {
break; break;
// Integer Array // Integer Array
case DVAR_INTARRAY: { case DVAR_INTARRAY: {
char *chr = (char *)strchr(param[0], '['); const char *chr = strchr(param[0], '[');
if (!chr) { if (!chr) {
DebugPrintf("You must access this array as %s[element]\n", param[0]); DebugPrintf("You must access this array as %s[element]\n", param[0]);
} else { } else {
@ -307,7 +339,8 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const
} else { } else {
// take common prefix of previous match and this command // take common prefix of previous match and this command
for (uint j = 0; j < completion.size(); j++) { for (uint j = 0; j < completion.size(); j++) {
if (completion[j] != i->_key[inputlen + j]) { if (inputlen + j >= i->_key.size() ||
completion[j] != i->_key[inputlen + j]) {
completion = Common::String(completion.begin(), completion.begin() + j); completion = Common::String(completion.begin(), completion.begin() + j);
// If there is no unambiguous completion, abort // If there is no unambiguous completion, abort
if (completion.empty()) if (completion.empty())
@ -325,6 +358,29 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const
return true; return true;
} }
#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE)
char *Debugger::readlineComplete(const char *input, int state) {
static CommandsMap::const_iterator iter;
// We assume that _cmds isn't changed between calls to readlineComplete,
// unless state is 0.
if (state == 0) {
iter = _cmds.begin();
} else {
++iter;
}
for (; iter != _cmds.end(); ++iter) {
if (iter->_key.hasPrefix(input)) {
char *ret = (char *)malloc(iter->_key.size() + 1);
strcpy(ret, iter->_key.c_str());
return ret;
}
}
return 0;
}
#endif
// Variable registration function // Variable registration function
void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) { void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) {
// TODO: Filter out duplicates // TODO: Filter out duplicates
@ -356,8 +412,15 @@ bool Debugger::Cmd_Exit(int argc, const char **argv) {
// Print a list of all registered commands (and variables, if any), // Print a list of all registered commands (and variables, if any),
// nicely word-wrapped. // nicely word-wrapped.
bool Debugger::Cmd_Help(int argc, const char **argv) { bool Debugger::Cmd_Help(int argc, const char **argv) {
#ifndef USE_TEXT_CONSOLE
const int charsPerLine = _debuggerDialog->getCharsPerLine(); const int charsPerLine = _debuggerDialog->getCharsPerLine();
#elif defined(USE_READLINE)
int charsPerLine, rows;
rl_get_screen_size(&rows, &charsPerLine);
#else
// Can we do better?
const int charsPerLine = 80;
#endif
int width, size; int width, size;
uint i; uint i;
@ -452,7 +515,7 @@ bool Debugger::Cmd_DebugFlagDisable(int argc, const char **argv) {
} }
// Console handler // Console handler
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) { bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) {
Debugger *debugger = (Debugger *)refCon; Debugger *debugger = (Debugger *)refCon;

View file

@ -32,10 +32,7 @@
namespace GUI { namespace GUI {
// Choose between text console or ScummConsole #ifndef USE_TEXT_CONSOLE
#define USE_CONSOLE 1
#ifdef USE_CONSOLE
class ConsoleDialog; class ConsoleDialog;
#endif #endif
@ -86,7 +83,9 @@ private:
bool _isAttached; bool _isAttached;
char *_errStr; char *_errStr;
bool _firstTime; bool _firstTime;
#ifndef USE_TEXT_CONSOLE
GUI::ConsoleDialog *_debuggerDialog; GUI::ConsoleDialog *_debuggerDialog;
#endif
protected: protected:
// Hook for subclasses: Called just before enter() is run // Hook for subclasses: Called just before enter() is run
@ -118,11 +117,15 @@ protected:
bool Cmd_DebugFlagEnable(int argc, const char **argv); bool Cmd_DebugFlagEnable(int argc, const char **argv);
bool Cmd_DebugFlagDisable(int argc, const char **argv); bool Cmd_DebugFlagDisable(int argc, const char **argv);
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
private: private:
static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon); static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon);
static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon); static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon);
#elif defined(USE_READLINE)
public:
char *readlineComplete(const char *input, int state);
#endif #endif
}; };
} // End of namespace GUI } // End of namespace GUI

View file

@ -638,6 +638,10 @@ void LauncherDialog::updateListing() {
// Select the last entry if the list has been reduced // Select the last entry if the list has been reduced
_list->setSelected(_list->getList().size() - 1); _list->setSelected(_list->getList().size() - 1);
updateButtons(); updateButtons();
// Update the filter settings, those are lost when "setList"
// is called.
_list->setFilter(_searchWidget->getEditString());
} }
void LauncherDialog::addGame() { void LauncherDialog::addGame() {

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