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
-include config.mk
ifeq "$(HAVE_GCC)" "1"
CXXFLAGS:= -Wall $(CXXFLAGS)
# 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...
#CXXFLAGS+= -Wpointer-arith -Wcast-qual -Wcast-align
#CXXFLAGS+= -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
CXXFLAGS+= -Wpointer-arith -Wcast-qual -Wcast-align
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"
#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
# used before being initialized. Very handy to catch a certain kind of
# bugs. Unfortunately, it only works when optimizations are turned on,
# which is why we normally don't use it.
#CXXFLAGS+= -O -Wuninitialized
endif
#######################################################################
# 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"
@echo "Running $(srcdir)/configure with the last specified parameters"
@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)
else
$(error You need to run $(srcdir)/configure before you can run make. Check $(srcdir)/configure --help for a list of parameters)
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),yes)
QUIET_CXX = @echo ' ' C++ ' ' $@;
QUIET_AS = @echo ' ' AS ' ' $@;
QUIET_NASM = @echo ' ' NASM ' ' $@;
QUIET_AR = @echo ' ' AR ' ' $@;
QUIET_RANLIB = @echo ' ' RANLIB ' ' $@;
QUIET_PLUGIN = @echo ' ' PLUGIN ' ' $@;
@ -75,26 +77,40 @@ clean:
$(RM_REC) $(DEPDIRS)
$(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.
%.o: %.cpp
$(QUIET)$(MKDIR) $(*D)/$(DEPDIR)
$(QUIET_CXX)$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
$(QUIET)$(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d
$(QUIET)$(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d"
$(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
$(QUIET_CXX)$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
# Build rule for Objective-C files. Strictly speaking, this is for OS X only.
%.o: %.m
$(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
# Include the dependency tracking files.
@ -134,25 +150,6 @@ CXXFLAGS+= -DRESIDUAL_SVN_REVISION=\"$(VER_SVNREV)\"
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
######################################################################
@ -198,10 +195,16 @@ dist-src: \
@#RPM-src?
@#DEB-src?
# Common files
DIST_FILES_DOCS:=$(addprefix $(srcdir)/,AUTHORS COPYING COPYING.LGPL COPYRIGHT NEWS README)
# Themes files
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
DIST_FILES_PLUGINS:=$(addprefix $(srcdir)/,$(PLUGINS))

View file

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

View file

@ -35,242 +35,38 @@
#include "engines/engine.h"
#include "gui/message.h"
#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, 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),
DefaultEventManager::DefaultEventManager(Common::EventSource *boss) :
_buttonState(0),
_modifierState(0),
_shouldQuit(false),
_shouldRTL(false),
_confirmExitDialogActive(false) {
assert(_boss);
assert(boss);
_recordFile = NULL;
_recordTimeFile = NULL;
_playbackFile = NULL;
_playbackTimeFile = NULL;
_timeMutex = g_system->createMutex();
_recorderMutex = g_system->createMutex();
_dispatcher.registerSource(boss, false);
_dispatcher.registerSource(&_artificialEventSource, false);
_eventCount = 0;
_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";
}
_dispatcher.registerObserver(this, kEventManPriority, false);
// Reset key repeat
_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
_vk = new Common::VirtualKeyboard();
#endif
#ifdef ENABLE_KEYMAPPER
_keymapper = new Common::Keymapper(this);
// EventDispatcher will automatically free the keymapper
_dispatcher.registerMapper(_keymapper);
_remap = false;
#endif
}
DefaultEventManager::~DefaultEventManager() {
#ifdef ENABLE_KEYMAPPER
delete _keymapper;
#endif
#ifdef ENABLE_VKEYBD
delete _vk;
#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() {
@ -283,145 +79,14 @@ void DefaultEventManager::init() {
#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) {
uint32 time = g_system->getMillis();
bool result;
bool result = false;
if (!artificialEventQueue.empty()) {
event = artificialEventQueue.pop();
_dispatcher.dispatch();
if (!_eventQueue.empty()) {
event = _eventQueue.pop();
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) {
@ -497,6 +162,16 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
}
}
#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;
case Common::EVENT_KEYUP:
@ -598,13 +273,12 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
}
void DefaultEventManager::pushEvent(const Common::Event &event) {
// If already received an EVENT_QUIT, don't add another one
if (event.type == Common::EVENT_QUIT) {
if (!_shouldQuit)
artificialEventQueue.push(event);
_artificialEventSource.addEvent(event);
} else
artificialEventQueue.push(event);
_artificialEventSource.addEvent(event);
}
#endif // !defined(DISABLE_DEFAULT_EVENTMANAGER)

View file

@ -27,8 +27,6 @@
#define BACKEND_EVENTS_DEFAULT_H
#include "common/events.h"
#include "common/savefile.h"
#include "common/mutex.h"
#include "common/queue.h"
namespace Common {
@ -41,21 +39,7 @@ namespace Common {
}
class EventProvider {
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;
class DefaultEventManager : public Common::EventManager, Common::EventObserver {
#ifdef ENABLE_VKEYBD
Common::VirtualKeyboard *_vk;
#endif
@ -65,7 +49,13 @@ class DefaultEventManager : public Common::EventManager {
bool _remap;
#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;
int _buttonState;
@ -74,44 +64,6 @@ class DefaultEventManager : public Common::EventManager {
bool _shouldRTL;
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)
enum {
kKeyRepeatInitialDelay = 400,
@ -124,18 +76,13 @@ class DefaultEventManager : public Common::EventManager {
int keycode;
} _currentKeyDown;
uint32 _keyRepeatTime;
void record(Common::Event &event);
bool playback(Common::Event &event);
public:
DefaultEventManager(EventProvider *boss);
DefaultEventManager(Common::EventSource *boss);
~DefaultEventManager();
virtual void init();
virtual bool pollEvent(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 int getButtonState() const { return _buttonState; }
@ -143,6 +90,9 @@ public:
virtual int shouldQuit() const { return _shouldQuit; }
virtual int shouldRTL() const { return _shouldRTL; }
virtual void resetRTL() { _shouldRTL = false; }
#ifdef FORCE_RTL
virtual void resetQuit() { _shouldQuit = false; }
#endif
#ifdef ENABLE_KEYMAPPER
virtual Common::Keymapper *getKeymapper() { return _keymapper; }

View file

@ -43,8 +43,6 @@
#define ENTER() /* debug(6, "Enter") */
#define LEAVE() /* debug(6, "Leave") */
const uint32 kExAllBufferSize = 40960; // TODO: is this okay for sure?
/**
* Implementation of the ScummVM file system API.
*
@ -57,30 +55,33 @@ protected:
Common::String _sPath;
bool _bIsDirectory;
bool _bIsValid;
uint32 _nProt;
/**
* Obtain the FileInfoBlock protection value for this FSNode,
* as defined in the <proto/dos.h> header.
*
* @return -1 if there were errors, 0 or a positive integer otherwise.
* Creates a list with all the volumes present in the root node.
*/
virtual int getFibProtection() const;
virtual AbstractFSList listVolumes() const;
public:
/**
* Creates a AmigaOSFilesystemNode with the root node as path.
* Creates an AmigaOSFilesystemNode with the root node as path.
*/
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.
*/
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);
@ -110,11 +111,6 @@ public:
virtual Common::SeekableReadStream *createReadStream();
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;
_sPath = "";
_pFileLock = 0;
_nProt = 0; // protection is ignored for the root volume
LEAVE();
}
@ -169,37 +166,27 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
_pFileLock = 0;
_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
BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK);
if (pLock) {
if (IDOS->Examine(pLock, fib) != DOSFALSE) {
if (FIB_IS_DRAWER(fib)) {
struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_StringNameInput,_sPath.c_str(),TAG_END);
if (pExd) {
_nProt = pExd->Protection;
if (EXD_IS_DIRECTORY(pExd)) {
_bIsDirectory = true;
_pFileLock = IDOS->DupLock(pLock);
_pFileLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);;
_bIsValid = (_pFileLock != 0);
// Add a trailing slash if it is needed
const char c = _sPath.lastChar();
if (c != '/' && c != ':')
_sPath += '/';
}
else {
} else {
//_bIsDirectory = false;
_bIsValid = true;
}
IDOS->FreeDosObject(DOS_EXAMINEDATA, pExd);
}
IDOS->UnLock(pLock);
}
IDOS->FreeDosObject(DOS_FIB, fib);
LEAVE();
}
@ -232,15 +219,10 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayNam
_bIsValid = false;
_bIsDirectory = false;
struct FileInfoBlock *fib = (struct FileInfoBlock *)IDOS->AllocDosObject(DOS_FIB, NULL);
if (!fib) {
debug(6, "FileInfoBlock is NULL");
LEAVE();
return;
}
if (IDOS->Examine(pLock, fib) != DOSFALSE) {
if (FIB_IS_DRAWER(fib)) {
struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_FileLockInput,pLock,TAG_END);
if (pExd) {
_nProt = pExd->Protection;
if (EXD_IS_DIRECTORY(pExd)) {
_bIsDirectory = true;
_pFileLock = IDOS->DupLock(pLock);
_bIsValid = _pFileLock != 0;
@ -248,25 +230,29 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayNam
const char c = _sPath.lastChar();
if (c != '/' && c != ':')
_sPath += '/';
}
else {
} else {
//_bIsDirectory = false;
_bIsValid = true;
}
IDOS->FreeDosObject(DOS_EXAMINEDATA, pExd);
} else {
debug(6, "ExamineObject() returned NULL");
}
IDOS->FreeDosObject(DOS_FIB, fib);
LEAVE();
}
// We need the custom copy constructor because of DupLock()
AmigaOSFilesystemNode::AmigaOSFilesystemNode(const AmigaOSFilesystemNode& node) {
AmigaOSFilesystemNode::AmigaOSFilesystemNode(const AmigaOSFilesystemNode& node)
: AbstractFSNode() {
ENTER();
_sDisplayName = node._sDisplayName;
_bIsValid = node._bIsValid;
_bIsDirectory = node._bIsDirectory;
_sPath = node._sPath;
_pFileLock = IDOS->DupLock(node._pFileLock);
_nProt = node._nProt;
LEAVE();
}
@ -284,21 +270,29 @@ bool AmigaOSFilesystemNode::exists() const {
bool nodeExists = false;
struct FileInfoBlock *fib = (struct FileInfoBlock *)IDOS->AllocDosObject(DOS_FIB, NULL);
if (!fib) {
debug(6, "FileInfoBlock is NULL");
LEAVE();
return false;
}
BPTR pLock = IDOS->Lock((STRPTR)_sPath.c_str(), SHARED_LOCK);
// previously we were trying to examine the node in order
// to determine if the node exists or not.
// I don't see the point : once you have been granted a
// lock on it then it means it exists...
//
// ============================= Old code
// 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 (IDOS->Examine(pLock, fib) != DOSFALSE)
nodeExists = true;
IDOS->UnLock(pLock);
}
IDOS->FreeDosObject(DOS_FIB, fib);
LEAVE();
return nodeExists;
}
@ -323,8 +317,10 @@ AbstractFSNode *AmigaOSFilesystemNode::getChild(const Common::String &n) const {
bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
ENTER();
bool ret = false;
//TODO: honor the hidden flag
// There is nothing like a hidden flag under AmigaOS...
if (!_bIsValid) {
debug(6, "Invalid node");
@ -345,85 +341,49 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
return true;
}
struct ExAllControl *eac = (struct ExAllControl *)IDOS->AllocDosObject(DOS_EXALLCONTROL, 0);
if (eac) {
struct ExAllData *data = (struct ExAllData *)IExec->AllocVec(kExAllBufferSize, MEMF_ANY);
if (data) {
BOOL bExMore;
eac->eac_LastKey = 0;
do {
// Examine directory
bExMore = IDOS->ExAll(_pFileLock, data, kExAllBufferSize, ED_TYPE, eac);
APTR context = IDOS->ObtainDirContextTags( EX_FileLockInput, _pFileLock,
EX_DoCurrentDir, TRUE, /* for softlinks */
EX_DataFields, (EXF_NAME|EXF_LINK|EXF_TYPE),
TAG_END);
if (context) {
struct ExamineData * pExd = NULL; // NB: no need to free value after usage, all is dealt by the DirContext release
LONG error = IDOS->IoErr();
if (!bExMore && error != ERROR_NO_MORE_ENTRIES)
break; // Abnormal failure
if (eac->eac_Entries == 0)
continue; // Normal failure, no entries
struct ExAllData *ead = data;
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);
AmigaOSFilesystemNode *entry ;
while ( (pExd = IDOS->ExamineDir(context)) ) {
if ( (EXD_IS_FILE(pExd) && ( Common::FSNode::kListFilesOnly == mode ))
|| (EXD_IS_DIRECTORY(pExd) && ( Common::FSNode::kListDirectoriesOnly == mode ))
|| Common::FSNode::kListAll == mode
)
{
BPTR pLock = IDOS->Lock( pExd->Name, SHARED_LOCK );
if (pLock) {
if (IDOS->Examine(pLock, fib) != DOSFALSE) {
fibProt = fib->fib_Protection;
entry = new AmigaOSFilesystemNode( pLock, pExd->Name );
if (entry) {
myList.push_back(entry);
}
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();
return fibProt;
return ret;
}
AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
@ -447,8 +407,7 @@ AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
if (parentDir) {
node = new AmigaOSFilesystemNode(parentDir);
IDOS->UnLock(parentDir);
}
else
} else
node = new AmigaOSFilesystemNode();
LEAVE();
@ -457,33 +416,19 @@ AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
}
bool AmigaOSFilesystemNode::isReadable() const {
bool readable = false;
int fibProt = getFibProtection();
if (fibProt >= 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);
}
// Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is readable whatever the
// protection says
bool readable = !(_nProt & EXDF_READ) || _pFileLock == 0;
return readable;
}
bool AmigaOSFilesystemNode::isWritable() const {
bool writable = false;
int fibProt = getFibProtection();
if (fibProt >= 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);
}
// Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is never writable whatever
// the protection says (because of the pseudo nature)
bool writable = !(_nProt & EXDF_WRITE) && _pFileLock !=0;
return writable;
}
@ -508,13 +453,10 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
if (dosList->dol_Type == DLT_VOLUME &&
dosList->dol_Name &&
dosList->dol_Task) {
//const char *volName = (const char *)BADDR(dosList->dol_Name)+1;
// Copy name to buffer
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'
char *volName = new char [strlen(buffer) + 1];
@ -536,15 +478,7 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
AmigaOSFilesystemNode *entry = new AmigaOSFilesystemNode(volumeLock, buffer);
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(volumeLock);

View file

@ -33,7 +33,14 @@ AbstractFSNode *PSPFilesystemFactory::makeRootFileNode() 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 {

View file

@ -26,7 +26,7 @@
#include "engines/engine.h"
#include "backends/fs/abstract-fs.h"
#include "backends/fs/stdiostream.h"
#include "backends/fs/psp/psp-stream.h"
#include <sys/stat.h>
#include <unistd.h>
@ -35,6 +35,8 @@
#define ROOT_PATH "ms0:/"
#include "backends/platform/psp/trace.h"
/**
* 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 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 getName() const { return _displayName; }
virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; }
virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; }
virtual bool isReadable() const;
virtual bool isWritable() const;
virtual AbstractFSNode *getChild(const Common::String &n) 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) {
struct stat st;
if (PowerMan.beginCriticalSection()==PowerManager::Blocked)
PSPDebugSuspend("Suspended in PSPFilesystemNode::PSPFilesystemNode\n");
_isValid = (0 == stat(_path.c_str(), &st));
PowerMan.endCriticalSection();
_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 {
// FIXME: Pretty lame implementation! We do no error checking to speak
// 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
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());
if (dfd > 0) {
SceIoDirent dir;
@ -149,10 +196,13 @@ bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool
}
sceIoDclose(dfd);
return true;
} else {
return false;
ret = true;
} else { // dfd <= 0
ret = false;
}
PowerMan.endCriticalSection();
return ret;
}
AbstractFSNode *PSPFilesystemNode::getParent() const {
@ -166,11 +216,11 @@ AbstractFSNode *PSPFilesystemNode::getParent() const {
}
Common::SeekableReadStream *PSPFilesystemNode::createReadStream() {
return StdioStream::makeFromPath(getPath().c_str(), false);
return PSPIoStream::makeFromPath(getPath(), false);
}
Common::WriteStream *PSPFilesystemNode::createWriteStream() {
return StdioStream::makeFromPath(getPath().c_str(), true);
return PSPIoStream::makeFromPath(getPath(), true);
}
#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);
virtual ~StdioStream();
bool err() const;
void clearErr();
bool eos() const;
virtual bool err() const;
virtual void clearErr();
virtual bool eos() const;
virtual uint32 write(const void *dataPtr, uint32 dataSize);
virtual bool flush();
virtual int32 pos() const;
virtual int32 size() const;
bool seek(int32 offs, int whence = SEEK_SET);
uint32 read(void *dataPtr, uint32 dataSize);
virtual bool seek(int32 offs, int whence = SEEK_SET);
virtual uint32 read(void *dataPtr, uint32 dataSize);
};
#endif

View file

@ -168,6 +168,15 @@ void Keymapper::popKeymap() {
_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) {
return mapKey(key, true);
}
@ -255,7 +264,7 @@ void Keymapper::executeAction(const Action *action, bool keyDown) {
}
evt.mouse = _eventMan->getMousePos();
_eventMan->pushEvent(evt);
addEvent(evt);
}
}

View file

@ -39,7 +39,7 @@
namespace Common {
class Keymapper {
class Keymapper : public Common::EventMapper, private Common::ArtificialEventSource {
public:
struct MapRecord {
@ -134,6 +134,10 @@ public:
*/
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.
* 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)) {
preprocessEvents(&ev);
switch (ev.type) {
case SDL_KEYDOWN:{
b = event.kbd.flags = SDLModToOSystemKeyFlags(SDL_GetModState());

View file

@ -26,6 +26,13 @@
#include "backends/platform/sdl/sdl.h"
#include "common/mutex.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);
}
#pragma mark -
#pragma mark --- Mouse ---
#pragma mark -
bool OSystem_SDL::showMouse(bool visible) {
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)
return;
/* 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);
#ifdef USE_RGB_COLOR
_mouseData = (byte *)malloc(w * h * _cursorFormat.bytesPerPixel);
memcpy(_mouseData, buf, w * h * _cursorFormat.bytesPerPixel);
#else
_mouseData = (byte *)malloc(w * h);
memcpy(_mouseData, buf, w * h);
#endif
blitCursor();*/
}

View file

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

View file

@ -33,7 +33,7 @@
#include "common/archive.h"
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/events.h"
#include "common/EventRecorder.h"
#include "common/util.h"
#ifdef UNIX
@ -215,7 +215,7 @@ OSystem_SDL::~OSystem_SDL() {
uint32 OSystem_SDL::getMillis() {
uint32 millis = SDL_GetTicks();
getEventManager()->processMillis(millis);
g_eventRec.processMillis(millis);
return millis;
}
@ -349,13 +349,20 @@ Common::WriteStream *OSystem_SDL::createConfigWriteStream() {
}
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());
}
@ -585,7 +592,6 @@ void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) {
void OSystem_SDL::setupMixer() {
SDL_AudioSpec desired;
SDL_AudioSpec obtained;
// Determine the desired output sampling frequency.
_samplesPerSec = 0;
@ -615,7 +621,7 @@ void OSystem_SDL::setupMixer() {
_mixer = new Audio::MixerImpl(this);
assert(_mixer);
if (SDL_OpenAudio(&desired, &obtained) != 0) {
if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) {
warning("Could not open audio device: %s", SDL_GetError());
_samplesPerSec = 0;
_mixer->setReady(false);
@ -623,7 +629,7 @@ void OSystem_SDL::setupMixer() {
// 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
// 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);
// Tell the mixer that we are ready and start the sound processing
@ -631,7 +637,7 @@ void OSystem_SDL::setupMixer() {
_mixer->setReady(true);
#ifdef MIXER_DOUBLE_BUFFERING
initThreadedMixer(_mixer, obtained.samples * 4);
initThreadedMixer(_mixer, _obtainedRate.samples * 4);
#endif
// start the sound system

View file

@ -77,7 +77,7 @@ public:
virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME)
// 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.
uint32 getMillis();
@ -127,6 +127,7 @@ public:
// Overlay
virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; }
virtual void showOverlay();
virtual void hideOverlay();
virtual void clearOverlay();
@ -143,6 +144,7 @@ public:
virtual bool hasFeature(Feature f);
virtual void setFeatureState(Feature f, bool enable);
virtual bool getFeatureState(Feature f);
virtual void preprocessEvents(SDL_Event *event) {};
virtual Common::SaveFileManager *getSavefileManager();
virtual FilesystemFactory *getFilesystemFactory();
@ -153,6 +155,7 @@ public:
protected:
bool _inited;
SDL_AudioSpec _obtainedRate;
#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::FSNode savePath(getSavePath());
checkPath(savePath);
Common::String savePathName = getSavePath();
checkPath(Common::FSNode(savePathName));
if (getError() != Common::kNoError)
return Common::StringList();
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSDirectory dir(savePath);
Common::ArchiveMemberList savefiles;
Common::StringList results;
@ -76,11 +79,14 @@ Common::StringList DefaultSaveFileManager::listSavefiles(const Common::String &p
Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) {
// Ensure that the savepath is valid. If not, generate an appropriate error.
Common::FSNode savePath(getSavePath());
checkPath(savePath);
Common::String savePathName = getSavePath();
checkPath(Common::FSNode(savePathName));
if (getError() != Common::kNoError)
return 0;
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSNode file = savePath.getChild(filename);
if (!file.exists())
return 0;
@ -93,11 +99,14 @@ Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String
Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename) {
// Ensure that the savepath is valid. If not, generate an appropriate error.
Common::FSNode savePath(getSavePath());
checkPath(savePath);
Common::String savePathName = getSavePath();
checkPath(Common::FSNode(savePathName));
if (getError() != Common::kNoError)
return 0;
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSNode file = savePath.getChild(filename);
// Open the file for saving
@ -107,13 +116,14 @@ Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String
}
bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
clearError();
Common::FSNode savePath(getSavePath());
checkPath(savePath);
Common::String savePathName = getSavePath();
checkPath(Common::FSNode(savePathName));
if (getError() != Common::kNoError)
return false;
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSNode file = savePath.getChild(filename);
// FIXME: remove does not exist on all systems. If your port fails to

View file

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

View file

@ -124,6 +124,12 @@ bool DefaultTimerManager::installTimerProc(TimerProc callback, int32 interval, v
slot->nextFireTimeMicro = interval % 1000;
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);
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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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
@ -31,7 +31,6 @@
#include "backends/vkeybd/virtual-keyboard-parser.h"
#include "backends/vkeybd/keycode-descriptions.h"
#include "common/config-manager.h"
#include "common/fs.h"
#include "common/unzip.h"
#define KEY_START_CHAR ('[')
@ -77,50 +76,76 @@ void VirtualKeyboard::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());
delete _fileArchive;
_fileArchive = 0;
_loaded = false;
FSNode vkDir;
bool opened = false;
if (ConfMan.hasKey("vkeybdpath"))
vkDir = FSNode(ConfMan.get("vkeybdpath"));
opened = openPack(packName, FSNode(ConfMan.get("vkeybdpath")));
else if (ConfMan.hasKey("extrapath"))
vkDir = FSNode(ConfMan.get("extrapath"));
else // use current directory
vkDir = FSNode(".");
opened = openPack(packName, FSNode(ConfMan.get("extrapath")));
if (vkDir.getChild(packName + ".xml").exists()) {
_fileArchive = new FSDirectory(vkDir, 1);
// 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;
}
// fallback to the current dir
if (!opened)
opened = openPack(packName, FSNode("."));
if (opened) {
_parser->setParseMode(VirtualKeyboardParser::kParseFull);
_loaded = _parser->parse();
if (_loaded)
if (_loaded) {
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;
}

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
* are too numerous to list here. Please refer to the COPYRIGHT
* 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
@ -37,6 +37,7 @@ class OSystem;
#include "common/keyboard.h"
#include "common/list.h"
#include "common/str.h"
#include "common/fs.h"
#include "backends/vkeybd/image-map.h"
#include "graphics/surface.h"
@ -190,7 +191,7 @@ public:
* searches for a compressed keyboard pack by looking for packName.zip.
* @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
@ -232,6 +233,7 @@ protected:
VirtualKeyboardParser *_parser;
void reset();
bool openPack(const String &packName, const FSNode &node);
void deleteEvents();
bool checkModeResolutions();
void switchMode(Mode *newMode);

View file

@ -34,6 +34,9 @@
#include "gui/ThemeEngine.h"
#define DETECTOR_TESTING_HACK
#define UPGRADE_ALL_TARGETS_HACK
namespace Base {
#ifndef DISABLE_COMMAND_LINE
@ -235,6 +238,18 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_COMMAND('z', "list-games")
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")
END_OPTION
@ -253,10 +268,13 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_OPTION_INT('m', "music-volume")
END_OPTION
DO_OPTION('s', "sfx-volume")
END_OPTION
DO_OPTION('r', "speech-volume")
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_OPTION('q', "language")
@ -264,6 +282,15 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
usage("Unrecognized language '%s'", 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")
settings["joystick_num"] = option;
settings.erase("joystick");
@ -275,24 +302,15 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_LONG_OPTION("soft-renderer")
END_OPTION
DO_LONG_OPTION_BOOL("disable-sdl-parachute")
END_OPTION
DO_LONG_OPTION("engine-speed")
END_OPTION
DO_LONG_OPTION("gamma")
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")
Common::FSNode path(option);
if (!path.exists()) {
@ -326,8 +344,15 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_LONG_COMMAND("list-themes")
END_OPTION
DO_LONG_OPTION("target-md5")
END_OPTION
DO_LONG_OPTION("text-speed")
END_OPTION
#ifdef ENABLE_SCUMM
DO_LONG_OPTION_INT("dimuse-tempo")
END_OPTION
#endif
DO_LONG_OPTION("speech-mode")
END_OPTION
@ -414,6 +439,192 @@ static void listThemes() {
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
@ -449,6 +660,18 @@ bool processSettings(Common::String &command, Common::StringMap &settings) {
printf(HELP_STRING, s_appName);
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

View file

@ -41,12 +41,16 @@
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/events.h"
#include "common/EventRecorder.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/system.h"
#include "gui/GuiManager.h"
#include "gui/message.h"
#include "sound/audiocd.h"
#include "backends/keymapper/keymapper.h"
#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
Common::String caption(ConfMan.get("description"));
Common::String desc = EngineMan.findGame(ConfMan.get("gameid")).description();
if (caption.empty() && !desc.empty())
caption = desc;
if (caption.empty()) {
caption = EngineMan.findGame(ConfMan.get("gameid")).description();
}
if (caption.empty())
caption = ConfMan.getActiveDomainName(); // Use the domain (=target) name
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
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
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
#ifndef FORCE_RTL
if (result == 0 && !g_system->getEventManager()->shouldRTL())
break;
#endif
// Reset RTL flag in case we want to load another engine
g_system->getEventManager()->resetRTL();
#ifdef FORCE_RTL
g_system->getEventManager()->resetQuit();
#endif
// Discard any command line options. It's unlikely that the user
// 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");
}
// 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
setupGraphics(system);
launcherDialog();

View file

@ -28,6 +28,9 @@
#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[]);
#endif

View file

@ -23,9 +23,39 @@
*
*/
#include "common/sys.h"
#include "base/internal_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 *gResidualBuildDate = __DATE__ " " __TIME__;
const char *gResidualVersionDate = RESIDUAL_VERSION " (" __DATE__ " " __TIME__ ")";
@ -52,6 +82,14 @@ const char *gResidualFeatures = ""
"MP3 "
#endif
#ifdef USE_ALSA
"ALSA "
#endif
#ifdef USE_RGB_COLOR
"RGB "
#endif
#ifdef USE_ZLIB
"zLib "
#endif

View file

@ -3,7 +3,7 @@
* 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

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();
for ( ; it != allNames.end(); ++it) {
if ((*it)->getName().matchString(lowercasePattern, true)) {
if ((*it)->getName().matchString(lowercasePattern, false, true)) {
list.push_back(*it);
matches++;
}
@ -123,6 +123,55 @@ void SearchSet::addDirectory(const String &name, const FSNode &dir, int 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) {
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);
/**
* 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.
*/

View file

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

View file

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

View file

@ -132,10 +132,10 @@ public:
//
// Some additional convenience accessors.
//
int getInt(const String &key, const String &domName = String::emptyString) const;
bool getBool(const String &key, const String &domName = String::emptyString) const;
void setInt(const String &key, int value, const String &domName = String::emptyString);
void setBool(const String &key, bool value, const String &domName = String::emptyString);
int getInt(const String &key, const String &domName = String()) const;
bool getBool(const String &key, const String &domName = String()) const;
void setInt(const String &key, int value, const String &domName = String());
void setBool(const String &key, bool value, const String &domName = String());
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];
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);
}
buf[STRINGBUFLEN-1] = '\0';
if (caret) {
buf[STRINGBUFLEN-2] = '\0';

View file

@ -28,28 +28,115 @@
#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
* and vice versa.
*/
FORCEINLINE uint32 SWAP_BYTES_32(uint32 a) {
return ((a >> 24) & 0x000000FF) |
((a >> 8) & 0x0000FF00) |
((a << 8) & 0x00FF0000) |
((a << 24) & 0xFF000000);
// machine/compiler-specific 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 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
* 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.
*/
#if defined(INVERSE_MKID)
#define MKID_BE(a) ((uint32) \
(((a) >> 24) & 0x000000FF) | \
(((a) >> 8) & 0x0000FF00) | \
(((a) << 8) & 0x00FF0000) | \
(((a) << 24) & 0xFF000000))
#define MKID_BE(a) SWAP_CONSTANT_32(a)
#else
# define MKID_BE(a) ((uint32)(a))
#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)
#define READ_UINT16(a) READ_LE_UINT16(a)
#define READ_UINT32(a) READ_LE_UINT32(a)
inline uint16 READ_UINT16(const void *ptr) {
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)
#define WRITE_UINT32(a, v) WRITE_LE_UINT32(a, v)
# elif defined(SYSTEM_BIG_ENDIAN)
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_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_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)
#define MKID(a) ((uint32)(a))
#define MKID_BE(a) ((uint32)(a))
#define READ_UINT16(a) READ_BE_UINT16(a)
#define READ_UINT32(a) READ_BE_UINT32(a)
#define READ_BE_UINT16(a) READ_UINT16(a)
#define READ_BE_UINT32(a) READ_UINT32(a)
#define WRITE_UINT16(a, v) WRITE_BE_UINT16(a, v)
#define WRITE_UINT32(a, v) WRITE_BE_UINT32(a, v)
#define WRITE_BE_UINT16(a, v) WRITE_UINT16(a, v)
#define WRITE_BE_UINT32(a, v) WRITE_UINT32(a, v)
#define FROM_LE_32(a) SWAP_BYTES_32(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_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
#error No endianness defined
#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];
inline uint16 READ_LE_UINT16(const void *ptr) {
return SWAP_BYTES_16(READ_UINT16(ptr));
}
FORCEINLINE uint32 READ_LE_UINT32(const void *ptr) {
const byte *b = (const byte *)ptr;
return (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + (b[0]);
inline uint32 READ_LE_UINT32(const void *ptr) {
return SWAP_BYTES_32(READ_UINT32(ptr));
}
FORCEINLINE void WRITE_LE_UINT16(void *ptr, uint16 value) {
byte *b = (byte *)ptr;
b[0] = (byte)(value >> 0);
b[1] = (byte)(value >> 8);
inline void WRITE_LE_UINT16(void *ptr, uint16 value) {
WRITE_UINT16(ptr, SWAP_BYTES_16(value));
}
FORCEINLINE void WRITE_LE_UINT32(void *ptr, uint32 value) {
byte *b = (byte *)ptr;
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]);
inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
WRITE_UINT32(ptr, SWAP_BYTES_32(value));
}
FORCEINLINE uint32 READ_BE_UINT24(const void *ptr) {
const byte *b = (const byte*)ptr;
return (b[0] << 16) + (b[1] << 8) + (b[2]);
# endif // if defined(SYSTEM_NEED_ALIGNMENT)
#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)

View file

@ -48,6 +48,7 @@ enum Error {
kInvalidPathError, //!< Engine initialization: Invalid game path was passed
kNoGameDataFoundError, //!< Engine initialization: No game data was found in the specified location
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

View file

@ -31,6 +31,9 @@
#include "common/rect.h"
#include "common/noncopyable.h"
#include "common/list.h"
#include "common/singleton.h"
namespace Common {
/**
@ -126,6 +129,190 @@ struct Event {
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;
/**
@ -161,11 +348,6 @@ public:
*/
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 */
virtual Common::Point getMousePos() const = 0;
@ -195,7 +377,9 @@ public:
* Used when we have returned to the launcher.
*/
virtual void resetRTL() = 0;
#ifdef FORCE_RTL
virtual void resetQuit() = 0;
#endif
// Optional: check whether a given key is currently pressed ????
//virtual bool isKeyPressed(int keycode) = 0;
@ -207,9 +391,21 @@ public:
virtual Common::Keymapper *getKeymapper() = 0;
#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

View file

@ -32,16 +32,6 @@
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()
: _handle(0) {
}
@ -120,15 +110,6 @@ bool File::isOpen() const {
return _handle != NULL;
}
bool File::ioFailed() const {
return !_handle || (eos() || err());
}
void File::clearIOFailed() {
if (_handle)
_handle->clearErr();
}
bool File::err() const {
assert(_handle);
return _handle->err();

View file

@ -48,10 +48,6 @@ protected:
String _name;
public:
static void addDefaultDirectory(const String &directory);
static void addDefaultDirectory(const FSNode &directory);
File();
virtual ~File();
@ -126,19 +122,6 @@ public:
*/
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
void clearErr(); // implement abstract Stream 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) {
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) {
@ -320,7 +320,7 @@ int FSDirectory::listMatchingMembers(ArchiveMemberList &list, const String &patt
int matches = 0;
NodeCache::iterator it = _fileCache.begin();
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)));
matches++;
}

View file

@ -40,6 +40,12 @@
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
// code produces (many collisions indicate either a bad hash function, or a
// hash table that is too small).
@ -93,39 +99,41 @@ public:
ObjectPool<Node, HASHMAP_MEMORYPOOL_SIZE> _nodePool;
Node *allocNode(const Key &key) {
return new (_nodePool) Node(key);
}
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 */
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 _deleted; ///< Number of deleted elements (_dummyNodes)
HashFunc _hash;
EqualFunc _equal;
// Default value, returned by the const getVal.
/** Default value, returned by the const getVal. */
const Val _defaultVal;
// Dummy node, used as marker for erased objects.
Node _dummyNode;
/** Dummy node, used as marker for erased objects. */
#define HASHMAP_DUMMY_NODE ((Node *)1)
#ifdef DEBUG_HASH_COLLISIONS
mutable int _collisions, _lookups, _dummyHits;
#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);
int lookup(const Key &key) const;
int lookupAndCreateIfMissing(const Key &key);
void expandStorage(uint newCapacity);
#ifndef __sgi
template<class T> friend class IteratorImpl;
#endif
/**
* Simple HashMap iterator implementation.
@ -133,7 +141,11 @@ public:
template<class NodeType>
class IteratorImpl {
friend class HashMap;
#ifdef __sgi
template<class T> friend class Common::IteratorImpl;
#else
template<class T> friend class IteratorImpl;
#endif
protected:
typedef const HashMap hashmap_t;
@ -148,6 +160,7 @@ public:
assert(_idx <= _hashmap->_mask);
Node *node = _hashmap->_storage[_idx];
assert(node != 0);
assert(node != HASHMAP_DUMMY_NODE);
return node;
}
@ -166,7 +179,7 @@ public:
assert(_hashmap);
do {
_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)
_idx = (uint)-1;
@ -207,6 +220,7 @@ public:
Val &getVal(const Key &key);
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 clear(bool shrinkArray = 0);
@ -218,7 +232,7 @@ public:
iterator begin() {
// Find and return the first non-empty entry
for (uint ctr = 0; ctr <= _mask; ++ctr) {
if (_storage[ctr])
if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
return iterator(ctr, this);
}
return end();
@ -230,7 +244,7 @@ public:
const_iterator begin() const {
// Find and return the first non-empty entry
for (uint ctr = 0; ctr <= _mask; ++ctr) {
if (_storage[ctr])
if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
return const_iterator(ctr, this);
}
return end();
@ -274,7 +288,7 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap()
#ifdef __PLAYSTATION2__
{
#else
: _defaultVal(), _dummyNode() {
: _defaultVal() {
#endif
_mask = HASHMAP_MIN_CAPACITY - 1;
_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>
HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
_defaultVal(), _dummyNode() {
_defaultVal() {
#ifdef DEBUG_HASH_COLLISIONS
_collisions = 0;
_lookups = 0;
@ -340,8 +354,8 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
_size = 0;
_deleted = 0;
for (uint ctr = 0; ctr <= _mask; ++ctr) {
if (map._storage[ctr] == &map._dummyNode) {
_storage[ctr] = &_dummyNode;
if (map._storage[ctr] == HASHMAP_DUMMY_NODE) {
_storage[ctr] = HASHMAP_DUMMY_NODE;
_deleted++;
} else if (map._storage[ctr] != NULL) {
_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) {
assert(newCapacity > _mask+1);
#ifndef NDEBUG
const uint old_size = _size;
#endif
const uint old_mask = _mask;
Node **old_storage = _storage;
@ -397,7 +413,7 @@ void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
// rehash all the old elements
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;
// 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().
const uint hash = _hash(old_storage[ctr]->_key);
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;
}
@ -430,7 +446,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
if (_storage[ctr] == NULL)
break;
if (_storage[ctr] == &_dummyNode) {
if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
#ifdef DEBUG_HASH_COLLISIONS
_dummyHits++;
#endif
@ -464,7 +480,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &
for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
if (_storage[ctr] == NULL)
break;
if (_storage[ctr] == &_dummyNode) {
if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
#ifdef DEBUG_HASH_COLLISIONS
_dummyHits++;
#endif
@ -540,11 +556,16 @@ Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) {
template<class Key, class Val, class HashFunc, class EqualFunc>
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);
if (_storage[ctr] != NULL)
return _storage[ctr]->_value;
else
return _defaultVal;
return defaultVal;
}
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.
freeNode(_storage[ctr]);
_storage[ctr] = &_dummyNode;
_storage[ctr] = HASHMAP_DUMMY_NODE;
_size--;
_deleted++;
return;
}
#undef HASHMAP_DUMMY_NODE
} // End of namespace Common
#endif

View file

@ -46,6 +46,12 @@ MemoryPool::MemoryPool(size_t chunkSize) {
}
MemoryPool::~MemoryPool() {
#if 0
freeUnusedPages();
if (!_pages.empty())
warning("Memory leak found in pool");
#endif
for (size_t i = 0; i < _pages.size(); ++i)
::free(_pages[i].start);
}
@ -62,7 +68,7 @@ void MemoryPool::allocPage() {
_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;
// Add the page to the pool of free chunk

View file

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

View file

@ -28,6 +28,8 @@
#include "common/memorypool.h"
#include <stdarg.h>
#if !defined(__SYMBIAN32__)
#include <new>
#endif
@ -350,12 +352,12 @@ bool String::contains(char x) const {
return strchr(c_str(), x) != NULL;
}
bool String::matchString(const char *pat, bool pathMode) const {
return Common::matchString(c_str(), pat, pathMode);
bool String::matchString(const char *pat, bool ignoreCase, bool pathMode) const {
return Common::matchString(c_str(), pat, ignoreCase, pathMode);
}
bool String::matchString(const String &pat, bool pathMode) const {
return Common::matchString(c_str(), pat.c_str(), pathMode);
bool String::matchString(const String &pat, bool ignoreCase, bool pathMode) const {
return Common::matchString(c_str(), pat.c_str(), ignoreCase, pathMode);
}
void String::deleteLastChar() {
@ -435,6 +437,50 @@ uint String::hash() const {
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 -
bool String::operator ==(const String &x) const {
@ -635,7 +681,7 @@ Common::String normalizePath(const Common::String &path, const char sep) {
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(pat);
@ -652,7 +698,7 @@ bool matchString(const char *str, const char *pat, bool pathMode) {
switch (*pat) {
case '*':
// Record pattern / string possition for backtracking
// Record pattern / string position for backtracking
p = ++pat;
q = str;
// If pattern ended with * -> match
@ -661,7 +707,8 @@ bool matchString(const char *str, const char *pat, bool pathMode) {
break;
default:
if (*pat != *str) {
if ((!ignoreCase && *pat != *str) ||
(ignoreCase && tolower(*pat) != tolower(*str))) {
if (p) {
// No match, oops -> try to backtrack
pat = p;

View file

@ -170,12 +170,13 @@ public:
*
* @param str Text to be matched against the given 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.
*
* @return true if str matches the pattern, false otherwise.
*/
bool matchString(const char *pat, bool pathMode = false) const;
bool matchString(const String &pat, bool pathMode = false) const;
bool matchString(const char *pat, bool ignoreCase = false, bool pathMode = false) const;
bool matchString(const String &pat, bool ignoreCase = false, bool pathMode = false) const;
inline const char *c_str() const { return _str; }
@ -218,6 +219,11 @@ public:
uint hash() const;
/**
* Printf-like function. Returns a formatted String.
*/
static Common::String printf(const char *fmt, ...) GCC_PRINTF(1,2);
public:
typedef char * 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 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.
*
* @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;

View file

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

View file

@ -125,7 +125,6 @@ public:
* like PocketPC, Palms, Symbian phones like the P800, Zaurus, etc.
*/
kFeatureVirtualKeyboard,
kFeatureIconifyWindow,
kFeatureOpenGL,
/**
@ -174,7 +173,6 @@ public:
* rather complicated for backend authors to fully understand and
* implement the semantics of the OSystem interface.
*/
//@{
/**
@ -323,8 +321,10 @@ public:
* @param hotspotY vertical offset from the top side to the hotspot
* @param keycolor transparency color index
* @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
* given value. The caption must be a pure ASCII string. Passing a
* non-ASCII string may lead to unexpected behavior, even crashes.
* given value. The caption must be a pure ISO LATIN 1 string. Passing a
* 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
* UTF-8 or UTF-16 encoded data, or maybe ISO LATIN 1.
*
* @param caption the window caption to use, as an ASCII string
* @param caption the window caption to use, as an ISO LATIN 1 string
*/
virtual void setWindowCaption(const char *caption) {}

View file

@ -24,6 +24,7 @@
#include "common/util.h"
#include "common/system.h"
#include "common/config-manager.h"
#include "gui/debugger.h"
#include "engines/engine.h"
@ -211,6 +212,7 @@ const LanguageDescription g_languages[] = {
{"ru", "Russian", RU_RUS},
{"es", "Spanish", ES_ESP},
{"se", "Swedish", SE_SWE},
{"hu", "Hungarian", HU_HUN},
{0, 0, UNK_LANG}
};
@ -419,6 +421,14 @@ String getGameGUIOptionsDescription(uint32 options) {
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

View file

@ -26,7 +26,6 @@
#define COMMON_UTIL_H
#include "common/sys.h"
#include "common/debug.h"
#include "common/str.h"
#if defined(WIN32)
@ -183,6 +182,7 @@ enum Language {
RU_RUS,
ES_ESP,
SE_SWE,
HU_HUN,
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);
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

175
config.guess vendored
View file

@ -1,10 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# 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.
timestamp='2009-04-27'
timestamp='2009-09-18'
# 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
@ -27,16 +27,16 @@ timestamp='2009-04-27'
# the same distribution terms that you use for the rest of that program.
# Originally written by Per Bothner <per@bothner.com>.
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
# Originally written by Per Bothner. Please send patches (context
# diff format) to <config-patches@gnu.org> and include a ChangeLog
# entry.
#
# This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1.
#
# The plan is that this can be called by configure scripts if you
# don't specify an explicit build system type.
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
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)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep __ELF__ >/dev/null
| grep -q __ELF__
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
@ -656,7 +656,7 @@ EOF
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep __LP64__ >/dev/null
grep -q __LP64__
then
HP_ARCH="hppa2.0w"
else
@ -822,6 +822,9 @@ EOF
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
exit ;;
8664:Windows_NT:*)
echo x86_64-pc-mks
exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# 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
@ -851,6 +854,20 @@ EOF
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
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:*:*)
eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
@ -873,6 +890,9 @@ EOF
frv:Linux:*:*)
echo frv-unknown-linux-gnu
exit ;;
i*86:Linux:*:*)
echo ${UNAME_MACHINE}-pc-linux-gnu
exit ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
@ -882,40 +902,17 @@ EOF
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
mips:Linux:*:*)
mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef mips
#undef mipsel
#undef ${UNAME_MACHINE}
#undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=mipsel
CPU=${UNAME_MACHINE}el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=mips
#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
CPU=${UNAME_MACHINE}
#else
CPU=
#endif
@ -931,29 +928,12 @@ EOF
or32:Linux:*:*)
echo or32-unknown-linux-gnu
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:*:*)
echo sparc-unknown-linux-gnu
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-gnu
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
@ -962,8 +942,11 @@ EOF
*) echo hppa-unknown-linux-gnu ;;
esac
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-gnu
ppc64:Linux:*:*)
echo powerpc64-unknown-linux-gnu
exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-gnu
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
@ -986,66 +969,6 @@ EOF
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
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*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
@ -1074,7 +997,7 @@ EOF
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
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}
exit ;;
i*86:*DOS:*:*)
@ -1182,7 +1105,7 @@ EOF
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
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}
exit ;;
SM[BE]S:UNIX_SV:*:*)
@ -1275,6 +1198,16 @@ EOF
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
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 ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}

27
config.sub vendored
View file

@ -1,10 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
# 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.
timestamp='2009-04-17'
timestamp='2009-08-19'
# This file is (in principle) common to ALL 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
# diff and a properly formatted ChangeLog entry.
# diff and a properly formatted GNU ChangeLog entry.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# 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.
# 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
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
@ -149,10 +152,13 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis | -knuth | -cray)
-apple | -axis | -knuth | -cray | -microblaze)
os=
basic_machine=$1
;;
-bluegene*)
os=-cnk
;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
@ -337,7 +343,7 @@ case $basic_machine in
| lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
@ -467,6 +473,10 @@ case $basic_machine in
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
bluegene*)
basic_machine=powerpc-ibm
os=-cnk
;;
c90)
basic_machine=c90-cray
os=-unicos
@ -719,6 +729,9 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
microblaze)
basic_machine=microblaze-xilinx
;;
mingw32)
basic_machine=i386-pc
os=-mingw32
@ -1260,7 +1273,7 @@ case $os in
# Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4.
-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* \
| -kopensolaris* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
@ -1613,7 +1626,7 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
-aix*)
-cnk*|-aix*)
vendor=ibm
;;
-beos*)

324
configure vendored
View file

@ -29,6 +29,8 @@ SAVED_LDFLAGS=$LDFLAGS
SAVED_CXX=$CXX
SAVED_CXXFLAGS=$CXXFLAGS
SAVED_CPPFLAGS=$CPPFLAGS
SAVED_ASFLAGS=$ASFLAGS
SAVED_WINDRESFLAGS=$WINDRESFLAGS
# Use environment vars if set
CXXFLAGS="$CXXFLAGS $CPPFLAGS"
@ -54,15 +56,22 @@ if test "$ac_emxsupport" != "no" -a "$ac_emxsupport" != "NO"; then
unset ac_TEMP_PATH
fi
set_var() {
eval ${1}='${2}'
}
get_var() {
eval echo \$${1}
}
# Add an engine: id name build subengines
add_engine() {
_engines="${_engines} ${1}"
eval _engine_${1}_name='${2}'
eval _engine_${1}_build='${3}'
eval _engine_${1}_subengines='${4}'
set_var _engine_${1}_name "${2}"
set_var _engine_${1}_build "${3}"
set_var _engine_${1}_subengines "${4}"
for sub in ${4}; do
eval _engine_${sub}_sub=yes
set_var _engine_${sub}_sub "yes"
done
}
@ -92,6 +101,7 @@ _plugins_default=static
_ranlib=ranlib
_strip=strip
_ar="ar cru"
_as="as"
_windres=windres
_win32path="C:/residual"
_aos4path="Games:Residual"
@ -107,6 +117,7 @@ _host_os=""
_host_alias=""
_srcdir=`dirname $0`
_port_mk="ports.mk"
# Determine a tmp file name, using mktemp(1) when available.
if type mktemp > /dev/null 2>&1 ; then
@ -225,7 +236,7 @@ find_sdlconfig() {
#
get_system_exe_extension() {
case $1 in
mingw* | *os2-emx)
mingw* | *os2-emx | wince)
_exeext=".exe"
;;
arm-riscos)
@ -237,7 +248,7 @@ get_system_exe_extension() {
gp2x-linux)
_exeext=".gp2x"
;;
dreamcast | wii | gamecube | psp)
dreamcast | wii | gamecube | nds | psp)
_exeext=".elf"
;;
*)
@ -271,22 +282,22 @@ Try \`$0 --help' for more information." >&2
# Get the name of the engine
get_engine_name() {
eval echo \$_engine_$1_name
get_var _engine_$1_name
}
# Will this engine be built?
get_engine_build() {
eval echo \$_engine_$1_build
get_var _engine_$1_build
}
# Get the subengines
get_engine_subengines() {
eval echo \$_engine_$1_subengines
get_var _engine_$1_subengines
}
# Ask if this is a subengine
get_engine_sub() {
sub=`eval echo \\$_engine_$1_sub`
sub=`get_var _engine_$1_sub`
if test -z "$sub" ; then
sub=no
fi
@ -296,14 +307,14 @@ get_engine_sub() {
# Enable *all* engines
engine_enable_all() {
for engine in $_engines; do
eval _engine_${engine}_build=yes
set_var _engine_${engine}_build "yes"
done
}
# Disable *all* engines
engine_disable_all() {
for engine in $_engines; do
eval _engine_${engine}_build=no
set_var _engine_${engine}_build "no"
done
}
@ -327,7 +338,7 @@ engine_enable() {
if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then
if test "`get_engine_name ${engine}`" != "" ; then
eval _engine_${engine}_build=$opt
set_var _engine_${engine}_build "$opt"
else
option_error
fi
@ -346,7 +357,7 @@ engine_disable() {
engine=`echo $1 | sed 's/-/_/g'`
if test "`get_engine_name ${engine}`" != "" ; then
eval _engine_${engine}_build=no
set_var _engine_${engine}_build "no"
else
option_error
fi
@ -493,7 +504,7 @@ Usage: $0 [OPTIONS]...
Configuration:
-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:
--prefix=DIR use this prefix for installing Residual [/usr/local]
@ -508,20 +519,23 @@ Special configuration feature:
dreamcast for Sega Dreamcast
wii for Nintendo Wii
gamecube for Nintendo Gamecube
nds for Nintendo DS
iphone for Apple iPhone
wince for Windows CE
psp for PlayStation Portable
Optional Features:
--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
Game engines:
--enable-all-engines enable all engines
--disable-all-engines disable all engines
$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
--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:
--with-ogg-prefix=DIR Prefix where libogg is installed (optional)
@ -548,6 +562,8 @@ Some influential environment variables:
CXXFLAGS C++ compiler flags
CPPFLAGS C++ preprocessor flags, e.g. -I<include dir> if you have
headers in a nonstandard directory <include dir>
ASFLAGS assembler flags
WINDRESFLAGS Windows resource compiler flags
EOF
exit 0
@ -566,8 +582,9 @@ for ac_option in $@; do
--disable-flac) _flac=no ;;
--enable-mad) _mad=yes ;;
--disable-mad) _mad=no ;;
--enable-plugins) _dynamic_modules=yes ;;
--enable-verbose-build) _verbose_build=yes ;;
--enable-plugins) _dynamic_modules=yes ;;
--default-dynamic) _plugins_default=dynamic ;;
--enable-vkeybd) _vkeybd=yes ;;
--disable-vkeybd) _vkeybd=no ;;
@ -676,6 +693,16 @@ linupy)
_host_os=linux
_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)
_host_os=riscos
_host_cpu=arm
@ -703,6 +730,11 @@ iphone)
_host_cpu=arm
_host_alias=arm-apple-darwin9
;;
wince)
_host_os=wince
_host_cpu=arm
_host_alias=arm-wince-mingw32ce
;;
neuros)
_host_os=linux
_host_cpu=arm
@ -719,17 +751,22 @@ wii)
_host_cpu=ppc
_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)
_host_os=psp
_host_cpu=mipsallegrexel
_host_alias=psp
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
guessed_host=`$_srcdir/config.sub $_host`
@ -742,6 +779,13 @@ esac
if test -z "$_host_alias"; then
_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
#
@ -766,7 +810,7 @@ esac
# Platform specific sanity checks
#
case $_host_os in
wii | gamecube)
wii | gamecube | nds)
if test -z "$DEVKITPRO"; then
echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>"
exit 1
@ -836,11 +880,29 @@ fi
#
echocheck "compiler version"
have_gcc=no
cxx_version=`( $CXX -dumpversion ) 2>&1`
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_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
if test "$have_gcc" = yes; then
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][-.]*)
_cxx_major=`echo $cxx_version | cut -d '.' -f 1`
@ -867,6 +929,30 @@ case $cxx_version in
cxx_verc_fail=yes
;;
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"
@ -1040,7 +1126,7 @@ case $_host_os in
;;
darwin*)
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"
;;
mingw*)
@ -1073,17 +1159,24 @@ case $_host_os in
wii)
CXXFLAGS="$CXXFLAGS -Os -mrvl -mcpu=750 -meabi -mhard-float"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include -I$DEVKITPRO/wii/include"
LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii -L$DEVKITPRO/wii/lib"
;;
gamecube)
CXXFLAGS="$CXXFLAGS -Os -mogc -mcpu=750 -meabi -mhard-float"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
LDFLAGS="$LDFLAGS -mogc -mcpu=750 -L$DEVKITPRO/libogc/lib/cube"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include -I$DEVKITPRO/cube/include"
LDFLAGS="$LDFLAGS -mogc -mcpu=750 -L$DEVKITPRO/libogc/lib/cube -L$DEVKITPRO/cube/lib"
;;
nds)
# TODO nds
;;
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
*)
@ -1098,16 +1191,6 @@ if test -n "$_host"; then
linupy|arm-riscos)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
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
_endian=little
_need_memalign=yes
@ -1115,6 +1198,44 @@ if test -n "$_host"; then
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'
;;
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*)
_need_memalign=yes
@ -1125,7 +1246,7 @@ if test -n "$_host"; then
;;
gp2xwiz)
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"
LDFLAGS="$LDFLAGS"
_endian=little
@ -1133,8 +1254,6 @@ if test -n "$_host"; then
type_1_byte='char'
type_2_byte='short'
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_SMUSH_ASM = 1'
_backend="gp2xwiz"
@ -1143,27 +1262,26 @@ if test -n "$_host"; then
;;
gp2x)
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"
ASFLAGS="$ASFLAGS -mfloat-abi=soft"
LDFLAGS="$LDFLAGS -static"
_endian=little
_need_memalign=yes
type_1_byte='char'
type_2_byte='short'
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_SMUSH_ASM = 1'
_backend="gp2x"
_build_hq_scalers="no"
_mt32emu="no"
;;
neuros)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
DEFINES="$DEFINES -DUNIX"
DEFINES="$DEFINES -DUNIX -DNEUROS"
_endian=little
_need_memalign=yes
add_line_to_config_h "#define NEUROS"
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
@ -1198,34 +1316,46 @@ if test -n "$_host"; then
_windres=$_host-windres
_ar="$_host-ar cru"
_ranlib=$_host-ranlib
_strip=$_host-strip
;;
iphone)
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
_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="iphone"
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_strip=$_host_alias-strip
;;
wince)
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)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
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
_need_memalign=yes
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
_backend="dc"
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_mad="yes"
_zlib="yes"
add_line_to_config_mk 'include $(srcdir)/backends/platform/dc/dreamcast.mk'
;;
wii)
@ -1235,16 +1365,14 @@ if test -n "$_host"; then
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_strip=$_host_alias-strip
_backend="wii"
_port_mk="backends/platform/wii/wii.mk"
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_MEMSTATS */"
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_SMB"
add_line_to_config_h "#define USE_WII_KBD"
;;
gamecube)
@ -1254,17 +1382,36 @@ if test -n "$_host"; then
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_strip=$_host_alias-strip
_backend="wii"
_port_mk="backends/platform/wii/wii.mk"
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 DEBUG_WII_USBGECKO */"
add_line_to_config_h "/* #define DEBUG_WII_MEMSTATS */"
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)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
_endian=little
@ -1272,10 +1419,8 @@ if test -n "$_host"; then
type_1_byte='char'
type_2_byte='short'
type_4_byte='int'
_ar="$_host_alias-ar cru"
_ranlib=$_host_alias-ranlib
_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."
@ -1667,6 +1812,12 @@ case $_backend in
LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`"
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)
find_sdlconfig
INCLUDES="$INCLUDES `$_sdlconfig --prefix="$_sdlpath" --cflags`"
@ -1685,6 +1836,10 @@ case $_backend in
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"
;;
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)
INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc -isystem $(ronindir)/include'
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"
case $_host_os in
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
;;
nds)
# TODO nds
;;
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"
LIBS="$LIBS -lSDL"
;;
@ -1716,11 +1874,12 @@ MODULES="$MODULES backends/platform/$_backend"
#
# Do CXXFLAGS now we know the compiler version
#
if test "$have_gcc" = yes ; then
if test "$_cxx_major" -ge "3" ; then
case $_host_os in
# newlib-based system include files suppress non-C89 function
# declarations under __STRICT_ANSI__
mingw* | dreamcast | wii | gamecube | psp | amigaos*)
mingw* | dreamcast | wii | gamecube | psp | wince | amigaos*)
CXXFLAGS="$CXXFLAGS -W -Wno-unused-parameter"
;;
*)
@ -1728,6 +1887,7 @@ if test "$_cxx_major" -ge "3" ; then
;;
esac
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;
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
CXXFLAGS="$CXXFLAGS -Wconversion"
fi;
fi;
# Some platforms use certain GNU extensions in header files
case $_host_os in
@ -1761,12 +1922,12 @@ for engine in $_engines; do
# If dynamic plugins aren't supported, mark
# all the engines as static
if test $_dynamic_modules = no ; then
eval _engine_${engine}_build=static
set_var _engine_${engine}_build "static"
else
# If it wasn't explicitly marked as static or
# dynamic, use the configured default
if test `get_engine_build $engine` = yes ; then
eval _engine_${engine}_build=${_plugins_default}
set_var _engine_${engine}_build "${_plugins_default}"
fi
fi
@ -1774,7 +1935,7 @@ for engine in $_engines; do
if test `get_engine_build $engine` = dynamic ; then
isbuilt=DYNAMIC_PLUGIN
else
eval _engine_${engine}_build=static
set_var _engine_${engine}_build "static"
isbuilt=STATIC_PLUGIN
fi
fi
@ -1871,7 +2032,10 @@ LIBS += $LIBS
RANLIB := $_ranlib
STRIP := $_strip
AR := $_ar
AS := $_as
ASFLAGS := $ASFLAGS
WINDRES := $_windres
WINDRESFLAGS := $WINDRESFLAGS
WIN32PATH=$_win32path
AOS4PATH=$_aos4path
STATICLIBPATH=$_staticlibpath
@ -1896,11 +2060,15 @@ LDFLAGS += $LDFLAGS
$_mak_plugins
port_mk = $_port_mk
SAVED_CONFIGFLAGS := $SAVED_CONFIGFLAGS
SAVED_LDFLAGS := $SAVED_LDFLAGS
SAVED_CXX := $SAVED_CXX
SAVED_CXXFLAGS := $SAVED_CXXFLAGS
SAVED_CPPFLAGS := $SAVED_CPPFLAGS
SAVED_ASFLAGS := $SAVED_ASFLAGS
SAVED_WINDRESFLAGS := $SAVED_WINDRESFLAGS
EOF
#

View file

@ -2,7 +2,7 @@ Source: residual
Section: games
Priority: optional
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
Package: residual

View file

@ -4,7 +4,7 @@ build: residual
residual:
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)
clean:

View file

@ -11,15 +11,12 @@ if not exist rpl.exe goto no_rpl
echo Creating MSVC9 project files from the MSVC8 ones
copy /y msvc8\*.vcproj 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 "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\residual.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
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\scummvm.sln
goto the_end
:no_rpl

View file

@ -240,6 +240,18 @@
RelativePath="..\..\common\error.h"
>
</File>
<File
RelativePath="..\..\common\EventDispatcher.cpp"
>
</File>
<File
RelativePath="..\..\common\EventRecorder.cpp"
>
</File>
<File
RelativePath="..\..\common\EventRecorder.h"
>
</File>
<File
RelativePath="..\..\common\events.h"
>
@ -460,6 +472,14 @@
<Filter
Name="sound"
>
<File
RelativePath="..\..\sound\audiocd.cpp"
>
</File>
<File
RelativePath="..\..\sound\audiocd.h"
>
</File>
<File
RelativePath="..\..\sound\audiostream.cpp"
>
@ -468,6 +488,14 @@
RelativePath="..\..\sound\audiostream.h"
>
</File>
<File
RelativePath="..\..\sound\flac.cpp"
>
</File>
<File
RelativePath="..\..\sound\flac.h"
>
</File>
<File
RelativePath="..\..\sound\mixer.cpp"
>
@ -480,6 +508,18 @@
RelativePath="..\..\sound\mixer_intern.h"
>
</File>
<File
RelativePath="..\..\sound\module.mk"
>
</File>
<File
RelativePath="..\..\sound\mp3.cpp"
>
</File>
<File
RelativePath="..\..\sound\mp3.h"
>
</File>
<File
RelativePath="..\..\sound\rate.cpp"
>
@ -488,6 +528,14 @@
RelativePath="..\..\sound\rate.h"
>
</File>
<File
RelativePath="..\..\sound\vorbis.cpp"
>
</File>
<File
RelativePath="..\..\sound\vorbis.h"
>
</File>
</Filter>
<Filter
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
copy /y msvc9\*.vcproj 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 "\tTargetFrameworkVersion=\"131072\"\n" "" msvc8\*.vcproj
rpl -e -q "\t\t\t\tRandomizedBaseAddress=\"1\"\n" "" msvc8\residual.vcproj
rpl -e -q "\t\t\t\tDataExecutionPrevention=\"0\"\n" "" msvc8\residual.vcproj
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
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\scummvm.sln
goto the_end
: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;
}
// 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());
if (!createInstance(syst, engine, agdDesc)) {
if (!createInstance(syst, engine, agdDesc))
return Common::kNoGameDataFoundError;
}
else
return Common::kNoError;
}

View file

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

View file

@ -221,7 +221,10 @@ void Engine::syncSoundSettings() {
}
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")) {
mute = !ConfMan.getBool("mute");

View file

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

View file

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

View file

@ -36,6 +36,10 @@
namespace Graphics {
class VectorRenderer;
typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const Graphics::DrawStep &);
struct DrawStep {
struct Color {
uint8 r, g, b;
@ -58,7 +62,10 @@ struct DrawStep {
kVectorAlignBottom,
kVectorAlignTop,
kVectorAlignCenter
} xAlign, yAlign;
};
VectorAlignment xAlign;
VectorAlignment yAlign;
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 */
void (VectorRenderer::*drawingCall)(const Common::Rect &, const DrawStep &); /** Pointer to drawing function */
DrawingFunctionCallback drawingCall; /**< Pointer to drawing function */
Graphics::Surface *blitSrc;
};

View file

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

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>
uint32 RGBToColor(uint8 r, uint8 g, uint8 b) {
return T::kAlphaMask |

View file

@ -57,14 +57,14 @@ bool CursorManager::showMouse(bool visible) {
return g_system->showMouse(visible);
}
void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetScale) {
Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, 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, format);
cur->_visible = isVisible();
_cursorStack.push(cur);
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()) {
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());
@ -93,15 +93,24 @@ void CursorManager::popAllCursors() {
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()) {
pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale);
pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format);
return;
}
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;
#endif
if (cur->_size < size) {
delete[] cur->_data;
@ -118,8 +127,14 @@ void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX,
cur->_hotspotY = hotspotY;
cur->_keycolor = keycolor;
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() {

View file

@ -28,6 +28,10 @@
#include "common/sys.h"
#include "common/stack.h"
#include "common/singleton.h"
#include "graphics/pixelformat.h"
#ifdef USE_RGB_COLOR
#include "common/system.h"
#endif
namespace Graphics {
@ -36,7 +40,21 @@ public:
/** Query whether the mouse cursor is visible. */
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);
/**
@ -51,12 +69,13 @@ public:
* @param hotspotY the hotspot Y coordinate
* @param keycolor the index for the transparent color
* @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
* useful to push a "dummy" cursor and modify it later. The
* 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
@ -76,8 +95,10 @@ public:
* @param hotspotY the hotspot Y coordinate
* @param keycolor the index for the transparent color
* @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.
@ -152,13 +173,24 @@ private:
uint _height;
int _hotspotX;
int _hotspotY;
byte _keycolor;
uint32 _keycolor;
Graphics::PixelFormat _format;
byte _targetScale;
uint _size;
Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int targetScale = 1) {
Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 0xFFFFFFFF, int targetScale = 1, const Graphics::PixelFormat *format = NULL) {
#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;
_keycolor = keycolor & 0xFF;
#endif
_data = new byte[_size];
if (data && _data)
memcpy(_data, data, _size);
@ -166,7 +198,6 @@ private:
_height = h;
_hotspotX = hotspotX;
_hotspotY = hotspotY;
_keycolor = keycolor;
_targetScale = targetScale;
}
@ -202,7 +233,6 @@ private:
delete[] _data;
}
};
Common::Stack<Cursor *> _cursorStack;
Common::Stack<Palette *> _cursorPaletteStack;
};

View file

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

View file

@ -27,6 +27,7 @@
#define GRAPHICS_PIXELFORMAT_H
#include "common/sys.h"
#include "common/list.h"
namespace Graphics {
@ -50,6 +51,24 @@ struct PixelFormat {
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. */
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 {
// TODO: If aLoss==8, then the value of aShift is irrelevant, and should be ignored.
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
#endif

View file

@ -84,7 +84,7 @@ void EditTextWidget::drawWidget() {
// Draw the text
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 {

View file

@ -72,7 +72,6 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled),
error("Failed to load any GUI theme, aborting");
}
}
_themeChange = false;
}
GuiManager::~GuiManager() {
@ -143,12 +142,20 @@ bool GuiManager::loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx)
// Enable the new theme
//
_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
for (int i = 0; i < _dialogStack.size(); ++i) {
for (int i = 0; i < _dialogStack.size(); ++i)
_dialogStack[i]->reflowLayout();
}
// We need to redraw immediately. Otherwise
// some other event may cause a widget to be
@ -157,10 +164,6 @@ bool GuiManager::loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx)
redraw();
_system->updateScreen();
Common::Event event;
event.type = Common::EVENT_SCREEN_CHANGED;
_system->getEventManager()->pushEvent(event);
return true;
}
@ -233,7 +236,6 @@ void GuiManager::runLoop() {
// _theme->refresh();
_themeChange = false;
_redrawStatus = kRedrawFull;
redraw();
}
@ -285,21 +287,6 @@ void GuiManager::runLoop() {
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()) {
_theme->updateScreen();
_system->updateScreen();

View file

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

View file

@ -24,6 +24,8 @@
#include "common/system.h"
#include "common/events.h"
#include "common/frac.h"
#include "gui/ListWidget.h"
#include "gui/ScrollBarWidget.h"
#include "gui/dialog.h"
@ -62,6 +64,7 @@ ListWidget::ListWidget(GuiObject *boss, const String &name, uint32 cmd)
_editable = true;
_quickSelect = true;
_editColor = ThemeEngine::kFontColorNormal;
}
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) {
// 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());
// 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)
drawCaret(true);
@ -131,6 +160,13 @@ void ListWidget::setList(const StringList &list) {
_dataList = list;
_list = list;
_filter.clear();
_listIndex.clear();
_listColors.clear();
if (colors) {
_listColors = *colors;
assert(_listColors.size() == _dataList.size());
}
int size = list.size();
if (_currentPos >= size)
@ -143,7 +179,19 @@ void ListWidget::setList(const StringList &list) {
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);
_list.push_back(s);
@ -356,8 +404,13 @@ bool ListWidget::handleKeyUp(Common::KeyState state) {
return true;
}
void ListWidget::receivedFocusWidget() {
// Redraw the widget so the selection color will change
draw();
}
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;
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
drawCaret(true);
@ -387,15 +440,14 @@ void ListWidget::drawWidget() {
for (i = 0, pos = _currentPos; i < _entriesPerPage && pos < len; i++, pos++) {
const int y = _y + _topPadding + kLineHeight * i;
const int fontHeight = kLineHeight;
bool inverted = false;
ThemeEngine::TextInversionState inverted = ThemeEngine::kTextInversionNone;
// Draw the selected item inverted, on a highlighted background.
if (_selectedItem == pos) {
if (_hasFocus)
inverted = true;
inverted = ThemeEngine::kTextInversionFocus;
else
g_gui.theme()->drawWidgetBackground(Common::Rect(_x, y - 1, _x + _w - 1, y + fontHeight - 1),
0, ThemeEngine::kWidgetBackgroundBorderSmall);
inverted = ThemeEngine::kTextInversion;
}
Common::Rect r(getEditRect());
@ -413,17 +465,27 @@ void ListWidget::drawWidget() {
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) {
buffer = _editString;
color = _editColor;
adjustOffset();
width = _w - r.left - _hlRightPadding - _leftPadding - scrollbarW;
g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2),
buffer, _state, Graphics::kTextAlignLeft, inverted, pad, true);
g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state,
Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
} else {
buffer = _list[pos];
width = _w - r.left - scrollbarW;
g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2),
buffer, _state, Graphics::kTextAlignLeft, inverted, pad, true);
g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state,
Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
}
_textWidth[i] = width;
@ -481,6 +543,14 @@ void ListWidget::startEditMode() {
if (_editable && !_editMode && _selectedItem >= 0) {
_editMode = true;
setEditString(_list[_selectedItem]);
if (_listColors.empty()) {
_editColor = ThemeEngine::kFontColorNormal;
} else {
if (_filter.empty())
_editColor = _listColors[_selectedItem];
else
_editColor = _listColors[_listIndex[_selectedItem]];
}
draw();
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
}
@ -522,13 +592,15 @@ void ListWidget::reflowLayout() {
// of the list.
// 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.
_entriesPerPage = ((_h - _topPadding - _bottomPadding) << 16) / kLineHeight;
frac_t entriesPerPage = intToFrac(_h - _topPadding - _bottomPadding) / kLineHeight;
if ((uint)(_entriesPerPage & 0xFFFF) >= 0xF000)
_entriesPerPage += (1 << 16);
// Our threshold before we add another entry is 0.9375 (0xF000 with FRAC_BITS being 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);
delete[] _textWidth;
@ -560,9 +632,12 @@ void ListWidget::setFilter(const String &filter, bool redraw) {
if (_filter.empty()) {
// No filter -> display everything
_list = _dataList;
_listIndex.clear();
} else {
// Restrict the list to everything which contains _filter as a substring,
// ignoring case.
// Restrict the list to everything which contains all words in _filter
// as substrings, ignoring case.
Common::StringTokenizer tok(_filter);
String tmp;
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) {
tmp = *i;
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);
_listIndex.push_back(n);
}

View file

@ -28,6 +28,8 @@
#include "gui/editable.h"
#include "common/str.h"
#include "gui/ThemeEngine.h"
namespace GUI {
class ScrollBarWidget;
@ -51,9 +53,11 @@ class ListWidget : public EditableWidget {
public:
typedef Common::String String;
typedef Common::StringList StringList;
typedef Common::Array<ThemeEngine::FontColor> ColorList;
protected:
StringList _list;
StringList _dataList;
ColorList _listColors;
Common::Array<int> _listIndex;
bool _editable;
bool _editMode;
@ -80,6 +84,8 @@ protected:
uint32 _cmd;
ThemeEngine::FontColor _editColor;
public:
ListWidget(GuiObject *boss, const String &name, 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);
void setList(const StringList &list);
void append(const String &s);
void setList(const StringList &list, const ColorList *colors = 0);
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);
int getSelected() const { return (_filter.empty() || _selectedItem == -1) ? _selectedItem : _listIndex[_selectedItem]; }
const String &getSelectedString() const { return _list[_selectedItem]; }
ThemeEngine::FontColor getSelectionColor() const;
void setNumberingMode(NumberingMode numberingMode) { _numberingMode = numberingMode; }
bool isEditable() const { return _editable; }
void setEditable(bool editable) { _editable = editable; }
void scrollTo(int item);
void scrollToEnd();
void enableQuickSelect(bool enable) { _quickSelect = enable; }
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);
virtual void handleTickle();
@ -115,10 +134,6 @@ public:
virtual bool wantsFocus() { return true; }
// Made startEditMode for SCUMM's SaveLoadChooser
void startEditMode();
void endEditMode();
protected:
void drawWidget();
@ -130,6 +145,7 @@ protected:
Common::Rect getEditRect() const;
void receivedFocusWidget();
void lostFocusWidget();
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));
} else {
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++;
_draggingPart = kDownArrowPart;
} else if (y < _sliderPos) {
_currentPos -= _entriesPerPage;
_currentPos -= _entriesPerPage - 1;
} else if (y >= _sliderPos + _sliderHeight) {
_currentPos += _entriesPerPage;
_currentPos += _entriesPerPage - 1;
} else {
_draggingPart = kSliderPart;
_sliderDeltaMouseDownPos = y - _sliderPos;

View file

@ -91,7 +91,37 @@ int TabWidget::addTab(const String &title) {
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) {
#endif
if (_tabWidth == 0)
_tabWidth = 40;
// Determine the new tab width
@ -217,6 +247,10 @@ void TabWidget::reflowLayout() {
if (_tabWidth == 0) {
_tabWidth = 40;
#ifdef __DS__
}
if (true) {
#endif
int maxWidth = _w / _tabs.size();
for (uint i = 0; i < _tabs.size(); ++i) {

View file

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

View file

@ -56,10 +56,10 @@ const char * const ThemeEngine::kImageSearch = "search.bmp";
struct TextDrawData {
const Graphics::Font *_fontPtr;
};
struct {
uint8 r, g, b;
} _color;
struct TextColorData {
int r, g, b;
};
struct WidgetDrawData {
@ -67,6 +67,7 @@ struct WidgetDrawData {
Common::List<Graphics::DrawStep> _steps;
TextData _textDataId;
TextColor _textColorId;
Graphics::TextAlign _textAlignH;
GUI::ThemeEngine::TextAlignVertical _textAlignV;
@ -116,16 +117,17 @@ protected:
class ThemeItemTextData : public ThemeItem {
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,
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) {}
void drawSelf(bool draw, bool restore);
protected:
const TextDrawData *_data;
const TextColorData *_color;
Common::String _text;
Graphics::TextAlign _alignH;
GUI::ThemeEngine::TextAlignVertical _alignV;
@ -167,6 +169,7 @@ static const DrawDataInfo kDrawDataDefaults[] = {
{kDDPlainColorBackground, "plain_bg", true, kDDNone},
{kDDDefaultBackground, "default_bg", true, kDDNone},
{kDDTextSelectionBackground, "text_selection", false, kDDNone},
{kDDTextSelectionFocusBackground, "text_selection_focus", false, kDDNone},
{kDDWidgetBackgroundDefault, "widget_default", true, kDDNone},
{kDDWidgetBackgroundSmall, "widget_small", true, kDDNone},
@ -179,7 +182,7 @@ static const DrawDataInfo kDrawDataDefaults[] = {
{kDDSliderFull, "slider_full", false, kDDNone},
{kDDSliderHover, "slider_hover", false, kDDNone},
{kDDSliderDisabled, "slider_disabled", true, kDDNone},
{kDDSliderDisabled, "slider_disabled", false, kDDNone},
{kDDCheckboxDefault, "checkbox_default", true, kDDNone},
{kDDCheckboxDisabled, "checkbox_disabled", true, kDDNone},
@ -231,7 +234,7 @@ void ThemeItemTextData::drawSelf(bool draw, bool restore) {
_engine->restoreBackground(_area);
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);
}
@ -276,6 +279,10 @@ ThemeEngine::ThemeEngine(Common::String id, GraphicsMode mode) :
_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:
// 1) Via 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);
}
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);
if (id == -1 || textId == -1 || !_widgets[id])
if (id == -1 || textId == -1 || colorId == kTextColorMAX || !_widgets[id])
return false;
_widgets[id]->_textDataId = textId;
_widgets[id]->_textColorId = colorId;
_widgets[id]->_textAlignH = alignH;
_widgets[id]->_textAlignV = alignV;
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)
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;
}
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) {
// Nothing has to be done if the bitmap already has been loaded.
Graphics::Surface *surf = _bitmaps[filename];
@ -655,6 +676,11 @@ void ThemeEngine::unloadTheme() {
_texts[i] = 0;
}
for (int i = 0; i < kTextColorMAX; ++i) {
delete _textColors[i];
_textColors[i] = 0;
}
_themeEval->reset();
_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) {
if (_texts[type] == 0)
@ -779,7 +805,7 @@ void ThemeEngine::queueDDText(TextData type, const Common::Rect &r, const Common
Common::Rect area = r;
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) {
_screenQueue.push_back(q);
@ -823,7 +849,7 @@ void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, W
dd = kDDButtonDisabled;
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) {
@ -846,7 +872,6 @@ void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str,
if (state == kStateDisabled)
dd = kDDCheckboxDisabled;
TextData td = (state == kStateHighlight) ? kTextDataHover : getTextData(dd);
const int checkBoxSize = MIN((int)r.height(), getFontHeight());
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.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) {
@ -957,7 +982,7 @@ void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &s
if (!sel.empty()) {
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())
return;
const int tabOffset = 2;
tabWidth -= tabOffset;
queueDD(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight));
for (int i = 0; i < (int)tabs.size(); ++i) {
if (i == active)
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);
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) {
Common::Rect tabRect(r.left + active * (tabWidth + tabOffset), r.top, r.left + active * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight);
const uint16 tabLeft = active * (tabWidth + tabOffset);
Common::Rect tabRect(r.left + active * tabWidth, r.top, r.left + (active + 1) * tabWidth, r.top + tabHeight);
const uint16 tabLeft = active * tabWidth;
const uint16 tabRight = MAX(r.right - tabRect.right, 0);
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())
return;
TextColor colorId = kTextColorMAX;
switch (color) {
case kFontColorNormal:
if (inverted) {
queueDD(kDDTextSelectionBackground, r);
queueDDText(kTextDataInverted, r, str, false, useEllipsis, align, kTextAlignVCenter, deltax);
colorId = kTextColorNormalInverted;
} 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;
}
switch (font) {
case kFontStyleNormal:
queueDDText(kTextDataNormalFont, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
return;
TextData textId = kTextDataNone;
if (font == kFontStyleNormal)
textId = kTextDataNormalFont;
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:
break;
}
switch (state) {
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;
}
queueDDText(textId, colorId, r, str, restore, useEllipsis, align, kTextAlignVCenter, deltax);
}
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())
return;
Common::Rect charArea = r;
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);
font->drawChar(&_screen, ch, charArea.left, charArea.top, color);
font->drawChar(&_screen, ch, charArea.left, charArea.top, rgbColor);
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) {
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;
}
@ -1189,6 +1326,9 @@ TextData ThemeEngine::getTextData(DrawData ddId) const {
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 {
for (int i = 0; i < kDrawDataMAX; ++i)
@ -1287,7 +1427,7 @@ bool ThemeEngine::themeConfigParseHeader(Common::String header, Common::String &
Common::StringTokenizer tok(header, ":");
if (tok.nextToken() != SCUMMVM_THEME_VERSION_STR)
if (tok.nextToken() != RESIDUAL_THEME_VERSION_STR)
return false;
themeName = tok.nextToken();
@ -1383,7 +1523,7 @@ void ThemeEngine::listUsableThemes(Common::List<ThemeDescriptor> &list) {
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())
return;

View file

@ -32,7 +32,7 @@
#include "graphics/surface.h"
#include "graphics/fontman.h"
#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.5"
#define RESIDUAL_THEME_VERSION_STR "RESIDUAL_STX0.8"
namespace Graphics {
struct DrawStep;
@ -45,6 +45,7 @@ struct WidgetDrawData;
struct DrawDataInfo;
struct TextDataInfo;
struct TextDrawData;
struct TextColorData;
class Dialog;
class GuiObject;
class ThemeEval;
@ -62,6 +63,7 @@ enum DrawData {
kDDPlainColorBackground,
kDDDefaultBackground,
kDDTextSelectionBackground,
kDDTextSelectionFocusBackground,
kDDWidgetBackgroundDefault,
kDDWidgetBackgroundSmall,
@ -104,15 +106,26 @@ enum DrawData {
enum TextData {
kTextDataNone = -1,
kTextDataDefault = 0,
kTextDataHover,
kTextDataDisabled,
kTextDataInverted,
kTextDataButton,
kTextDataButtonHover,
kTextDataNormalFont,
kTextDataMAX
};
enum TextColor {
kTextColorNormal = 0,
kTextColorNormalInverted,
kTextColorNormalHover,
kTextColorNormalDisabled,
kTextColorAlternative,
kTextColorAlternativeInverted,
kTextColorAlternativeHover,
kTextColorAlternativeDisabled,
kTextColorButton,
kTextColorButtonHover,
kTextColorButtonDisabled,
kTextColorMAX
};
class ThemeEngine {
protected:
typedef Common::HashMap<Common::String, Graphics::Surface*> ImagesMap;
@ -156,6 +169,13 @@ public:
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 {
kScrollbarStateNo,
kScrollbarStateUp,
@ -175,6 +195,13 @@ public:
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
enum ShadingStyle {
kShadingNone, //!< No special post processing
@ -302,9 +329,9 @@ public:
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;
TextData getTextData(DrawData ddId) const;
TextColor getTextColor(DrawData ddId) const;
/**
@ -363,9 +391,16 @@ public:
*
* @param fontName Identifier name for the font.
* @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.
*/
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
* 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:
/**
@ -503,7 +538,7 @@ protected:
* 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 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);
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 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:
OSystem *_system; /** Global system object. */
@ -572,8 +607,14 @@ protected:
/** Array of all the text fonts that can be drawn. */
TextDrawData *_texts[kTextDataMAX];
/** Array of all font colors available. */
TextColorData *_textColors[kTextColorMAX];
ImagesMap _bitmaps;
Graphics::PixelFormat _overlayFormat;
#ifdef USE_RGB_COLOR
Graphics::PixelFormat _cursorFormat;
#endif
/** List of all the dirty screens that must be blitted to the overlay. */
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/ThemeEval.h"
#include "gui/ThemeParser.h"
#include "gui/GuiManager.h"
#include "graphics/VectorRenderer.h"
namespace GUI {
@ -45,11 +39,7 @@ struct TextDataInfo {
static const TextDataInfo kTextDataDefaults[] = {
{ kTextDataDefault, "text_default" },
{kTextDataHover, "text_hover"},
{kTextDataDisabled, "text_disabled"},
{kTextDataInverted, "text_inverted"},
{ kTextDataButton, "text_button" },
{kTextDataButtonHover, "text_button_hover"},
{ kTextDataNormalFont, "text_normal" }
};
@ -62,6 +52,33 @@ static TextData parseTextDataId(const Common::String &name) {
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) {
if (val == "left")
return Graphics::kTextAlignLeft;
@ -86,19 +103,6 @@ static GUI::ThemeEngine::TextAlignVertical parseTextVAlign(const Common::String
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();
_defaultStepLocal = 0;
_theme = parent;
@ -107,8 +111,6 @@ ThemeParser::ThemeParser(ThemeEngine *parent) : XMLParser() {
ThemeParser::~ThemeParser() {
delete _defaultStepGlobal;
delete _defaultStepLocal;
_palette.clear();
_drawFunctions.clear();
}
void ThemeParser::cleanup() {
@ -169,21 +171,32 @@ bool ThemeParser::parserCallback_defaults(ParserNode *node) {
}
bool ThemeParser::parserCallback_font(ParserNode *node) {
int red, green, blue;
if (resolutionCheck(node->values["resolution"]) == false) {
node->ignore = 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"]))
getPaletteColor(node->values["color"], 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->addFont(textDataId, node->values["file"], red, green, blue))
return parserError("Error loading Font in theme engine.");
if (!_theme->addTextColor(colorId, red, green, blue))
return parserError("Error while adding text color information.");
return true;
}
@ -236,8 +249,9 @@ bool ThemeParser::parserCallback_text(ParserNode *node) {
Common::String id = getParentNode(node)->values["id"];
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 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) {
Graphics::DrawStep *drawstep = newDrawStep();
Common::String functionName = node->values["func"];
if (_drawFunctions.contains(functionName) == false)
return parserError("%s is not a valid drawing function name", functionName.c_str());
drawstep->drawingCall = getDrawingFunctionCallback(functionName);
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))
return false;

View file

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

View file

@ -247,7 +247,7 @@ void AboutDialog::drawDialog() {
str++;
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;
}
}

View file

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

View file

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

View file

@ -143,7 +143,7 @@ public:
void handleKeyDown(Common::KeyState state);
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);
#undef putchar
void putchar(int c);

View file

@ -27,10 +27,14 @@
#include "common/system.h"
#include "gui/debugger.h"
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
#include "gui/console.h"
#elif defined(USE_READLINE)
#include <readline/readline.h>
#include <readline/history.h>
#endif
namespace GUI {
Debugger::Debugger() {
@ -39,9 +43,11 @@ Debugger::Debugger() {
_isAttached = false;
_errStr = NULL;
_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->setCompletionCallback(debuggerCompletionCallback, this);
#endif
//DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
DCmd_Register("exit", WRAP_METHOD(Debugger, Cmd_Exit));
@ -55,7 +61,9 @@ Debugger::Debugger() {
}
Debugger::~Debugger() {
#ifndef USE_TEXT_CONSOLE
delete _debuggerDialog;
#endif
}
@ -65,7 +73,7 @@ int Debugger::DebugPrintf(const char *format, ...) {
va_start(argptr, format);
int count;
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
count = _debuggerDialog->vprintf(format, argptr);
#else
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
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) {
DebugPrintf("Debugger started, type 'exit' to return to the game.\n");
DebugPrintf("Type 'help' to see a little list of commands and variables.\n");
@ -129,18 +150,28 @@ void Debugger::enter() {
_debuggerDialog->runModal();
#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");
#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;
char buf[256];
@ -156,6 +187,7 @@ void Debugger::enter() {
if (i == 0)
continue;
} while (parseCommand(buf));
#endif
#endif
}
@ -211,7 +243,7 @@ bool Debugger::parseCommand(const char *inputOrig) {
break;
// Integer Array
case DVAR_INTARRAY: {
char *chr = (char *)strchr(param[0], '[');
const char *chr = strchr(param[0], '[');
if (!chr) {
DebugPrintf("You must access this array as %s[element]\n", param[0]);
} else {
@ -307,7 +339,8 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const
} else {
// take common prefix of previous match and this command
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);
// If there is no unambiguous completion, abort
if (completion.empty())
@ -325,6 +358,29 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const
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
void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) {
// 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),
// nicely word-wrapped.
bool Debugger::Cmd_Help(int argc, const char **argv) {
#ifndef USE_TEXT_CONSOLE
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;
uint i;
@ -452,7 +515,7 @@ bool Debugger::Cmd_DebugFlagDisable(int argc, const char **argv) {
}
// Console handler
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) {
Debugger *debugger = (Debugger *)refCon;

View file

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

View file

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

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