ALL: synced with scummvm

This commit is contained in:
Pawel Kolodziejski 2013-12-08 13:25:24 +01:00
parent 0511571850
commit b22d441a00
61 changed files with 1401 additions and 357 deletions

7
.gitignore vendored
View file

@ -69,6 +69,9 @@ project.xcworkspace
/plugins /plugins
/engines/plugins_table.h
/engines/engines.mk
/test/runner /test/runner
/test/runner.cpp /test/runner.cpp
/test/*.dSYM /test/*.dSYM
@ -126,6 +129,10 @@ ResidualVM.includes
#Ignore Mac DS_Store files #Ignore Mac DS_Store files
.DS_Store .DS_Store
#Ignore MS Visual C++ temporary files/subdirectories (except create_project.bat)
dists/msvc*/**
!dists/msvc*/create_project.bat
# Emacs files # Emacs files
*~ *~
.#* .#*

View file

@ -82,7 +82,8 @@ EXECUTABLE := $(EXEPRE)residualvm$(EXEEXT)
include $(srcdir)/Makefile.common include $(srcdir)/Makefile.common
# check if configure has been run or has been changed since last run # check if configure has been run or has been changed since last run
config.h config.mk: $(srcdir)/configure $(srcdir)/engines/configure.engines ENGINE_SUBDIRS_CONFIGURE := $(wildcard $(srcdir)/engines/*/configure.engine)
config.h: $(srcdir)/configure $(ENGINE_SUBDIRS_CONFIGURE)
ifeq "$(findstring config.mk,$(MAKEFILE_LIST))" "config.mk" ifeq "$(findstring config.mk,$(MAKEFILE_LIST))" "config.mk"
@echo "Running $(srcdir)/configure with the last specified parameters" @echo "Running $(srcdir)/configure with the last specified parameters"
@sleep 2 @sleep 2
@ -94,6 +95,14 @@ else
$(error You need to run $(srcdir)/configure before you can run make. Check $(srcdir)/configure --help for a list of parameters) $(error You need to run $(srcdir)/configure before you can run make. Check $(srcdir)/configure --help for a list of parameters)
endif endif
config.mk engines/plugins_table.h engines/engines.mk: config.h
@if test -f $@; then \
touch $@; \
else \
rm -f config.h; \
$(MAKE) config.h; \
fi
ifneq ($(origin port_mk), undefined) ifneq ($(origin port_mk), undefined)
include $(srcdir)/$(port_mk) include $(srcdir)/$(port_mk)
endif endif

View file

@ -17,7 +17,7 @@ all: $(EXECUTABLE) plugins
PLUGINS := PLUGINS :=
MODULES := test devtools base $(MODULES) MODULES := test devtools base $(MODULES)
-include $(srcdir)/engines/engines.mk -include engines/engines.mk
# After the game specific modules follow the shared modules # After the game specific modules follow the shared modules
MODULES += \ MODULES += \
@ -81,7 +81,7 @@ $(EXECUTABLE): $(OBJS)
$(QUIET_LINK)$(LD) $(LDFLAGS) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) -o $@ $(QUIET_LINK)$(LD) $(LDFLAGS) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) -o $@
distclean: clean clean-devtools distclean: clean clean-devtools
$(RM) config.h config.mk config.log $(RM) config.h config.mk config.log engines/engines.mk engines/plugins_table.h
clean: clean:
$(RM_REC) $(DEPDIRS) $(RM_REC) $(DEPDIRS)
@ -149,7 +149,7 @@ endif
# recreate them (which it can't), and in particular from looking for potential # recreate them (which it can't), and in particular from looking for potential
# source files. This can save quite a bit of disk access time. # source files. This can save quite a bit of disk access time.
.PHONY: $(wildcard $(addsuffix /*.d,$(DEPDIRS))) $(addprefix $(srcdir)/, $(addsuffix /module.mk,$(MODULES))) \ .PHONY: $(wildcard $(addsuffix /*.d,$(DEPDIRS))) $(addprefix $(srcdir)/, $(addsuffix /module.mk,$(MODULES))) \
$(srcdir)/$(port_mk) $(srcdir)/rules.mk $(srcdir)/engines/engines.mk $(srcdir)/$(port_mk) $(srcdir)/rules.mk
###################################################################### ######################################################################
# Get the current version information # Get the current version information

View file

@ -460,9 +460,6 @@ bool MT32EmuMusicPlugin::checkDevice(MidiDriver::DeviceHandle) const {
} }
Common::Error MT32EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { Common::Error MT32EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
if (ConfMan.hasKey("extrapath"))
SearchMan.addDirectory("extrapath", ConfMan.get("extrapath"));
*mididriver = new MidiDriver_MT32(g_system->getMixer()); *mididriver = new MidiDriver_MT32(g_system->getMixer());
return Common::kNoError; return Common::kNoError;

View file

@ -405,8 +405,17 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
return false; return false;
case SDL_VIDEORESIZE: case SDL_VIDEORESIZE:
if (_graphicsManager) if (_graphicsManager) {
_graphicsManager->notifyResize(ev.resize.w, ev.resize.h); _graphicsManager->notifyResize(ev.resize.w, ev.resize.h);
// If the screen changed, send an Common::EVENT_SCREEN_CHANGED
int screenID = ((OSystem_SDL *)g_system)->getGraphicsManager()->getScreenChangeID();
if (screenID != _lastScreenID) {
_lastScreenID = screenID;
event.type = Common::EVENT_SCREEN_CHANGED;
return true;
}
}
return false; return false;
case SDL_QUIT: case SDL_QUIT:

View file

@ -335,7 +335,7 @@ bool AmigaOSFilesystemNode::isReadable() const {
// Regular RWED protection flags are low-active or inverted, thus the negation. // Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is readable whatever the // moreover pseudo root filesystem (null _pFileLock) is readable whatever the
// protection says // protection says
bool readable = !(_nProt & EXDF_READ) || _pFileLock == 0; bool readable = !(_nProt & EXDF_OTR_READ) || _pFileLock == 0;
return readable; return readable;
} }
@ -344,7 +344,7 @@ bool AmigaOSFilesystemNode::isWritable() const {
// Regular RWED protection flags are low-active or inverted, thus the negation. // Regular RWED protection flags are low-active or inverted, thus the negation.
// moreover pseudo root filesystem (null _pFileLock) is never writable whatever // moreover pseudo root filesystem (null _pFileLock) is never writable whatever
// the protection says (because of the pseudo nature) // the protection says (because of the pseudo nature)
bool writable = !(_nProt & EXDF_WRITE) && _pFileLock !=0; bool writable = !(_nProt & EXDF_OTR_WRITE) && _pFileLock !=0;
return writable; return writable;
} }
@ -367,8 +367,14 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES); dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES);
while (dosList) { while (dosList) {
if (dosList->dol_Type == DLT_VOLUME && if (dosList->dol_Type == DLT_VOLUME &&
dosList->dol_Name && dosList->dol_Name) {
dosList->dol_Task) {
// Original was
// dosList->dol_Name &&
// dosList->dol_Task) {
// which errored using SDK 53.24 with a 'struct dosList' has no member called 'dol_Task'
// I removed dol_Task because it's not used anywhere else
// and it neither brought up further errors nor crashes or regressions.
// Copy name to buffer // Copy name to buffer
IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN); IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN);

View file

@ -37,6 +37,27 @@ class GraphicsManager : public PaletteManager {
public: public:
virtual ~GraphicsManager() {} virtual ~GraphicsManager() {}
/**
* Makes this graphics manager active. That means it should be ready to
* process inputs now. However, even without being active it should be
* able to query the supported modes and other bits.
*
* HACK: Actually this is specific to SdlGraphicsManager subclasses.
* But sadly we cannot cast from GraphicsManager to SdlGraphicsManager
* because there is no relation between these two.
*/
virtual void activateManager() {}
/**
* Makes this graphics manager inactive. This should allow another
* graphics manager to become active again.
*
* HACK: Actually this is specific to SdlGraphicsManager subclasses.
* But sadly we cannot cast from GraphicsManager to SdlGraphicsManager
* because there is no relation between these two.
*/
virtual void deactivateManager() {}
virtual bool hasFeature(OSystem::Feature f) = 0; virtual bool hasFeature(OSystem::Feature f) = 0;
virtual void setFeatureState(OSystem::Feature f, bool enable) = 0; virtual void setFeatureState(OSystem::Feature f, bool enable) = 0;
virtual bool getFeatureState(OSystem::Feature f) = 0; virtual bool getFeatureState(OSystem::Feature f) = 0;

View file

@ -26,10 +26,15 @@
SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source) SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source)
: _eventSource(source) { : _eventSource(source) {
_eventSource->setGraphicsManager(this);
} }
SdlGraphicsManager::~SdlGraphicsManager() { SdlGraphicsManager::~SdlGraphicsManager() {
_eventSource->setGraphicsManager(0);
} }
void SdlGraphicsManager::initEventSource() {
_eventSource->setGraphicsManager(this);
}
void SdlGraphicsManager::deinitEventSource() {
_eventSource->setGraphicsManager(0);
}

View file

@ -80,6 +80,9 @@ public:
virtual void notifyMousePos(Common::Point mouse) = 0; virtual void notifyMousePos(Common::Point mouse) = 0;
protected: protected:
void initEventSource();
void deinitEventSource();
SdlEventSource *_eventSource; SdlEventSource *_eventSource;
}; };

View file

@ -59,31 +59,30 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou
, _overlayNumTex(0), _overlayTexIds(0) , _overlayNumTex(0), _overlayTexIds(0)
#endif #endif
{ {
if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
error("Could not initialize SDL: %s", SDL_GetError());
}
// This is also called in initSDL(), but initializing graphics
// may reset it.
SDL_EnableUNICODE(1);
SDL_ShowCursor(SDL_DISABLE);
} }
SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() { SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() {
// Unregister the event observer
if (g_system->getEventManager()->getEventDispatcher() != NULL)
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
closeOverlay(); closeOverlay();
} }
void SurfaceSdlGraphicsManager::initEventObserver() { void SurfaceSdlGraphicsManager::activateManager() {
GraphicsManager::activateManager();
initEventSource();
// Register the graphics manager as a event observer // Register the graphics manager as a event observer
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
} }
void SurfaceSdlGraphicsManager::deactivateManager() {
// Unregister the event observer
if (g_system->getEventManager()->getEventDispatcher()) {
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
}
deinitEventSource();
GraphicsManager::deactivateManager();
}
void SurfaceSdlGraphicsManager::resetGraphicsScale() { void SurfaceSdlGraphicsManager::resetGraphicsScale() {
setGraphicsMode(0); setGraphicsMode(0);
} }
@ -117,10 +116,6 @@ bool SurfaceSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
} }
} }
const OSystem::GraphicsMode *SurfaceSdlGraphicsManager::supportedGraphicsModes() {
return s_supportedGraphicsModes;
}
const OSystem::GraphicsMode *SurfaceSdlGraphicsManager::getSupportedGraphicsModes() const { const OSystem::GraphicsMode *SurfaceSdlGraphicsManager::getSupportedGraphicsModes() const {
return s_supportedGraphicsModes; return s_supportedGraphicsModes;
} }

View file

@ -52,13 +52,13 @@ public:
SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource); SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource);
virtual ~SurfaceSdlGraphicsManager(); virtual ~SurfaceSdlGraphicsManager();
virtual void initEventObserver(); virtual void activateManager();
virtual void deactivateManager();
virtual bool hasFeature(OSystem::Feature f); virtual bool hasFeature(OSystem::Feature f);
virtual void setFeatureState(OSystem::Feature f, bool enable); virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f); virtual bool getFeatureState(OSystem::Feature f);
static const OSystem::GraphicsMode *supportedGraphicsModes();
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const; virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const; virtual int getDefaultGraphicsMode() const;
virtual bool setGraphicsMode(int mode); virtual bool setGraphicsMode(int mode);

View file

@ -80,15 +80,16 @@ bool OSystem_POSIX::hasFeature(Feature f) {
} }
Common::String OSystem_POSIX::getDefaultConfigFileName() { Common::String OSystem_POSIX::getDefaultConfigFileName() {
char configFile[MAXPATHLEN]; Common::String configFile;
// On POSIX type systems, by default we store the config file inside // On POSIX type systems, by default we store the config file inside
// to the HOME directory of the user. // to the HOME directory of the user.
const char *home = getenv("HOME"); const char *home = getenv("HOME");
if (home != NULL && strlen(home) < MAXPATHLEN) if (home != NULL && (strlen(home) + 1 + _baseConfigName.size()) < MAXPATHLEN) {
snprintf(configFile, MAXPATHLEN, "%s/%s", home, _baseConfigName.c_str()); configFile = Common::String::format("%s/%s", home, _baseConfigName.c_str());
else } else {
strcpy(configFile, _baseConfigName.c_str()); configFile = _baseConfigName;
}
return configFile; return configFile;
} }

View file

@ -77,6 +77,9 @@ OSystem_SDL::~OSystem_SDL() {
// Hence, we perform the destruction on our own. // Hence, we perform the destruction on our own.
delete _savefileManager; delete _savefileManager;
_savefileManager = 0; _savefileManager = 0;
if (_graphicsManager) {
_graphicsManager->deactivateManager();
}
delete _graphicsManager; delete _graphicsManager;
_graphicsManager = 0; _graphicsManager = 0;
delete _eventManager; delete _eventManager;
@ -110,6 +113,12 @@ void OSystem_SDL::init() {
// Initialize SDL // Initialize SDL
initSDL(); initSDL();
// Enable unicode support if possible
SDL_EnableUNICODE(1);
// Disable OS cursor
SDL_ShowCursor(SDL_DISABLE);
if (!_logger) if (!_logger)
_logger = new Backends::Log::Log(this); _logger = new Backends::Log::Log(this);
@ -129,6 +138,7 @@ void OSystem_SDL::init() {
if (_taskbarManager == 0) if (_taskbarManager == 0)
_taskbarManager = new Common::TaskbarManager(); _taskbarManager = new Common::TaskbarManager();
#endif #endif
} }
void OSystem_SDL::initBackend() { void OSystem_SDL::initBackend() {
@ -140,12 +150,9 @@ void OSystem_SDL::initBackend() {
if (_eventSource == 0) if (_eventSource == 0)
_eventSource = new SdlEventSource(); _eventSource = new SdlEventSource();
int graphicsManagerType = 0;
if (_graphicsManager == 0) { if (_graphicsManager == 0) {
if (_graphicsManager == 0) { if (_graphicsManager == 0) {
_graphicsManager = new SurfaceSdlGraphicsManager(_eventSource); _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource);
graphicsManagerType = 0;
} }
} }
@ -188,8 +195,7 @@ void OSystem_SDL::initBackend() {
// so the virtual keyboard can be initialized, but we have to add the // so the virtual keyboard can be initialized, but we have to add the
// graphics manager as an event observer after initializing the event // graphics manager as an event observer after initializing the event
// manager. // manager.
if (graphicsManagerType == 0) _graphicsManager->activateManager();
((SurfaceSdlGraphicsManager *)_graphicsManager)->initEventObserver();
} }
#if defined(USE_TASKBAR) #if defined(USE_TASKBAR)
@ -210,22 +216,19 @@ void OSystem_SDL::engineDone() {
void OSystem_SDL::initSDL() { void OSystem_SDL::initSDL() {
// Check if SDL has not been initialized // Check if SDL has not been initialized
if (!_initedSDL) { if (!_initedSDL) {
uint32 sdlFlags = 0; // We always initialize the video subsystem because we will need it to
// be initialized before the graphics managers to retrieve the desktop
// resolution, for example. WebOS also requires this initialization
// or otherwise the application won't start.
uint32 sdlFlags = SDL_INIT_VIDEO;
if (ConfMan.hasKey("disable_sdl_parachute")) if (ConfMan.hasKey("disable_sdl_parachute"))
sdlFlags |= SDL_INIT_NOPARACHUTE; sdlFlags |= SDL_INIT_NOPARACHUTE;
#ifdef WEBOS
// WebOS needs this flag or otherwise the application won't start
sdlFlags |= SDL_INIT_VIDEO;
#endif
// Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers) // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers)
if (SDL_Init(sdlFlags) == -1) if (SDL_Init(sdlFlags) == -1)
error("Could not initialize SDL: %s", SDL_GetError()); error("Could not initialize SDL: %s", SDL_GetError());
// Enable unicode support if possible
SDL_EnableUNICODE(1);
_initedSDL = true; _initedSDL = true;
} }
} }
@ -321,17 +324,6 @@ Common::String OSystem_SDL::getSystemLanguage() const {
const LCID languageIdentifier = GetThreadLocale(); const LCID languageIdentifier = GetThreadLocale();
// GetLocalInfo is only supported starting from Windows 2000, according to this:
// http://msdn.microsoft.com/en-us/library/dd318101%28VS.85%29.aspx
// On the other hand the locale constants used, seem to exist on Windows 98 too,
// check this for that: http://msdn.microsoft.com/en-us/library/dd464799%28v=VS.85%29.aspx
//
// I am not exactly sure what is the truth now, it might be very well that this breaks
// support for systems older than Windows 2000....
//
// TODO: Check whether this (or ScummVM at all ;-) works on a system with Windows 98 for
// example and if it does not and we still want Windows 9x support, we should definitly
// think of another solution.
if (GetLocaleInfo(languageIdentifier, LOCALE_SISO639LANGNAME, langName, sizeof(langName)) != 0 && if (GetLocaleInfo(languageIdentifier, LOCALE_SISO639LANGNAME, langName, sizeof(langName)) != 0 &&
GetLocaleInfo(languageIdentifier, LOCALE_SISO3166CTRYNAME, ctryName, sizeof(ctryName)) != 0) { GetLocaleInfo(languageIdentifier, LOCALE_SISO3166CTRYNAME, ctryName, sizeof(ctryName)) != 0) {
Common::String localeName = langName; Common::String localeName = langName;
@ -344,10 +336,15 @@ Common::String OSystem_SDL::getSystemLanguage() const {
} }
#else // WIN32 #else // WIN32
// Activating current locale settings // Activating current locale settings
const char *locale = setlocale(LC_ALL, ""); const Common::String locale = setlocale(LC_ALL, "");
// Restore default C locale to prevent issues with
// portability of sscanf(), atof(), etc.
// See bug #3615148
setlocale(LC_ALL, "C");
// Detect the language from the locale // Detect the language from the locale
if (!locale) { if (locale.empty()) {
return ModularBackend::getSystemLanguage(); return ModularBackend::getSystemLanguage();
} else { } else {
int length = 0; int length = 0;
@ -356,14 +353,14 @@ Common::String OSystem_SDL::getSystemLanguage() const {
// ".UTF-8" or the like. We do this, since // ".UTF-8" or the like. We do this, since
// our translation languages are usually // our translation languages are usually
// specified without any charset information. // specified without any charset information.
for (int i = 0; locale[i]; ++i, ++length) { for (int size = locale.size(); length < size; ++length) {
// TODO: Check whether "@" should really be checked // TODO: Check whether "@" should really be checked
// here. // here.
if (locale[i] == '.' || locale[i] == ' ' || locale[i] == '@') if (locale[length] == '.' || locale[length] == ' ' || locale[length] == '@')
break; break;
} }
return Common::String(locale, length); return Common::String(locale.c_str(), length);
} }
#endif // WIN32 #endif // WIN32
#else // USE_DETECTLANG #else // USE_DETECTLANG
@ -484,4 +481,3 @@ Common::TimerManager *OSystem_SDL::getTimerManager() {
return _timerManager; return _timerManager;
#endif #endif
} }

View file

@ -35,6 +35,8 @@
#include "backends/events/sdl/sdl-events.h" #include "backends/events/sdl/sdl-events.h"
#include "backends/log/log.h" #include "backends/log/log.h"
#include "common/array.h"
/** /**
* Base OSystem class for all SDL ports. * Base OSystem class for all SDL ports.
*/ */

View file

@ -31,7 +31,9 @@
// Custom nullptr replacement. This is not type safe as the real C++11 nullptr // Custom nullptr replacement. This is not type safe as the real C++11 nullptr
// though. // though.
// //
#if !defined(nullptr) // XCode 5.0.1 has __cplusplus=199711 but defines this
#define nullptr 0 #define nullptr 0
#endif
// //
// Replacement for the override keyword. This allows compilation of code // Replacement for the override keyword. This allows compilation of code

View file

@ -28,6 +28,7 @@ namespace Common {
const LanguageDescription g_languages[] = { const LanguageDescription g_languages[] = {
{ "zh-cn", "zh_CN", "Chinese (China)", ZH_CNA }, { "zh-cn", "zh_CN", "Chinese (China)", ZH_CNA },
{ "zh", "zh_TW", "Chinese (Taiwan)", ZH_TWN }, { "zh", "zh_TW", "Chinese (Taiwan)", ZH_TWN },
{ "hr", "hr_HR", "Croatian", HR_HRV },
{ "cz", "cs_CZ", "Czech", CZ_CZE }, { "cz", "cs_CZ", "Czech", CZ_CZE },
{ "nl", "nl_NL", "Dutch", NL_NLD }, { "nl", "nl_NL", "Dutch", NL_NLD },
{ "en", "en", "English", EN_ANY }, // Generic English (when only one game version exist) { "en", "en", "English", EN_ANY }, // Generic English (when only one game version exist)
@ -38,11 +39,11 @@ const LanguageDescription g_languages[] = {
{ "gr", "el_GR", "Greek", GR_GRE }, { "gr", "el_GR", "Greek", GR_GRE },
{ "he", "he_IL", "Hebrew", HE_ISR }, { "he", "he_IL", "Hebrew", HE_ISR },
{ "hb", "he_IL", "Hebrew", HE_ISR }, // Deprecated { "hb", "he_IL", "Hebrew", HE_ISR }, // Deprecated
{ "hr", "hr_HR", "Croatian", HR_HRV },
{ "hu", "hu_HU", "Hungarian", HU_HUN }, { "hu", "hu_HU", "Hungarian", HU_HUN },
{ "it", "it_IT", "Italian", IT_ITA }, { "it", "it_IT", "Italian", IT_ITA },
{ "jp", "ja_JP", "Japanese", JA_JPN }, { "jp", "ja_JP", "Japanese", JA_JPN },
{ "kr", "ko_KR", "Korean", KO_KOR }, { "kr", "ko_KR", "Korean", KO_KOR },
{ "lv", "lv_LV", "Latvian", LV_LAT },
{ "nb", "nb_NO", "Norwegian Bokm\xE5l", NB_NOR }, // TODO Someone should verify the unix locale { "nb", "nb_NO", "Norwegian Bokm\xE5l", NB_NOR }, // TODO Someone should verify the unix locale
{ "pl", "pl_PL", "Polish", PL_POL }, { "pl", "pl_PL", "Polish", PL_POL },
{ "br", "pt_BR", "Portuguese", PT_BRA }, { "br", "pt_BR", "Portuguese", PT_BRA },

View file

@ -34,6 +34,7 @@ class String;
enum Language { enum Language {
ZH_CNA, ZH_CNA,
ZH_TWN, ZH_TWN,
HR_HRV,
CZ_CZE, CZ_CZE,
NL_NLD, NL_NLD,
EN_ANY, // Generic English (when only one game version exist) EN_ANY, // Generic English (when only one game version exist)
@ -43,11 +44,11 @@ enum Language {
DE_DEU, DE_DEU,
GR_GRE, GR_GRE,
HE_ISR, HE_ISR,
HR_HRV,
HU_HUN, HU_HUN,
IT_ITA, IT_ITA,
JA_JPN, JA_JPN,
KO_KOR, KO_KOR,
LV_LAT,
NB_NOR, NB_NOR,
PL_POL, PL_POL,
PT_BRA, PT_BRA,

View file

@ -28,6 +28,7 @@ MODULE_OBJS := \
textconsole.o \ textconsole.o \
tokenizer.o \ tokenizer.o \
translation.o \ translation.o \
ustr.o \
unzip.o \ unzip.o \
util.o \ util.o \
winexe.o \ winexe.o \

View file

@ -45,6 +45,8 @@ PlaybackFile::PlaybackFile() : _tmpRecordFile(_tmpBuffer, kRecordBuffSize), _tmp
_recordCount = 0; _recordCount = 0;
_eventsSize = 0; _eventsSize = 0;
memset(_tmpBuffer, 1, kRecordBuffSize); memset(_tmpBuffer, 1, kRecordBuffSize);
_playbackParseState = kFileStateCheckFormat;
} }
PlaybackFile::~PlaybackFile() { PlaybackFile::~PlaybackFile() {

View file

@ -410,6 +410,8 @@
typedef unsigned int uint32; typedef unsigned int uint32;
typedef signed int int32; typedef signed int int32;
typedef unsigned int uint; typedef unsigned int uint;
typedef signed long long int64;
typedef unsigned long long uint64;
#endif #endif

View file

@ -234,6 +234,13 @@ public:
static String vformat(const char *fmt, va_list args); static String vformat(const char *fmt, va_list args);
public: public:
typedef char value_type;
/**
* Unsigned version of the underlying type. This can be used to cast
* individual string characters to bigger integer types without sign
* extension happening.
*/
typedef unsigned char unsigned_type;
typedef char * iterator; typedef char * iterator;
typedef const char * const_iterator; typedef const char * const_iterator;

329
common/ustr.cpp Normal file
View file

@ -0,0 +1,329 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common/ustr.h"
#include "common/memorypool.h"
#include "common/util.h"
namespace Common {
extern MemoryPool *g_refCountPool;
static uint32 computeCapacity(uint32 len) {
// By default, for the capacity we use the next multiple of 32
return ((len + 32 - 1) & ~0x1F);
}
U32String::U32String(const value_type *str) : _size(0), _str(_storage) {
if (str == 0) {
_storage[0] = 0;
_size = 0;
} else {
uint32 len = 0;
const value_type *s = str;
while (*s++) {
++len;
}
initWithCStr(str, len);
}
}
U32String::U32String(const value_type *str, uint32 len) : _size(0), _str(_storage) {
initWithCStr(str, len);
}
U32String::U32String(const value_type *beginP, const value_type *endP) : _size(0), _str(_storage) {
assert(endP >= beginP);
initWithCStr(beginP, endP - beginP);
}
U32String::U32String(const U32String &str)
: _size(str._size) {
if (str.isStorageIntern()) {
// String in internal storage: just copy it
memcpy(_storage, str._storage, _builtinCapacity * sizeof(value_type));
_str = _storage;
} else {
// String in external storage: use refcount mechanism
str.incRefCount();
_extern._refCount = str._extern._refCount;
_extern._capacity = str._extern._capacity;
_str = str._str;
}
assert(_str != 0);
}
U32String::~U32String() {
decRefCount(_extern._refCount);
}
U32String &U32String::operator=(const U32String &str) {
if (&str == this)
return *this;
if (str.isStorageIntern()) {
decRefCount(_extern._refCount);
_size = str._size;
_str = _storage;
memcpy(_str, str._str, (_size + 1) * sizeof(value_type));
} else {
str.incRefCount();
decRefCount(_extern._refCount);
_extern._refCount = str._extern._refCount;
_extern._capacity = str._extern._capacity;
_size = str._size;
_str = str._str;
}
return *this;
}
U32String &U32String::operator+=(const U32String &str) {
if (&str == this) {
return operator+=(U32String(str));
}
int len = str._size;
if (len > 0) {
ensureCapacity(_size + len, true);
memcpy(_str + _size, str._str, (len + 1) * sizeof(value_type));
_size += len;
}
return *this;
}
U32String &U32String::operator+=(value_type c) {
ensureCapacity(_size + 1, true);
_str[_size++] = c;
_str[_size] = 0;
return *this;
}
bool U32String::equals(const U32String &x) const {
if (this == &x || _str == x._str) {
return true;
}
if (x.size() != _size) {
return false;
}
return !memcmp(_str, x._str, _size * sizeof(value_type));
}
bool U32String::contains(value_type x) const {
for (uint32 i = 0; i < _size; ++i) {
if (_str[i] == x) {
return true;
}
}
return false;
}
void U32String::deleteChar(uint32 p) {
assert(p < _size);
makeUnique();
while (p++ < _size)
_str[p - 1] = _str[p];
_size--;
}
void U32String::clear() {
decRefCount(_extern._refCount);
_size = 0;
_str = _storage;
_storage[0] = 0;
}
void U32String::toLowercase() {
makeUnique();
for (uint32 i = 0; i < _size; ++i) {
if (_str[i] < 128) {
_str[i] = tolower(_str[i]);
}
}
}
void U32String::toUppercase() {
makeUnique();
for (uint32 i = 0; i < _size; ++i) {
if (_str[i] < 128) {
_str[i] = toupper(_str[i]);
}
}
}
uint32 U32String::find(const U32String &str, uint32 pos) const {
if (pos >= _size) {
return npos;
}
const value_type *strP = str.c_str();
for (const_iterator cur = begin() + pos; *cur; ++cur) {
uint i = 0;
while (true) {
if (!strP[i]) {
return cur - begin();
}
if (cur[i] != strP[i]) {
break;
}
++i;
}
}
return npos;
}
void U32String::makeUnique() {
ensureCapacity(_size, true);
}
void U32String::ensureCapacity(uint32 new_size, bool keep_old) {
bool isShared;
uint32 curCapacity, newCapacity;
value_type *newStorage;
int *oldRefCount = _extern._refCount;
if (isStorageIntern()) {
isShared = false;
curCapacity = _builtinCapacity;
} else {
isShared = (oldRefCount && *oldRefCount > 1);
curCapacity = _extern._capacity;
}
// Special case: If there is enough space, and we do not share
// the storage, then there is nothing to do.
if (!isShared && new_size < curCapacity)
return;
if (isShared && new_size < _builtinCapacity) {
// We share the storage, but there is enough internal storage: Use that.
newStorage = _storage;
newCapacity = _builtinCapacity;
} else {
// We need to allocate storage on the heap!
// Compute a suitable new capacity limit
// If the current capacity is sufficient we use the same capacity
if (new_size < curCapacity)
newCapacity = curCapacity;
else
newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
// Allocate new storage
newStorage = new value_type[newCapacity];
assert(newStorage);
}
// Copy old data if needed, elsewise reset the new storage.
if (keep_old) {
assert(_size < newCapacity);
memcpy(newStorage, _str, (_size + 1) * sizeof(value_type));
} else {
_size = 0;
newStorage[0] = 0;
}
// Release hold on the old storage ...
decRefCount(oldRefCount);
// ... in favor of the new storage
_str = newStorage;
if (!isStorageIntern()) {
// Set the ref count & capacity if we use an external storage.
// It is important to do this *after* copying any old content,
// else we would override data that has not yet been copied!
_extern._refCount = 0;
_extern._capacity = newCapacity;
}
}
void U32String::incRefCount() const {
assert(!isStorageIntern());
if (_extern._refCount == 0) {
if (g_refCountPool == 0) {
g_refCountPool = new MemoryPool(sizeof(int));
assert(g_refCountPool);
}
_extern._refCount = (int *)g_refCountPool->allocChunk();
*_extern._refCount = 2;
} else {
++(*_extern._refCount);
}
}
void U32String::decRefCount(int *oldRefCount) {
if (isStorageIntern())
return;
if (oldRefCount) {
--(*oldRefCount);
}
if (!oldRefCount || *oldRefCount <= 0) {
// The ref count reached zero, so we free the string storage
// and the ref count storage.
if (oldRefCount) {
assert(g_refCountPool);
g_refCountPool->freeChunk(oldRefCount);
}
delete[] _str;
// Even though _str points to a freed memory block now,
// we do not change its value, because any code that calls
// decRefCount will have to do this afterwards anyway.
}
}
void U32String::initWithCStr(const value_type *str, uint32 len) {
assert(str);
_storage[0] = 0;
_size = len;
if (len >= _builtinCapacity) {
// Not enough internal storage, so allocate more
_extern._capacity = computeCapacity(len+1);
_extern._refCount = 0;
_str = new value_type[_extern._capacity];
assert(_str != 0);
}
// Copy the string into the storage area
memmove(_str, str, len * sizeof(value_type));
_str[len] = 0;
}
} // End of namespace Common

194
common/ustr.h Normal file
View file

@ -0,0 +1,194 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef COMMON_USTR_H
#define COMMON_USTR_H
#include "common/scummsys.h"
namespace Common {
/**
* Very simple string class for UTF-32 strings in ScummVM. The main intention
* behind this class is to feature a simple way of displaying UTF-32 strings
* through the Graphics::Font API.
*
* Please note that operations like equals, deleteCharacter, toUppercase, etc.
* are only very simplified convenience operations. They might not fully work
* as you would expect for a proper UTF-32 string class.
*
* The presence of \0 characters in the string will cause undefined
* behavior in some operations.
*/
class U32String {
public:
static const uint32 npos = 0xFFFFFFFF;
typedef uint32 value_type;
typedef uint32 unsigned_type;
private:
/**
* The size of the internal storage. Increasing this means less heap
* allocations are needed, at the cost of more stack memory usage,
* and of course lots of wasted memory.
*/
static const uint32 _builtinCapacity = 32;
/**
* Length of the string.
*/
uint32 _size;
/**
* Pointer to the actual string storage. Either points to _storage,
* or to a block allocated on the heap via malloc.
*/
value_type *_str;
union {
/**
* Internal string storage.
*/
value_type _storage[_builtinCapacity];
/**
* External string storage data -- the refcounter, and the
* capacity of the string _str points to.
*/
struct {
mutable int *_refCount;
uint32 _capacity;
} _extern;
};
inline bool isStorageIntern() const {
return _str == _storage;
}
public:
/** Construct a new empty string. */
U32String() : _size(0), _str(_storage) { _storage[0] = 0; }
/** Construct a new string from the given NULL-terminated C string. */
explicit U32String(const value_type *str);
/** Construct a new string containing exactly len characters read from address str. */
U32String(const value_type *str, uint32 len);
/** Construct a new string containing the characters between beginP (including) and endP (excluding). */
U32String(const value_type *beginP, const value_type *endP);
/** Construct a copy of the given string. */
U32String(const U32String &str);
~U32String();
U32String &operator=(const U32String &str);
U32String &operator+=(const U32String &str);
U32String &operator+=(value_type c);
/**
* Equivalence comparison operator.
* @see equals
*/
bool operator==(const U32String &x) const { return equals(x); }
/**
* Compares whether two U32String are the same based on memory comparison.
* This does *not* do comparison based on canonical equivalence.
*/
bool equals(const U32String &x) const;
bool contains(value_type x) const;
inline const value_type *c_str() const { return _str; }
inline uint32 size() const { return _size; }
inline bool empty() const { return (_size == 0); }
value_type operator[](int idx) const {
assert(_str && idx >= 0 && idx < (int)_size);
return _str[idx];
}
/**
* Removes the value at position p from the string.
* Using this on decomposed characters will not remove the whole
* character!
*/
void deleteChar(uint32 p);
/** Clears the string, making it empty. */
void clear();
/**
* Convert all characters in the string to lowercase.
*
* Be aware that this only affects the case of ASCII characters. All
* other characters will not be touched at all.
*/
void toLowercase();
/**
* Convert all characters in the string to uppercase.
*
* Be aware that this only affects the case of ASCII characters. All
* other characters will not be touched at all.
*/
void toUppercase();
uint32 find(const U32String &str, uint32 pos = 0) const;
typedef value_type * iterator;
typedef const value_type * const_iterator;
iterator begin() {
// Since the user could potentially
// change the string via the returned
// iterator we have to assure we are
// pointing to a unique storage.
makeUnique();
return _str;
}
iterator end() {
return begin() + size();
}
const_iterator begin() const {
return _str;
}
const_iterator end() const {
return begin() + size();
}
private:
void makeUnique();
void ensureCapacity(uint32 new_size, bool keep_old);
void incRefCount() const;
void decRefCount(int *oldRefCount);
void initWithCStr(const value_type *str, uint32 len);
};
} // End of namespace Common
#endif

View file

@ -27,6 +27,7 @@
#include "common/ptr.h" #include "common/ptr.h"
#include "common/util.h" #include "common/util.h"
#include "common/stream.h" #include "common/stream.h"
#include "common/textconsole.h"
#if defined(USE_ZLIB) #if defined(USE_ZLIB)
#ifdef __SYMBIAN32__ #ifdef __SYMBIAN32__
@ -158,10 +159,11 @@ protected:
uint32 _pos; uint32 _pos;
uint32 _origSize; uint32 _origSize;
bool _eos; bool _eos;
bool _shownBackwardSeekingWarning;
public: public:
GZipReadStream(SeekableReadStream *w, uint32 knownSize = 0) : _wrapped(w), _stream() { GZipReadStream(SeekableReadStream *w, uint32 knownSize = 0) : _wrapped(w), _stream(), _shownBackwardSeekingWarning(false) {
assert(w != 0); assert(w != 0);
// Verify file header is correct // Verify file header is correct
@ -241,13 +243,17 @@ public:
} }
bool seek(int32 offset, int whence = SEEK_SET) { bool seek(int32 offset, int whence = SEEK_SET) {
int32 newPos = 0; int32 newPos = 0;
assert(whence != SEEK_END); // SEEK_END not supported
switch (whence) { switch (whence) {
case SEEK_SET: case SEEK_SET:
newPos = offset; newPos = offset;
break; break;
case SEEK_CUR: case SEEK_CUR:
newPos = _pos + offset; newPos = _pos + offset;
break;
case SEEK_END:
// NOTE: This can be an expensive operation (see below).
newPos = size() + offset;
break;
} }
assert(newPos >= 0); assert(newPos >= 0);
@ -256,9 +262,15 @@ public:
// To search backward, we have to restart the whole decompression // To search backward, we have to restart the whole decompression
// from the start of the file. A rather wasteful operation, best // from the start of the file. A rather wasteful operation, best
// to avoid it. :/ // to avoid it. :/
#if DEBUG
warning("Backward seeking in GZipReadStream detected"); if (!_shownBackwardSeekingWarning) {
#endif // We only throw this warning once per stream, to avoid
// getting the console swarmed with warnings when consecutive
// seeks are made.
warning("Backward seeking in GZipReadStream detected");
_shownBackwardSeekingWarning = true;
}
_pos = 0; _pos = 0;
_wrapped->seek(0, SEEK_SET); _wrapped->seek(0, SEEK_SET);
_zlibErr = inflateReset(&_stream); _zlibErr = inflateReset(&_stream);

72
configure vendored
View file

@ -97,7 +97,9 @@ add_feature() {
_srcdir=`dirname $0` _srcdir=`dirname $0`
# Read list of engines # Read list of engines
. $_srcdir/engines/configure.engines for i in $_srcdir/engines/*/configure.engine; do
. "$i"
done
# #
# Default settings # Default settings
@ -4245,8 +4247,18 @@ for engine in $_engines; do
fi fi
done done
# Prepare the information to be shown # Sort engines to place our headline engine at start...
# No technical reason, just historical convention
headline_engine=grime
_sorted_engines="${headline_engine}"
for engine in $_engines; do for engine in $_engines; do
if test "${engine}" != "${headline_engine}" ; then
_sorted_engines="${_sorted_engines} ${engine}"
fi
done
# Prepare the information to be shown
for engine in $_sorted_engines; do
if test "`get_engine_sub $engine`" = "no" ; then if test "`get_engine_sub $engine`" = "no" ; then
# It's a main engine # It's a main engine
prepare_engine_build_strings $engine prepare_engine_build_strings $engine
@ -4430,3 +4442,59 @@ include \$(srcdir)/Makefile
EOF EOF
fi fi
# Ensure engines folder exists prior to trying to generate
# files into it (used for out-of-tree-builds)
mkdir -p engines
echo "Creating engines/engines.mk"
cat > engines/engines.mk << EOF
# This file is automatically generated by configure
# DO NOT EDIT MANUALLY
# This file is being included by "Makefile.common"
EOF
for engine in $_sorted_engines; do
j=`echo $engine | tr '[:lower:]' '[:upper:]'`
if test "`get_engine_sub $engine`" = "no" ; then
# main engine
cat >> engines/engines.mk << EOF
ifdef ENABLE_$j
DEFINES += -DENABLE_$j=\$(ENABLE_$j)
MODULES += engines/$engine
EOF
for subeng in `get_engine_subengines $engine` ; do
k=`echo $subeng | tr '[:lower:]' '[:upper:]'`
cat >> engines/engines.mk << EOF
ifdef ENABLE_$k
DEFINES += -DENABLE_$k
endif
EOF
done
cat >> engines/engines.mk << EOF
endif
EOF
fi
done
echo "Creating engines/plugins_table.h"
cat > engines/plugins_table.h << EOF
/* This file is automatically generated by configure */
/* DO NOT EDIT MANUALLY */
// This file is being included by "base/plugins.cpp"
EOF
for engine in $_sorted_engines; do
if test "`get_engine_sub $engine`" = "no" ; then
j=`echo $engine | tr '[:lower:]' '[:upper:]'`
cat >> engines/plugins_table.h << EOF
#if PLUGIN_ENABLED_STATIC($j)
LINK_PLUGIN($j)
#endif
EOF
fi
done

View file

@ -120,6 +120,7 @@ void CodeBlocksProvider::createProjectFile(const std::string &name, const std::s
"\t\t\t\t\t<Add directory=\"..\\..\\engines\" />\n" "\t\t\t\t\t<Add directory=\"..\\..\\engines\" />\n"
"\t\t\t\t\t<Add directory=\"..\\..\\common\" />\n" "\t\t\t\t\t<Add directory=\"..\\..\\common\" />\n"
"\t\t\t\t\t<Add directory=\"..\\..\" />\n" "\t\t\t\t\t<Add directory=\"..\\..\" />\n"
"\t\t\t\t\t<Add directory=\".\\\" />\n"
"\t\t\t\t</Compiler>\n"; "\t\t\t\t</Compiler>\n";
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View file

@ -27,6 +27,7 @@
#define PROJECT_NAME "residualvm" // Used for folders, icons, resources and project/solution name #define PROJECT_NAME "residualvm" // Used for folders, icons, resources and project/solution name
#define LIBS_DEFINE "RESIDUALVM_LIBS" // Name of the include environment variable #define LIBS_DEFINE "RESIDUALVM_LIBS" // Name of the include environment variable
#define REVISION_DEFINE "SCUMMVM_INTERNAL_REVISION" #define REVISION_DEFINE "SCUMMVM_INTERNAL_REVISION"
#define FIRST_ENGINE "grime" // Name of the engine which should be sorted as first element
#define ENABLE_LANGUAGE_EXTENSIONS "grim,myst3" // Comma separated list of projects that need language extensions #define ENABLE_LANGUAGE_EXTENSIONS "grim,myst3" // Comma separated list of projects that need language extensions
#define DISABLE_EDIT_AND_CONTINUE "grim,myst3,residualvm" // Comma separated list of projects that need Edit&Continue to be disabled for co-routine support (the main project is automatically added) #define DISABLE_EDIT_AND_CONTINUE "grim,myst3,residualvm" // Comma separated list of projects that need Edit&Continue to be disabled for co-routine support (the main project is automatically added)

View file

@ -43,6 +43,7 @@
#include <stack> #include <stack>
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
#include <iterator>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
@ -59,6 +60,7 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#endif #endif
namespace { namespace {
@ -81,22 +83,6 @@ std::string unifyPath(const std::string &path);
* @param exe Name of the executable. * @param exe Name of the executable.
*/ */
void displayHelp(const char *exe); void displayHelp(const char *exe);
/**
* Structure for describing an FSNode. This is a very minimalistic
* description, which includes everything we need.
* It only contains the name of the node and whether it is a directory
* or not.
*/
struct FSNode {
FSNode() : name(), isDirectory(false) {}
FSNode(const std::string &n, bool iD) : name(n), isDirectory(iD) {}
std::string name; ///< Name of the file system node
bool isDirectory; ///< Whether it is a directory or not
};
typedef std::list<FSNode> FileList;
} // End of anonymous namespace } // End of anonymous namespace
enum ProjectType { enum ProjectType {
@ -128,7 +114,7 @@ int main(int argc, char *argv[]) {
setup.filePrefix = setup.srcDir; setup.filePrefix = setup.srcDir;
setup.outputDir = '.'; setup.outputDir = '.';
setup.engines = parseConfigure(setup.srcDir); setup.engines = parseEngines(setup.srcDir);
if (setup.engines.empty()) { if (setup.engines.empty()) {
std::cout << "WARNING: No engines found in configure file or configure file missing in \"" << setup.srcDir << "\"\n"; std::cout << "WARNING: No engines found in configure file or configure file missing in \"" << setup.srcDir << "\"\n";
@ -672,47 +658,70 @@ void displayHelp(const char *exe) {
} }
/** /**
* Try to parse a given line and create an engine definition * Parse the configure.engine file of a given engine directory and return a
* out of the result. * list of all defined engines.
* *
* This may take *any* input line, when the line is not used * @param engineDir The directory of the engine.
* to define an engine the result of the function will be "false". * @return The list of all defined engines.
*
* Note that the contents of "engine" are undefined, when this
* function returns "false".
*
* @param line Text input line.
* @param engine Reference to an object, where the engine information
* is to be stored in.
* @return "true", when parsing succeeded, "false" otherwise.
*/ */
bool parseEngine(const std::string &line, EngineDesc &engine); EngineDescList parseEngineConfigure(const std::string &engineDir);
/**
* Compares two FSNode entries in a strict-weak fashion based on the name.
*
* @param left The first operand.
* @param right The second operand.
* @return "true" when the name of the left operand is strictly smaller than
* the name of the second operand. "false" otherwise.
*/
bool compareFSNode(const CreateProjectTool::FSNode &left, const CreateProjectTool::FSNode &right);
#ifdef FIRST_ENGINE
/**
* Compares two FSNode entries in a strict-weak fashion based on engine name
* order.
*
* @param left The first operand.
* @param right The second operand.
* @return "true" when the name of the left operand is strictly smaller than
* the name of the second operand. "false" otherwise.
*/
bool compareEngineNames(const CreateProjectTool::FSNode &left, const CreateProjectTool::FSNode &right);
#endif
} // End of anonymous namespace } // End of anonymous namespace
EngineDescList parseConfigure(const std::string &srcDir) { EngineDescList parseEngines(const std::string &srcDir) {
std::string configureFile = srcDir + "/engines/configure.engines"; using CreateProjectTool::FileList;
using CreateProjectTool::listDirectory;
std::ifstream configure(configureFile.c_str()); EngineDescList engineList;
if (!configure)
return EngineDescList();
std::string line; FileList engineFiles = listDirectory(srcDir + "/engines/");
EngineDescList engines;
for (;;) { #ifdef FIRST_ENGINE
std::getline(configure, line); // In case we want to sort an engine to the front of the list we will
if (configure.eof()) // use some manual sorting predicate which assures that.
break; engineFiles.sort(&compareEngineNames);
#else
// Otherwise, we simply sort the file list alphabetically this allows
// for a nicer order in --list-engines output, for example.
engineFiles.sort(&compareFSNode);
#endif
if (configure.fail()) for (FileList::const_iterator i = engineFiles.begin(), end = engineFiles.end(); i != end; ++i) {
error("Failed while reading from " + configureFile); // Each engine requires its own sub directory thus we will skip all
// non directory file nodes here.
if (!i->isDirectory) {
continue;
}
EngineDesc desc; // Retrieve all engines defined in this sub directory and add them to
if (parseEngine(line, desc)) // the list of all engines.
engines.push_back(desc); EngineDescList list = parseEngineConfigure(srcDir + "/engines/" + i->name);
engineList.splice(engineList.end(), list);
} }
return engines; return engineList;
} }
bool isSubEngine(const std::string &name, const EngineDescList &engines) { bool isSubEngine(const std::string &name, const EngineDescList &engines) {
@ -777,6 +786,21 @@ StringList getEngineDefines(const EngineDescList &engines) {
} }
namespace { namespace {
/**
* Try to parse a given line and create an engine definition
* out of the result.
*
* This may take *any* input line, when the line is not used
* to define an engine the result of the function will be "false".
*
* Note that the contents of "engine" are undefined, when this
* function returns "false".
*
* @param line Text input line.
* @param engine Reference to an object, where the engine information
* is to be stored in.
* @return "true", when parsing succeeded, "false" otherwise.
*/
bool parseEngine(const std::string &line, EngineDesc &engine) { bool parseEngine(const std::string &line, EngineDesc &engine) {
// Format: // Format:
// add_engine engine_name "Readable Description" enable_default ["SubEngineList"] // add_engine engine_name "Readable Description" enable_default ["SubEngineList"]
@ -799,6 +823,48 @@ bool parseEngine(const std::string &line, EngineDesc &engine) {
return true; return true;
} }
EngineDescList parseEngineConfigure(const std::string &engineDir) {
std::string configureFile = engineDir + "/configure.engine";
std::ifstream configure(configureFile.c_str());
if (!configure)
return EngineDescList();
std::string line;
EngineDescList engines;
for (;;) {
std::getline(configure, line);
if (configure.eof())
break;
if (configure.fail())
error("Failed while reading from " + configureFile);
EngineDesc desc;
if (parseEngine(line, desc))
engines.push_back(desc);
}
return engines;
}
bool compareFSNode(const CreateProjectTool::FSNode &left, const CreateProjectTool::FSNode &right) {
return left.name < right.name;
}
#ifdef FIRST_ENGINE
bool compareEngineNames(const CreateProjectTool::FSNode &left, const CreateProjectTool::FSNode &right) {
if (left.name == FIRST_ENGINE) {
return right.name != FIRST_ENGINE;
} else if (right.name == FIRST_ENGINE) {
return false;
} else {
return compareFSNode(left, right);
}
}
#endif
} // End of anonymous namespace } // End of anonymous namespace
TokenList tokenize(const std::string &input, char separator) { TokenList tokenize(const std::string &input, char separator) {
@ -1048,13 +1114,6 @@ bool compareNodes(const FileNode *l, const FileNode *r) {
} }
} }
/**
* Returns a list of all files and directories in the specified
* path.
*
* @param dir Directory which should be listed.
* @return List of all children.
*/
FileList listDirectory(const std::string &dir) { FileList listDirectory(const std::string &dir) {
FileList result; FileList result;
#ifdef USE_WIN32_API #ifdef USE_WIN32_API
@ -1095,6 +1154,32 @@ FileList listDirectory(const std::string &dir) {
return result; return result;
} }
void createDirectory(const std::string &dir) {
#if defined(_WIN32) || defined(WIN32)
if (!CreateDirectory(dir.c_str(), NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
error("Could not create folder \"" + dir + "\"");
}
}
#else
if (mkdir(dir.c_str(), 0777) == -1) {
if (errno == EEXIST) {
// Try to open as a folder (might be a file / symbolic link)
DIR *dirp = opendir(dir.c_str());
if (dirp == NULL) {
error("Could not create folder \"" + dir + "\"");
} else {
// The folder exists, just close the stream and return
closedir(dirp);
}
} else {
error("Could not create folder \"" + dir + "\"");
}
}
#endif
}
/** /**
* Scans the specified directory against files, which should be included * Scans the specified directory against files, which should be included
* in the project files. It will not include files present in the exclude list. * in the project files. It will not include files present in the exclude list.
@ -1246,6 +1331,12 @@ void ProjectProvider::createProject(BuildSetup &setup) {
// Create other misc. build files // Create other misc. build files
createOtherBuildFiles(setup); createOtherBuildFiles(setup);
// In case we create the main ScummVM project files we will need to
// generate engines/plugins_table.h too.
if (!setup.tests && !setup.devTools) {
createEnginePluginsTable(setup);
}
} }
ProjectProvider::UUIDMap ProjectProvider::createUUIDMap(const BuildSetup &setup) const { ProjectProvider::UUIDMap ProjectProvider::createUUIDMap(const BuildSetup &setup) const {
@ -1573,6 +1664,37 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin
error("Malformed file " + moduleMkFile); error("Malformed file " + moduleMkFile);
} }
void ProjectProvider::createEnginePluginsTable(const BuildSetup &setup) {
// First we need to create the "engines" directory.
createDirectory(setup.outputDir + "/engines");
// Then, we can generate the actual "plugins_table.h" file.
const std::string enginePluginsTableFile = setup.outputDir + "/engines/plugins_table.h";
std::ofstream enginePluginsTable(enginePluginsTableFile.c_str());
if (!enginePluginsTable) {
error("Could not open \"" + enginePluginsTableFile + "\" for writing");
}
enginePluginsTable << "/* This file is automatically generated by create_project */\n"
<< "/* DO NOT EDIT MANUALLY */\n"
<< "// This file is being included by \"base/plugins.cpp\"\n";
for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) {
// We ignore all sub engines here because they require no special
// handling.
if (isSubEngine(i->name, setup.engines)) {
continue;
}
// Make the engine name all uppercase.
std::string engineName;
std::transform(i->name.begin(), i->name.end(), std::back_inserter(engineName), toupper);
enginePluginsTable << "#if PLUGIN_ENABLED_STATIC(" << engineName << ")\n"
<< "LINK_PLUGIN(" << engineName << ")\n"
<< "#endif\n";
}
}
} // End of anonymous namespace } // End of anonymous namespace
void error(const std::string &message) { void error(const std::string &message) {

View file

@ -102,16 +102,17 @@ struct EngineDesc {
typedef std::list<EngineDesc> EngineDescList; typedef std::list<EngineDesc> EngineDescList;
/** /**
* This function parses the project configure file and creates a list * This function parses the project directory and creates a list of
* of available engines. * available engines.
* *
* It will also automatically setup the default build state (enabled * It will also automatically setup the default build state (enabled
* or disabled) to the state specified in the "configure" file. * or disabled) to the state specified in the individual configure.engine
* files.
* *
* @param srcDir Path to the root of the project source. * @param srcDir Path to the root of the project source.
* @return List of available engines. * @return List of available engines.
*/ */
EngineDescList parseConfigure(const std::string &srcDir); EngineDescList parseEngines(const std::string &srcDir);
/** /**
* Checks whether the specified engine is a sub engine. To determine this * Checks whether the specified engine is a sub engine. To determine this
@ -262,6 +263,22 @@ void NORETURN_PRE error(const std::string &message) NORETURN_POST;
namespace CreateProjectTool { namespace CreateProjectTool {
/**
* Structure for describing an FSNode. This is a very minimalistic
* description, which includes everything we need.
* It only contains the name of the node and whether it is a directory
* or not.
*/
struct FSNode {
FSNode() : name(), isDirectory(false) {}
FSNode(const std::string &n, bool iD) : name(n), isDirectory(iD) {}
std::string name; ///< Name of the file system node
bool isDirectory; ///< Whether it is a directory or not
};
typedef std::list<FSNode> FileList;
/** /**
* Gets a proper sequence of \t characters for the given * Gets a proper sequence of \t characters for the given
* indentation level. * indentation level.
@ -314,6 +331,22 @@ bool producesObjectFile(const std::string &fileName);
*/ */
std::string toString(int num); std::string toString(int num);
/**
* Returns a list of all files and directories in the specified
* path.
*
* @param dir Directory which should be listed.
* @return List of all children.
*/
FileList listDirectory(const std::string &dir);
/**
* Create a directory at the given path.
*
* @param dir The path to create.
*/
void createDirectory(const std::string &dir);
/** /**
* Structure representing a file tree. This contains two * Structure representing a file tree. This contains two
* members: name and children. "name" holds the name of * members: name and children. "name" holds the name of
@ -474,6 +507,15 @@ protected:
* @return A new UUID as string. * @return A new UUID as string.
*/ */
std::string createUUID() const; std::string createUUID() const;
private:
/**
* This creates the engines/plugins_table.h file required for building
* ScummVM.
*
* @param setup Description of the desired build.
*/
void createEnginePluginsTable(const BuildSetup &setup);
}; };
} // End of CreateProjectTool namespace } // End of CreateProjectTool namespace

View file

@ -360,7 +360,7 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea
"\t\t<ClCompile>\n" "\t\t<ClCompile>\n"
"\t\t\t<DisableLanguageExtensions>true</DisableLanguageExtensions>\n" "\t\t\t<DisableLanguageExtensions>true</DisableLanguageExtensions>\n"
"\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n" "\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n"
"\t\t\t<AdditionalIncludeDirectories>$(" << LIBS_DEFINE << ")\\include;" << prefix << ";" << prefix << "\\engines;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" "\t\t\t<AdditionalIncludeDirectories>$(" << LIBS_DEFINE << ")\\include;.\\;" << prefix << ";" << prefix << "\\engines;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
"\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" "\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
"\t\t\t<ExceptionHandling>" << ((setup.devTools || setup.tests) ? "Sync" : "") << "</ExceptionHandling>\n"; "\t\t\t<ExceptionHandling>" << ((setup.devTools || setup.tests) ? "Sync" : "") << "</ExceptionHandling>\n";

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Debug visualizers for a few common ScummVM types for Visual Studio 2012 and up.
To use, copy this file into Documents\Visual Studio 20xx\Visualizers.
Known issues:
* Lists appear to be infinite (the same elements repeat over and over again).
Unfortunately, Lists don't store length information, and it's not possible to
detect whether a Node is the last one by the Node itself.
* In HashMaps, missing and dummy nodes are shown along with the useful ones.
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Common::Array&lt;*&gt;">
<DisplayString>{{size = {_size}}}</DisplayString>
<Expand>
<Item Name="[size]">_size</Item>
<Item Name="[capacity]">_capacity</Item>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_storage</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="Common::HashMap&lt;*,*,*,*&gt;">
<DisplayString>{{ size = {_size} }}</DisplayString>
<Expand>
<Item Name="[size]">_size</Item>
<Item Name="[capacity]">_mask + 1</Item>
<Item Name="[deleted]">_deleted</Item>
<IndexListItems>
<Size>_mask + 1</Size>
<ValueNode Condition="_storage[$i] &amp;&amp; _storage[$i] != (Common::HashMap&lt;$T1,$T2,$T3,$T4&gt;::Node *)1">*_storage[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
<Type Name="Common::List&lt;*&gt;">
<DisplayString Condition="&amp;_anchor == _anchor._next">{{ empty }}</DisplayString>
<DisplayString Condition="&amp;_anchor != _anchor._next">{{ non-empty }}</DisplayString>
<Expand>
<LinkedListItems Condition="&amp;_anchor != _anchor._next">
<HeadPointer>_anchor._next</HeadPointer>
<NextPointer>_next</NextPointer>
<ValueNode>((Common::ListInternal::Node&lt;$T1&gt;*)this)->_data</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="Common::String">
<DisplayString>{_str,[_size]}</DisplayString>
<StringView>_str,[_size]</StringView>
<Expand>
<Item Name="[size]">_size</Item>
<Item Condition="_str != _storage" Name="[capacity]">_extern._capacity</Item>
<Item Condition="_str != _storage" Name="[refCount]">*_extern._refCount</Item>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_str</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>

View file

@ -232,7 +232,7 @@ void VisualStudioProvider::outputGlobalPropFile(const BuildSetup &setup, std::of
"\t\tName=\"VCCLCompilerTool\"\n" "\t\tName=\"VCCLCompilerTool\"\n"
"\t\tDisableLanguageExtensions=\"" << (setup.devTools ? "false" : "true") << "\"\n" "\t\tDisableLanguageExtensions=\"" << (setup.devTools ? "false" : "true") << "\"\n"
"\t\tDisableSpecificWarnings=\"" << warnings << "\"\n" "\t\tDisableSpecificWarnings=\"" << warnings << "\"\n"
"\t\tAdditionalIncludeDirectories=\"" << prefix << ";" << prefix << "\\engines;$(" << LIBS_DEFINE << ")\\include;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir)\"\n" "\t\tAdditionalIncludeDirectories=\".\\;" << prefix << ";" << prefix << "\\engines;$(" << LIBS_DEFINE << ")\\include;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir)\"\n"
"\t\tPreprocessorDefinitions=\"" << definesList << "\"\n" "\t\tPreprocessorDefinitions=\"" << definesList << "\"\n"
"\t\tExceptionHandling=\"" << ((setup.devTools || setup.tests) ? "1" : "0") << "\"\n"; "\t\tExceptionHandling=\"" << ((setup.devTools || setup.tests) ? "1" : "0") << "\"\n";

View file

@ -26,15 +26,6 @@
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#if defined(_WIN32) || defined(WIN32)
#include <windows.h>
#else
#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#endif
namespace CreateProjectTool { namespace CreateProjectTool {
#define DEBUG_XCODE_HASH 0 #define DEBUG_XCODE_HASH 0
@ -88,27 +79,7 @@ XCodeProvider::XCodeProvider(StringList &global_warnings, std::map<std::string,
void XCodeProvider::createWorkspace(const BuildSetup &setup) { void XCodeProvider::createWorkspace(const BuildSetup &setup) {
// Create project folder // Create project folder
std::string workspace = setup.outputDir + '/' + PROJECT_NAME ".xcodeproj"; std::string workspace = setup.outputDir + '/' + PROJECT_NAME ".xcodeproj";
createDirectory(workspace);
#if defined(_WIN32) || defined(WIN32)
if (!CreateDirectory(workspace.c_str(), NULL))
if (GetLastError() != ERROR_ALREADY_EXISTS)
error("Could not create folder \"" + setup.outputDir + '/' + PROJECT_NAME ".xcodeproj\"");
#else
if (mkdir(workspace.c_str(), 0777) == -1) {
if (errno == EEXIST) {
// Try to open as a folder (might be a file / symbolic link)
DIR *dirp = opendir(workspace.c_str());
if (dirp == NULL) {
error("Could not create folder \"" + setup.outputDir + '/' + PROJECT_NAME ".xcodeproj\"");
} else {
// The folder exists, just close the stream and return
closedir(dirp);
}
} else {
error("Could not create folder \"" + setup.outputDir + '/' + PROJECT_NAME ".xcodeproj\"");
}
}
#endif
// Setup global objects // Setup global objects
setupDefines(setup); setupDefines(setup);

View file

@ -48,7 +48,7 @@ if ($mode eq "") {
$Text::Wrap::unexpand = 0; $Text::Wrap::unexpand = 0;
if ($mode eq "TEXT") { if ($mode eq "TEXT") {
$Text::Wrap::columns = 78; $Text::Wrap::columns = 78;
$max_name_width = 23; # The maximal width of a name. $max_name_width = 28; # The maximal width of a name.
} elsif ($mode eq "CPP") { } elsif ($mode eq "CPP") {
$Text::Wrap::columns = 48; # Approx. $Text::Wrap::columns = 48; # Approx.
} }
@ -60,6 +60,7 @@ sub html_entities_to_ascii {
# For now we hardcode these mappings # For now we hardcode these mappings
# &aacute; -> a # &aacute; -> a
# &eacute; -> e # &eacute; -> e
# &iacute; -> i
# &igrave; -> i # &igrave; -> i
# &oacute; -> o # &oacute; -> o
# &oslash; -> o # &oslash; -> o
@ -72,8 +73,10 @@ sub html_entities_to_ascii {
# &#322; -> l # &#322; -> l
# &#347; -> s # &#347; -> s
# &Scaron; -> S # &Scaron; -> S
# &ntilde; -> n
$text =~ s/&aacute;/a/g; $text =~ s/&aacute;/a/g;
$text =~ s/&eacute;/e/g; $text =~ s/&eacute;/e/g;
$text =~ s/&iacute;/i/g;
$text =~ s/&igrave;/i/g; $text =~ s/&igrave;/i/g;
$text =~ s/&oacute;/o/g; $text =~ s/&oacute;/o/g;
$text =~ s/&oslash;/o/g; $text =~ s/&oslash;/o/g;
@ -81,6 +84,7 @@ sub html_entities_to_ascii {
$text =~ s/&#347;/s/g; $text =~ s/&#347;/s/g;
$text =~ s/&Scaron;/S/g; $text =~ s/&Scaron;/S/g;
$text =~ s/&aring;/aa/g; $text =~ s/&aring;/aa/g;
$text =~ s/&ntilde;/n/g;
$text =~ s/&auml;/a/g; $text =~ s/&auml;/a/g;
$text =~ s/&euml;/e/g; $text =~ s/&euml;/e/g;
@ -101,6 +105,7 @@ sub html_entities_to_cpp {
# The numerical values are octal! # The numerical values are octal!
$text =~ s/&aacute;/\\341/g; $text =~ s/&aacute;/\\341/g;
$text =~ s/&eacute;/\\351/g; $text =~ s/&eacute;/\\351/g;
$text =~ s/&iacute;/\\355/g;
$text =~ s/&igrave;/\\354/g; $text =~ s/&igrave;/\\354/g;
$text =~ s/&oacute;/\\363/g; $text =~ s/&oacute;/\\363/g;
$text =~ s/&oslash;/\\370/g; $text =~ s/&oslash;/\\370/g;
@ -108,6 +113,7 @@ sub html_entities_to_cpp {
$text =~ s/&#347;/s/g; $text =~ s/&#347;/s/g;
$text =~ s/&Scaron;/S/g; $text =~ s/&Scaron;/S/g;
$text =~ s/&aring;/\\345/g; $text =~ s/&aring;/\\345/g;
$text =~ s/&ntilde;/\\361/g;
$text =~ s/&auml;/\\344/g; $text =~ s/&auml;/\\344/g;
$text =~ s/&euml;/\\353/g; $text =~ s/&euml;/\\353/g;
@ -126,6 +132,7 @@ sub html_entities_to_rtf {
$text =~ s/&aacute;/\\'87/g; $text =~ s/&aacute;/\\'87/g;
$text =~ s/&eacute;/\\'8e/g; $text =~ s/&eacute;/\\'8e/g;
$text =~ s/&iacute;/\\'92/g;
$text =~ s/&igrave;/\\'93/g; $text =~ s/&igrave;/\\'93/g;
$text =~ s/&oacute;/\\'97/g; $text =~ s/&oacute;/\\'97/g;
$text =~ s/&oslash;/\\'bf/g; $text =~ s/&oslash;/\\'bf/g;
@ -135,6 +142,8 @@ sub html_entities_to_rtf {
$text =~ s/&Scaron;/\\uc0\\u540 /g; $text =~ s/&Scaron;/\\uc0\\u540 /g;
# Back to hex numbers # Back to hex numbers
$text =~ s/&ntilde;/\\'96/g;
$text =~ s/&auml;/\\'8a/g; $text =~ s/&auml;/\\'8a/g;
$text =~ s/&euml;/\\'eb/g; $text =~ s/&euml;/\\'eb/g;
$text =~ s/&ouml;/\\'9a/g; $text =~ s/&ouml;/\\'9a/g;
@ -151,12 +160,14 @@ sub html_entities_to_tex {
$text =~ s/&aacute;/\\'a/g; $text =~ s/&aacute;/\\'a/g;
$text =~ s/&eacute;/\\'e/g; $text =~ s/&eacute;/\\'e/g;
$text =~ s/&iacute;/\\'i/g;
$text =~ s/&igrave;/\\`\\i/g; $text =~ s/&igrave;/\\`\\i/g;
$text =~ s/&oacute;/\\'o/g; $text =~ s/&oacute;/\\'o/g;
$text =~ s/&oslash;/{\\o}/g; $text =~ s/&oslash;/{\\o}/g;
$text =~ s/&aring;/\\aa /g; $text =~ s/&aring;/\\aa /g;
$text =~ s/&#322;/{\\l}/g; $text =~ s/&#322;/{\\l}/g;
$text =~ s/&Scaron;/{\\v S}/g; $text =~ s/&Scaron;/{\\v S}/g;
$text =~ s/&ntilde;/\\˜n/g;
$text =~ s/&auml;/\\"a/g; $text =~ s/&auml;/\\"a/g;
$text =~ s/&ouml;/\\"o/g; $text =~ s/&ouml;/\\"o/g;

View file

@ -3,4 +3,7 @@ files using the create_project tool inside the /devtools/create_project folder.
To create the default project files, build create_project.exe, copy it inside To create the default project files, build create_project.exe, copy it inside
this folder and run the create_msvc11.bat file for a default build. You can run this folder and run the create_msvc11.bat file for a default build. You can run
create_project.exe with no parameters to check the possible command-line options create_project.exe with no parameters to check the possible command-line options.
To enable debug visualization for common types, see the comment in
/devtools/create_project/scripts/scummvm.natvis.

View file

@ -3,4 +3,7 @@ files using the create_project tool inside the /devtools/create_project folder.
To create the default project files, build create_project.exe, copy it inside To create the default project files, build create_project.exe, copy it inside
this folder and run the create_msvc12.bat file for a default build. You can run this folder and run the create_msvc12.bat file for a default build. You can run
create_project.exe with no parameters to check the possible command-line options create_project.exe with no parameters to check the possible command-line options.
To enable debug visualization for common types, see the comment in
/devtools/create_project/scripts/scummvm.natvis.

View file

@ -183,7 +183,7 @@ void initCommonGFX(bool defaultTo1XScaler) {
g_system->setGraphicsMode(gfxMode.c_str()); g_system->setGraphicsMode(gfxMode.c_str());
// HACK: For OpenGL modes, we will still honor the graphics scale override // HACK: For OpenGL modes, we will still honor the graphics scale override
if (defaultTo1XScaler && (gfxMode.equalsIgnoreCase("gl1") || gfxMode.equalsIgnoreCase("gl2") || gfxMode.equalsIgnoreCase("gl4"))) if (defaultTo1XScaler && (gfxMode.equalsIgnoreCase("opengl_linear") || gfxMode.equalsIgnoreCase("opengl_nearest")))
g_system->resetGraphicsScale(); g_system->resetGraphicsScale();
} }
} }

View file

@ -1,14 +0,0 @@
ifdef ENABLE_GRIM
DEFINES += -DENABLE_GRIM=$(ENABLE_GRIM)
MODULES += engines/grim
ifdef ENABLE_MONKEY4
DEFINES += -DENABLE_MONKEY4
endif
endif
ifdef ENABLE_MYST3
DEFINES += -DENABLE_MYST3=$(ENABLE_MYST3)
MODULES += engines/myst3
endif

View file

@ -2,4 +2,3 @@
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine grim "Grim" yes "monkey4" "Grim Fandango" "zlib" add_engine grim "Grim" yes "monkey4" "Grim Fandango" "zlib"
add_engine monkey4 "Escape from Monkey Island" yes add_engine monkey4 "Escape from Monkey Island" yes
add_engine myst3 "Myst 3" yes

View file

@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine myst3 "Myst 3" yes

View file

@ -1,7 +0,0 @@
// This file is being included by "base/plugins.cpp"
#if PLUGIN_ENABLED_STATIC(GRIM)
LINK_PLUGIN(GRIM)
#endif
#if PLUGIN_ENABLED_STATIC(MYST3)
LINK_PLUGIN(MYST3)
#endif

View file

@ -44,6 +44,9 @@ public:
/** /**
* Load an image from the specified stream * Load an image from the specified stream
*
* loadStream() should implicitly call destroy() to free the memory
* of the last loadStream() call.
* *
* @param stream the input stream * @param stream the input stream
* @return whether loading the file succeeded * @return whether loading the file succeeded
@ -54,6 +57,9 @@ public:
/** /**
* Destroy this decoder's surface and palette * Destroy this decoder's surface and palette
*
* This should be called by a loadStream() implementation as well
* as the destructor.
*/ */
virtual void destroy() = 0; virtual void destroy() = 0;

View file

@ -50,6 +50,8 @@ void TGADecoder::destroy() {
} }
bool TGADecoder::loadStream(Common::SeekableReadStream &tga) { bool TGADecoder::loadStream(Common::SeekableReadStream &tga) {
destroy();
byte imageType, pixelDepth; byte imageType, pixelDepth;
bool success; bool success;
success = readHeader(tga, imageType, pixelDepth); success = readHeader(tga, imageType, pixelDepth);

View file

@ -26,6 +26,7 @@
/* /*
* TGA decoder used in engines: * TGA decoder used in engines:
* - wintermute * - wintermute
* - zvision
*/ */
#ifndef GRAPHICS_DECODERS_TGA_H #ifndef GRAPHICS_DECODERS_TGA_H

View file

@ -26,93 +26,32 @@
namespace Graphics { namespace Graphics {
int Font::getKerningOffset(byte left, byte right) const { int Font::getKerningOffset(uint32 left, uint32 right) const {
return 0; return 0;
} }
int Font::getStringWidth(const Common::String &str) const { namespace {
template<class StringType>
int getStringWidthImpl(const Font &font, const StringType &str) {
int space = 0; int space = 0;
uint last = 0; typename StringType::unsigned_type last = 0;
for (uint i = 0; i < str.size(); ++i) { for (uint i = 0; i < str.size(); ++i) {
const uint cur = str[i]; const typename StringType::unsigned_type cur = str[i];
space += getCharWidth(cur) + getKerningOffset(last, cur); space += font.getCharWidth(cur) + font.getKerningOffset(last, cur);
last = cur; last = cur;
} }
return space; return space;
} }
void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { template<class StringType>
void drawStringImpl(const Font &font, Surface *dst, const StringType &str, int x, int y, int w, uint32 color, TextAlign align, int deltax) {
assert(dst != 0); assert(dst != 0);
const int leftX = x, rightX = x + w; const int leftX = x, rightX = x + w;
uint i; int width = font.getStringWidth(str);
Common::String s = sOld;
int width = getStringWidth(s);
Common::String str;
if (useEllipsis && width > w && s.hasSuffix("...")) {
// String is too wide. Check whether it ends in an ellipsis
// ("..."). If so, remove that and try again!
s.deleteLastChar();
s.deleteLastChar();
s.deleteLastChar();
width = getStringWidth(s);
}
if (useEllipsis && width > w) {
// String is too wide. So we shorten it "intelligently" by
// replacing parts of the string by an ellipsis. There are
// three possibilities for this: replace the start, the end, or
// the middle of the string. What is best really depends on the
// context; but unless we want to make this configurable,
// replacing the middle seems to be a good compromise.
const int ellipsisWidth = getStringWidth("...");
// SLOW algorithm to remove enough of the middle. But it is good enough
// for now.
const int halfWidth = (w - ellipsisWidth) / 2;
int w2 = 0;
uint last = 0;
for (i = 0; i < s.size(); ++i) {
const uint cur = s[i];
int charWidth = getCharWidth(cur) + getKerningOffset(last, cur);
if (w2 + charWidth > halfWidth)
break;
last = cur;
w2 += charWidth;
str += cur;
}
// At this point we know that the first 'i' chars are together 'w2'
// pixels wide. We took the first i-1, and add "..." to them.
str += "...";
last = '.';
// The original string is width wide. Of those we already skipped past
// w2 pixels, which means (width - w2) remain.
// The new str is (w2+ellipsisWidth) wide, so we can accommodate about
// (w - (w2+ellipsisWidth)) more pixels.
// Thus we skip ((width - w2) - (w - (w2+ellipsisWidth))) =
// (width + ellipsisWidth - w)
int skip = width + ellipsisWidth - w;
for (; i < s.size() && skip > 0; ++i) {
const uint cur = s[i];
skip -= getCharWidth(cur) + getKerningOffset(last, cur);
last = cur;
}
// Append the remaining chars, if any
for (; i < s.size(); ++i) {
str += s[i];
}
width = getStringWidth(str);
} else {
str = s;
}
if (align == kTextAlignCenter) if (align == kTextAlignCenter)
x = x + (w - width)/2; x = x + (w - width)/2;
@ -120,29 +59,29 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in
x = x + w - width; x = x + w - width;
x += deltax; x += deltax;
uint last = 0; typename StringType::unsigned_type last = 0;
for (i = 0; i < str.size(); ++i) { for (typename StringType::const_iterator i = str.begin(), end = str.end(); i != end; ++i) {
const uint cur = str[i]; const typename StringType::unsigned_type cur = *i;
x += getKerningOffset(last, cur); x += font.getKerningOffset(last, cur);
last = cur; last = cur;
w = getCharWidth(cur); w = font.getCharWidth(cur);
if (x+w > rightX) if (x+w > rightX)
break; break;
if (x+w >= leftX) if (x+w >= leftX)
drawChar(dst, str[i], x, y, color); font.drawChar(dst, cur, x, y, color);
x += w; x += w;
} }
} }
template<class StringType>
struct WordWrapper { struct WordWrapper {
Common::Array<Common::String> &lines; Common::Array<StringType> &lines;
int actualMaxLineWidth; int actualMaxLineWidth;
WordWrapper(Common::Array<Common::String> &l) : lines(l), actualMaxLineWidth(0) { WordWrapper(Common::Array<StringType> &l) : lines(l), actualMaxLineWidth(0) {
} }
void add(Common::String &line, int &w) { void add(StringType &line, int &w) {
if (actualMaxLineWidth < w) if (actualMaxLineWidth < w)
actualMaxLineWidth = w; actualMaxLineWidth = w;
@ -153,10 +92,11 @@ struct WordWrapper {
} }
}; };
int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const { template<class StringType>
WordWrapper wrapper(lines); int wordWrapTextImpl(const Font &font, const StringType &str, int maxWidth, Common::Array<StringType> &lines) {
Common::String line; WordWrapper<StringType> wrapper(lines);
Common::String tmpStr; StringType line;
StringType tmpStr;
int lineWidth = 0; int lineWidth = 0;
int tmpWidth = 0; int tmpWidth = 0;
@ -173,10 +113,10 @@ int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Co
// of a line. If we encounter such a word, we have to wrap it over multiple // of a line. If we encounter such a word, we have to wrap it over multiple
// lines. // lines.
uint last = 0; typename StringType::unsigned_type last = 0;
for (Common::String::const_iterator x = str.begin(); x != str.end(); ++x) { for (typename StringType::const_iterator x = str.begin(); x != str.end(); ++x) {
const byte c = *x; const typename StringType::unsigned_type c = *x;
const int w = getCharWidth(c) + getKerningOffset(last, c); const int w = font.getCharWidth(c) + font.getKerningOffset(last, c);
last = c; last = c;
const bool wouldExceedWidth = (lineWidth + tmpWidth + w > maxWidth); const bool wouldExceedWidth = (lineWidth + tmpWidth + w > maxWidth);
@ -212,7 +152,7 @@ int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Co
tmpStr.deleteChar(0); tmpStr.deleteChar(0);
// This is not very fast, but it is the simplest way to // This is not very fast, but it is the simplest way to
// assure we do not mess something up because of kerning. // assure we do not mess something up because of kerning.
tmpWidth = getStringWidth(tmpStr); tmpWidth = font.getStringWidth(tmpStr);
} }
} else { } else {
wrapper.add(tmpStr, tmpWidth); wrapper.add(tmpStr, tmpWidth);
@ -232,5 +172,98 @@ int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Co
return wrapper.actualMaxLineWidth; return wrapper.actualMaxLineWidth;
} }
} // End of anonymous namespace
int Font::getStringWidth(const Common::String &str) const {
return getStringWidthImpl(*this, str);
}
int Font::getStringWidth(const Common::U32String &str) const {
return getStringWidthImpl(*this, str);
}
void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
Common::String s = sOld;
int width = getStringWidth(s);
Common::String str;
if (useEllipsis && width > w && s.hasSuffix("...")) {
// String is too wide. Check whether it ends in an ellipsis
// ("..."). If so, remove that and try again!
s.deleteLastChar();
s.deleteLastChar();
s.deleteLastChar();
width = getStringWidth(s);
}
if (useEllipsis && width > w) {
// String is too wide. So we shorten it "intelligently" by
// replacing parts of the string by an ellipsis. There are
// three possibilities for this: replace the start, the end, or
// the middle of the string. What is best really depends on the
// context; but unless we want to make this configurable,
// replacing the middle seems to be a good compromise.
const int ellipsisWidth = getStringWidth("...");
// SLOW algorithm to remove enough of the middle. But it is good enough
// for now.
const int halfWidth = (w - ellipsisWidth) / 2;
int w2 = 0;
Common::String::unsigned_type last = 0;
uint i;
for (i = 0; i < s.size(); ++i) {
const Common::String::unsigned_type cur = s[i];
int charWidth = getCharWidth(cur) + getKerningOffset(last, cur);
if (w2 + charWidth > halfWidth)
break;
last = cur;
w2 += charWidth;
str += cur;
}
// At this point we know that the first 'i' chars are together 'w2'
// pixels wide. We took the first i-1, and add "..." to them.
str += "...";
last = '.';
// The original string is width wide. Of those we already skipped past
// w2 pixels, which means (width - w2) remain.
// The new str is (w2+ellipsisWidth) wide, so we can accommodate about
// (w - (w2+ellipsisWidth)) more pixels.
// Thus we skip ((width - w2) - (w - (w2+ellipsisWidth))) =
// (width + ellipsisWidth - w)
int skip = width + ellipsisWidth - w;
for (; i < s.size() && skip > 0; ++i) {
const Common::String::unsigned_type cur = s[i];
skip -= getCharWidth(cur) + getKerningOffset(last, cur);
last = cur;
}
// Append the remaining chars, if any
for (; i < s.size(); ++i) {
str += s[i];
}
width = getStringWidth(str);
} else {
str = s;
}
drawStringImpl(*this, dst, str, x, y, w, color, align, deltax);
}
void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align) const {
drawStringImpl(*this, dst, str, x, y, w, color, align, 0);
}
int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const {
return wordWrapTextImpl(*this, str, maxWidth, lines);
}
int Font::wordWrapText(const Common::U32String &str, int maxWidth, Common::Array<Common::U32String> &lines) const {
return wordWrapTextImpl(*this, str, maxWidth, lines);
}
} // End of namespace Graphics } // End of namespace Graphics

View file

@ -23,6 +23,7 @@
#define GRAPHICS_FONT_H #define GRAPHICS_FONT_H
#include "common/str.h" #include "common/str.h"
#include "common/ustr.h"
namespace Common { namespace Common {
template<class T> class Array; template<class T> class Array;
@ -70,7 +71,7 @@ public:
* @param chr The character to query the width of. * @param chr The character to query the width of.
* @return The character's width. * @return The character's width.
*/ */
virtual int getCharWidth(byte chr) const = 0; virtual int getCharWidth(uint32 chr) const = 0;
/** /**
* Query the kerning offset between two characters. * Query the kerning offset between two characters.
@ -79,7 +80,7 @@ public:
* @param right The right character. May be 0. * @param right The right character. May be 0.
* @return The horizontal displacement. * @return The horizontal displacement.
*/ */
virtual int getKerningOffset(byte left, byte right) const; virtual int getKerningOffset(uint32 left, uint32 right) const;
/** /**
* Draw a character at a specific point on a surface. * Draw a character at a specific point on a surface.
@ -96,15 +97,17 @@ public:
* @param y The y coordinate where to draw the character. * @param y The y coordinate where to draw the character.
* @param color The color of the character. * @param color The color of the character.
*/ */
virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const = 0; virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const = 0;
// TODO: Add doxygen comments to this // TODO: Add doxygen comments to this
void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft) const;
/** /**
* Compute and return the width the string str has when rendered using this font. * Compute and return the width the string str has when rendered using this font.
*/ */
int getStringWidth(const Common::String &str) const; int getStringWidth(const Common::String &str) const;
int getStringWidth(const Common::U32String &str) const;
/** /**
* Take a text (which may contain newline characters) and word wrap it so that * Take a text (which may contain newline characters) and word wrap it so that
@ -120,6 +123,7 @@ public:
* @return the maximal width of any of the lines added to lines * @return the maximal width of any of the lines added to lines
*/ */
int wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const; int wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const;
int wordWrapText(const Common::U32String &str, int maxWidth, Common::Array<Common::U32String> &lines) const;
}; };
} // End of namespace Graphics } // End of namespace Graphics

View file

@ -51,7 +51,7 @@ int BdfFont::getMaxCharWidth() const {
return _data.maxAdvance; return _data.maxAdvance;
} }
int BdfFont::getCharWidth(byte chr) const { int BdfFont::getCharWidth(uint32 chr) const {
// In case all font have the same advance value, we use the maximum. // In case all font have the same advance value, we use the maximum.
if (!_data.advances) if (!_data.advances)
return _data.maxAdvance; return _data.maxAdvance;
@ -85,9 +85,9 @@ void drawCharIntern(byte *ptr, uint pitch, const byte *src, int h, int width, in
} }
} }
int BdfFont::mapToIndex(byte ch) const { int BdfFont::mapToIndex(uint32 ch) const {
// Check whether the character is included // Check whether the character is included
if (_data.firstCharacter <= ch && ch <= _data.firstCharacter + _data.numCharacters) { if (_data.firstCharacter <= (int)ch && (int)ch <= _data.firstCharacter + _data.numCharacters) {
if (_data.bitmaps[ch - _data.firstCharacter]) if (_data.bitmaps[ch - _data.firstCharacter])
return ch - _data.firstCharacter; return ch - _data.firstCharacter;
} }
@ -95,7 +95,7 @@ int BdfFont::mapToIndex(byte ch) const {
return _data.defaultCharacter - _data.firstCharacter; return _data.defaultCharacter - _data.firstCharacter;
} }
void BdfFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const uint32 color) const { void BdfFont::drawChar(Surface *dst, uint32 chr, const int tx, const int ty, const uint32 color) const {
assert(dst != 0); assert(dst != 0);
// TODO: Where is the relation between the max advance being smaller or // TODO: Where is the relation between the max advance being smaller or

View file

@ -61,14 +61,14 @@ public:
virtual int getFontHeight() const; virtual int getFontHeight() const;
virtual int getMaxCharWidth() const; virtual int getMaxCharWidth() const;
virtual int getCharWidth(byte chr) const; virtual int getCharWidth(uint32 chr) const;
virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const; virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
static BdfFont *loadFont(Common::SeekableReadStream &stream); static BdfFont *loadFont(Common::SeekableReadStream &stream);
static bool cacheFontData(const BdfFont &font, const Common::String &filename); static bool cacheFontData(const BdfFont &font, const Common::String &filename);
static BdfFont *loadFromCache(Common::SeekableReadStream &stream); static BdfFont *loadFromCache(Common::SeekableReadStream &stream);
private: private:
int mapToIndex(byte ch) const; int mapToIndex(uint32 ch) const;
const BdfFontData _data; const BdfFontData _data;
const DisposeAfterUse::Flag _dispose; const DisposeAfterUse::Flag _dispose;

View file

@ -107,11 +107,11 @@ public:
virtual int getMaxCharWidth() const; virtual int getMaxCharWidth() const;
virtual int getCharWidth(byte chr) const; virtual int getCharWidth(uint32 chr) const;
virtual int getKerningOffset(byte left, byte right) const; virtual int getKerningOffset(uint32 left, uint32 right) const;
virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const; virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
private: private:
bool _initialized; bool _initialized;
FT_Face _face; FT_Face _face;
@ -126,13 +126,14 @@ private:
Surface image; Surface image;
int xOffset, yOffset; int xOffset, yOffset;
int advance; int advance;
FT_UInt slot;
}; };
bool cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr); bool cacheGlyph(Glyph &glyph, uint32 chr) const;
typedef Common::HashMap<byte, Glyph> GlyphCache; typedef Common::HashMap<uint32, Glyph> GlyphCache;
GlyphCache _glyphs; mutable GlyphCache _glyphs;
bool _allowLateCaching;
FT_UInt _glyphSlots[256]; void assureCached(uint32 chr) const;
bool _monochrome; bool _monochrome;
bool _hasKerning; bool _hasKerning;
@ -140,7 +141,7 @@ private:
TTFFont::TTFFont() TTFFont::TTFFont()
: _initialized(false), _face(), _ttfFile(0), _size(0), _width(0), _height(0), _ascent(0), : _initialized(false), _face(), _ttfFile(0), _size(0), _width(0), _height(0), _ascent(0),
_descent(0), _glyphs(), _glyphSlots(), _monochrome(false), _hasKerning(false) { _descent(0), _glyphs(), _monochrome(false), _hasKerning(false), _allowLateCaching(false) {
} }
TTFFont::~TTFFont() { TTFFont::~TTFFont() {
@ -212,19 +213,26 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, bool
_height = _ascent - _descent + 1; _height = _ascent - _descent + 1;
if (!mapping) { if (!mapping) {
// Allow loading of all unicode characters.
_allowLateCaching = true;
// Load all ISO-8859-1 characters. // Load all ISO-8859-1 characters.
for (uint i = 0; i < 256; ++i) { for (uint i = 0; i < 256; ++i) {
if (!cacheGlyph(_glyphs[i], _glyphSlots[i], i)) if (!cacheGlyph(_glyphs[i], i)) {
_glyphSlots[i] = 0; _glyphs.erase(i);
}
} }
} else { } else {
// We have a fixed map of characters do not load more later.
_allowLateCaching = false;
for (uint i = 0; i < 256; ++i) { for (uint i = 0; i < 256; ++i) {
const uint32 unicode = mapping[i] & 0x7FFFFFFF; const uint32 unicode = mapping[i] & 0x7FFFFFFF;
const bool isRequired = (mapping[i] & 0x80000000) != 0; const bool isRequired = (mapping[i] & 0x80000000) != 0;
// Check whether loading an important glyph fails and error out if // Check whether loading an important glyph fails and error out if
// that is the case. // that is the case.
if (!cacheGlyph(_glyphs[i], _glyphSlots[i], unicode)) { if (!cacheGlyph(_glyphs[i], unicode)) {
_glyphSlots[i] = 0; _glyphs.erase(i);
if (isRequired) if (isRequired)
return false; return false;
} }
@ -243,7 +251,8 @@ int TTFFont::getMaxCharWidth() const {
return _width; return _width;
} }
int TTFFont::getCharWidth(byte chr) const { int TTFFont::getCharWidth(uint32 chr) const {
assureCached(chr);
GlyphCache::const_iterator glyphEntry = _glyphs.find(chr); GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
if (glyphEntry == _glyphs.end()) if (glyphEntry == _glyphs.end())
return 0; return 0;
@ -251,12 +260,29 @@ int TTFFont::getCharWidth(byte chr) const {
return glyphEntry->_value.advance; return glyphEntry->_value.advance;
} }
int TTFFont::getKerningOffset(byte left, byte right) const { int TTFFont::getKerningOffset(uint32 left, uint32 right) const {
if (!_hasKerning) if (!_hasKerning)
return 0; return 0;
FT_UInt leftGlyph = _glyphSlots[left]; assureCached(left);
FT_UInt rightGlyph = _glyphSlots[right]; assureCached(right);
FT_UInt leftGlyph, rightGlyph;
GlyphCache::const_iterator glyphEntry;
glyphEntry = _glyphs.find(left);
if (glyphEntry != _glyphs.end()) {
leftGlyph = glyphEntry->_value.slot;
} else {
return 0;
}
glyphEntry = _glyphs.find(right);
if (glyphEntry != _glyphs.end()) {
rightGlyph = glyphEntry->_value.slot;
} else {
return 0;
}
if (!leftGlyph || !rightGlyph) if (!leftGlyph || !rightGlyph)
return 0; return 0;
@ -304,7 +330,8 @@ void renderGlyph(uint8 *dstPos, const int dstPitch, const uint8 *srcPos, const i
} // End of anonymous namespace } // End of anonymous namespace
void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const { void TTFFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
assureCached(chr);
GlyphCache::const_iterator glyphEntry = _glyphs.find(chr); GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
if (glyphEntry == _glyphs.end()) if (glyphEntry == _glyphs.end())
return; return;
@ -376,11 +403,13 @@ void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const
} }
} }
bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) { bool TTFFont::cacheGlyph(Glyph &glyph, uint32 chr) const {
slot = FT_Get_Char_Index(_face, chr); FT_UInt slot = FT_Get_Char_Index(_face, chr);
if (!slot) if (!slot)
return false; return false;
glyph.slot = slot;
// We use the light target and render mode to improve the looks of the // We use the light target and render mode to improve the looks of the
// glyphs. It is most noticable in FreeSansBold.ttf, where otherwise the // glyphs. It is most noticable in FreeSansBold.ttf, where otherwise the
// 't' glyph looks like it is cut off on the right side. // 't' glyph looks like it is cut off on the right side.
@ -456,12 +485,24 @@ bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) {
default: default:
warning("TTFFont::cacheGlyph: Unsupported pixel mode %d", bitmap.pixel_mode); warning("TTFFont::cacheGlyph: Unsupported pixel mode %d", bitmap.pixel_mode);
glyph.image.free();
return false; return false;
} }
return true; return true;
} }
void TTFFont::assureCached(uint32 chr) const {
if (!chr || !_allowLateCaching || _glyphs.contains(chr)) {
return;
}
Glyph newGlyph;
if (cacheGlyph(newGlyph, chr)) {
_glyphs[chr] = newGlyph;
}
}
Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping) { Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping) {
TTFFont *font = new TTFFont(); TTFFont *font = new TTFFont();

View file

@ -133,6 +133,30 @@ const Surface Surface::getSubArea(const Common::Rect &area) const {
return subSurface; return subSurface;
} }
void Surface::copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) {
assert(buffer);
assert(destX >= 0 && destX < w);
assert(destY >= 0 && destY < h);
assert(height > 0 && destY + height <= h);
assert(width > 0 && destX + width <= w);
// Copy buffer data to internal buffer
const byte *src = (const byte *)buffer;
byte *dst = (byte *)getBasePtr(destX, destY);
for (int i = 0; i < height; i++) {
memcpy(dst, src, width * format.bytesPerPixel);
src += srcPitch;
dst += pitch;
}
}
void Surface::copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect) {
assert(srcSurface.format == format);
copyRectToSurface(srcSurface.getBasePtr(subRect.left, subRect.top), srcSurface.pitch, destX, destY, subRect.width(), subRect.height());
}
void Surface::hLine(int x, int y, int x2, uint32 color) { void Surface::hLine(int x, int y, int x2, uint32 color) {
// Clipping // Clipping
if (y < 0 || y >= h) if (y < 0 || y >= h)

View file

@ -208,6 +208,30 @@ public:
*/ */
const Surface getSubArea(const Common::Rect &area) const; const Surface getSubArea(const Common::Rect &area) const;
/**
* Copies a bitmap to the Surface internal buffer. The pixel format
* of buffer must match the pixel format of the Surface.
*
* @param buffer The buffer containing the graphics data source
* @param pitch The pitch of the buffer (number of bytes in a scanline)
* @param destX The x coordinate of the destination rectangle
* @param destY The y coordinate of the destination rectangle
* @param width The width of the destination rectangle
* @param height The height of the destination rectangle
*/
void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height);
/**
* Copies a bitmap to the Surface internal buffer. The pixel format
* of buffer must match the pixel format of the Surface.
*
* @param srcSurface The source of the bitmap data
* @param destX The x coordinate of the destination rectangle
* @param destY The y coordinate of the destination rectangle
* @param subRect The subRect of surface to be blitted
* @return
*/
void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect);
/** /**
* Convert the data to another pixel format. * Convert the data to another pixel format.
* *
@ -310,7 +334,9 @@ public:
*/ */
struct SharedPtrSurfaceDeleter { struct SharedPtrSurfaceDeleter {
void operator()(Surface *ptr) { void operator()(Surface *ptr) {
ptr->free(); if (ptr) {
ptr->free();
}
delete ptr; delete ptr;
} }
}; };

View file

@ -1360,17 +1360,17 @@ bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int
// If there is no entry yet for this color in the palette: Add one // If there is no entry yet for this color in the palette: Add one
if (!colorToIndex.contains(col)) { if (!colorToIndex.contains(col)) {
if (colorsFound >= MAX_CURS_COLORS) {
warning("Cursor contains too many colors (%d, but only %d are allowed)", colorsFound, MAX_CURS_COLORS);
return false;
}
const int index = colorsFound++; const int index = colorsFound++;
colorToIndex[col] = index; colorToIndex[col] = index;
_cursorPal[index * 3 + 0] = r; _cursorPal[index * 3 + 0] = r;
_cursorPal[index * 3 + 1] = g; _cursorPal[index * 3 + 1] = g;
_cursorPal[index * 3 + 2] = b; _cursorPal[index * 3 + 2] = b;
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 // Copy pixel from the 16 bit source surface to the 8bit target surface

View file

@ -82,8 +82,6 @@ ConsoleDialog::ConsoleDialog(float widthPercent, float heightPercent)
_historyIndex = 0; _historyIndex = 0;
_historyLine = 0; _historyLine = 0;
_historySize = 0; _historySize = 0;
for (int i = 0; i < kHistorySize; i++)
_history[i][0] = '\0';
// Display greetings & prompt // Display greetings & prompt
print(gScummVMFullVersion); print(gScummVMFullVersion);
@ -274,24 +272,19 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
if (len > 0) { if (len > 0) {
// We have to allocate the string buffer with new, since VC++ sadly does not Common::String str;
// comply to the C++ standard, so we can't use a dynamic sized stack array.
char *str = new char[len + 1];
// Copy the user input to str // Copy the user input to str
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
str[i] = buffer(_promptStartPos + i); str.insertChar(buffer(_promptStartPos + i), i);
str[len] = '\0';
// Add the input to the history // Add the input to the history
addToHistory(str); addToHistory(str);
// Pass it to the input callback, if any // Pass it to the input callback, if any
if (_callbackProc) if (_callbackProc)
keepRunning = (*_callbackProc)(this, str, _callbackRefCon); keepRunning = (*_callbackProc)(this, str.c_str(), _callbackRefCon);
// Get rid of the string buffer
delete[] str;
} }
print(PROMPT); print(PROMPT);
@ -575,8 +568,8 @@ void ConsoleDialog::killLastWord() {
} }
} }
void ConsoleDialog::addToHistory(const char *str) { void ConsoleDialog::addToHistory(const Common::String &str) {
strcpy(_history[_historyIndex], str); _history[_historyIndex] = str;
_historyIndex = (_historyIndex + 1) % kHistorySize; _historyIndex = (_historyIndex + 1) % kHistorySize;
_historyLine = 0; _historyLine = 0;
if (_historySize < kHistorySize) if (_historySize < kHistorySize)
@ -590,8 +583,7 @@ void ConsoleDialog::historyScroll(int direction) {
if (_historyLine == 0 && direction > 0) { if (_historyLine == 0 && direction > 0) {
int i; int i;
for (i = 0; i < _promptEndPos - _promptStartPos; i++) for (i = 0; i < _promptEndPos - _promptStartPos; i++)
_history[_historyIndex][i] = buffer(_promptStartPos + i); _history[_historyIndex].insertChar(buffer(_promptStartPos + i), i);
_history[_historyIndex][i] = '\0';
} }
// Advance to the next line in the history // Advance to the next line in the history
@ -617,7 +609,8 @@ void ConsoleDialog::historyScroll(int direction) {
idx = (_historyIndex - _historyLine + _historySize) % _historySize; idx = (_historyIndex - _historyLine + _historySize) % _historySize;
else else
idx = _historyIndex; idx = _historyIndex;
for (int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++) int length = _history[idx].size();
for (int i = 0; i < length; i++)
printCharIntern(_history[idx][i]); printCharIntern(_history[idx][i]);
_promptEndPos = _currentPos; _promptEndPos = _currentPos;

View file

@ -23,6 +23,7 @@
#define CONSOLE_DIALOG_H #define CONSOLE_DIALOG_H
#include "gui/dialog.h" #include "gui/dialog.h"
#include "common/str.h"
namespace GUI { namespace GUI {
@ -69,7 +70,6 @@ protected:
enum { enum {
kBufferSize = 32768, kBufferSize = 32768,
kCharsPerLine = 128, kCharsPerLine = 128,
kLineBufferSize = 256,
kHistorySize = 20 kHistorySize = 20
}; };
@ -112,7 +112,7 @@ protected:
CompletionCallbackProc _completionCallbackProc; CompletionCallbackProc _completionCallbackProc;
void *_completionCallbackRefCon; void *_completionCallbackRefCon;
char _history[kHistorySize][kLineBufferSize]; Common::String _history[kHistorySize];
int _historySize; int _historySize;
int _historyIndex; int _historyIndex;
int _historyLine; int _historyLine;
@ -184,7 +184,7 @@ protected:
void killLastWord(); void killLastWord();
// History // History
void addToHistory(const char *str); void addToHistory(const Common::String &str);
void historyScroll(int direction); void historyScroll(int direction);
}; };

View file

@ -309,6 +309,19 @@ void GuiManager::runLoop() {
Common::Event event; Common::Event event;
while (eventMan->pollEvent(event)) { while (eventMan->pollEvent(event)) {
// We will need to check whether the screen changed while polling
// for an event here. While we do send EVENT_SCREEN_CHANGED
// whenever this happens we still cannot be sure that we get such
// an event immediately. For example, we might have an mouse move
// event queued before an screen changed event. In some rare cases
// this would make the GUI redraw (with the code a few lines
// below) when it is not yet updated for new overlay dimensions.
// As a result ScummVM would crash because it tries to copy data
// outside the actual overlay screen.
if (event.type != Common::EVENT_SCREEN_CHANGED) {
checkScreenChange();
}
// The top dialog can change during the event loop. In that case, flush all the // The top dialog can change during the event loop. In that case, flush all the
// dialog-related events since they were probably generated while the old dialog // dialog-related events since they were probably generated while the old dialog
// was still visible, and therefore not intended for the new one. // was still visible, and therefore not intended for the new one.

View file

@ -752,7 +752,8 @@ bool PredictiveDialog::matchWord() {
char tmp[kMaxLineLen]; char tmp[kMaxLineLen];
strncpy(tmp, _unitedDict.dictLine[line], kMaxLineLen); strncpy(tmp, _unitedDict.dictLine[line], kMaxLineLen);
tmp[kMaxLineLen - 1] = 0; tmp[kMaxLineLen - 1] = 0;
char *tok = strtok(tmp, " "); char *tok;
strtok(tmp, " ");
tok = strtok(NULL, " "); tok = strtok(NULL, " ");
_currentWord = Common::String(tok, _currentCode.size()); _currentWord = Common::String(tok, _currentCode.size());
return true; return true;

View file

@ -261,23 +261,45 @@ void EditableWidget::drawCaret(bool erase) {
int x = editRect.left; int x = editRect.left;
int y = editRect.top; int y = editRect.top;
x += getCaretOffset(); const int caretOffset = getCaretOffset();
x += caretOffset;
if (y < 0 || y + editRect.height() - 2 >= _h) if (y < 0 || y + editRect.height() > _h)
return; return;
x += getAbsX(); x += getAbsX();
y += getAbsY(); y += getAbsY();
g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + editRect.height() - 2), erase); g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + editRect.height()), erase);
if (erase) { if (erase) {
GUI::EditableWidget::String character;
int width;
if ((uint)_caretPos < _editString.size()) { if ((uint)_caretPos < _editString.size()) {
GUI::EditableWidget::String chr(_editString[_caretPos]); const byte chr = _editString[_caretPos];
int chrWidth = g_gui.getCharWidth(_editString[_caretPos], _font); width = g_gui.getCharWidth(chr, _font);
character = chr;
const uint last = (_caretPos > 0) ? _editString[_caretPos - 1] : 0; const uint last = (_caretPos > 0) ? _editString[_caretPos - 1] : 0;
x += g_gui.getKerningOffset(last, _editString[_caretPos], _font); x += g_gui.getKerningOffset(last, chr, _font);
g_gui.theme()->drawText(Common::Rect(x, y, x + chrWidth, y + editRect.height() - 2), chr, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea); } else {
// We draw a fake space here to assure that removing the caret
// does not result in color glitches in case the edit rect is
// drawn with an inversion.
width = g_gui.getCharWidth(' ', _font);
character = " ";
}
// TODO: Right now we manually prevent text from being drawn outside
// the edit area here. We might want to consider to use
// setTextDrawableArea for this. However, it seems that only
// EditTextWidget uses that but not ListWidget. Thus, one should check
// whether we can unify the drawing in the text area first to avoid
// possible glitches due to different methods used.
width = MIN(editRect.width() - caretOffset, width);
if (width > 0) {
g_gui.theme()->drawText(Common::Rect(x, y, x + width, y + editRect.height()), character, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea);
} }
} }

View file

@ -78,6 +78,11 @@ protected:
virtual void startEditMode() = 0; virtual void startEditMode() = 0;
virtual void endEditMode() = 0; virtual void endEditMode() = 0;
virtual void abortEditMode() = 0; virtual void abortEditMode() = 0;
/**
* The area where text input is being made. This should exactly match the
* rect with which the actual edit string is drawn otherwise nasty
* graphics glitches when redrawing the caret can occur.
*/
virtual Common::Rect getEditRect() const = 0; virtual Common::Rect getEditRect() const = 0;
virtual int getCaretOffset() const; virtual int getCaretOffset() const;
void drawCaret(bool erase); void drawCaret(bool erase);

View file

@ -101,7 +101,7 @@ void EditTextWidget::drawWidget() {
} }
Common::Rect EditTextWidget::getEditRect() const { Common::Rect EditTextWidget::getEditRect() const {
Common::Rect r(2 + _leftPadding, 2, _w - 2 - _leftPadding - _rightPadding, _h - 1); Common::Rect r(2 + _leftPadding, 2, _w - 2 - _leftPadding - _rightPadding, _h);
return r; return r;
} }

View file

@ -541,7 +541,7 @@ void ListWidget::drawWidget() {
} }
Common::Rect ListWidget::getEditRect() const { Common::Rect ListWidget::getEditRect() const {
Common::Rect r(_hlLeftPadding, 0, _w - _hlLeftPadding - _hlRightPadding, kLineHeight - 1); Common::Rect r(_hlLeftPadding, 0, _w - _hlLeftPadding - _hlRightPadding, kLineHeight - 2);
const int offset = (_selectedItem - _currentPos) * kLineHeight + _topPadding; const int offset = (_selectedItem - _currentPos) * kLineHeight + _topPadding;
r.top += offset; r.top += offset;
r.bottom += offset; r.bottom += offset;

View file

@ -273,15 +273,15 @@ else ifeq "$(CUR_BRANCH)" ""
$(error You must be on a release branch) $(error You must be on a release branch)
endif endif
@echo Creating Code::Blocks project files... @echo Creating Code::Blocks project files...
@cd $(srcdir)/dists/codeblocks && ../../devtools/create_project/create_project ../.. --codeblocks >/dev/null && git add -f *.workspace *.cbp @cd $(srcdir)/dists/codeblocks && ../../devtools/create_project/create_project ../.. --codeblocks >/dev/null && git add -f engines/plugins_table.h *.workspace *.cbp
@echo Creating MSVC8 project files... @echo Creating MSVC8 project files...
@cd $(srcdir)/dists/msvc8 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 8 >/dev/null && git add -f *.sln *.vcproj *.vsprops @cd $(srcdir)/dists/msvc8 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 8 >/dev/null && git add -f engines/plugins_table.h *.sln *.vcproj *.vsprops
@echo Creating MSVC9 project files... @echo Creating MSVC9 project files...
@cd $(srcdir)/dists/msvc9 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 9 >/dev/null && git add -f *.sln *.vcproj *.vsprops @cd $(srcdir)/dists/msvc9 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 9 >/dev/null && git add -f engines/plugins_table.h *.sln *.vcproj *.vsprops
@echo Creating MSVC10 project files... @echo Creating MSVC10 project files...
@cd $(srcdir)/dists/msvc10 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 10 >/dev/null && git add -f *.sln *.vcxproj *.vcxproj.filters *.props @cd $(srcdir)/dists/msvc10 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 10 >/dev/null && git add -f engines/plugins_table.h *.sln *.vcxproj *.vcxproj.filters *.props
@echo Creating MSVC11 project files... @echo Creating MSVC11 project files...
@cd $(srcdir)/dists/msvc11 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 11 >/dev/null && git add -f *.sln *.vcxproj *.vcxproj.filters *.props @cd $(srcdir)/dists/msvc11 && ../../devtools/create_project/create_project ../.. --msvc --msvc-version 11 >/dev/null && git add -f engines/plugins_table.h *.sln *.vcxproj *.vcxproj.filters *.props
@echo @echo
@echo All is done. @echo All is done.
@echo Now run @echo Now run