ALL: synced with scummvm
This commit is contained in:
parent
0511571850
commit
b22d441a00
61 changed files with 1401 additions and 357 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -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
|
||||||
*~
|
*~
|
||||||
.#*
|
.#*
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 },
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
329
common/ustr.cpp
Normal 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
194
common/ustr.h
Normal 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
|
|
@ -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
72
configure
vendored
|
@ -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
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
68
devtools/create_project/scripts/scummvm.natvis
Normal file
68
devtools/create_project/scripts/scummvm.natvis
Normal 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<*>">
|
||||||
|
<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<*,*,*,*>">
|
||||||
|
<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] && _storage[$i] != (Common::HashMap<$T1,$T2,$T3,$T4>::Node *)1">*_storage[$i]</ValueNode>
|
||||||
|
</IndexListItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="Common::List<*>">
|
||||||
|
<DisplayString Condition="&_anchor == _anchor._next">{{ empty }}</DisplayString>
|
||||||
|
<DisplayString Condition="&_anchor != _anchor._next">{{ non-empty }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<LinkedListItems Condition="&_anchor != _anchor._next">
|
||||||
|
<HeadPointer>_anchor._next</HeadPointer>
|
||||||
|
<NextPointer>_next</NextPointer>
|
||||||
|
<ValueNode>((Common::ListInternal::Node<$T1>*)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>
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
# á -> a
|
# á -> a
|
||||||
# é -> e
|
# é -> e
|
||||||
|
# í -> i
|
||||||
# ì -> i
|
# ì -> i
|
||||||
# ó -> o
|
# ó -> o
|
||||||
# ø -> o
|
# ø -> o
|
||||||
|
@ -72,8 +73,10 @@ sub html_entities_to_ascii {
|
||||||
# ł -> l
|
# ł -> l
|
||||||
# ś -> s
|
# ś -> s
|
||||||
# Š -> S
|
# Š -> S
|
||||||
|
# ñ -> n
|
||||||
$text =~ s/á/a/g;
|
$text =~ s/á/a/g;
|
||||||
$text =~ s/é/e/g;
|
$text =~ s/é/e/g;
|
||||||
|
$text =~ s/í/i/g;
|
||||||
$text =~ s/ì/i/g;
|
$text =~ s/ì/i/g;
|
||||||
$text =~ s/ó/o/g;
|
$text =~ s/ó/o/g;
|
||||||
$text =~ s/ø/o/g;
|
$text =~ s/ø/o/g;
|
||||||
|
@ -81,6 +84,7 @@ sub html_entities_to_ascii {
|
||||||
$text =~ s/ś/s/g;
|
$text =~ s/ś/s/g;
|
||||||
$text =~ s/Š/S/g;
|
$text =~ s/Š/S/g;
|
||||||
$text =~ s/å/aa/g;
|
$text =~ s/å/aa/g;
|
||||||
|
$text =~ s/ñ/n/g;
|
||||||
|
|
||||||
$text =~ s/ä/a/g;
|
$text =~ s/ä/a/g;
|
||||||
$text =~ s/ë/e/g;
|
$text =~ s/ë/e/g;
|
||||||
|
@ -101,6 +105,7 @@ sub html_entities_to_cpp {
|
||||||
# The numerical values are octal!
|
# The numerical values are octal!
|
||||||
$text =~ s/á/\\341/g;
|
$text =~ s/á/\\341/g;
|
||||||
$text =~ s/é/\\351/g;
|
$text =~ s/é/\\351/g;
|
||||||
|
$text =~ s/í/\\355/g;
|
||||||
$text =~ s/ì/\\354/g;
|
$text =~ s/ì/\\354/g;
|
||||||
$text =~ s/ó/\\363/g;
|
$text =~ s/ó/\\363/g;
|
||||||
$text =~ s/ø/\\370/g;
|
$text =~ s/ø/\\370/g;
|
||||||
|
@ -108,6 +113,7 @@ sub html_entities_to_cpp {
|
||||||
$text =~ s/ś/s/g;
|
$text =~ s/ś/s/g;
|
||||||
$text =~ s/Š/S/g;
|
$text =~ s/Š/S/g;
|
||||||
$text =~ s/å/\\345/g;
|
$text =~ s/å/\\345/g;
|
||||||
|
$text =~ s/ñ/\\361/g;
|
||||||
|
|
||||||
$text =~ s/ä/\\344/g;
|
$text =~ s/ä/\\344/g;
|
||||||
$text =~ s/ë/\\353/g;
|
$text =~ s/ë/\\353/g;
|
||||||
|
@ -126,6 +132,7 @@ sub html_entities_to_rtf {
|
||||||
|
|
||||||
$text =~ s/á/\\'87/g;
|
$text =~ s/á/\\'87/g;
|
||||||
$text =~ s/é/\\'8e/g;
|
$text =~ s/é/\\'8e/g;
|
||||||
|
$text =~ s/í/\\'92/g;
|
||||||
$text =~ s/ì/\\'93/g;
|
$text =~ s/ì/\\'93/g;
|
||||||
$text =~ s/ó/\\'97/g;
|
$text =~ s/ó/\\'97/g;
|
||||||
$text =~ s/ø/\\'bf/g;
|
$text =~ s/ø/\\'bf/g;
|
||||||
|
@ -135,6 +142,8 @@ sub html_entities_to_rtf {
|
||||||
$text =~ s/Š/\\uc0\\u540 /g;
|
$text =~ s/Š/\\uc0\\u540 /g;
|
||||||
|
|
||||||
# Back to hex numbers
|
# Back to hex numbers
|
||||||
|
$text =~ s/ñ/\\'96/g;
|
||||||
|
|
||||||
$text =~ s/ä/\\'8a/g;
|
$text =~ s/ä/\\'8a/g;
|
||||||
$text =~ s/ë/\\'eb/g;
|
$text =~ s/ë/\\'eb/g;
|
||||||
$text =~ s/ö/\\'9a/g;
|
$text =~ s/ö/\\'9a/g;
|
||||||
|
@ -151,12 +160,14 @@ sub html_entities_to_tex {
|
||||||
|
|
||||||
$text =~ s/á/\\'a/g;
|
$text =~ s/á/\\'a/g;
|
||||||
$text =~ s/é/\\'e/g;
|
$text =~ s/é/\\'e/g;
|
||||||
|
$text =~ s/í/\\'i/g;
|
||||||
$text =~ s/ì/\\`\\i/g;
|
$text =~ s/ì/\\`\\i/g;
|
||||||
$text =~ s/ó/\\'o/g;
|
$text =~ s/ó/\\'o/g;
|
||||||
$text =~ s/ø/{\\o}/g;
|
$text =~ s/ø/{\\o}/g;
|
||||||
$text =~ s/å/\\aa /g;
|
$text =~ s/å/\\aa /g;
|
||||||
$text =~ s/ł/{\\l}/g;
|
$text =~ s/ł/{\\l}/g;
|
||||||
$text =~ s/Š/{\\v S}/g;
|
$text =~ s/Š/{\\v S}/g;
|
||||||
|
$text =~ s/ñ/\\˜n/g;
|
||||||
|
|
||||||
$text =~ s/ä/\\"a/g;
|
$text =~ s/ä/\\"a/g;
|
||||||
$text =~ s/ö/\\"o/g;
|
$text =~ s/ö/\\"o/g;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
3
engines/myst3/configure.engine
Normal file
3
engines/myst3/configure.engine
Normal 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
|
|
@ -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
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
10
ports.mk
10
ports.mk
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue