diff --git a/.gitignore b/.gitignore index c7b6023e6e8..ea7953fd390 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,7 @@ project.xcworkspace /plugins +/engines/detection_table.h /engines/plugins_table.h /engines/engines.mk diff --git a/Makefile b/Makefile index 0b022e33c42..8e2631bd116 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,10 @@ DEPDIR := .deps MODULES := MODULE_DIRS := +# All game detection-related object files for engines +DETECT_OBJS := +LOAD_RULES_MK := 1 + # Load the make rules generated by configure -include config.mk diff --git a/Makefile.common b/Makefile.common index 46331ff7933..257cd9e828c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -54,6 +54,38 @@ CPPFLAGS := $(DEFINES) $(INCLUDES) # Include the build instructions for all modules -include $(addprefix $(srcdir)/, $(addsuffix /module.mk,$(MODULES))) +# Store original info +MODULES_ORIG:= $(MODULES) +MODULE_DIRS_ORIG := $(MODULE_DIRS) +KYRARPG_COMMON_OBJ_ORIG := $(KYRARPG_COMMON_OBJ) + +# Skip rules for these files, by resetting the LOAD_RULES_MK +LOAD_RULES_MK := + +# Reset detection objects, which uptill now are filled with only +# enabled engines. +DETECT_OBJS := + +# Include all engine's module files, which populate DETECT_OBJS +-include $(srcdir)/engines/*/module.mk + +# Reset stuff +MODULES := $(MODULES_ORIG) +MODULE := +MODULE_OBJS := +MODULE_DIRS := $(MODULE_DIRS_ORIG) +PLUGIN := +KYRARPG_COMMON_OBJ := $(KYRARPG_COMMON_OBJ_ORIG) + +# Enable-rules again +LOAD_RULES_MK := 1 + +ifneq ($(DETECTION_STATIC), 1) +-include $(srcdir)/engines/detect_modules.mk +else +MODULE_DIRS += $(sort $(dir $(DETECT_OBJS))) +endif + # Depdir information DEPDIRS = $(addsuffix $(DEPDIR),$(MODULE_DIRS)) DEPFILES = @@ -88,7 +120,7 @@ endif endif # The build rule for the ResidualVM executable -$(EXECUTABLE): $(OBJS) +$(EXECUTABLE): $(DETECT_OBJS) $(OBJS) $(QUIET_LINK)$(LD) $(LDFLAGS) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) -o $@ ifdef SPLIT_DWARF @@ -101,7 +133,7 @@ distclean: clean clean-devtools clean: $(RM_REC) $(DEPDIRS) - $(RM) $(OBJS) $(EXECUTABLE) + $(RM) $(OBJS) $(DETECT_OBJS) $(EXECUTABLE) ifdef SPLIT_DWARF $(RM) $(OBJS:.o=.dwo) $(RM) $(EXECUTABLE).dwp diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index a2be54a8878..790e29c64b3 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -2635,6 +2635,14 @@ SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height, return nullptr; } +#if defined(MACOSX) && SDL_VERSION_ATLEAST(2, 0, 10) + // WORKAROUND: Bug #11430: "macOS: blurry content on Retina displays" + // Since SDL 2.0.10, Metal takes priority over OpenGL rendering on macOS, + // but this causes blurriness issues on Retina displays. Just switch + // back to OpenGL for now. + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); +#endif + _renderer = SDL_CreateRenderer(_window->getSDLWindow(), -1, 0); if (!_renderer) { deinitializeRenderer(); diff --git a/base/commandLine.cpp b/base/commandLine.cpp index 52ae2511a66..04ba50191f8 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -335,6 +335,10 @@ void registerDefaults() { ConfMan.registerDefault("gui_browser_show_hidden", false); ConfMan.registerDefault("gui_browser_native", true); + // Specify threshold for scanning directories in the launcher + // If number of game entries in scummvm.ini exceeds the specified + // number, then skip scanning. -1 = scan always + ConfMan.registerDefault("gui_list_max_scan_entries", -1); ConfMan.registerDefault("game", ""); #ifdef USE_FLUIDSYNTH @@ -850,7 +854,7 @@ static void listGames() { const PluginList &plugins = EngineMan.getPlugins(); for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); ++iter) { - const MetaEngine &metaengine = (*iter)->get(); + const MetaEngineStatic &metaengine = (*iter)->get(); PlainGameList list = metaengine.getSupportedGames(); for (PlainGameList::const_iterator v = list.begin(); v != list.end(); ++v) { @@ -866,7 +870,7 @@ static void listEngines() { const PluginList &plugins = EngineMan.getPlugins(); for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); ++iter) { - const MetaEngine &metaEngine = (*iter)->get(); + const MetaEngineStatic &metaEngine = (*iter)->get(); printf("%-15s %s\n", metaEngine.getEngineId(), metaEngine.getName()); } } @@ -933,15 +937,18 @@ static Common::Error listSaves(const Common::String &singleTarget) { // the specified game name, or alternatively whether there is a matching game id. Common::String currentTarget; QualifiedGameDescriptor game; - const Plugin *plugin = nullptr; + + const Plugin *metaEnginePlugin = nullptr; + const Plugin *enginePlugin = nullptr; + if (ConfMan.hasGameDomain(*i)) { // The name is a known target currentTarget = *i; EngineMan.upgradeTargetIfNecessary(*i); - game = EngineMan.findTarget(*i, &plugin); + game = EngineMan.findTarget(*i, &metaEnginePlugin); } else if (game = findGameMatchingName(*i), !game.gameId.empty()) { // The name is a known game id - plugin = EngineMan.findPlugin(game.engineId); + metaEnginePlugin = EngineMan.findPlugin(game.engineId); currentTarget = createTemporaryTarget(game.engineId, game.gameId); } else { return Common::Error(Common::kEnginePluginNotFound, Common::String::format("target '%s'", singleTarget.c_str())); @@ -950,16 +957,27 @@ static Common::Error listSaves(const Common::String &singleTarget) { // If we actually found a domain, we're going to change the domain ConfMan.setActiveDomain(currentTarget); - if (!plugin) { + if (!metaEnginePlugin) { // If the target was specified, treat this as an error, and otherwise skip it. if (!singleTarget.empty()) - return Common::Error(Common::kEnginePluginNotFound, + return Common::Error(Common::kMetaEnginePluginNotFound, Common::String::format("target '%s'", i->c_str())); - printf("Plugin could not be loaded for target '%s'\n", i->c_str()); + printf("MetaEnginePlugin could not be loaded for target '%s'\n", i->c_str()); continue; + } else { + enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + + if (!enginePlugin) { + // If the target was specified, treat this as an error, and otherwise skip it. + if (!singleTarget.empty()) + return Common::Error(Common::kEnginePluginNotFound, + Common::String::format("target '%s'", i->c_str())); + printf("EnginePlugin could not be loaded for target '%s'\n", i->c_str()); + continue; + } } - const MetaEngine &metaEngine = plugin->get(); + const MetaEngine &metaEngine = enginePlugin->get(); Common::String qualifiedGameId = buildQualifiedGameName(game.engineId, game.gameId); if (!metaEngine.hasFeature(MetaEngine::kSupportsListSaves)) { diff --git a/base/internal_plugins.h b/base/internal_plugins.h index 1af16070225..6eb98e747f1 100644 --- a/base/internal_plugins.h +++ b/base/internal_plugins.h @@ -17,3 +17,5 @@ #else #define PLUGIN_ENABLED_DYNAMIC(ID) 0 #endif + +#define PLUGIN_ENABLED(ID) (ENABLE_##ID) diff --git a/base/main.cpp b/base/main.cpp index 01154e60229..b5554e1944a 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -133,7 +133,7 @@ static const Plugin *detectPlugin() { // Query the plugin for the game descriptor printf(" Looking for a plugin supporting this target... %s\n", plugin->getName()); - PlainGameDescriptor game = plugin->get().findGame(gameId.c_str()); + PlainGameDescriptor game = plugin->get().findGame(gameId.c_str()); if (!game.gameId) { warning("'%s' is an invalid game ID for the engine '%s'. Use the --list-games option to list supported game IDs", gameId.c_str(), engineId.c_str()); return 0; @@ -153,6 +153,8 @@ void saveLastLaunchedTarget(const Common::String &target) { // TODO: specify the possible return values here static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common::String &edebuglevels) { + assert(plugin); + // Determine the game data path, for validation and error messages Common::FSNode dir(ConfMan.get("path")); Common::String target = ConfMan.getActiveDomainName(); @@ -179,17 +181,28 @@ static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common err = Common::kPathNotDirectory; } - // Create the game engine - const MetaEngine &metaEngine = plugin->get(); + // Create the game's MetaEngine. + const MetaEngineStatic &metaEngine = plugin->get(); if (err.getCode() == Common::kNoError) { // Set default values for all of the custom engine options // Apparently some engines query them in their constructor, thus we // need to set this up before instance creation. metaEngine.registerDefaultSettings(target); - - err = metaEngine.createInstance(&system, &engine); } + // Right now we have a MetaEngine plugin. We must find the matching engine plugin to + // call createInstance and other connecting functions. + Plugin *enginePluginToLaunchGame = PluginMan.getEngineFromMetaEngine(plugin); + + if (!enginePluginToLaunchGame) { + err = Common::kEnginePluginNotFound; + return err; + } + + // Create the game's MetaEngineConnect. + const MetaEngine &metaEngineConnect = enginePluginToLaunchGame->get(); + err = metaEngineConnect.createInstance(&system, &engine); + // Check for errors if (!engine || err.getCode() != Common::kNoError) { @@ -279,7 +292,7 @@ static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common #endif // USE_TRANSLATION // Initialize any game-specific keymaps - Common::KeymapArray gameKeymaps = metaEngine.initKeymaps(target.c_str()); + Common::KeymapArray gameKeymaps = metaEngineConnect.initKeymaps(target.c_str()); Common::Keymapper *keymapper = system.getEventManager()->getKeymapper(); for (uint i = 0; i < gameKeymaps.size(); i++) { keymapper->addGameKeymap(gameKeymaps[i]); @@ -423,8 +436,10 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { gDebugChannelsOnly = true; + ConfMan.registerDefault("always_run_fallback_detection_extern", true); PluginManager::instance().init(); PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager + PluginManager::instance().loadDetectionPlugin(); // load detection plugin for uncached plugin manager // If we received an invalid music parameter via command line we check this here. // We can't check this before loading the music plugins. @@ -536,12 +551,23 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { EngineMan.upgradeTargetIfNecessary(ConfMan.getActiveDomainName()); - // Try to find a plugin which feels responsible for the specified game. + // Try to find a MetaEnginePlugin which feels responsible for the specified game. const Plugin *plugin = detectPlugin(); if (plugin) { - // Unload all plugins not needed for this game, - // to save memory - PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, plugin); + // Unload all plugins not needed for this game, to save memory + + // Right now, we have a MetaEngine plugin, and we want to unload all except Engine. + // First, get the relevant Engine plugin from MetaEngine. + const Plugin *enginePlugin = PluginMan.getEngineFromMetaEngine(plugin); + + // Then, pass in the pointer to enginePlugin, with the matching type, so our function behaves as-is. + PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, enginePlugin); + +#if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES) + // Unload all MetaEngines not needed for the current engine, if we're using uncached plugins + // to save extra memory. + PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_METAENGINE, plugin); +#endif #ifdef ENABLE_EVENTRECORDER Common::String recordMode = ConfMan.get("record_mode"); @@ -582,6 +608,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { #if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES) // do our best to prevent fragmentation by unloading as soon as we can PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); + PluginManager::instance().unloadDetectionPlugin(); // reallocate the config manager to get rid of any fragmentation ConfMan.defragment(); // The keymapper keeps pointers to the configuration domains. It needs to be reinitialized. @@ -637,6 +664,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { } PluginManager::instance().loadAllPluginsOfType(PLUGIN_TYPE_ENGINE); // only for cached manager + PluginManager::instance().loadDetectionPlugin(); // only for uncached manager } else { GUI::displayErrorDialog(_("Could not find any engine capable of running the selected game")); @@ -660,6 +688,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { Cloud::CloudManager::destroy(); #endif #endif + PluginManager::instance().unloadDetectionPlugin(); PluginManager::instance().unloadAllPlugins(); PluginManager::destroy(); GUI::GuiManager::destroy(); diff --git a/base/plugins.cpp b/base/plugins.cpp index d54f2da22ad..d64bea1904d 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -30,11 +30,15 @@ #include "common/fs.h" #endif +#include "engines/detection.h" + // Plugin versioning int pluginTypeVersions[PLUGIN_TYPE_MAX] = { + PLUGIN_TYPE_METAENGINE_VERSION, PLUGIN_TYPE_ENGINE_VERSION, PLUGIN_TYPE_MUSIC_VERSION, + PLUGIN_TYPE_DETECTION_VERSION, }; @@ -48,22 +52,27 @@ const char *Plugin::getName() const { return _pluginObject->getName(); } -class StaticPlugin : public Plugin { -public: - StaticPlugin(PluginObject *pluginobject, PluginType type) { - assert(pluginobject); - assert(type < PLUGIN_TYPE_MAX); - _pluginObject = pluginobject; - _type = type; +const char *Plugin::getEngineId() const { + if (_type == PLUGIN_TYPE_METAENGINE) { + return _pluginObject->getEngineId(); } - ~StaticPlugin() { - delete _pluginObject; - } + return nullptr; +} - virtual bool loadPlugin() { return true; } - virtual void unloadPlugin() {} -}; +StaticPlugin::StaticPlugin(PluginObject *pluginobject, PluginType type) { + assert(pluginobject); + assert(type < PLUGIN_TYPE_MAX); + _pluginObject = pluginobject; + _type = type; +} + +StaticPlugin::~StaticPlugin() { + delete _pluginObject; +} + +bool StaticPlugin::loadPlugin() { return true; } +void StaticPlugin::unloadPlugin() {} class StaticPluginProvider : public PluginProvider { public: @@ -87,6 +96,11 @@ public: // Engine plugins #include "engines/plugins_table.h" + #ifdef DETECTION_STATIC + // Engine-detection plugins are included if we don't use uncached plugins. + #include "engines/detection_table.h" + #endif + // Music plugins // TODO: Use defines to disable or enable each MIDI driver as a // static/dynamic plugin, like it's done for the engines @@ -257,15 +271,86 @@ void PluginManager::addPluginProvider(PluginProvider *pp) { _providers.push_back(pp); } +Plugin *PluginManager::getEngineFromMetaEngine(const Plugin *plugin) { + assert(plugin->getType() == PLUGIN_TYPE_METAENGINE); + + Plugin *enginePlugin = nullptr; + bool found = false; + + // Use the engineID from MetaEngine for comparasion. + Common::String metaEnginePluginName = plugin->getEngineId(); + PluginMan.loadFirstPlugin(); + do { + PluginList pl = PluginMan.getPlugins(PLUGIN_TYPE_ENGINE); + // Iterate over all engine plugins. + for (PluginList::const_iterator itr = pl.begin(); itr != pl.end(); itr++) { + // The getName() provides a name which is similiar to getEngineId. + // Because engines are engines themselves, this function is simply named getName. + Common::String enginePluginName((*itr)->getName()); + + if (metaEnginePluginName.equalsIgnoreCase(enginePluginName)) { + enginePlugin = (*itr); + found = true; + break; + } + } + } while (!found && PluginMan.loadNextPlugin()); + + if (enginePlugin) { + debug(9, "MetaEngine: %s \t matched to \t Engine: %s", plugin->getName(), enginePlugin->getFileName()); + return enginePlugin; + } + + debug(9, "MetaEngine: %s couldn't find a match for an engine plugin.", plugin->getName()); + return nullptr; +} + +Plugin *PluginManager::getMetaEngineFromEngine(const Plugin *plugin) { + assert(plugin->getType() == PLUGIN_TYPE_ENGINE); + + Plugin *metaEngine = nullptr; + + PluginList pl = PluginMan.getPlugins(PLUGIN_TYPE_METAENGINE); + + // This will return a name of the Engine plugin, which will be identical to + // a getEngineID from a relevant MetaEngine. + Common::String enginePluginName(plugin->getName()); + + for (PluginList::const_iterator itr = pl.begin(); itr != pl.end(); itr++) { + Common::String metaEngineName = (*itr)->getEngineId(); + + if (metaEngineName.equalsIgnoreCase(enginePluginName)) { + metaEngine = (*itr); + break; + } + } + + if (metaEngine) { + debug(9, "Engine: %s matched to MetaEngine: %s", plugin->getFileName(), metaEngine->getName()); + return metaEngine; + } + + debug(9, "Engine: %s couldn't find a match for an MetaEngine plugin.", plugin->getFileName()); + return nullptr; +} + /** * This should only be called once by main() **/ void PluginManagerUncached::init() { unloadAllPlugins(); _allEnginePlugins.clear(); + ConfMan.setBool("always_run_fallback_detection_extern", false); unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); // empty the engine plugins + Common::String detectPluginName = "detection"; +#ifdef PLUGIN_SUFFIX + detectPluginName += PLUGIN_SUFFIX; +#endif + + bool foundDetectPlugin = false; + for (ProviderList::iterator pp = _providers.begin(); pp != _providers.end(); ++pp) { @@ -276,6 +361,16 @@ void PluginManagerUncached::init() { // file plugins. Currently this is the case. If it changes, we // should find a fast way of detecting whether a plugin is a // music or an engine plugin. + if (!foundDetectPlugin && (*pp)->isFilePluginProvider()) { + Common::String pName = (*p)->getFileName(); + if (pName.hasSuffix(detectPluginName)) { + _detectionPlugin = (*p); + foundDetectPlugin = true; + debug(9, "Detection plugin found!"); + continue; + } + } + if ((*pp)->isFilePluginProvider()) { _allEnginePlugins.push_back(*p); } else if ((*p)->loadPlugin()) { // and this is the proper method @@ -348,6 +443,48 @@ void PluginManagerUncached::updateConfigWithFileName(const Common::String &engin } } +void PluginManagerUncached::loadDetectionPlugin() { + bool linkMetaEngines = false; + + if (_isDetectionLoaded) { + debug(9, "Detection plugin is already loaded. Adding each available engines to the memory."); + linkMetaEngines = true; + } else { + if (_detectionPlugin) { + if (_detectionPlugin->loadPlugin()) { + assert((_detectionPlugin)->getType() == PLUGIN_TYPE_DETECTION); + + linkMetaEngines = true; + _isDetectionLoaded = true; + } else { + debug(9, "Detection plugin was not loaded correctly."); + return; + } + } else { + debug(9, "Detection plugin not found."); + return; + } + } + + if (linkMetaEngines) { + _pluginsInMem[PLUGIN_TYPE_METAENGINE].clear(); + const Detection &detectionConnect = _detectionPlugin->get(); + const PluginList &pl = detectionConnect.getPlugins(); + Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManagerUncached::tryLoadPlugin), this)); + } + +} + +void PluginManagerUncached::unloadDetectionPlugin() { + if (_isDetectionLoaded) { + _pluginsInMem[PLUGIN_TYPE_METAENGINE].clear(); + _detectionPlugin->unloadPlugin(); + _isDetectionLoaded = false; + } else { + debug(9, "Detection plugin is already unloaded."); + } +} + void PluginManagerUncached::loadFirstPlugin() { unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); @@ -424,8 +561,9 @@ void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, b found = *p; } else { (*p)->unloadPlugin(); - if (deletePlugin) + if (deletePlugin) { delete *p; + } } } _pluginsInMem[type].clear(); @@ -498,7 +636,7 @@ QualifiedGameList EngineManager::findGamesMatching(const Common::String &engineI // If we got an engine name, look for THE game only in that engine const Plugin *p = EngineMan.findPlugin(engineId); if (p) { - const MetaEngine &engine = p->get(); + const MetaEngineStatic &engine = p->get(); PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str()); if (pluginResult.gameId) { @@ -527,7 +665,7 @@ QualifiedGameList EngineManager::findGameInLoadedPlugins(const Common::String &g PluginList::const_iterator iter; for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - const MetaEngine &engine = (*iter)->get(); + const MetaEngineStatic &engine = (*iter)->get(); PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str()); if (pluginResult.gameId) { @@ -542,29 +680,29 @@ DetectionResults EngineManager::detectGames(const Common::FSList &fslist) const DetectedGames candidates; PluginList plugins; PluginList::const_iterator iter; - PluginMan.loadFirstPlugin(); - do { - plugins = getPlugins(); - // Iterate over all known games and for each check if it might be - // the game in the presented directory. - for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - const MetaEngine &metaEngine = (*iter)->get(); - DetectedGames engineCandidates = metaEngine.detectGames(fslist); - for (uint i = 0; i < engineCandidates.size(); i++) { - engineCandidates[i].path = fslist.begin()->getParent().getPath(); - engineCandidates[i].shortPath = fslist.begin()->getParent().getDisplayName(); - candidates.push_back(engineCandidates[i]); - } + // MetaEngines are always loaded into memory, so, get them and + // run detection for all of them. + plugins = getPlugins(PLUGIN_TYPE_METAENGINE); + // Iterate over all known games and for each check if it might be + // the game in the presented directory. + for (iter = plugins.begin(); iter != plugins.end(); ++iter) { + const MetaEngineStatic &metaEngine = (*iter)->get(); + DetectedGames engineCandidates = metaEngine.detectGames(fslist); + + for (uint i = 0; i < engineCandidates.size(); i++) { + engineCandidates[i].path = fslist.begin()->getParent().getPath(); + engineCandidates[i].shortPath = fslist.begin()->getParent().getDisplayName(); + candidates.push_back(engineCandidates[i]); } - } while (PluginMan.loadNextPlugin()); + } return DetectionResults(candidates); } -const PluginList &EngineManager::getPlugins() const { - return PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE); +const PluginList &EngineManager::getPlugins(const PluginType fetchPluginType) const { + return PluginManager::instance().getPlugins(fetchPluginType); } namespace { @@ -628,7 +766,7 @@ const Plugin *EngineManager::findLoadedPlugin(const Common::String &engineId) co const PluginList &plugins = getPlugins(); for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); iter++) - if (engineId == (*iter)->get().getEngineId()) + if (engineId == (*iter)->get().getEngineId()) return *iter; return 0; @@ -680,7 +818,7 @@ QualifiedGameDescriptor EngineManager::findTarget(const Common::String &target, } // Make sure it does support the game ID - const MetaEngine &engine = foundPlugin->get(); + const MetaEngineStatic &engine = foundPlugin->get(); PlainGameDescriptor desc = engine.findGame(domain->getVal("gameid").c_str()); if (!desc.gameId) { return QualifiedGameDescriptor(); @@ -698,6 +836,14 @@ void EngineManager::upgradeTargetIfNecessary(const Common::String &target) const if (!domain->contains("engineid")) { upgradeTargetForEngineId(target); + } else { + if (domain->getVal("engineid").equals("fullpipe")) { + domain->setVal("engineid", "ngi"); + + debug("Upgrading engineid from 'fullpipe' to 'ngi'"); + + ConfMan.flushToDisk(); + } } } @@ -737,7 +883,7 @@ void EngineManager::upgradeTargetForEngineId(const Common::String &target) const } // Take the first detection entry - const MetaEngine &metaEngine = plugin->get(); + const MetaEngineStatic &metaEngine = plugin->get(); DetectedGames candidates = metaEngine.detectGames(files); if (candidates.empty()) { warning("No games supported by the engine '%s' were found in path '%s' when upgrading target '%s'", diff --git a/base/plugins.h b/base/plugins.h index 9919c1a3782..50f933b2534 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -60,8 +60,10 @@ #define PLUGIN_VERSION 1 enum PluginType { - PLUGIN_TYPE_ENGINE = 0, + PLUGIN_TYPE_METAENGINE = 0, + PLUGIN_TYPE_ENGINE, PLUGIN_TYPE_MUSIC, + PLUGIN_TYPE_DETECTION, /* PLUGIN_TYPE_SCALER, */ // TODO: Add graphics scaler plugins PLUGIN_TYPE_MAX @@ -69,8 +71,10 @@ enum PluginType { // TODO: Make the engine API version depend on ScummVM's version // because of the backlinking (posibly from the checkout revision) -#define PLUGIN_TYPE_ENGINE_VERSION 1 +#define PLUGIN_TYPE_METAENGINE_VERSION 1 +#define PLUGIN_TYPE_ENGINE_VERSION 2 #define PLUGIN_TYPE_MUSIC_VERSION 1 +#define PLUGIN_TYPE_DETECTION_VERSION 1 extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; @@ -150,6 +154,18 @@ public: /** Returns the name of the plugin. */ virtual const char *getName() const = 0; + + /** + * Returns the engine id of the plugin, if implemented. + * This mostly has the use with MetaEngines, but if another + * type of plugins request this, we return a nullptr. + * This is used because MetaEngines are now available in the + * executable, and querying this we can match a MetaEngine + * with it's related engine. + */ + virtual const char *getEngineId() const { + return nullptr; + } }; /** @@ -180,6 +196,7 @@ public: **/ PluginType getType() const; const char *getName() const; + const char *getEngineId() const; template T &get() const { @@ -198,6 +215,15 @@ public: virtual const char *getFileName() const { return 0; } }; +class StaticPlugin : public Plugin { +public: + StaticPlugin(PluginObject *pluginobject, PluginType type); + ~StaticPlugin(); + virtual bool loadPlugin(); + virtual void unloadPlugin(); +}; + + /** List of Plugin instances. */ typedef Common::Array PluginList; @@ -311,12 +337,38 @@ public: void addPluginProvider(PluginProvider *pp); + /** + * A method which takes in a plugin of type ENGINE, + * and returns the appropriate & matching METAENGINE. + * It uses the Engine plugin's getName method, which is an identifier, + * and then tries to matches it with each plugin present in memory. + * + * @param A plugin of type ENGINE. + * + * @return A plugin of type METAENGINE. + */ + Plugin *getMetaEngineFromEngine(const Plugin *plugin); + + /** + * A method which takes in a plugin of type METAENGINE, + * and returns the appropriate & matching ENGINE. + * It uses the MetaEngine's getEngineID to reconstruct the name + * of engine plugin, and then tries to matches it with each plugin in memory. + * + * @param A plugin of type METAENGINE. + * + * @return A plugin of type ENGINE. + */ + Plugin *getEngineFromMetaEngine(const Plugin *plugin); + // Functions used by the uncached PluginManager virtual void init() {} virtual void loadFirstPlugin() {} virtual bool loadNextPlugin() { return false; } virtual bool loadPluginFromEngineId(const Common::String &engineId) { return false; } virtual void updateConfigWithFileName(const Common::String &engineId) {} + virtual void loadDetectionPlugin() {} + virtual void unloadDetectionPlugin() {} // Functions used only by the cached PluginManager virtual void loadAllPlugins(); @@ -336,20 +388,25 @@ class PluginManagerUncached : public PluginManager { protected: friend class PluginManager; PluginList _allEnginePlugins; + Plugin *_detectionPlugin; PluginList::iterator _currentPlugin; - PluginManagerUncached() {} + bool _isDetectionLoaded; + + PluginManagerUncached() : _isDetectionLoaded(false) {} bool loadPluginByFileName(const Common::String &filename); public: - virtual void init(); - virtual void loadFirstPlugin(); - virtual bool loadNextPlugin(); - virtual bool loadPluginFromEngineId(const Common::String &engineId); - virtual void updateConfigWithFileName(const Common::String &engineId); + virtual void init() override; + virtual void loadFirstPlugin() override; + virtual bool loadNextPlugin() override; + virtual bool loadPluginFromEngineId(const Common::String &engineId) override; + virtual void updateConfigWithFileName(const Common::String &engineId) override; + virtual void loadDetectionPlugin() override; + virtual void unloadDetectionPlugin() override; - virtual void loadAllPlugins() {} // we don't allow these - virtual void loadAllPluginsOfType(PluginType type) {} + virtual void loadAllPlugins() override {} // we don't allow these + virtual void loadAllPluginsOfType(PluginType type) override {} }; #endif diff --git a/common/achievements.h b/common/achievements.h index 550aecd8e49..0355374ed80 100644 --- a/common/achievements.h +++ b/common/achievements.h @@ -30,6 +30,15 @@ namespace Common { +/** + * @defgroup common_achieve Achievements + * @ingroup common + * + * @brief API related to in-game achievements. + * + * @{ + */ + /** * List of game achievements provider platforms. * Possible candidates are XBOX Gamerscore, PSN Trophies, Kongregate Badges, etc... @@ -96,6 +105,7 @@ private: /** Shortcut for accessing the achievements manager. */ #define AchMan Common::AchievementsManager::instance() +/** @} */ } // End of namespace Common diff --git a/common/algorithm.h b/common/algorithm.h index 1aac0376dbc..5e669e7e119 100644 --- a/common/algorithm.h +++ b/common/algorithm.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_alg Algorithms + * @ingroup common + * + * @brief Templates for algorithms used to manipulate data. + * + * @{ + */ + /** * Copies data from the range [first, last) to [dst, dst + (last - first)). * It requires the range [dst, dst + (last - first)) to be valid. @@ -308,5 +317,9 @@ void replace(It begin, It end, const Dat &original, const Dat &replaced) { } } +/** @} */ + + } // End of namespace Common + #endif diff --git a/common/archive.h b/common/archive.h index 2cf75553713..c7a0f731f75 100644 --- a/common/archive.h +++ b/common/archive.h @@ -30,6 +30,18 @@ namespace Common { +/** + * @defgroup common_arch Archive + * @ingroup common + * + * @brief The Archive module allows managing the member of arbitrary containers in a uniform + * fashion. + * It also supports looking up by names and file names, opening a file, and returning usable input stream. + * + * @{ + */ + + class FSNode; class SeekableReadStream; @@ -276,6 +288,8 @@ private: /** Shortcut for accessing the search manager. */ #define SearchMan Common::SearchManager::instance() +/** @} */ + } // namespace Common #endif diff --git a/common/array.h b/common/array.h index c57d0a109d4..191febf3c36 100644 --- a/common/array.h +++ b/common/array.h @@ -28,8 +28,22 @@ #include "common/textconsole.h" // For error() #include "common/memory.h" +#ifdef USE_CXX11 +#include "common/initializer_list.h" +#endif + namespace Common { +/** + * @defgroup common_array Arrays + * @ingroup common + * + * @brief Functions for working on arrays. + * + * @{ + */ + + /** * This class implements a dynamically sized container, which * can be accessed similar to a regular C++ array. Accessing @@ -84,6 +98,26 @@ public: } } +#ifdef USE_CXX11 + /** + * Constructs an array as a copy of the given array using the c++11 move semantic. + */ + Array(Array &&old) : _capacity(old._capacity), _size(old._size), _storage(old._storage) { + old._storage = nullptr; + old._capacity = 0; + old._size = 0; + } + + /** + * Constructs an array using list initialization. + */ + Array(std::initializer_list list) : _size(list.size()) { + allocCapacity(list.size()); + if (_storage) + Common::uninitialized_copy(list.begin(), list.end(), _storage); + } +#endif + /** * Construct an array by copying data from a regular array. */ @@ -210,6 +244,24 @@ public: return *this; } +#ifdef USE_CXX11 + Array &operator=(Array &&old) { + if (this == &old) + return *this; + + freeStorage(_storage, _size); + _capacity = old._capacity; + _size = old._size; + _storage = old._storage; + + old._storage = nullptr; + old._capacity = 0; + old._size = 0; + + return *this; + } +#endif + size_type size() const { return _size; } @@ -456,6 +508,8 @@ private: Comparator _comparator; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/bitstream.h b/common/bitstream.h index 81976efdc89..775a83abaa6 100644 --- a/common/bitstream.h +++ b/common/bitstream.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_bitstream Bit stream + * @ingroup common + * + * @brief API for implementing a bit stream. + * + * @{ + */ + /** * A template implementing a bit stream for different data memory layouts. * @@ -470,6 +479,7 @@ typedef BitStreamImpl BitStreamMemory32 /** 32-bit big-endian data, LSB to MSB. */ typedef BitStreamImpl BitStreamMemory32BELSB; +/** @} */ } // End of namespace Common diff --git a/common/bufferedstream.h b/common/bufferedstream.h index bbd25722a84..94117276bcb 100644 --- a/common/bufferedstream.h +++ b/common/bufferedstream.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_buffstream Buffered stream + * @ingroup common + * + * @brief API for implementing a buffered stream. + * + * @{ + */ + /** * Take an arbitrary ReadStream and wrap it in a custom stream which * transparently provides buffering. @@ -61,6 +70,8 @@ SeekableReadStream *wrapBufferedSeekableReadStream(SeekableReadStream *parentStr */ WriteStream *wrapBufferedWriteStream(WriteStream *parentStream, uint32 bufSize); +/** @} */ + } // End of namespace Common #endif diff --git a/common/callback.h b/common/callback.h index c6c249a511c..c1ada14c34b 100644 --- a/common/callback.h +++ b/common/callback.h @@ -25,6 +25,15 @@ namespace Common { +/** + * @defgroup common_callback Callbacks + * @ingroup common + * + * @brief Callback templates. + * + * @{ + */ + /** * BaseCallback is a simple base class for object-oriented callbacks. * @@ -133,6 +142,8 @@ public: void operator()(S data) { (_object->*_method)(_outerCallback, data); } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/config-manager.h b/common/config-manager.h index 0295abf1709..f2cfd7b145b 100644 --- a/common/config-manager.h +++ b/common/config-manager.h @@ -31,6 +31,16 @@ namespace Common { +/** + * @defgroup common_config Configuration manager + * @ingroup common + * + * @brief The (singleton) configuration manager, used to query & set configuration + * values using string keys. + * + * @{ + */ + class WriteStream; class SeekableReadStream; @@ -207,6 +217,8 @@ private: String _filename; }; +/** @} */ + } // End of namespace Common /** Shortcut for accessing the configuration manager. */ diff --git a/common/coroutines.h b/common/coroutines.h index 10e0bb28da3..68f0fa692d9 100644 --- a/common/coroutines.h +++ b/common/coroutines.h @@ -31,14 +31,16 @@ namespace Common { /** - * @defgroup Coroutine support for simulating multi-threading. + * @defgroup common_coroutine Coroutine support for simulating multi-threading + * @ingroup common * - * The following is loosely based on an article by Simon Tatham: - * . - * However, many improvements and tweaks have been made, in particular - * by taking advantage of C++ features not available in C. + * @brief The following implementation is loosely based on an article by Simon Tatham: + * @linkCoroutine. + * However, many improvements and tweaks have been made, in particular + * by taking advantage of C++ features not available in C. + * + * @{ */ -//@{ #define CoroScheduler (Common::CoroutineScheduler::instance()) @@ -555,7 +557,7 @@ public: void pulseEvent(uint32 pidEvent); }; -//@} +/** @} */ } // end of namespace Common diff --git a/common/cosinetables.h b/common/cosinetables.h index 65cfc2e6b9c..d790c757ada 100644 --- a/common/cosinetables.h +++ b/common/cosinetables.h @@ -25,6 +25,15 @@ namespace Common { +/** + * @defgroup common_cosinetables Cosine tables + * @ingroup common + * + * @brief Functions for working with cosine tables. + * + * @{ + */ + class CosineTable { public: /** @@ -69,6 +78,8 @@ private: int _nPoints; // range of operator[] }; +/** @} */ + } // End of namespace Common #endif // COMMON_COSINETABLES_H diff --git a/common/dcl.h b/common/dcl.h index ade7ebd9854..fa7b95d6be4 100644 --- a/common/dcl.h +++ b/common/dcl.h @@ -21,12 +21,8 @@ */ /** - * @file - * PKWARE DCL ("explode") ("PKWARE data compression library") decompressor used in engines: - * - agos (exclusively for Simon 2 setup.shr file) - * - mohawk - * - neverhood - * - sci + * + */ #ifndef COMMON_DCL_H @@ -36,6 +32,21 @@ namespace Common { +/** + * @defgroup common_dcl Data compression library + * @ingroup common + * + * @brief PKWARE data compression library. + * + * @details PKWARE DCL ("explode") ("PKWARE data compression library") decompressor used in engines: + * - agos (exclusively for Simon 2 setup.shr file) + * - mohawk + * - neverhood + * - sci + * + * @{ + */ + class ReadStream; class SeekableReadStream; @@ -57,6 +68,8 @@ SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream, uint32 packe */ SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream); +/** @} */ + } // End of namespace Common #endif diff --git a/common/dct.h b/common/dct.h index 882856a8a9b..c8d025d5172 100644 --- a/common/dct.h +++ b/common/dct.h @@ -37,6 +37,15 @@ namespace Common { +/** + * @defgroup common_dct Discrete Cosine Transforms + * @ingroup common + * + * @brief Discrete Cosine Transforms. + * + * @{ + */ + /** * (Inverse) Discrete Cosine Transforms. * @@ -74,6 +83,8 @@ private: void calcDSTI (float *data); }; +/** @} */ + } // End of namespace Common #endif // COMMON_DCT_H diff --git a/common/debug-channels.h b/common/debug-channels.h index a2df35102ff..2cef6b40beb 100644 --- a/common/debug-channels.h +++ b/common/debug-channels.h @@ -34,6 +34,15 @@ namespace Common { +/** + * @defgroup common_debug_channels Debug channels + * @ingroup common_debug + * + * @brief Functions for managing debug channels. + * + * @{ + */ + // TODO: Find a better name for this class DebugManager : public Singleton { public: @@ -148,6 +157,8 @@ private: /** Shortcut for accessing the debug manager. */ #define DebugMan Common::DebugManager::instance() +/** @} */ + } // End of namespace Common #endif diff --git a/common/debug.h b/common/debug.h index 5ec37f2f1ed..7beef8acb0c 100644 --- a/common/debug.h +++ b/common/debug.h @@ -38,6 +38,14 @@ inline void debugCN(uint32 debugChannels, const char *s, ...) {} #else +/** + * @defgroup common_debug Debug functions + * @ingroup common + * + * @brief Debug functions. + * + * @{ + */ /** * Print a debug message to the text console (stdout). @@ -144,4 +152,6 @@ enum GlobalDebugLevels { kDebugLevelEventRec = 1 << 30 }; +/** @} */ + #endif diff --git a/common/dialogs.h b/common/dialogs.h index fd165e9ee29..083104d3b59 100644 --- a/common/dialogs.h +++ b/common/dialogs.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_dialogs Dialog Manager + * @ingroup common + * + * @brief The Dialog Manager allows GUI code to interact with native system dialogs. + * + * @{ + */ + /** * The DialogManager allows GUI code to interact with native system dialogs. */ @@ -97,6 +106,8 @@ protected: } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/encoding.cpp b/common/encoding.cpp index 0b7fbab899e..5d701d3cd10 100644 --- a/common/encoding.cpp +++ b/common/encoding.cpp @@ -44,7 +44,7 @@ String addUtfEndianness(const String &str) { return str + "LE"; #endif } else - return String(str); + return str; } Encoding::Encoding(const String &to, const String &from) @@ -55,7 +55,7 @@ Encoding::Encoding(const String &to, const String &from) char *Encoding::switchEndian(const char *string, int length, int bitCount) { assert(bitCount % 8 == 0); assert(length % (bitCount / 8) == 0); - char *newString = (char *)malloc(length); + char *newString = (char *)calloc(sizeof(char), length + 4); if (!newString) { warning("Could not allocate memory for string conversion"); return nullptr; @@ -98,19 +98,33 @@ char *Encoding::convertWithTransliteration(const String &to, const String &from, return result; } - if ((addUtfEndianness(to).equalsIgnoreCase("utf-16be") && - addUtfEndianness(from).equalsIgnoreCase("utf-16le")) || - (addUtfEndianness(to).equalsIgnoreCase("utf-16le") && - addUtfEndianness(from).equalsIgnoreCase("utf-16be")) || - (addUtfEndianness(to).equalsIgnoreCase("utf-32be") && - addUtfEndianness(from).equalsIgnoreCase("utf-32le")) || - (addUtfEndianness(to).equalsIgnoreCase("utf-32le") && - addUtfEndianness(from).equalsIgnoreCase("utf-32be"))) { - // The encoding is the same, we just need to switch the endianness - if (to.hasPrefixIgnoreCase("utf-16")) - return switchEndian(string, length, 16); - else - return switchEndian(string, length, 32); + if ((to.hasPrefixIgnoreCase("utf-16") && from.hasPrefixIgnoreCase("utf-16")) || + (to.hasPrefixIgnoreCase("utf-32") && from.hasPrefixIgnoreCase("utf-32"))) { + // Since the two strings are not equal as this is already checked above, + // this likely mean that one or both has an endianness suffix, and we + // just need to switch the endianess. +#ifdef SCUMM_BIG_ENDIAN + bool fromBigEndian = !from.hasSuffixIgnoreCase("le"); + bool toBigEndian = !to.hasSuffixIgnoreCase("le"); +#else + bool fromBigEndian = from.hasSuffixIgnoreCase("be"); + bool toBigEndian = to.hasSuffixIgnoreCase("be"); +#endif + if (fromBigEndian == toBigEndian) { + // don't convert, just copy the string and return it + char *result = (char *)calloc(sizeof(char), length + 4); + if (!result) { + warning("Could not allocate memory for string conversion"); + return nullptr; + } + memcpy(result, string, length); + return result; + } else { + if (to.hasPrefixIgnoreCase("utf-16")) + return switchEndian(string, length, 16); + else + return switchEndian(string, length, 32); + } } char *newString = nullptr; diff --git a/common/encoding.h b/common/encoding.h index 503fbf5ab8f..6d91bb3a462 100644 --- a/common/encoding.h +++ b/common/encoding.h @@ -30,6 +30,15 @@ namespace Common { +/** + * @defgroup common_encoding Text encoding + * @ingroup common + * + * @brief Functions for managing text encoding. + * + * @{ + */ + /** * A class, that allows conversion between different text encoding, * the encodings available depend on the current backend and if the @@ -221,6 +230,8 @@ class Encoding { static uint32 *transliterateUTF32(const uint32 *string, size_t length); }; +/** @} */ + } #endif // COMMON_ENCODING_H diff --git a/common/endian.h b/common/endian.h index fad9f3ccae8..6ba2709b5eb 100644 --- a/common/endian.h +++ b/common/endian.h @@ -25,10 +25,14 @@ #include "common/scummsys.h" + /** - * \file endian.h - * Endian conversion and byteswap conversion functions or macros + * @defgroup common_endian Endian conversions + * @ingroup common * + * @brief Endian conversion and byteswap conversion functions and macros. + * + * @details * SWAP_BYTES_??(a) - inverse byte order * SWAP_CONSTANT_??(a) - inverse byte order, implemented as macro. * Use with compiletime-constants only, the result will be a compiletime-constant aswell. @@ -42,6 +46,8 @@ * CONSTANT_??_??(a) - convert LE/BE value v to native, implemented as macro. * Use with compiletime-constants only, the result will be a compiletime-constant aswell. * Unlike most other functions these can be used for eg. switch-case labels + * + * @{ */ // Sanity check @@ -632,4 +638,6 @@ inline void WRITE_BE_INT32(void *ptr, int32 value) { WRITE_BE_UINT32(ptr, static_cast(value)); } +/** @} */ + #endif diff --git a/common/error.h b/common/error.h index 00495e06b28..4962c84ef76 100644 --- a/common/error.h +++ b/common/error.h @@ -28,11 +28,14 @@ namespace Common { /** - * This file contains an enum with commonly used error codes. + * @defgroup common_error Error codes + * @ingroup common + * + * @brief Commonly used error codes. + * + * @{ */ - - /** * Error codes which may be reported by plugins under various circumstances. * @@ -60,7 +63,12 @@ enum ErrorCode { kWritingFailed, ///< Failure to write data -- disk full? // The following are used by --list-saves - kEnginePluginNotFound, ///< Failed to find plugin to handle target + + // Failed to find a MetaEnginePlugin. This should never happen, because all MetaEngines must always + // be built into the executable, regardless if the engine plugins are present or not. + kMetaEnginePluginNotFound, ///< See comment above + + kEnginePluginNotFound, ///< Failed to find a Engine plugin to handle target kEnginePluginNotSupportSaves, ///< Failed if plugin does not support listing save states kUserCanceled, ///< User has canceled the launching of the game @@ -103,6 +111,8 @@ public: ErrorCode getCode() const { return _code; } }; +/** @} */ + } // End of namespace Common #endif //COMMON_ERROR_H diff --git a/common/events.h b/common/events.h index 5ed445baa43..bd100301878 100644 --- a/common/events.h +++ b/common/events.h @@ -34,14 +34,18 @@ namespace Common { /** - * The types of events backends may generate. - * @see Event + * @defgroup common_events Events + * @ingroup common + * + * @brief The types of events backends may generate. * * @todo Merge EVENT_LBUTTONDOWN, EVENT_RBUTTONDOWN and EVENT_WHEELDOWN; * likewise EVENT_LBUTTONUP, EVENT_RBUTTONUP, EVENT_WHEELUP. * To do that, we just have to add a field to the Event which * indicates which button was pressed. + * @{ */ + enum EventType { EVENT_INVALID = 0, /** A key was pressed, details in Event::kbd. */ @@ -555,6 +559,8 @@ protected: */ EventSource *makeKeyboardRepeatingEventSource(EventSource *eventSource); +/** @} */ + } // End of namespace Common #endif diff --git a/common/fft.h b/common/fft.h index ed66d32b717..2a9f2166505 100644 --- a/common/fft.h +++ b/common/fft.h @@ -34,10 +34,19 @@ namespace Common { +/** + * @defgroup common_fft Fast Fourier Transform (FFT) + * @ingroup common + * + * @brief API for the FFT algorithm. + * + * @{ + */ + class CosineTable; /** - * (Inverse) Fast Fourier Transform. + * (Inverse) Fast Fourier Transform * * Used in engines: * - scumm @@ -80,6 +89,8 @@ private: void fft(int n, int logn, Complex *z); }; +/** @} */ + } // End of namespace Common #endif // COMMON_FFT_H diff --git a/common/file.h b/common/file.h index 2d5232abccf..e06f75d5ca2 100644 --- a/common/file.h +++ b/common/file.h @@ -31,6 +31,15 @@ namespace Common { +/** + * @defgroup common_files Files + * @ingroup common + * + * @brief API for operations on files. + * + * @{ + */ + class Archive; /** @@ -168,6 +177,8 @@ public: virtual int32 size() const override; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/frac.h b/common/frac.h index 4e3bcf267f3..c6637b3bded 100644 --- a/common/frac.h +++ b/common/frac.h @@ -25,6 +25,15 @@ #include "common/scummsys.h" +/** + * @defgroup common_frac Fixed-point fractions + * @ingroup common + * + * @brief API for fixed-point fractions. + * + * @{ + */ + /** * The precision of the fractional (fixed point) type we define below. * Normally you should never have to modify this value. @@ -49,4 +58,6 @@ inline double fracToDouble(frac_t value) { return ((double)value) / FRAC_ONE; } inline frac_t intToFrac(int16 value) { return value * (1 << FRAC_BITS); } inline int16 fracToInt(frac_t value) { return value / (1 << FRAC_BITS); } +/** @} */ + #endif diff --git a/common/fs.h b/common/fs.h index 718f47ff561..e550bef34b9 100644 --- a/common/fs.h +++ b/common/fs.h @@ -34,6 +34,15 @@ class AbstractFSNode; namespace Common { +/** + * @defgroup common_fs File system + * @ingroup common + * + * @brief API for operations on the file system. + * + * @{ + */ + class FSNode; class SeekableReadStream; class WriteStream; @@ -371,6 +380,7 @@ public: virtual SeekableReadStream *createReadStreamForMember(const String &name) const; }; +/** @} */ } // End of namespace Common diff --git a/common/func.h b/common/func.h index b58474b2f39..3ffe78c934a 100644 --- a/common/func.h +++ b/common/func.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_func Functions + * @ingroup common + * + * @brief API for managing functions. + * + * @{ + */ + + /** * Generic unary function. */ @@ -536,6 +546,8 @@ GENERATE_TRIVIAL_HASH_FUNCTOR(unsigned long); #undef GENERATE_TRIVIAL_HASH_FUNCTOR +/** @} */ + } // End of namespace Common #endif diff --git a/common/gui_options.h b/common/gui_options.h index e07da2709c0..4a10a8df891 100644 --- a/common/gui_options.h +++ b/common/gui_options.h @@ -95,6 +95,15 @@ namespace Common { +/** + * @defgroup common_gui_options GUI options + * @ingroup common + * + * @brief API for managing the options of the graphical user interface (GUI). + * + * @{ + */ + class String; bool checkGameGUIOption(const String &option, const String &str); @@ -108,6 +117,7 @@ const String getGameGUIOptionsDescription(const String &options); */ void updateGameGUIOptions(const String &options, const String &langOption); +/** @} */ } // End of namespace Common diff --git a/common/hash-ptr.h b/common/hash-ptr.h index 1099478c3b7..d27cdf41187 100644 --- a/common/hash-ptr.h +++ b/common/hash-ptr.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_hashmap_ptr Hash table pointer + * @ingroup common_hashmap + * + * @brief Template for a HashMap pointer. + * + * @{ + */ + /** * Partial specialization of the Hash functor to be able to use pointers as HashMap keys */ @@ -38,6 +47,8 @@ struct Hash { } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/hashmap.h b/common/hashmap.h index 861f0556628..804f179da9c 100644 --- a/common/hashmap.h +++ b/common/hashmap.h @@ -57,6 +57,15 @@ namespace Common { +/** + * @defgroup common_hashmap Hash table (HashMap) + * @ingroup common + * + * @brief API for operations on a hash table. + * + * @{ + */ + // The sgi IRIX MIPSpro Compiler has difficulties with nested templates. // This and the other __sgi conditionals below work around these problems. // The Intel C++ Compiler suffers from the same problems. @@ -624,6 +633,8 @@ void HashMap::erase(const Key &key) { #undef HASHMAP_DUMMY_NODE +/** @} */ + } // End of namespace Common #endif diff --git a/common/huffman.h b/common/huffman.h index 052c7bf8251..d98d90cc73f 100644 --- a/common/huffman.h +++ b/common/huffman.h @@ -31,6 +31,18 @@ namespace Common { +/** + * @defgroup common_huffmann Huffman bitstream decoding + * @ingroup common + * + * @brief API for operations related to Huffman bitstream decoding. + * + * @details Used in engines: + * - scumm + * + * @{ + */ + inline uint32 REVERSEBITS(uint32 x) { x = (((x & ~0x55555555) >> 1) | ((x & 0x55555555) << 1)); x = (((x & ~0x33333333) >> 2) | ((x & 0x33333333) << 2)); @@ -43,8 +55,6 @@ inline uint32 REVERSEBITS(uint32 x) { /** * Huffman bitstream decoding * - * Used in engines: - * - scumm */ template class Huffman { @@ -159,6 +169,8 @@ uint32 Huffman::getSymbol(BITSTREAM &bits) const { return 0; } +/** @} */ + } // End of namespace Common #endif // COMMON_HUFFMAN_H diff --git a/common/iff_container.h b/common/iff_container.h index a88b1597332..83bb62ac742 100644 --- a/common/iff_container.h +++ b/common/iff_container.h @@ -31,6 +31,16 @@ namespace Common { +/** + * @defgroup common_iff Interchange File Format (IFF) + * @ingroup common + * + * @brief API for operations on IFF container files. + * + * + * @{ + */ + typedef uint32 IFF_ID; #define ID_FORM MKTAG('F','O','R','M') @@ -265,6 +275,8 @@ public: uint32 read(void *dataPtr, uint32 dataSize); }; +/** @} */ + } // namespace Common #endif diff --git a/common/ini-file.h b/common/ini-file.h index f84ca6009c9..4b66936ac07 100644 --- a/common/ini-file.h +++ b/common/ini-file.h @@ -29,6 +29,16 @@ namespace Common { +/** + * @defgroup common_ini_file INI files + * @ingroup common + * + * @brief API for operations on INI configuration files. + * + * + * @{ + */ + class SeekableReadStream; class WriteStream; @@ -128,6 +138,8 @@ private: const Section *getSection(const String §ion) const; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/installshield_cab.h b/common/installshield_cab.h index d3c584815ed..af2699a70b4 100644 --- a/common/installshield_cab.h +++ b/common/installshield_cab.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_installshield InstallShield + * @ingroup common + * + * @brief API for managing the InstallShield. + * + * + * @{ + */ + class Archive; class SeekableReadStream; @@ -38,6 +48,8 @@ class SeekableReadStream; */ Archive *makeInstallShieldArchive(SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); +/** @} */ + } // End of namespace Common #endif diff --git a/common/keyboard.h b/common/keyboard.h index fae2555286e..b06a309baed 100644 --- a/common/keyboard.h +++ b/common/keyboard.h @@ -36,6 +36,16 @@ namespace Common { +/** + * @defgroup common_keyboard Keyboard + * @ingroup common + * + * @brief API for keyboard operations. + * + * + * @{ + */ + enum KeyCode { KEYCODE_INVALID = 0, @@ -356,6 +366,8 @@ struct KeyState { } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/language.h b/common/language.h index 8c7369a8a3a..e787fe79f12 100644 --- a/common/language.h +++ b/common/language.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_language Language + * @ingroup common + * + * @brief API for managing game language. + * + * + * @{ + */ + class String; /** @@ -93,6 +103,8 @@ const String getGameGUIOptionsDescriptionLanguage(Common::Language lang); // TODO: Document this GUIO related function bool checkGameGUIOptionLanguage(Common::Language lang, const String &str); +/** @} */ + } // End of namespace Common #endif diff --git a/common/list.h b/common/list.h index 31cf161d221..f889dbc9cba 100644 --- a/common/list.h +++ b/common/list.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_list Lists + * @ingroup common + * + * @brief API and templates for managing lists. + * + * + * @{ + */ + /** * Simple double linked list, modeled after the list template of the standard * C++ library. @@ -255,6 +265,8 @@ protected: } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/localization.h b/common/localization.h index 51803279e75..f5c63a2db71 100644 --- a/common/localization.h +++ b/common/localization.h @@ -28,6 +28,16 @@ namespace Common { +/** + * @defgroup common_localization Localization + * @ingroup common + * + * @brief Functions for managing localized elements of the GUI. + * + * + * @{ + */ + /** * Get localized equivalents for Y/N buttons of the specified language. In * case there is no specialized keys for the given language it will fall back @@ -48,6 +58,8 @@ void getLanguageYesNo(Language id, KeyCode &keyYes, KeyCode &keyNo); */ void getLanguageYesNo(KeyCode &keyYes, KeyCode &keyNo); +/** @} */ + } // End of namespace Common #endif diff --git a/common/macresman.h b/common/macresman.h index 6ac831fe2e7..5ab2b4d6b70 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -22,12 +22,7 @@ /** * @file - * Macintosh resource fork manager used in engines: - * - groovie - * - mohawk - * - pegasus - * - sci - * - scumm + */ #include "common/array.h" @@ -40,6 +35,21 @@ namespace Common { +/** + * @defgroup common_macresman Macintosh resource fork manager + * @ingroup common + * + * @brief API for Macintosh resource fork manager. + * + * @details Used in engines: + * - groovie + * - mohawk + * - pegasus + * - sci + * - scumm + * @{ + */ + typedef Array MacResIDArray; typedef Array MacResTagArray; @@ -282,6 +292,8 @@ private: ResPtr *_resLists; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/md5.h b/common/md5.h index 640326efe77..62562b60630 100644 --- a/common/md5.h +++ b/common/md5.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_md5 MD5 checksum + * @ingroup common + * + * @brief API for computing the MD5 checksum. + * + * @{ + */ + class ReadStream; class String; @@ -54,6 +63,8 @@ bool computeStreamMD5(ReadStream &stream, uint8 digest[16], uint32 length = 0); */ String computeStreamMD5AsString(ReadStream &stream, uint32 length = 0); +/** @} */ + } // End of namespace Common #endif diff --git a/common/memory.h b/common/memory.h index 91a320080b5..bdd521a17a0 100644 --- a/common/memory.h +++ b/common/memory.h @@ -27,6 +27,14 @@ namespace Common { +/** + * @defgroup common_memory Memory + * @ingroup common + * + * @brief Functions for managing the memory. + * @{ + */ + /** * Copies data from the range [first, last) to [dst, dst + (last - first)). * It requires the range [dst, dst + (last - first)) to be valid and @@ -61,6 +69,8 @@ void uninitialized_fill_n(Type *dst, size_t n, const Value &x) { new ((void *)dst++) Type(x); } +/** @} */ + } // End of namespace Common #endif diff --git a/common/memorypool.h b/common/memorypool.h index b84012232cb..6567dbe59cb 100644 --- a/common/memorypool.h +++ b/common/memorypool.h @@ -29,6 +29,14 @@ namespace Common { +/** + * @defgroup common_memory_pool Memory pool + * @ingroup common_memory + * + * @brief API for managing the memory pool. + * @{ + */ + /** * This class provides a pool of memory 'chunks' of identical size. * The size of a chunk is determined when creating the memory pool. @@ -141,6 +149,8 @@ public: } }; +/** @} */ + } // End of namespace Common /** diff --git a/common/memstream.h b/common/memstream.h index 9452e4f24ba..5bfd7f08119 100644 --- a/common/memstream.h +++ b/common/memstream.h @@ -29,6 +29,14 @@ namespace Common { +/** + * @defgroup common_memory_pool Memory stream + * @ingroup common_memory + * + * @brief API for managing the memory stream. + * @{ + */ + /** * Simple memory based 'stream', which implements the ReadStream interface for * a plain memory block. @@ -334,6 +342,8 @@ public: byte *getData() { return _data; } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/mutex.h b/common/mutex.h index 1b52bb40dd2..3c64b0214c5 100644 --- a/common/mutex.h +++ b/common/mutex.h @@ -28,6 +28,14 @@ namespace Common { +/** + * @defgroup common_mutex Mutex + * @ingroup common + * + * @brief API for managing the mutex. + * @{ + */ + class Mutex; /** @@ -62,6 +70,7 @@ public: void unlock(); }; +/** @} */ } // End of namespace Common diff --git a/common/noncopyable.h b/common/noncopyable.h index 24021f42a66..8ab24e67288 100644 --- a/common/noncopyable.h +++ b/common/noncopyable.h @@ -25,6 +25,14 @@ namespace Common { +/** + * @defgroup common_noncopy NonCopyable class + * @ingroup common + * + * @brief API for NonCopyable class. + * @{ + */ + /** * Subclass of NonCopyable can not be copied due to the fact that * we made the copy constructor and assigment operator private. @@ -38,6 +46,8 @@ private: NonCopyable& operator=(const NonCopyable&); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/osd_message_queue.h b/common/osd_message_queue.h index 4da2f1d2e64..88dd89b1852 100644 --- a/common/osd_message_queue.h +++ b/common/osd_message_queue.h @@ -32,6 +32,14 @@ namespace Common { +/** + * @defgroup common_osd_message_queue OSD message queue + * @ingroup common + * + * @brief API for managing the queue of On Screen Display (OSD) messages. + * @{ + */ + /** * Queue OSD messages from any thread to be displayed by the graphic thread. */ @@ -68,6 +76,8 @@ private: uint32 _lastUpdate; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/platform.h b/common/platform.h index bdf1772807e..f9a3b8dedb0 100644 --- a/common/platform.h +++ b/common/platform.h @@ -27,6 +27,14 @@ namespace Common { +/** + * @defgroup common_platform Game platforms + * @ingroup common + * + * @brief API for managing game platforms. + * @{ + */ + class String; /** @@ -84,6 +92,8 @@ extern const char *getPlatformCode(Platform id); extern const char *getPlatformAbbrev(Platform id); extern const char *getPlatformDescription(Platform id); +/** @} */ + } // End of namespace Common #endif diff --git a/common/ptr.h b/common/ptr.h index 565c9d8ceea..cc247f12a66 100644 --- a/common/ptr.h +++ b/common/ptr.h @@ -30,6 +30,14 @@ namespace Common { +/** + * @defgroup common_ptr Pointers + * @ingroup common + * + * @brief API and templates for pointers. + * @{ + */ + class SharedPtrDeletionInternal { public: virtual ~SharedPtrDeletionInternal() {} @@ -329,6 +337,8 @@ private: DisposeAfterUse::Flag _dispose; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/queue.h b/common/queue.h index ee14d5b3644..ed5f964f1bc 100644 --- a/common/queue.h +++ b/common/queue.h @@ -28,6 +28,14 @@ namespace Common { +/** + * @defgroup common_queue Queue + * @ingroup common + * + * @brief API and templates for queues. + * @{ + */ + /** * Variable size Queue class, implemented using our List class. */ @@ -82,6 +90,8 @@ private: List _impl; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/quicktime.h b/common/quicktime.h index 26fc44ac713..4d8af4db6f4 100644 --- a/common/quicktime.h +++ b/common/quicktime.h @@ -41,13 +41,18 @@ namespace Common { class MacResManager; /** - * Parser for QuickTime/MPEG-4 files. + * @defgroup common_quicktime Quicktime file parser + * @ingroup common * - * File parser used in engines: - * - groovie - * - mohawk - * - sci + * @brief Parser for QuickTime/MPEG-4 files. + * + * @details File parser used in engines: + * - groovie + * - mohawk + * - sci + * @{ */ + class QuickTimeParser { public: QuickTimeParser(); @@ -211,6 +216,8 @@ private: int readSMI(Atom atom); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/random.h b/common/random.h index 48cde26dc5c..29f648ecd2a 100644 --- a/common/random.h +++ b/common/random.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_rng RNG + * @ingroup common + * + * @brief Random number generator (RNG) implementation. + * + * @{ + */ + class String; /** @@ -75,6 +84,8 @@ public: uint getRandomNumberRng(uint min, uint max); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/rational.h b/common/rational.h index bd240c99f3a..afa7c56a715 100644 --- a/common/rational.h +++ b/common/rational.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_rational Rational class + * @ingroup common + * + * @brief API for rational class. + * + * @{ + */ + /** A simple rational class that holds fractions. */ class Rational { public: @@ -108,6 +117,8 @@ bool operator<(int left, const Rational &right); bool operator>=(int left, const Rational &right); bool operator<=(int left, const Rational &right); +/** @} */ + } // End of namespace Common #endif diff --git a/common/rdft.h b/common/rdft.h index ae06c72ef82..f8316981622 100644 --- a/common/rdft.h +++ b/common/rdft.h @@ -37,9 +37,18 @@ namespace Common { /** - * (Inverse) Real Discrete Fourier Transform. + * @defgroup common_rdft RDFT algorithm + * @ingroup common * - * Used in audio: + * @brief API for the Real Discrete Fourier Transform (RDFT) algorithm. + * + * @{ + */ + +/** + * @brief (Inverse) Real Discrete Fourier Transform. + * + * @details Used in audio: * - QDM2 * * Used in engines: @@ -107,6 +116,8 @@ private: FFT *_fft; }; +/** @} */ + } // End of namespace Common #endif // COMMON_RDFT_H diff --git a/common/rect.h b/common/rect.h index 96fbe0cbf69..c6a066603ef 100644 --- a/common/rect.h +++ b/common/rect.h @@ -31,6 +31,15 @@ namespace Common { +/** + * @defgroup common_rect Rectangular zones + * @ingroup common + * + * @brief API for operations on rectangular zones. + * + * @{ + */ + /** * Simple class for handling both 2D position and size. */ @@ -297,6 +306,8 @@ struct Rect { } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/rendermode.h b/common/rendermode.h index ae1a7bc7902..7432dcb5aa4 100644 --- a/common/rendermode.h +++ b/common/rendermode.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_rendermode Render modes + * @ingroup common + * + * @brief API for render modes. + * + * @{ + */ + class String; /** @@ -70,6 +79,7 @@ extern String renderMode2GUIO(RenderMode id); // TODO: Rename the following to something better; also, document it extern String allRenderModesGUIOs(); +/** @} */ } // End of namespace Common diff --git a/common/safe-bool.h b/common/safe-bool.h index 92c8af51aac..978040ece40 100644 --- a/common/safe-bool.h +++ b/common/safe-bool.h @@ -40,6 +40,15 @@ namespace Common { }; } + /** + * @defgroup common_safe_bool Safe Boolean + * @ingroup common + * + * @brief Template for a SafeBool function. + * + * @{ + */ + /** * Prevents `operator bool` from implicitly converting to other types. */ @@ -60,6 +69,7 @@ namespace Common { &impl_t::stub : 0; } }; + /** @} */ } // End of namespace Common #endif diff --git a/common/savefile.h b/common/savefile.h index bc76de5659c..8a1bd285530 100644 --- a/common/savefile.h +++ b/common/savefile.h @@ -31,6 +31,14 @@ namespace Common { +/** + * @defgroup common_savefile Save files + * @ingroup common + * + * @brief API for managing save files. + * + * @{ + */ /** * A class which allows game engines to load game state data. @@ -209,6 +217,8 @@ public: virtual void updateSavefilesList(StringArray &lockedFiles) = 0; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/serializer.h b/common/serializer.h index 18fb38563be..84780307593 100644 --- a/common/serializer.h +++ b/common/serializer.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_serializer Serializer + * @ingroup common + * + * @brief API for serializing data. + * + * @{ + */ + #define VER(x) Common::Serializer::Version(x) #define SYNC_AS(SUFFIX,TYPE,SIZE) \ @@ -280,6 +289,7 @@ public: virtual void saveLoadWithSerializer(Serializer &ser) = 0; }; +/** @} */ } // End of namespace Common diff --git a/common/sinetables.h b/common/sinetables.h index bd030ca8330..321983ec0fc 100644 --- a/common/sinetables.h +++ b/common/sinetables.h @@ -25,6 +25,15 @@ namespace Common { +/** + * @defgroup common_sinetables Sine tables + * @ingroup common + * + * @brief API for managing sine tables. + * + * @{ + */ + class SineTable { public: /** @@ -69,6 +78,8 @@ private: int _nPoints; // range of operator[] }; +/** @} */ + } // End of namespace Common #endif // COMMON_SINETABLES_H diff --git a/common/singleton.h b/common/singleton.h index 7deb1dd7dc7..cc0b09400d2 100644 --- a/common/singleton.h +++ b/common/singleton.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_singleton Singleton + * @ingroup common + * + * @brief API for managing singletons. + * + * @{ + */ + /** * Generic template base class for implementing the singleton design pattern. */ @@ -101,6 +110,8 @@ protected: #define DECLARE_SINGLETON(T) \ template<> T *Singleton::_singleton = 0 +/** @} */ + } // End of namespace Common #endif diff --git a/common/stack.h b/common/stack.h index cba3fb124d3..5ee7fad5174 100644 --- a/common/stack.h +++ b/common/stack.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_stack Stack + * @ingroup common + * + * @brief Fixed-size stack implementation. + * + * @{ + */ + /** * Extremly simple fixed size stack class. */ @@ -140,6 +149,8 @@ public: } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/str-array.h b/common/str-array.h index ecd10b459a7..b0693674798 100644 --- a/common/str-array.h +++ b/common/str-array.h @@ -29,12 +29,22 @@ namespace Common { +/** + * @defgroup common_str_array String array + * @ingroup common_str + * + * @brief String array implementation. + * + * @{ + */ + /** * An array of of strings. */ typedef Array StringArray; typedef Array U32StringArray; +/** @} */ } // End of namespace Common diff --git a/common/str.h b/common/str.h index ce1d79fa95c..33c8aa29b7a 100644 --- a/common/str.h +++ b/common/str.h @@ -31,6 +31,15 @@ namespace Common { +/** + * @defgroup common_str Strings + * @ingroup common + * + * @brief API for working with strings. + * + * @{ + */ + class U32String; /** @@ -566,6 +575,8 @@ size_t strnlen(const char *src, size_t maxSize); */ String toPrintable(const String &src, bool keepNewLines = true); +/** @} */ + } // End of namespace Common extern int scumm_stricmp(const char *s1, const char *s2); diff --git a/common/stream.h b/common/stream.h index 1da3cba5609..1dafd841800 100644 --- a/common/stream.h +++ b/common/stream.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_stream Streams + * @ingroup common + * + * @brief API for managing readable and writable data streams. + * + * @{ + */ + class ReadStream; class SeekableReadStream; @@ -714,6 +723,7 @@ public: SeekableReadStreamEndian(bool bigEndian) : ReadStreamEndian(bigEndian) {} }; +/** @} */ } // End of namespace Common diff --git a/common/substream.h b/common/substream.h index 8bc68cc8a99..01cecf1bb5d 100644 --- a/common/substream.h +++ b/common/substream.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_substream Substreams + * @ingroup common_stream + * + * @brief API for managing readable data substreams. + * + * @{ + */ + /** * SubReadStream provides access to a ReadStream restricted to the range * [currentPosition, currentPosition+end). @@ -124,6 +133,7 @@ public: virtual uint32 read(void *dataPtr, uint32 dataSize); }; +/** @} */ } // End of namespace Common diff --git a/common/system.h b/common/system.h index 8776389ab7a..c48b2c7b967 100644 --- a/common/system.h +++ b/common/system.h @@ -69,6 +69,15 @@ class Encoding; typedef Array KeymapArray; } +/** + * @defgroup common_system System + * @ingroup common + * + * @brief Operating system related API. + * + * @{ + */ + class AudioCDManager; class FilesystemFactory; class PaletteManager; @@ -822,6 +831,7 @@ public: */ virtual int getStretchMode() const { return 0; } + /** * Set the size and color format of the virtual screen. Typical sizes include: * - 320x200 (e.g. for most SCUMM games, and Simon) @@ -1699,4 +1709,6 @@ protected: /** The global OSystem instance. Initialized in main(). */ extern OSystem *g_system; +/** @} */ + #endif diff --git a/common/taskbar.h b/common/taskbar.h index d5e62087ba4..cdcee74913d 100644 --- a/common/taskbar.h +++ b/common/taskbar.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_taskbar Taskbar Manager + * @ingroup common + * + * @brief The TaskbarManager module allows for interaction with the ScummVM application icon. + * + * @{ + */ + /** * The TaskbarManager allows interaction with the ScummVM application icon: * - in the taskbar on Windows 7 and later @@ -187,6 +196,8 @@ return (path); \ } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/text-to-speech.h b/common/text-to-speech.h index 041842aa850..e91ed872392 100644 --- a/common/text-to-speech.h +++ b/common/text-to-speech.h @@ -32,6 +32,15 @@ namespace Common { +/** + * @defgroup common_text_speech Text-to-speech Manager + * @ingroup common + * + * @brief The TTS module allows for speech synthesis. + * + * @{ + */ + /** * Text to speech voice class. */ @@ -340,6 +349,8 @@ protected: virtual void updateVoices() {}; }; +/** @} */ + } // End of namespace Common #endif // USE_TTS diff --git a/common/textconsole.h b/common/textconsole.h index e7654dd7e58..6a6baa45ed5 100644 --- a/common/textconsole.h +++ b/common/textconsole.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_text_console Text console + * @ingroup common + * + * @brief Output formatter, typically used for debugging. + * + * @{ + */ + /** * An output formatter takes a source string and 'decorates' it with * extra information, storing the result in a destination buffer. @@ -57,6 +66,8 @@ typedef void (*ErrorHandler)(const char *msg); */ void setErrorHandler(ErrorHandler handler); +/** @} */ + } // End of namespace Common diff --git a/common/timer.h b/common/timer.h index 2db163327de..d1662896201 100644 --- a/common/timer.h +++ b/common/timer.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_timer Timer + * @ingroup common + * + * @brief API for managing the timer. + * + * @{ + */ + class TimerManager : NonCopyable { public: typedef void (*TimerProc)(void *refCon); @@ -57,6 +66,8 @@ public: virtual void removeTimerProc(TimerProc proc) = 0; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/tokenizer.h b/common/tokenizer.h index 82befbd4af8..3dd0797aebc 100644 --- a/common/tokenizer.h +++ b/common/tokenizer.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_tokenizer String tokenizer + * @ingroup common + * + * @brief String tokenizer for creating tokens out of parts of a string. + * + * @{ + */ + /** * A simple non-optimized string tokenizer. * @@ -81,6 +90,9 @@ private: U32String::const_iterator _tokenBegin; ///< Latest found token's begin iterator (Valid after a call to nextToken()) U32String::const_iterator _tokenEnd; ///< Latest found token's end iterator (Valid after a call to nextToken()) }; + +/** @} */ + } // End of namespace Common #endif diff --git a/common/translation.h b/common/translation.h index e910b36ac00..02ad825ad20 100644 --- a/common/translation.h +++ b/common/translation.h @@ -34,6 +34,15 @@ namespace Common { +/** + * @defgroup common_translation Message translation manager + * @ingroup common + * + * @brief API related to translation. + * + * @{ + */ + class File; enum TranslationIDs { @@ -217,6 +226,8 @@ private: int _currentLang; }; +/** @} */ + } // End of namespace Common #define TransMan Common::TranslationManager::instance() diff --git a/common/unarj.h b/common/unarj.h index 2be514c9366..743984127da 100644 --- a/common/unarj.h +++ b/common/unarj.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_unarj ARJ decompressor + * @ingroup common + * + * @brief API related to ARJ archive files. + * + * @{ + */ + class Archive; /** @@ -43,6 +52,8 @@ class Archive; */ Archive *makeArjArchive(const String &name); +/** @} */ + } // End of namespace Common #endif diff --git a/common/unzip.h b/common/unzip.h index f249c5db19b..51b3b18187d 100644 --- a/common/unzip.h +++ b/common/unzip.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_unzip ZIP decompressor + * @ingroup common + * + * @brief API related to ZIP archive files. + * + * @{ + */ + class Archive; class FSNode; class SeekableReadStream; @@ -57,6 +66,8 @@ Archive *makeZipArchive(const FSNode &node); */ Archive *makeZipArchive(SeekableReadStream *stream); +/** @} */ + } // End of namespace Common #endif diff --git a/common/updates.h b/common/updates.h index 1f1c190304d..f671b7cb726 100644 --- a/common/updates.h +++ b/common/updates.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_update Update Manager + * @ingroup common + * + * @brief The UpdateManager module allows for automatic update checking. + * + * @{ + */ + /** * The UpdateManager allows configuring of the automatic update checking * for systems that support it: @@ -127,6 +136,8 @@ public: static int normalizeInterval(int interval); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/ustr.h b/common/ustr.h index 261894bdfda..db4d078717e 100644 --- a/common/ustr.h +++ b/common/ustr.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_ustr UTF-32 strings + * @ingroup common_str + * + * @brief API for working with UTF-32 strings. + * + * @{ + */ + class String; class UnicodeBiDiText; @@ -280,6 +289,9 @@ private: }; U32String operator+(const U32String &x, const U32String &y); + +/** @} */ + } // End of namespace Common #endif diff --git a/common/util.h b/common/util.h index 58d2b981d63..273d0273183 100644 --- a/common/util.h +++ b/common/util.h @@ -26,6 +26,15 @@ #include "common/scummsys.h" #include "common/str.h" +/** + * @defgroup common_util Util + * @ingroup common + * + * @brief Various utility functions. + * + * @{ + */ + /** * Check whether a given pointer is aligned correctly. * Note that 'alignment' must be a power of two! @@ -105,8 +114,15 @@ template inline void ARRAYCLEAR(T (&array) [N], const T &v # define SCUMMVM_CURRENT_FUNCTION "" #endif +/** @} */ + namespace Common { +/** + * @addtogroup common_util + * @{ + */ + /** * Print a hexdump of the data passed in. The number of bytes per line is * customizable. @@ -252,6 +268,8 @@ bool isGraph(int c); */ Common::String getHumanReadableBytes(uint64 bytes, Common::String &unitsOut); +/** @} */ + } // End of namespace Common #endif diff --git a/common/winexe.h b/common/winexe.h index cab08675878..1bf203338a3 100644 --- a/common/winexe.h +++ b/common/winexe.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_winexe Windows resources + * @ingroup common + * + * @brief API for managing Windows resources. + * + * @{ + */ + class SeekableReadStream; /** The default Windows resources. */ @@ -136,6 +145,8 @@ public: static VersionHash *parseVersionInfo(SeekableReadStream *stream); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/winexe_ne.h b/common/winexe_ne.h index 118629abe1d..85b42489c20 100644 --- a/common/winexe_ne.h +++ b/common/winexe_ne.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_winexe_ne Windows New Executable resources + * @ingroup common_winexe + * + * @brief API for managing Windows New Executable resources. + * + * @{ + */ + template class Array; class SeekableReadStream; @@ -90,6 +99,8 @@ private: static String getResourceString(SeekableReadStream &exe, uint32 offset); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/winexe_pe.h b/common/winexe_pe.h index 79b913043aa..67a34a3c7d9 100644 --- a/common/winexe_pe.h +++ b/common/winexe_pe.h @@ -30,6 +30,15 @@ namespace Common { +/** + * @defgroup common_winexe_ne Windows Portable Executable resources + * @ingroup common_winexe + * + * @brief API for managing Windows Portable Executable resources. + * + * @{ + */ + template class Array; class SeekableReadStream; @@ -92,6 +101,8 @@ private: TypeMap _resources; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/xmlparser.h b/common/xmlparser.h index dbd9d0e0cb2..f555e64cead 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -36,6 +36,15 @@ namespace Common { +/** + * @defgroup common_xmlparser XML parser + * @ingroup common + * + * @brief The XML parser allows for parsing XML-like files. + * + * @{ + */ + class SeekableReadStream; #define MAX_XML_DEPTH 8 @@ -349,6 +358,8 @@ private: Stack _activeKey; /** Node stack of the parsed keys */ }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/zlib.h b/common/zlib.h index a1723995111..839c23ba173 100644 --- a/common/zlib.h +++ b/common/zlib.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_zlib zlib + * @ingroup common + * + * @brief API for zlib operations. + * + * @{ + */ + class SeekableReadStream; class WriteStream; @@ -145,6 +154,8 @@ SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped, ui */ WriteStream *wrapCompressedWriteStream(WriteStream *toBeWrapped); +/** @} */ + } // End of namespace Common #endif diff --git a/configure b/configure index 88bfb3363d1..46a4f729300 100755 --- a/configure +++ b/configure @@ -249,6 +249,8 @@ PANDOC="" _pandocpath="$PATH" _pandocformat="default" _pandocext="default" +# Detection features to be linked into executable or not +_detection_features_static=yes # The following variables are automatically detected, and should not # be modified otherwise. Consider them read-only. _posix=no @@ -275,6 +277,7 @@ add_feature vorbis "Vorbis file support" "_vorbis _tremor" add_feature zlib "zlib" "_zlib" add_feature lua "lua" "_lua" add_feature fribidi "FriBidi" "_fribidi" +add_feature cxx11 "c++11" "_use_cxx11" add_feature test_cxx11 "Test C++11" "_test_cxx11" # Directories for installing ScummVM. @@ -1008,6 +1011,8 @@ Game engines: $engines_help Optional Features: --enable-static build a static binary instead of using shared objects + --enable-detection-static build detection features into executable (default) + --enable-detection-dynamic build detection features into a library --enable-c++11 build as C++11 if the compiler allows that --disable-debug disable building with debugging symbols --enable-Werror treat warnings as errors @@ -1196,6 +1201,8 @@ for ac_option in $@; do --enable-dependency-tracking) ;; # End of ignored options. --enable-static) _static_build=yes ;; + --enable-detection-static) _detection_features_static=yes;; + --enable-detection-dynamic) _detection_features_static=no;; # --disable-16bit) _16bit=no ;; #ResidualVM: not supported # --enable-highres) _highres=yes ;; #ResidualVM: not supported # --disable-highres) _highres=no ;; #ResidualVM: not supported @@ -2286,6 +2293,32 @@ if test "$_use_cxx11" = "yes" ; then append_var CXXFLAGS "-std=c++11" fi echo $_use_cxx11 +define_in_config_if_yes "$_use_cxx11" 'USE_CXX11' + +# +# Additional tests for C++11 features that may not be present +# +if test "$_use_cxx11" = "yes" ; then + # Check if initializer list is available + echo_n "Checking if C++11 initializer list is available... " + cat > $TMPC << EOF +#include +#include +class FOO { +public: + FOO(std::initializer_list list) : _size(list.size()) {} + size_t _size; +}; +int main(int argc, char *argv[]) { return 0; } +EOF + cc_check + if test "$TMPR" -eq 0; then + echo yes + else + echo no + define_in_config_if_yes yes 'NO_CXX11_INITIALIZER_LIST' + fi +fi # # Determine extra build flags for debug and/or release builds @@ -4178,6 +4211,12 @@ if test "$_dynamic_modules" = yes ; then add_line_to_config_mk "PLUGIN_SUFFIX := $_plugin_suffix" fi +# +# Set up a define for detection to be used as static or not +# +define_in_config_if_yes "$_detection_features_static" "DETECTION_STATIC" +echo_n "Checking if detection features building statically... " +echo "$_detection_features_static" # # Check whether integrated MT-32 emulator support is requested @@ -6349,6 +6388,27 @@ EOF fi done +# Name which is suffixed to each detection plugin +detectId="_DETECTION" + +echo "Creating engines/detection_table.h" +cat > engines/detection_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:]'` + detectEngine="${j}${detectId}" + cat >> engines/detection_table.h << EOF +LINK_PLUGIN($detectEngine) +EOF + fi +done + + echo "Creating engines/plugins_table.h" cat > engines/plugins_table.h << EOF /* This file is automatically generated by configure */ diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp index eed1a1617d8..9d2d64c4ee1 100644 --- a/devtools/create_project/create_project.cpp +++ b/devtools/create_project/create_project.cpp @@ -103,6 +103,8 @@ enum ProjectType { kProjectXcode }; +std::map isEngineEnabled; + int main(int argc, char *argv[]) { #ifndef USE_WIN32_API // Initialize random number generator for UUID creation @@ -312,6 +314,7 @@ int main(int argc, char *argv[]) { break; } } + isEngineEnabled[i->name] = true; } } @@ -402,6 +405,10 @@ int main(int argc, char *argv[]) { setup.defines.push_back("USE_SDL2"); } + if (setup.useStaticDetection) { + setup.defines.push_back("DETECTION_STATIC"); + } + // List of global warnings and map of project-specific warnings // FIXME: As shown below these two structures have different behavior for // Code::Blocks and MSVC. In Code::Blocks this is used to enable *and* @@ -1059,6 +1066,9 @@ const Feature s_features[] = { // is just no current way of properly detecting this... { "text-console", "USE_TEXT_CONSOLE_FOR_DEBUGGER", false, false, "Text console debugger" }, // This feature is always applied in xcode projects // { "tts", "USE_TTS", false, true, "Text to speech support"} + {"builtin-resources", "BUILTIN_RESOURCES", false, true, "include resources (e.g. engine data, fonts) into the binary"}, + {"detection-static", "USE_DETECTION_FEATURES_STATIC", false, true, "Static linking of detection objects for engines."}, + { "cxx11", "USE_CXX11", false, true, "Compile with c++11 support"} }; const Tool s_tools[] = { @@ -1531,6 +1541,24 @@ void ProjectProvider::createProject(BuildSetup &setup) { //ResidualVM specific: createModuleList(setup.srcDir + "/math", setup.defines, setup.testDirs, in, ex); + // Create engine-detection submodules. + if (setup.useStaticDetection) { + std::vector detectionModuleDirs; + detectionModuleDirs.reserve(setup.engines.size()); + + 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; + } + detectionModuleDirs.push_back(setup.srcDir + "/engines/" + i->name); + } + + for (std::string &str : detectionModuleDirs) { + createModuleList(str, setup.defines, setup.testDirs, in, ex, true); + } + } + // Resource files addResourceFiles(setup, in, ex); @@ -1554,7 +1582,7 @@ void ProjectProvider::createProject(BuildSetup &setup) { createOtherBuildFiles(setup); // In case we create the main ScummVM project files we will need to - // generate engines/plugins_table.h too. + // generate engines/plugins_table.h & engines/detection_table.h if (!setup.tests && !setup.devTools) { createEnginePluginsTable(setup); } @@ -1732,7 +1760,7 @@ void ProjectProvider::addFilesToProject(const std::string &dir, std::ofstream &p delete files; } -void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList) const { +void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, bool forDetection) const { const std::string moduleMkFile = moduleDir + "/module.mk"; std::ifstream moduleMk(moduleMkFile.c_str()); if (!moduleMk) @@ -1744,6 +1772,7 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin shouldInclude.push(true); StringList filesInVariableList; + std::string moduleRootDir; bool hadModule = false; std::string line; @@ -1777,6 +1806,10 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin error("MODULE root " + moduleRoot + " does not match base dir " + moduleDir); hadModule = true; + if (forDetection) { + moduleRootDir = moduleRoot; + break; + } } else if (*i == "MODULE_OBJS") { if (tokens.size() < 3) error("Malformed MODULE_OBJS definition in " + moduleMkFile); @@ -1944,12 +1977,95 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin shouldInclude.pop(); } else if (*i == "elif") { error("Unsupported operation 'elif' in " + moduleMkFile); - } else if (*i == "ifeq") { + } else if (*i == "ifeq" || *i == "ifneq") { //XXX shouldInclude.push(false); } } + if (forDetection) { + int p = moduleRootDir.find('/'); + std::string engineName = moduleRootDir.substr(p + 1); + std::string engineNameUpper; + + for (char &c : engineName) { + engineNameUpper += toupper(c); + } + for (;;) { + std::getline(moduleMk, line); + + if (moduleMk.eof()) + break; + + if (moduleMk.fail()) + error("Failed while reading from " + moduleMkFile); + + TokenList tokens = tokenize(line); + if (tokens.empty()) + continue; + + TokenList::const_iterator i = tokens.begin(); + + if (*i != "DETECT_OBJS" && *i != "ifneq") { + continue; + } + + if (*i == "ifneq") { + ++i; + if (*i != ("($(ENABLE_" + engineNameUpper + "),")) { + continue; + } + + // If the engine is already enabled, skip the additional + // dependencies for detection objects. + if (isEngineEnabled[engineName]) { + bool breakEarly = false; + while (true) { + std::getline(moduleMk, line); + if (moduleMk.eof()) { + error("Unexpected EOF found, while parsing for " + engineName + " engine's module file."); + } else if (line != "endif") { + continue; + } else { + breakEarly = true; + break; + } + } + if (breakEarly) { + break; + } + } + + while (*i != "DETECT_OBJS") { + std::getline(moduleMk, line); + if (moduleMk.eof()) { + break; + } + + tokens = tokenize(line); + + if (tokens.empty()) + continue; + i = tokens.begin(); + } + } + + + if (tokens.size() < 3) + error("Malformed DETECT_OBJS definition in " + moduleMkFile); + ++i; + + if (*i != "+=") + error("Malformed DETECT_OBJS definition in " + moduleMkFile); + + ++i; + + p = (*i).find('/'); + const std::string filename = moduleDir + "/" + (*i).substr(p + 1); + + includeList.push_back(filename); + } + } if (shouldInclude.size() != 1) error("Malformed file " + moduleMkFile); } @@ -1958,17 +2074,29 @@ 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. + // Then, we can generate the actual "plugins_table.h" & "detection_table.h" file. const std::string enginePluginsTableFile = setup.outputDir + "/engines/plugins_table.h"; + const std::string detectionTableFile = setup.outputDir + "/engines/detection_table.h"; + std::ofstream enginePluginsTable(enginePluginsTableFile.c_str()); + std::ofstream detectionTable(detectionTableFile.c_str()); + if (!enginePluginsTable) { error("Could not open \"" + enginePluginsTableFile + "\" for writing"); } + if (!detectionTable) { + error("Could not open \"" + detectionTableFile + "\" 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"; + detectionTable << "/* 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. @@ -1983,6 +2111,8 @@ void ProjectProvider::createEnginePluginsTable(const BuildSetup &setup) { enginePluginsTable << "#if PLUGIN_ENABLED_STATIC(" << engineName << ")\n" << "LINK_PLUGIN(" << engineName << ")\n" << "#endif\n"; + + detectionTable << "LINK_PLUGIN(" << engineName << "_DETECTION)\n"; } } } // namespace CreateProjectTool diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h index a3a4fd20e89..1c4aaac7ece 100644 --- a/devtools/create_project/create_project.h +++ b/devtools/create_project/create_project.h @@ -29,7 +29,9 @@ #include #include +#include #include +#include #include @@ -238,6 +240,7 @@ struct BuildSetup { bool createInstaller; ///< Create installer after the build bool useSDL2; ///< Whether to use SDL2 or not. bool useCanonicalLibNames; ///< Whether to use canonical libraries names or default ones + bool useStaticDetection; ///< Whether to link detection features inside the executable or not. BuildSetup() { devTools = false; @@ -246,6 +249,7 @@ struct BuildSetup { createInstaller = false; useSDL2 = true; useCanonicalLibNames = false; + useStaticDetection = true; } }; @@ -565,7 +569,7 @@ protected: * @param includeList Reference to a list, where included files should be added. * @param excludeList Reference to a list, where excluded files should be added. */ - void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList) const; + void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, bool forDetection = false) const; /** * Creates an UUID for every enabled engine of the diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp index 0ba61630da9..83012996814 100644 --- a/devtools/create_project/xcode.cpp +++ b/devtools/create_project/xcode.cpp @@ -455,6 +455,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { DEF_SYSTBD("libiconv"); // Local libraries + if (CONTAINS_DEFINE(setup.defines, "USE_FAAD")) { + DEF_LOCALLIB_STATIC("libfaad"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) { DEF_LOCALLIB_STATIC("libFLAC"); } @@ -476,6 +479,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) { DEF_LOCALLIB_STATIC("libmad"); } + if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { + DEF_LOCALLIB_STATIC("libmpeg2"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FRIBIDI")) { DEF_LOCALLIB_STATIC("libfribidi"); } @@ -494,12 +500,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { } if (CONTAINS_DEFINE(setup.defines, "USE_THEORADEC")) { DEF_LOCALLIB_STATIC("libtheoradec"); - } if (CONTAINS_DEFINE(setup.defines, "USE_GLEW")) { // ResidualVM specific DEF_LOCALLIB_STATIC("libGLEW"); } - if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { // ResidualVM specific - DEF_LOCALLIB_STATIC("libmpeg2"); } if (CONTAINS_DEFINE(setup.defines, "USE_ZLIB")) { DEF_SYSTBD("libz"); @@ -554,6 +557,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { frameworks_iOS.push_back("QuartzCore.framework"); frameworks_iOS.push_back("OpenGLES.framework"); + if (CONTAINS_DEFINE(setup.defines, "USE_FAAD")) { + frameworks_iOS.push_back("libfaad.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) { frameworks_iOS.push_back("libFLAC.a"); } @@ -582,6 +588,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) { frameworks_iOS.push_back("libmad.a"); } + if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { + frameworks_iOS.push_back("libmpeg2.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FRIBIDI")) { frameworks_iOS.push_back("libfribidi.a"); } @@ -645,6 +654,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { frameworks_osx.push_back("OpenGL.framework"); // ResidualVM specific frameworks_osx.push_back("AudioUnit.framework"); + if (CONTAINS_DEFINE(setup.defines, "USE_FAAD")) { + frameworks_osx.push_back("libfaad.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) { frameworks_osx.push_back("libFLAC.a"); } @@ -665,6 +677,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) { frameworks_osx.push_back("libmad.a"); } + if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { + frameworks_osx.push_back("libmpeg2.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FRIBIDI")) { frameworks_osx.push_back("libfribidi.a"); } @@ -687,12 +702,12 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_GLEW")) { // ResidualVM specific frameworks_osx.push_back("libGLEW.a"); } - if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { // ResidualVM specific - frameworks_osx.push_back("libmpeg2.a"); - } if (CONTAINS_DEFINE(setup.defines, "USE_ZLIB")) { frameworks_osx.push_back("libz.tbd"); } + if (CONTAINS_DEFINE(setup.defines, "USE_DISCORD")) { + frameworks_osx.push_back("libdiscord-rpc.a"); + } if (setup.useSDL2) { frameworks_osx.push_back("libSDL2main.a"); @@ -939,6 +954,9 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) { ADD_SETTING(scummvm_Debug, "ALWAYS_SEARCH_USER_PATHS", "NO"); ADD_SETTING_QUOTE(scummvm_Debug, "USER_HEADER_SEARCH_PATHS", "$(SRCROOT) $(SRCROOT)/engines"); ADD_SETTING(scummvm_Debug, "CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED", "YES"); + if (CONTAINS_DEFINE(setup.defines, "USE_CXX11")) { + ADD_SETTING(scummvm_Debug, "CLANG_CXX_LANGUAGE_STANDARD", "\"c++0x\""); + } ADD_SETTING(scummvm_Debug, "CLANG_WARN_BOOL_CONVERSION", "YES"); ADD_SETTING(scummvm_Debug, "CLANG_WARN_CONSTANT_CONVERSION", "YES"); ADD_SETTING(scummvm_Debug, "CLANG_WARN_EMPTY_BODY", "YES"); @@ -1097,6 +1115,9 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) { ADD_SETTING(scummvmOSX_Debug, "COPY_PHASE_STRIP", "NO"); ADD_SETTING_QUOTE(scummvmOSX_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf"); ADD_SETTING_QUOTE(scummvmOSX_Debug, "FRAMEWORK_SEARCH_PATHS", ""); + if (CONTAINS_DEFINE(setup.defines, "USE_CXX11")) { + ADD_SETTING(scummvmOSX_Debug, "CLANG_CXX_LANGUAGE_STANDARD", "\"c++0x\""); + } ADD_SETTING(scummvmOSX_Debug, "GCC_C_LANGUAGE_STANDARD", "c99"); ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO"); ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_RTTI", "YES"); diff --git a/devtools/credits.pl b/devtools/credits.pl index 668beea8782..563050c260f 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -6,8 +6,6 @@ # - The AUTHORS file # - The gui/credits.h header file # - The Credits.rtf file used by the Mac OS X port -# - The credits.xml file, part of the DocBook manual -# - The credits.xml, for use on the website (different format than the DocBook one) # - The credits.yaml, alternative version for use on the website # # Initial version written by Fingolfin in December 2004. @@ -40,17 +38,15 @@ my @section_count = ( 0, 0, 0 ); if ($#ARGV >= 0) { $mode = "TEXT" if ($ARGV[0] eq "--text"); # AUTHORS file - $mode = "XML-WEB" if ($ARGV[0] eq "--xml-website"); # credits.xml (for use on the website) $mode = "CPP" if ($ARGV[0] eq "--cpp"); # credits.h (for use by about.cpp) - $mode = "XML-DOC" if ($ARGV[0] eq "--xml-docbook"); # credits.xml (DocBook) $mode = "RTF" if ($ARGV[0] eq "--rtf"); # Credits.rtf (Mac OS X About box) $mode = "STRONGHELP" if ($ARGV[0] eq "--stronghelp"); # AUTHORS (RISC OS StrongHelp manual) - $mode = "YAML" if ($ARGV[0] eq "--yaml"); # YAML (Simple format) + $mode = "YAML" if ($ARGV[0] eq "--yaml"); # YAML (Simple format, used in the Website) } if ($mode eq "") { - print STDERR "Usage: $0 [--text | --xml-website | --cpp | --xml-docbook | --rtf | --stronghelp | --yaml]\n"; - print STDERR " Just pass --text / --xml-website / --cpp / --xml-docbook / --rtf / --stronghelp / --yaml as parameter, and credits.pl\n"; + print STDERR "Usage: $0 [--text | --cpp | --rtf | --stronghelp | --yaml]\n"; + print STDERR " Just pass --text / --cpp / --rtf / --stronghelp / --yaml as parameter, and credits.pl\n"; print STDERR " will print out the corresponding version of the credits to stdout.\n"; exit 1; } @@ -68,27 +64,6 @@ sub html_entities_to_ascii { my $text = shift; # For now we hardcode these mappings - # Á -> A - # á -> a - # é -> e - # í -> i - # ì -> i - # ó -> o - # ø -> o - # ú -> u - # ö -> o / oe - # ä -> a - # ë -> e - # ü -> ue - # å -> aa - # & -> & - # ą -> a - # Ł -> L - # ł -> l - # ś -> s - # Š -> S - # Ľ -> L - # ñ -> n $text =~ s/Á/A/g; $text =~ s/á/a/g; $text =~ s/é/e/g; @@ -236,9 +211,7 @@ sub html_entities_to_rtf { sub begin_credits { my $title = shift; - if ($mode eq "TEXT") { - #print html_entities_to_ascii($title)."\n"; - } elsif ($mode eq "RTF") { + if ($mode eq "RTF") { print '{\rtf1\mac\ansicpg10000' . "\n"; print '{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;}' . "\n"; print '{\colortbl;\red255\green255\blue255;\red0\green128\blue0;\red128\green128\blue128;}' . "\n"; @@ -247,26 +220,8 @@ sub begin_credits { } elsif ($mode eq "CPP") { print "// This file was generated by credits.pl. Do not edit by hand!\n"; print "static const char *credits[] = {\n"; - } elsif ($mode eq "XML-DOC") { - print "\n"; - print "\n"; - print "\n"; - print "\n"; - print " " . $title . "\n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - } elsif ($mode eq "XML-WEB") { - print "\n"; - print "\n"; - print "\n"; } elsif ($mode eq "YAML") { print "# This file was generated by credits.pl. Do not edit by hand!\n"; - print "credits:\n"; } elsif ($mode eq "STRONGHELP") { print "ScummVM - AUTHORS\n"; print "# This file was generated by credits.pl. Do not edit by hand!\n"; @@ -279,13 +234,6 @@ sub end_credits { print "}\n"; } elsif ($mode eq "CPP") { print "};\n"; - } elsif ($mode eq "XML-DOC") { - print " \n"; - print " \n"; - print " \n"; - print "\n"; - } elsif ($mode eq "XML-WEB") { - print "\n"; } } @@ -336,30 +284,9 @@ sub begin_section { $title = html_entities_to_cpp($title); print '"C1""'.$title.'",' . "\n"; } - } elsif ($mode eq "XML-DOC") { - print " "; - print "" . $title . ":"; - print "\n"; - } elsif ($mode eq "XML-WEB") { - if ($section_level eq 0) { - print "\t
\n"; - print "\t\t" . $title . "\n"; - if ($anchor) { - print "\t\t" . $anchor . "\n"; - } - } elsif ($section_level eq 1) { - print "\t\t\n"; - print "\t\t\t" . $title . "\n"; - if ($anchor) { - print "\t\t\t" . $anchor . "\n"; - } - } else { - #print "\t\t\t" . $title . "\n"; - #print "\t\t\t\t" . $title . "\n"; - } } elsif ($mode eq "YAML") { - my $key = "section:\n"; - $indent = " " . (" " x $section_level); + my $key = ""; + $indent = (" " x ($section_level)); if ($section_level eq 1) { $key = "subsection:\n"; } @@ -405,16 +332,6 @@ sub end_section { # nothing } elsif ($mode eq "CPP") { print '"",' . "\n"; - } elsif ($mode eq "XML-DOC") { - print " \n\n"; - } elsif ($mode eq "XML-WEB") { - if ($section_level eq 0) { - print "\t
\n"; - } elsif ($section_level eq 1) { - print "\t\t\n"; - } else { - #print "\t\t\t\n"; - } } } @@ -422,12 +339,8 @@ sub begin_persons { my $title = shift; my $level = shift; - if ($mode eq "XML-WEB") { - print "\t\t\t\n"; - print "\t\t\t\t" . $title . "\n"; - #print "\t\t\t\t\n"; - } elsif ($mode eq "YAML") { - $group_indent = $level eq 1 ? " " : " " . (" " x $section_level); + if ($mode eq "YAML") { + $group_indent = $level eq 1 ? " " : (" " x $section_level); if ($group_started == 0) { print $group_indent . "group:\n"; $group_started = 1; @@ -443,9 +356,6 @@ sub end_persons { print "\n"; } elsif ($mode eq "RTF") { # nothing - } elsif ($mode eq "XML-WEB") { - #print "\t\t\t\t\n"; - print "\t\t\t\n"; } elsif ($mode eq "STRONGHELP") { print "\n"; } elsif ($mode eq "YAML") { @@ -504,17 +414,6 @@ sub add_person { $desc = html_entities_to_cpp($desc); print '"C2""'.$desc.'",' . "\n"; } - } elsif ($mode eq "XML-DOC") { - $name = $nick if $name eq ""; - print " " . $name . ""; - print "" . $desc . "\n"; - } elsif ($mode eq "XML-WEB") { - $name = "???" if $name eq ""; - print "\t\t\t\t\n"; - print "\t\t\t\t\t" . $name . "\n"; - print "\t\t\t\t\t" . $nick . "\n"; - print "\t\t\t\t\t" . $desc . "\n"; - print "\t\t\t\t\n"; } elsif ($mode eq "YAML") { $indent = $group_indent . " "; @@ -559,13 +458,8 @@ sub add_paragraph { my $line_end = '",'; print $line_start . $text . $line_end . "\n"; print $line_start . $line_end . "\n"; - } elsif ($mode eq "XML-DOC") { - print " " . $text . "\n"; - print " \n\n"; - } elsif ($mode eq "XML-WEB") { - print "\t\t" . $text . "\n"; } elsif ($mode eq "YAML") { - $indent = " " . (" " x $section_level); + $indent = (" " x $section_level); if ($paragraph_started eq 0) { print $indent . "paragraph:\n"; $paragraph_started = 1; diff --git a/devtools/encode-macbinary.sh b/devtools/encode-macbinary.sh index 25b2b5f1b7e..d8f18b109ca 100755 --- a/devtools/encode-macbinary.sh +++ b/devtools/encode-macbinary.sh @@ -104,6 +104,11 @@ for parm in "$@" ; do fi done # for parm in ... +if [[ $# -eq 0 ]] ; then + usage + exit 0 +fi + if [[ $1 == "macbinary" ]] ; then if ! `command -v macbinary >/dev/null 2>/dev/null` ; then echo "macbinary not found. Exiting" diff --git a/dists/ps3/ICON0.PNG b/dists/ps3/ICON0.PNG deleted file mode 100644 index 82b293328b2..00000000000 Binary files a/dists/ps3/ICON0.PNG and /dev/null differ diff --git a/dists/ps3/readme-ps3.md b/dists/ps3/readme-ps3.md deleted file mode 100644 index 9304fcde8c4..00000000000 --- a/dists/ps3/readme-ps3.md +++ /dev/null @@ -1,55 +0,0 @@ -Prerequisites -============= -- A homebrew enabled PlayStation 3 console. As of now that mostly means having a custom firmware installed. Obtaining and installing such a software is out of the scope of this document. Sorry, but you're on your own for that one. -- At least one ResidualVM supported game. The list of compatible games can be seen here: https://www.residualvm.org/compatibility/ -- An USB drive. - -Installing -========== -From a computer, download the installable package of the PS3 port from ResidualVM's main site. It should be a .pkg file. Copy it to an USB drive. -After having plugged the USB drive to you PS3, the installation package should appear in the XMB under the "Games > Install Package" menu. Installing it copies ResidualVM and its dependencies to your PS3's hard drive. It also adds the "Games > PlayStation 3 > ResidualVM" XMB entry which is to be used to launch ResidualVM. - -Configuring and playing games -============================= -The user manual describes how to add games to ResidualVM and launch them : https://wiki.residualvm.org/index.php/Running_ResidualVM - -PlayStation 3 Specifics -======================= -Games can be launched either from an USB drive or from the internal hard drive. The internal hard drive has better performance though. -Savegames are wrote in the /hdd0/game/RESI12000/saves folder. - -Joypad button mapping -===================== -- Left stick => Mouse -- R1 + Left stick => Slow Mouse -- Cross => Left mouse button -- Circle => Right mouse button -- DPad => Cursor Keys (useful for character motion) -- R1 + DPad => Diagonal Cursor Keys -- L1 => Game menu (F5) -- R1 => Shift (used to enable Mass Add in menu) -- Square => Period '.' (used to skip dialog lines) -- R1 + Square => Space ' ' -- Triangle => Escape (used to skip cutscenes) -- R1 + Triangle => Return -- Start => ResidualVM's global in-game menu -- Select => Toggle virtual keyboard -- R1 + Select => AGI predictive input dialog - -Disclaimer -========== -Unauthorized distribution of an installable package with non freeware games included is a violation of the copyright law and is as such forbidden. - -Building from source -==================== -This port of ResidualVM to the PS3 is based on SDL2. It uses the open source SDK PSL1GHT. - -The dependencies needed to build it are : - -- The toolchain from https://github.com/ps3dev/ps3toolchain -- SDL from https://bitbucket.org/bgK/sdl_psl1ght -- ResidualVM from https://github.com/residualvm/residualvm - -Once all the dependencies are correctly setup, an installable package can be obtained from source by issuing the following command : - -./configure --host=ps3 && make ps3pkg diff --git a/dists/ps3/sfo.xml b/dists/ps3/sfo.xml deleted file mode 100644 index b2bd942db63..00000000000 --- a/dists/ps3/sfo.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - 0 - - - 1 - - - HG - - - 0 - - - 01.8000 - - - 63 - - - 279 - - - ResidualVM - - - RESI12000 - - - 01.00 - - diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index 58b162805a0..1d579ab7c76 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -40,7 +40,7 @@ */ class FileMapArchive : public Common::Archive { public: - FileMapArchive(const AdvancedMetaEngine::FileMap &fileMap) : _fileMap(fileMap) {} + FileMapArchive(const AdvancedMetaEngineStatic::FileMap &fileMap) : _fileMap(fileMap) {} bool hasFile(const Common::String &name) const override { return _fileMap.contains(name); @@ -48,7 +48,7 @@ public: int listMembers(Common::ArchiveMemberList &list) const override { int files = 0; - for (AdvancedMetaEngine::FileMap::const_iterator it = _fileMap.begin(); it != _fileMap.end(); ++it) { + for (AdvancedMetaEngineStatic::FileMap::const_iterator it = _fileMap.begin(); it != _fileMap.end(); ++it) { list.push_back(Common::ArchiveMemberPtr(new Common::FSNode(it->_value))); ++files; } @@ -57,7 +57,7 @@ public: } const Common::ArchiveMemberPtr getMember(const Common::String &name) const override { - AdvancedMetaEngine::FileMap::const_iterator it = _fileMap.find(name); + AdvancedMetaEngineStatic::FileMap::const_iterator it = _fileMap.find(name); if (it == _fileMap.end()) { return Common::ArchiveMemberPtr(); } @@ -71,7 +71,7 @@ public: } private: - const AdvancedMetaEngine::FileMap &_fileMap; + const AdvancedMetaEngineStatic::FileMap &_fileMap; }; static Common::String sanitizeName(const char *name) { @@ -120,7 +120,7 @@ static Common::String generatePreferredTarget(const ADGameDescription *desc) { return res; } -DetectedGame AdvancedMetaEngine::toDetectedGame(const ADDetectedGame &adGame) const { +DetectedGame AdvancedMetaEngineStatic::toDetectedGame(const ADDetectedGame &adGame) const { const ADGameDescription *desc = adGame.desc; const char *title; @@ -186,7 +186,7 @@ bool cleanupPirated(ADDetectedGames &matched) { } -DetectedGames AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const { +DetectedGames AdvancedMetaEngineStatic::detectGames(const Common::FSList &fslist) const { FileMap allFiles; if (fslist.empty()) @@ -232,7 +232,7 @@ DetectedGames AdvancedMetaEngine::detectGames(const Common::FSList &fslist) cons return detectedGames; } -const ExtraGuiOptions AdvancedMetaEngine::getExtraGuiOptions(const Common::String &target) const { +const ExtraGuiOptions AdvancedMetaEngineStatic::getExtraGuiOptions(const Common::String &target) const { if (!_extraGuiOptions) return ExtraGuiOptions(); @@ -260,7 +260,7 @@ const ExtraGuiOptions AdvancedMetaEngine::getExtraGuiOptions(const Common::Strin return options; } -Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const { +Common::Error AdvancedMetaEngineStatic::createInstance(OSystem *syst, Engine **engine) const { assert(engine); Common::Language language = Common::UNK_LANG; @@ -348,13 +348,26 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) debug(2, "Running %s", gameDescriptor.description.c_str()); initSubSystems(agdDesc.desc); - if (!createInstance(syst, engine, agdDesc.desc)) - return Common::kNoGameDataFoundError; - else - return Common::kNoError; + + PluginList pl = EngineMan.getPlugins(PLUGIN_TYPE_ENGINE); + Plugin *plugin = nullptr; + + // By this point of time, we should have only one plugin in memory. + if (pl.size() == 1) { + plugin = pl[0]; + } + + if (plugin) { + // Call child class's createInstanceMethod. + if (plugin->get().createInstance(syst, engine, agdDesc.desc)) { + return Common::Error(Common::kNoError); + } + } + + return Common::Error(Common::kNoGameDataFoundError); } -void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName) const { +void AdvancedMetaEngineStatic::composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName) const { if (depth <= 0) return; @@ -394,7 +407,7 @@ void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSL } } -bool AdvancedMetaEngine::getFileProperties(const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const { +bool AdvancedMetaEngineStatic::getFileProperties(const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const { // FIXME/TODO: We don't handle the case that a file is listed as a regular // file and as one with resource fork. @@ -426,7 +439,39 @@ bool AdvancedMetaEngine::getFileProperties(const FileMap &allFiles, const ADGame return true; } -ADDetectedGames AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const { +bool AdvancedMetaEngine::getFilePropertiesExtern(uint md5Bytes, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const { + // FIXME/TODO: We don't handle the case that a file is listed as a regular + // file and as one with resource fork. + + if (game.flags & ADGF_MACRESFORK) { + FileMapArchive fileMapArchive(allFiles); + + Common::MacResManager macResMan; + + if (!macResMan.open(fname, fileMapArchive)) + return false; + + fileProps.md5 = macResMan.computeResForkMD5AsString(md5Bytes); + fileProps.size = macResMan.getResForkDataSize(); + + if (fileProps.size != 0) + return true; + } + + if (!allFiles.contains(fname)) + return false; + + Common::File testFile; + + if (!testFile.open(allFiles[fname])) + return false; + + fileProps.size = (int32)testFile.size(); + fileProps.md5 = Common::computeStreamMD5AsString(testFile, md5Bytes); + return true; +} + +ADDetectedGames AdvancedMetaEngineStatic::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const { FilePropertiesMap filesProps; ADDetectedGames matched; @@ -551,7 +596,7 @@ ADDetectedGames AdvancedMetaEngine::detectGame(const Common::FSNode &parent, con return matched; } -ADDetectedGame AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const { +ADDetectedGame AdvancedMetaEngineStatic::detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const { const ADFileBasedFallback *ptr; const char* const* filenames; @@ -599,11 +644,11 @@ ADDetectedGame AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, return result; } -PlainGameList AdvancedMetaEngine::getSupportedGames() const { +PlainGameList AdvancedMetaEngineStatic::getSupportedGames() const { return PlainGameList(_gameIds); } -PlainGameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const { +PlainGameDescriptor AdvancedMetaEngineStatic::findGame(const char *gameId) const { // First search the list of supported gameids for a match. const PlainGameDescriptor *g = findPlainGameDescriptor(gameId, _gameIds); if (g) @@ -613,7 +658,7 @@ PlainGameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const { return PlainGameDescriptor::empty(); } -AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions) +AdvancedMetaEngineStatic::AdvancedMetaEngineStatic(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions) : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameIds(gameIds), _extraGuiOptions(extraGuiOptions) { @@ -625,10 +670,22 @@ AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, con _matchFullPaths = false; } -void AdvancedMetaEngine::initSubSystems(const ADGameDescription *gameDesc) const { +void AdvancedMetaEngineStatic::initSubSystems(const ADGameDescription *gameDesc) const { #ifdef ENABLE_EVENTRECORDER if (gameDesc) { g_eventRec.processGameDescription(gameDesc); } #endif } + +Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const { + PluginList pl = PluginMan.getPlugins(PLUGIN_TYPE_ENGINE); + if (pl.size() == 1) { + Plugin *metaEnginePlugin = PluginMan.getMetaEngineFromEngine(pl[0]); + if (metaEnginePlugin) { + return metaEnginePlugin->get().createInstance(syst, engine); + } + } + + return Common::Error(); +} diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index 941f59d4976..a48b5cdb8af 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -166,9 +166,9 @@ struct ADExtraGuiOptionsMap { #define AD_EXTRA_GUI_OPTIONS_TERMINATOR { 0, { 0, 0, 0, 0 } } /** - * A MetaEngine implementation based around the advanced detector code. + * A MetaEngineStatic implementation based around the advanced detector code. */ -class AdvancedMetaEngine : public MetaEngine { +class AdvancedMetaEngineStatic : public MetaEngineStatic { protected: /** * Pointer to an array of objects which are either ADGameDescription @@ -246,7 +246,7 @@ protected: bool _matchFullPaths; public: - AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions = 0); + AdvancedMetaEngineStatic(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions = 0); /** * Returns list of targets supported by the engine. @@ -258,14 +258,16 @@ public: DetectedGames detectGames(const Common::FSList &fslist) const override; - virtual Common::Error createInstance(OSystem *syst, Engine **engine) const override; + /** + * A generic createInstance. + * For instantiating engine objects, this method is called first, + * and then the subclass implemented createInstance is called from within. + */ + Common::Error createInstance(OSystem *syst, Engine **engine) const; virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override; protected: - // To be implemented by subclasses - virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const = 0; - typedef Common::HashMap FileMap; /** @@ -322,4 +324,57 @@ protected: friend class FileMapArchive; // for FileMap }; +/** + * A MetaEngine implementation of AdvancedMetaEngine. + */ +class AdvancedMetaEngine : public MetaEngine { +public: + /** + * Base createInstance for AMEC. + * The AME provides a default createInstance which is called first, so we should invoke that + * first. + * By the point of time we call this, we assume that we only have one + * plugin engine loaded in memory. + */ + virtual Common::Error createInstance(OSystem *syst, Engine **engine) const override; + + /** + * To be implemented by subclasses, which is called after we call the base + * createInstance function above. + */ + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const = 0; + + /** + * Provide the engineID here, must match the one from MetaEngine. + * + * @see MetaEngineConnect::getName(). + */ + virtual const char *getName() const override = 0; + +public: + typedef Common::HashMap FileMap; + + /** + * An (optional) generic fallback detect function which is invoked + * if the regular MD5 based detection failed to detect anything. + * NOTE: This is only meant to be used if fallback detection is heavily dependant on engine resources. + * + * To use this, implement the intended fallbackDetectExtern inside the relevant MetaEngineConnect class. + * Then, override the method "fallbackDetect" inside your MetaEngine class. + * Finally, provide a "hook" to fetch the relevant MetaEngineConnect class and then use the orignal detection + * method. + * + * An example for the way this is used can be found in the Wintermute Engine. + */ + virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist) const { + return ADDetectedGame(); + } + + /** + * Get the properties (size and MD5) of this file. + * Based on MetaEngine::getFileProperties. + */ + bool getFilePropertiesExtern(uint md5Bytes, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const; +}; + #endif diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp index 9314c0b9eeb..a6c6497e7e8 100644 --- a/engines/dialogs.cpp +++ b/engines/dialogs.cpp @@ -285,7 +285,7 @@ ConfigDialog::ConfigDialog() : int tabId = tab->addTab(_("Game"), "GlobalConfig_Engine"); if (g_engine->hasFeature(Engine::kSupportsChangingOptionsDuringRuntime)) { - _engineOptions = metaEngine.buildEngineOptionsWidget(tab, "GlobalConfig_Engine.Container", gameDomain); + _engineOptions = metaEngine.buildEngineOptionsWidgetDynamic(tab, "GlobalConfig_Engine.Container", gameDomain); } if (_engineOptions) { diff --git a/engines/engine.cpp b/engines/engine.cpp index 2c11f83fe7e..c4183d1dac1 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -875,10 +875,20 @@ EnginePlugin *Engine::getMetaEnginePlugin() const { */ -MetaEngine &Engine::getMetaEngine() { +MetaEngineStatic &Engine::getMetaEngineStatic() { const Plugin *plugin = EngineMan.findPlugin(ConfMan.get("engineid")); assert(plugin); - return plugin->get(); + return plugin->get(); +} + +MetaEngine &Engine::getMetaEngine() { + const Plugin *metaEnginePlugin = EngineMan.findPlugin(ConfMan.get("engineid")); + assert(metaEnginePlugin); + + const Plugin *enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + assert(enginePlugin); + + return enginePlugin->get(); } PauseToken::PauseToken() : _engine(nullptr) {} diff --git a/engines/engine.h b/engines/engine.h index dd0a81d5b7c..707000aeaae 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -31,6 +31,7 @@ #include "common/singleton.h" class OSystem; +class MetaEngineStatic; class MetaEngine; namespace Audio { @@ -386,6 +387,7 @@ public: */ static bool shouldQuit(); + static MetaEngineStatic &getMetaEngineStatic(); static MetaEngine &getMetaEngine(); /** diff --git a/engines/metaengine.cpp b/engines/metaengine.cpp index 2a8bc127bfe..2b1222ae580 100644 --- a/engines/metaengine.cpp +++ b/engines/metaengine.cpp @@ -260,9 +260,9 @@ WARN_UNUSED_RESULT bool MetaEngine::readSavegameHeader(Common::InSaveFile *in, E } -/////////////////////////////////////// -// MetaEngine default implementations -/////////////////////////////////////// +////////////////////////////////////////////// +// MetaEngineConnect default implementations +////////////////////////////////////////////// SaveStateList MetaEngine::listSaves(const char *target) const { if (!hasFeature(kSavesUseExtendedFormat)) @@ -334,7 +334,7 @@ SaveStateList MetaEngine::listSaves(const char *target, bool saveMode) const { return saveList; } -void MetaEngine::registerDefaultSettings(const Common::String &) const { +void MetaEngineStatic::registerDefaultSettings(const Common::String &) const { // Note that as we don't pass the target to getExtraGuiOptions // we get all the options, even those not relevant for the current // game. This is necessary because some engines unconditionally @@ -345,7 +345,16 @@ void MetaEngine::registerDefaultSettings(const Common::String &) const { } } -GUI::OptionsContainerWidget *MetaEngine::buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const { +GUI::OptionsContainerWidget *MetaEngineStatic::buildEngineOptionsWidgetStatic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const { + const ExtraGuiOptions engineOptions = getExtraGuiOptions(target); + if (engineOptions.empty()) { + return nullptr; + } + + return new GUI::ExtraGuiOptionsWidget(boss, name, target, engineOptions); +} + +GUI::OptionsContainerWidget *MetaEngine::buildEngineOptionsWidgetDynamic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const { const ExtraGuiOptions engineOptions = getExtraGuiOptions(target); if (engineOptions.empty()) { return nullptr; diff --git a/engines/metaengine.h b/engines/metaengine.h index 7e9657b7cfd..816a19f1da0 100644 --- a/engines/metaengine.h +++ b/engines/metaengine.h @@ -94,21 +94,17 @@ struct ExtendedSavegameHeader { }; /** - * A meta engine is essentially a factory for Engine instances with the + * A meta engine static is essentially a factory for Engine instances with the * added ability of listing and detecting supported games. - * Every engine "plugin" provides a hook to get an instance of a MetaEngine - * subclass for that "engine plugin". E.g. SCUMM povides ScummMetaEngine. + * Every engine "plugin" provides a hook to get an instance of a MetaEngineStatic + * subclass for that "engine plugin". E.g. SCUMM povides ScummMetaEngineStatic. * This is then in turn used by the frontend code to detect games, - * and instantiate actual Engine objects. + * and other useful functionality. To instantiate actual Engine objects, + * See the class MetaEngine below. */ -class MetaEngine : public PluginObject { -private: - /** - * Converts the current screen contents to a thumbnail, and saves it - */ - static void saveScreenThumbnail(Common::OutSaveFile *saveFile); +class MetaEngineStatic : public PluginObject { public: - virtual ~MetaEngine() {} + virtual ~MetaEngineStatic() {} /** Get the engine ID */ virtual const char *getEngineId() const = 0; @@ -129,6 +125,78 @@ public: */ virtual DetectedGames detectGames(const Common::FSList &fslist) const = 0; + /** + * Return a list of extra GUI options for the specified target. + * If no target is specified, all of the available custom GUI options are + * Returned for the plugin (used to set default values). + * + * Currently, this only supports options with checkboxes. + * + * The default implementation returns an empty list. + * + * @param target name of a config manager target + * @return a list of extra GUI options for an engine plugin and + * target + */ + virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const { + return ExtraGuiOptions(); + } + + /** + * Register the default values for the settings the engine uses into the + * configuration manager. + * + * @param target name of a config manager target + */ + virtual void registerDefaultSettings(const Common::String &target) const; + + /** + * Return a GUI widget container for configuring the specified target options. + * + * The returned widget is shown in the Engine tab in the edit game dialog. + * Engines can build custom options dialogs, but by default a simple widget + * allowing to configure the extra GUI options is used. + * + * Engines that don't want to have an Engine tab in the edit game dialog + * can return nullptr. + * + * @param boss the widget / dialog the returned widget is a child of + * @param name the name the returned widget must use + * @param target name of a config manager target + */ + virtual GUI::OptionsContainerWidget *buildEngineOptionsWidgetStatic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const; +}; + +/** + * A MetaEngine is another factory for Engine instances, and is very + * similiar to meta engines. This class, however, composes of bridged functionalities + * that can be used to connect an actual Engine with a MetaEngine. + * Every engine "plugin" provides a hook to get an instance of MetaEngine subclass + * for that "engine plugin.". E.g. SCUMM provides a ScummMetaEngine. + * This is then in turn used for things like instantiating engine objects, listing savefiles, + * querying save metadata, etc. + * Since engine plugins can be used a external runtime libraries, these can live and build inside + * the engine, while a MetaEngine will always build into the executable to be able to detect code. + */ +class MetaEngine : public PluginObject { +private: + /** + * Converts the current screen contents to a thumbnail, and saves it + */ + static void saveScreenThumbnail(Common::OutSaveFile *saveFile); +public: + virtual ~MetaEngine() {} + + /** + * Name of the engine plugin. + * Classes inheriting a MetaEngineConnect must provide a engineID here, + * which can then be used to match an Engine with MetaEngine. + * E.g. ScummMetaEngine inherits MetaEngine & provides a engineID of "Scumm". + * ScummMetaEngineConnect inherits MetaEngineConnect & provides the name "Scumm". + * This way, we can easily match a Engine with a MetaEngine. + */ + virtual const char *getName() const = 0; + /** * Tries to instantiate an engine instance based on the settings of * the currently active ConfMan target. That is, the MetaEngine should @@ -181,60 +249,6 @@ public: return 0; } - /** - * Return a list of extra GUI options for the specified target. - * If no target is specified, all of the available custom GUI options are - * Returned for the plugin (used to set default values). - * - * Currently, this only supports options with checkboxes. - * - * The default implementation returns an empty list. - * - * @param target name of a config manager target - * @return a list of extra GUI options for an engine plugin and - * target - */ - virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const { - return ExtraGuiOptions(); - } - - /** - * Register the default values for the settings the engine uses into the - * configuration manager. - * - * @param target name of a config manager target - */ - virtual void registerDefaultSettings(const Common::String &target) const; - - /** - * Return a GUI widget container for configuring the specified target options. - * - * The returned widget is shown in the Engine tab in the edit game dialog. - * Engines can build custom options dialogs, but by default a simple widget - * allowing to configure the extra GUI options is used. - * - * Engines that don't want to have an Engine tab in the edit game dialog - * can return nullptr. - * - * @param boss the widget / dialog the returned widget is a child of - * @param name the name the returned widget must use - * @param target name of a config manager target - */ - virtual GUI::OptionsContainerWidget *buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const; - - /** - * Return a list of achievement descriptions for the specified target. - * - * The default implementation returns an empty list. - * - * @param target name of a config manager target - * @return a list of achievement descriptions for an engine plugin - * and target - */ - virtual const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const { - return Common::AchievementsInfo(); - } - /** * Return the maximum save slot that the engine supports. * @@ -299,6 +313,28 @@ public: */ virtual Common::Array initKeymaps(const char *target) const; + virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const { + return ExtraGuiOptions(); + } + + /** + * Return a GUI widget container for configuring the specified target options. + * + * Engines can build custom options dialogs from here, but by default a simple widget + * allowing to configure the extra GUI options is used. + * + * A engine that builds the "Engines" tab in "Edit Game" uses a MetaEngine. + * A engine that specifies a custom dialog, when a game is running, uses a MetaEngineConnect. + * + * Engines that don't want to have an Engine tab in the edit game dialog + * can return nullptr. + * + * @param boss the widget / dialog the returned widget is a child of + * @param name the name the returned widget must use + * @param target name of a config manager target + */ + virtual GUI::OptionsContainerWidget *buildEngineOptionsWidgetDynamic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const; + /** @name MetaEngineFeature flags */ //@{ @@ -386,19 +422,31 @@ public: kSavesUseExtendedFormat }; + //@} + + /** + * Return a list of achievement descriptions for the specified target. + * + * The default implementation returns an empty list. + * + * @param target name of a config manager target + * @return a list of achievement descriptions for an engine plugin + * and target + */ + virtual const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const { + return Common::AchievementsInfo(); + } + /** * Determine whether the engine supports the specified MetaEngine feature. * Used by e.g. the launcher to determine whether to enable the "Load" button. */ virtual bool hasFeature(MetaEngineFeature f) const; - static void appendExtendedSave(Common::OutSaveFile *saveFile, uint32 playtime, - Common::String desc, bool isAutosave); + static void appendExtendedSave(Common::OutSaveFile *saveFile, uint32 playtime, Common::String desc, bool isAutosave); static void parseSavegameHeader(ExtendedSavegameHeader *header, SaveStateDescriptor *desc); static void fillDummyHeader(ExtendedSavegameHeader *header); static WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, ExtendedSavegameHeader *header, bool skipThumbnail = true); - - //@} }; /** @@ -416,8 +464,14 @@ public: /** Find a plugin by its engine ID */ const Plugin *findPlugin(const Common::String &engineId) const; - /** Get the list of all engine plugins */ - const PluginList &getPlugins() const; + /** + * Get the list of all plugins for the type specified. + * By default, it will get METAENGINES, for now. + * If usage of actual engines never occurs, we can skip + * the default arguments, and always have it return + * PLUGIN_TYPE_METAENGINE. + */ + const PluginList &getPlugins(const PluginType fetchPluginType = PLUGIN_TYPE_METAENGINE) const; /** Find a target */ QualifiedGameDescriptor findTarget(const Common::String &target, const Plugin **plugin = NULL) const; diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h index 5888b84a5e4..582c426d1b1 100644 --- a/engines/wintermute/base/base_engine.h +++ b/engines/wintermute/base/base_engine.h @@ -34,97 +34,10 @@ #include "common/random.h" #include "common/language.h" +#include "engines/wintermute/detection.h" + namespace Wintermute { -enum WMETargetExecutable { - OLDEST_VERSION, - WME_1_0_12, // DEAD:CODE 2003 - WME_1_0_19, // DEAD:CODE 2003 - WME_1_0_20, // DEAD:CODE 2003 - WME_1_0_22, // DEAD:CODE 2003 - WME_1_0_24, // DEAD:CODE 2003 - WME_1_0_25, // DEAD:CODE 2003 - WME_1_0_28, // DEAD:CODE 2003 - WME_1_0_30, // DEAD:CODE 2003 - WME_1_0_31, // DEAD:CODE 2003 - WME_1_1_33, // DEAD:CODE 2003 - WME_1_1_35, // DEAD:CODE 2003 - WME_1_1_37, // DEAD:CODE 2003 - WME_1_1_39, // DEAD:CODE 2004 - WME_1_2_43, // DEAD:CODE 2004 - WME_1_2_44, // DEAD:CODE 2004 - WME_1_3_0, // DEAD:CODE 2004 - WME_1_3_2, // DEAD:CODE 2004 - WME_1_3_3, // DEAD:CODE 2004 - WME_1_4_0, // DEAD:CODE 2005 - WME_1_4_1, // DEAD:CODE 2005 - WME_1_5_0, // DEAD:CODE 2005 - WME_1_5_2, // DEAD:CODE 2005 - WME_1_6_0, // DEAD:CODE 2006 - WME_1_6_1, // DEAD:CODE 2006 - WME_1_7_0, // DEAD:CODE 2007 - WME_1_7_1, // DEAD:CODE 2007 - WME_1_7_2, // DEAD:CODE 2007 - WME_1_7_3, // DEAD:CODE 2007 - WME_1_7_93, // DEAD:CODE 2007 - WME_1_7_94, // DEAD:CODE 2007 - WME_1_8_0, // DEAD:CODE 2007 - WME_1_8_1, // DEAD:CODE 2007 - WME_1_8_2, // DEAD:CODE 2008 - WME_1_8_3, // DEAD:CODE 2008 - WME_1_8_4, // DEAD:CODE 2008 - WME_1_8_5, // DEAD:CODE 2008 - WME_1_8_6, // DEAD:CODE 2008 - WME_1_8_7, // DEAD:CODE 2008, released as "1.8.7 beta" - WME_1_8_8, // DEAD:CODE 2008, released as "1.8.8 beta" - WME_1_8_9, // DEAD:CODE 2008, released as "1.8.9 beta" - WME_1_8_10, // DEAD:CODE 2009 - - // fork of WME_1_8_10 - WME_ANDISHE_VARAN, // Andishe Varan Engine 1.0.0.0 - - WME_1_8_11, // DEAD:CODE 2009 - WME_1_9_0, // DEAD:CODE 2009, released as "1.9.0 beta" - - // fork of WME_1_9_0 - WME_KINJAL_1_0, - WME_KINJAL_1_1, - WME_KINJAL_1_2, - WME_KINJAL_1_3, - WME_KINJAL_1_4, - - // fork of WME_KINJAL_1_4 - WME_HEROCRAFT, - - WME_1_9_1, // DEAD:CODE 2010 - - // fork of WME_1_9_1 - WME_KINJAL_1_5, - WME_KINJAL_1_6, - WME_KINJAL_1_7, - WME_KINJAL_1_7a, - WME_KINJAL_1_7b, - WME_KINJAL_1_8, - WME_KINJAL_1_9, - WME_KINJAL_2_0, - - WME_1_9_2, // DEAD:CODE 2010 - WME_1_9_3, // DEAD:CODE 2012, released as "1.10.1 beta" - WME_LITE, - LATEST_VERSION, - - // fork of WME_LITE - FOXTAIL_OLDEST_VERSION, - FOXTAIL_1_2_227, - FOXTAIL_1_2_230, - FOXTAIL_1_2_304, - FOXTAIL_1_2_362, - FOXTAIL_1_2_527, - FOXTAIL_1_2_896, - FOXTAIL_1_2_902, - FOXTAIL_LATEST_VERSION -}; - class BaseFileManager; class BaseRegistry; class BaseGame; diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp index cde1225eadb..eb88e3de097 100644 --- a/engines/wintermute/base/base_sprite.cpp +++ b/engines/wintermute/base/base_sprite.cpp @@ -41,7 +41,7 @@ #include "engines/wintermute/base/scriptables/script_value.h" #include "engines/wintermute/base/scriptables/script.h" #include "engines/wintermute/base/scriptables/script_stack.h" -#include "engines/wintermute/game_description.h" +#include "engines/wintermute/detection.h" namespace Wintermute { diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp index 1ad248c192b..4318d7e0b14 100644 --- a/engines/wintermute/detection.cpp +++ b/engines/wintermute/detection.cpp @@ -21,11 +21,7 @@ */ #include "engines/advancedDetector.h" -#include "engines/wintermute/wintermute.h" -#include "engines/wintermute/game_description.h" -#include "engines/wintermute/base/base_persistence_manager.h" -#include "common/achievements.h" #include "common/config-manager.h" #include "common/error.h" #include "common/fs.h" @@ -34,27 +30,11 @@ #include "engines/metaengine.h" -#include "engines/wintermute/achievements_tables.h" -#include "engines/wintermute/detection_tables.h" -#include "engines/wintermute/keymapper_tables.h" +#include "wintermute/detection.h" +#include "wintermute/detection_tables.h" namespace Wintermute { -/** - * The fallback game descriptor used by the Wintermute engine's fallbackDetector. - * Contents of this struct are overwritten by the fallbackDetector. (logic copied partially - * from the SCI-engine). - */ -static ADGameDescription s_fallbackDesc = { - "", - "", - AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor - Common::UNK_LANG, - Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO0() -}; - static const ADExtraGuiOptionsMap gameGuiOptions[] = { { GAMEOPTION_SHOW_FPS, @@ -79,8 +59,6 @@ static const ADExtraGuiOptionsMap gameGuiOptions[] = { AD_EXTRA_GUI_OPTIONS_TERMINATOR }; -static char s_fallbackExtraBuf[256]; - static const char *directoryGlobs[] = { "language", // To detect the various languages "languages", // To detect the various languages @@ -88,9 +66,9 @@ static const char *directoryGlobs[] = { 0 }; -class WintermuteMetaEngine : public AdvancedMetaEngine { +class WintermuteMetaEngineStatic : public AdvancedMetaEngineStatic { public: - WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) { + WintermuteMetaEngineStatic() : AdvancedMetaEngineStatic(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) { // Use kADFlagUseExtraAsHint to distinguish between SD and HD versions // of J.U.L.I.A. when their datafiles sit in the same directory (e.g. in Steam distribution). _flags = kADFlagUseExtraAsHint; @@ -112,153 +90,37 @@ public: } ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override { - // Set some defaults - s_fallbackDesc.extra = ""; - s_fallbackDesc.language = Common::UNK_LANG; - s_fallbackDesc.flags = ADGF_UNSTABLE; - s_fallbackDesc.platform = Common::kPlatformWindows; // default to Windows - s_fallbackDesc.gameId = "wintermute"; - s_fallbackDesc.guiOptions = GUIO0(); + /** + * Fallback detection for Wintermute heavily depends on engine resources, so it's not possible + * to use them without the engine present in a clean way. + */ - if (!allFiles.contains("data.dcp")) { - return ADDetectedGame(); - } - - Common::String name, caption; - if (!WintermuteEngine::getGameInfo(fslist, name, caption)) { - return ADDetectedGame(); - } - - Common::String extra = caption; - if (extra.empty()) { - extra = name; - } - - if (!extra.empty()) { - Common::strlcpy(s_fallbackExtraBuf, extra.c_str(), sizeof(s_fallbackExtraBuf) - 1); - s_fallbackDesc.extra = s_fallbackExtraBuf; - s_fallbackDesc.flags |= ADGF_USEEXTRAASTITLE; - s_fallbackDesc.flags |= ADGF_AUTOGENTARGET; - } - - ADDetectedGame game(&s_fallbackDesc); - - for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { - if (file->isDirectory()) continue; - if (!file->getName().hasSuffixIgnoreCase(".dcp")) continue; - - FileProperties tmp; - if (getFileProperties(allFiles, s_fallbackDesc, file->getName(), tmp)) { - game.hasUnknownFiles = true; - game.matchedFiles[file->getName()] = tmp; + if (ConfMan.hasKey("always_run_fallback_detection_extern")) { + if (ConfMan.getBool("always_run_fallback_detection_extern") == false) { + warning("WINTERMUTE: Fallback detection is disabled."); + return ADDetectedGame(); } } - return game; - } + const Plugin *metaEnginePlugin = EngineMan.findPlugin(getEngineId()); - bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override { - assert(syst); - assert(engine); - const WMEGameDescription *gd = (const WMEGameDescription *)desc; - *engine = new Wintermute::WintermuteEngine(syst, gd); - return true; - } - - bool hasFeature(MetaEngineFeature f) const override { - switch (f) { - case MetaEngine::kSupportsListSaves: - return true; - case MetaEngine::kSupportsLoadingDuringStartup: - return true; - case MetaEngine::kSupportsDeleteSave: - return true; - case MetaEngine::kSavesSupportCreationDate: - return true; - case MetaEngine::kSavesSupportMetaInfo: - return true; - case MetaEngine::kSavesSupportThumbnail: - return true; - default: - return false; - } - } - - SaveStateList listSaves(const char *target) const override { - SaveStateList saves; - Wintermute::BasePersistenceManager pm(target, true); - for (int i = 0; i < getMaximumSaveSlot(); i++) { - if (pm.getSaveExists(i)) { - SaveStateDescriptor desc; - pm.getSaveStateDesc(i, desc); - saves.push_back(desc); - } - } - return saves; - } - - int getMaximumSaveSlot() const override { - return 100; - } - - void removeSaveState(const char *target, int slot) const override { - Wintermute::BasePersistenceManager pm(target, true); - pm.deleteSaveSlot(slot); - } - - SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override { - Wintermute::BasePersistenceManager pm(target, true); - SaveStateDescriptor retVal; - retVal.setDescription("Invalid savegame"); - pm.getSaveStateDesc(slot, retVal); - return retVal; - } - - const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const override { - Common::String gameId = ConfMan.get("gameid", target); - - // HACK: "juliauntold" is a DLC of "juliastars", they share the same achievements list - if (gameId == "juliauntold") { - gameId = "juliastars"; - } - - Common::AchievementsPlatform platform = Common::STEAM_ACHIEVEMENTS; - if (ConfMan.get("extra", target).contains("GOG")) { - platform = Common::GALAXY_ACHIEVEMENTS; - } - - // "(gameId, platform) -> result" search - Common::AchievementsInfo result; - for (const AchievementDescriptionList *i = achievementDescriptionList; i->gameId; i++) { - if (i->gameId == gameId && i->platform == platform) { - result.platform = i->platform; - result.appId = i->appId; - for (const Common::AchievementDescription *it = i->descriptions; it->id; it++) { - result.descriptions.push_back(*it); + if (metaEnginePlugin) { + const Plugin *enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + if (enginePlugin) { + return enginePlugin->get().fallbackDetectExtern(_md5Bytes, allFiles, fslist); + } else { + static bool warn = true; + if (warn) { + warning("Engine plugin for Wintermute not present. Fallback detection is disabled."); + warn = false; } - break; } } - return result; - } - - Common::KeymapArray initKeymaps(const char *target) const override { - Common::String gameId = ConfMan.get("gameid", target); - const char *gameDescr = "Unknown WME game"; - for (const PlainGameDescriptor *it = Wintermute::wintermuteGames; it->gameId ; it++ ) { - if (gameId == it->gameId) { - gameDescr = it->description; - } - } - return getWintermuteKeymaps(target, gameId, gameDescr); + return ADDetectedGame(); } }; } // End of namespace Wintermute -#if PLUGIN_ENABLED_DYNAMIC(WINTERMUTE) - REGISTER_PLUGIN_DYNAMIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, Wintermute::WintermuteMetaEngine); -#else - REGISTER_PLUGIN_STATIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, Wintermute::WintermuteMetaEngine); -#endif +REGISTER_PLUGIN_STATIC(WINTERMUTE_DETECTION, PLUGIN_TYPE_METAENGINE, Wintermute::WintermuteMetaEngineStatic); diff --git a/engines/wintermute/ext/wme_galaxy.cpp b/engines/wintermute/ext/wme_galaxy.cpp index 949839a046a..3d42cc4d432 100644 --- a/engines/wintermute/ext/wme_galaxy.cpp +++ b/engines/wintermute/ext/wme_galaxy.cpp @@ -50,7 +50,7 @@ SXWMEGalaxyAPI::SXWMEGalaxyAPI(BaseGame *inGame, ScStack *stack) : BaseScriptabl ////////////////////////////////////////////////////////////////////////// void SXWMEGalaxyAPI::init() { - MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); + const MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); const Common::String target = BaseEngine::instance().getGameTargetName(); _achievementsInfo = meta.getAchievementsInfo(target); diff --git a/engines/wintermute/ext/wme_steam.cpp b/engines/wintermute/ext/wme_steam.cpp index 47812abc324..c776d9ec35e 100644 --- a/engines/wintermute/ext/wme_steam.cpp +++ b/engines/wintermute/ext/wme_steam.cpp @@ -50,7 +50,7 @@ SXSteamAPI::SXSteamAPI(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame ////////////////////////////////////////////////////////////////////////// void SXSteamAPI::init() { - MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); + const MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); const Common::String target = BaseEngine::instance().getGameTargetName(); _achievementsInfo = meta.getAchievementsInfo(target); diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index 5bbb30d6ced..7dd1dc68b29 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -156,10 +156,10 @@ MODULE_OBJS := \ debugger/script_monitor.o \ debugger/watch.o \ debugger/watch_instance.o \ - detection.o \ math/math_util.o \ math/matrix4.o \ math/vector2.o \ + metaengine.o \ platform_osystem.o \ system/sys_class.o \ system/sys_class_registry.o \ @@ -194,3 +194,6 @@ endif # Include common rules include $(srcdir)/rules.mk + +# Detection objects +DETECT_OBJS += $(MODULE)/detection.o diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index 7c335b2daf1..0e7c2cf4556 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -35,9 +35,9 @@ #include "engines/wintermute/ad/ad_game.h" #include "engines/wintermute/wintermute.h" #include "engines/wintermute/debugger.h" -#include "engines/wintermute/game_description.h" #include "engines/wintermute/platform_osystem.h" #include "engines/wintermute/base/base_engine.h" +#include "engines/wintermute/detection.h" #include "engines/wintermute/base/sound/base_sound_manager.h" #include "engines/wintermute/base/base_file_manager.h" diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h index 655b287907f..1e9f8213ec4 100644 --- a/engines/wintermute/wintermute.h +++ b/engines/wintermute/wintermute.h @@ -26,6 +26,7 @@ #include "engines/engine.h" #include "gui/debugger.h" #include "common/fs.h" +#include "wintermute/detection.h" namespace Wintermute { @@ -33,7 +34,6 @@ class Console; class BaseGame; class SystemClassRegistry; class DebuggerController; -struct WMEGameDescription; const int INT_MAX_VALUE = 0x7fffffff; const int INT_MIN_VALUE = -INT_MAX_VALUE - 1; // WME3D @@ -48,14 +48,6 @@ enum { kWintermuteDebugGeneral = 1 << 5 }; -enum WintermuteGameFeatures { - /** A game with low-spec resources. */ - GF_LOWSPEC_ASSETS = 1 << 0, - GF_IGNORE_SD_FILES = 1 << 1, - GF_IGNORE_HD_FILES = 1 << 2, - GF_3D = 1 << 3 -}; - class WintermuteEngine : public Engine { public: WintermuteEngine(OSystem *syst, const WMEGameDescription *desc); diff --git a/gui/about.cpp b/gui/about.cpp index f1e91ae7d05..e008ec45af4 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -127,7 +127,7 @@ AboutDialog::AboutDialog() addLine(str); str = "C2"; - str += (*iter)->get().getOriginalCopyright(); + str += (*iter)->get().getOriginalCopyright(); addLine(str); //addLine(""); diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp index 8ec1563a69a..1cc80bf000f 100644 --- a/gui/editgamedialog.cpp +++ b/gui/editgamedialog.cpp @@ -109,10 +109,16 @@ EditGameDialog::EditGameDialog(const String &domain) // Retrieve the plugin, since we need to access the engine's MetaEngine // implementation. - const Plugin *plugin = nullptr; - QualifiedGameDescriptor qgd = EngineMan.findTarget(domain, &plugin); - if (!plugin) { - warning("Plugin for target \"%s\" not found! Game specific settings might be missing", domain.c_str()); + const Plugin *metaEnginePlugin = nullptr; + const Plugin *enginePlugin = nullptr; + QualifiedGameDescriptor qgd = EngineMan.findTarget(domain, &metaEnginePlugin); + if (!metaEnginePlugin) { + warning("MetaEnginePlugin for target \"%s\" not found!", domain.c_str()); + } else { + enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + if (!enginePlugin) { + warning("Engine Plugin for target \"%s\" not found! Game specific settings might be missing.", domain.c_str()); + } } // GAME: Path to game data (r/o), extra data (r/o), and save data (r/w) @@ -176,12 +182,12 @@ EditGameDialog::EditGameDialog(const String &domain) // 2) The engine tab (shown only if the engine implements one or there are custom engine options) // - if (plugin) { + if (metaEnginePlugin) { int tabId = tab->addTab(_("Engine"), "GameOptions_Engine"); - const MetaEngine &metaEngine = plugin->get(); + const MetaEngineStatic &metaEngine = metaEnginePlugin->get(); metaEngine.registerDefaultSettings(_domain); - _engineOptions = metaEngine.buildEngineOptionsWidget(tab, "GameOptions_Engine.Container", _domain); + _engineOptions = metaEngine.buildEngineOptionsWidgetStatic(tab, "GameOptions_Engine.Container", _domain); if (_engineOptions) { _engineOptions->setParentDialog(this); @@ -225,8 +231,8 @@ EditGameDialog::EditGameDialog(const String &domain) // The Keymap tab // Common::KeymapArray keymaps; - if (plugin) { - keymaps = plugin->get().initKeymaps(domain.c_str()); + if (enginePlugin) { + keymaps = enginePlugin->get().initKeymaps(domain.c_str()); } if (!keymaps.empty()) { @@ -333,9 +339,9 @@ EditGameDialog::EditGameDialog(const String &domain) // // 9) The Achievements tab // - if (plugin) { - const MetaEngine &metaEngine = plugin->get(); - Common::AchievementsInfo achievementsInfo = metaEngine.getAchievementsInfo(domain); + if (enginePlugin) { + const MetaEngine &metaEngineConnect = enginePlugin->get(); + Common::AchievementsInfo achievementsInfo = metaEngineConnect.getAchievementsInfo(domain); if (achievementsInfo.descriptions.size() > 0) { tab->addTab(_("Achievements"), "GameOptions_Achievements"); addAchievementsControls(tab, "GameOptions_Achievements.", achievementsInfo); diff --git a/gui/launcher.cpp b/gui/launcher.cpp index e4d73d93705..9c3fa9e68ea 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -258,10 +258,13 @@ void LauncherDialog::updateListing() { U32StringArray l; ListWidget::ColorList colors; ThemeEngine::FontColor color; + int numEntries = ConfMan.getInt("gui_list_max_scan_entries"); // Retrieve a list of all games defined in the config file _domains.clear(); const ConfigManager::DomainMap &domains = ConfMan.getGameDomains(); + bool scanEntries = numEntries == -1 ? true : (domains.size() <= numEntries); + ConfigManager::DomainMap::const_iterator iter; for (iter = domains.begin(); iter != domains.end(); ++iter) { #ifdef __DS__ @@ -274,7 +277,6 @@ void LauncherDialog::updateListing() { String gameid(iter->_value.getVal("gameid")); String description(iter->_value.getVal("description")); - Common::FSNode path(iter->_value.getVal("path")); if (gameid.empty()) gameid = iter->_key; @@ -297,13 +299,17 @@ void LauncherDialog::updateListing() { pos++; color = ThemeEngine::kFontColorNormal; - if (!path.isDirectory()) { - color = ThemeEngine::kFontColorAlternate; - // If more conditions which grey out entries are added we should consider - // enabling this so that it is easy to spot why a certain game entry cannot - // be started. - // description += Common::String::format(" (%s)", _("Not found")); + if (scanEntries) { + Common::FSNode path(iter->_value.getVal("path")); + if (!path.isDirectory()) { + color = ThemeEngine::kFontColorAlternate; + // If more conditions which grey out entries are added we should consider + // enabling this so that it is easy to spot why a certain game entry cannot + // be started. + + // description += Common::String::format(" (%s)", _("Not found")); + } } l.insert_at(pos, description); @@ -469,14 +475,20 @@ void LauncherDialog::loadGame(int item) { EngineMan.upgradeTargetIfNecessary(target); // Look for the plugin - const Plugin *plugin = nullptr; - EngineMan.findTarget(target, &plugin); + const Plugin *metaEnginePlugin = nullptr; + const Plugin *enginePlugin = nullptr; + EngineMan.findTarget(target, &metaEnginePlugin); - if (plugin) { - const MetaEngine &metaEngine = plugin->get(); - if (metaEngine.hasFeature(MetaEngine::kSupportsListSaves) && - metaEngine.hasFeature(MetaEngine::kSupportsLoadingDuringStartup)) { - int slot = _loadDialog->runModalWithPluginAndTarget(plugin, target); + // If we found a relevant plugin, find the matching engine plugin. + if (metaEnginePlugin) { + enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + } + + if (enginePlugin) { + const MetaEngine &metaEngineConnect = enginePlugin->get(); + if (metaEngineConnect.hasFeature(MetaEngine::kSupportsListSaves) && + metaEngineConnect.hasFeature(MetaEngine::kSupportsLoadingDuringStartup)) { + int slot = _loadDialog->runModalWithPluginAndTarget(enginePlugin, target); if (slot >= 0) { ConfMan.setActiveDomain(_domains[item]); ConfMan.setInt("save_slot", slot, Common::ConfigManager::kTransientDomain); diff --git a/gui/saveload-dialog.h b/gui/saveload-dialog.h index aaea785b230..f0d986fbb31 100644 --- a/gui/saveload-dialog.h +++ b/gui/saveload-dialog.h @@ -110,16 +110,16 @@ protected: */ virtual void listSaves(); - const bool _saveMode; - const MetaEngine *_metaEngine; - bool _delSupport; - bool _metaInfoSupport; - bool _thumbnailSupport; - bool _saveDateSupport; - bool _playTimeSupport; - Common::String _target; + const bool _saveMode; + const MetaEngine *_metaEngine; + bool _delSupport; + bool _metaInfoSupport; + bool _thumbnailSupport; + bool _saveDateSupport; + bool _playTimeSupport; + Common::String _target; bool _dialogWasShown; - SaveStateList _saveList; + SaveStateList _saveList; #ifndef DISABLE_SAVELOADCHOOSER_GRID ButtonWidget *_listButton; diff --git a/gui/saveload.cpp b/gui/saveload.cpp index f37d3ed57dc..084bbc0f484 100644 --- a/gui/saveload.cpp +++ b/gui/saveload.cpp @@ -77,13 +77,23 @@ Common::String SaveLoadChooser::createDefaultSaveDescription(const int slot) con int SaveLoadChooser::runModalWithCurrentTarget() { const Plugin *plugin = EngineMan.findPlugin(ConfMan.get("engineid")); + const Plugin *enginePlugin = nullptr; if (!plugin) { error("SaveLoadChooser::runModalWithCurrentTarget(): Cannot find plugin"); + } else { + enginePlugin = PluginMan.getEngineFromMetaEngine(plugin); + + if (!enginePlugin) { + error("SaveLoadChooser::runModalWithCurrentTarget(): Couldn't match a Engine from the MetaEngine. \ + You will not be able to see savefiles until you have the necessary plugins."); + } } - return runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + return runModalWithPluginAndTarget(enginePlugin, ConfMan.getActiveDomainName()); } int SaveLoadChooser::runModalWithPluginAndTarget(const Plugin *plugin, const String &target) { + assert(plugin->getType() == PLUGIN_TYPE_ENGINE); + selectChooser(plugin->get()); if (!_impl) return -1; diff --git a/rules.mk b/rules.mk index b793ea480b1..a3bbec59776 100644 --- a/rules.mk +++ b/rules.mk @@ -3,6 +3,7 @@ # ############################################### +ifeq ($(LOAD_RULES_MK), 1) # Copy the list of objects to a new variable. The name of the new variable # contains the module name, a trick we use so we can keep multiple different @@ -103,3 +104,5 @@ ifdef SPLIT_DWARF endif .PHONY: clean-$(MODULE) $(MODULE) + +endif # LOAD_RULES_MK diff --git a/test/common/array.h b/test/common/array.h index bf0ff556398..f86d291ab2c 100644 --- a/test/common/array.h +++ b/test/common/array.h @@ -322,6 +322,16 @@ class ArrayTestSuite : public CxxTest::TestSuite Common::Array nonCopyable(1); } + void test_array_constructor_list() { +#ifdef USE_CXX11 + Common::Array array = {1, 42, 255}; + TS_ASSERT_EQUALS(array.size(), 3U); + TS_ASSERT_EQUALS(array[0], 1); + TS_ASSERT_EQUALS(array[1], 42); + TS_ASSERT_EQUALS(array[2], 255); +#endif + } + void test_array_constructor_count_copy_value() { Common::Array trivial(5, 1); TS_ASSERT_EQUALS(trivial.size(), 5U); diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp index 72a8aa0c3dd..d9e79bc0700 100644 --- a/video/flic_decoder.cpp +++ b/video/flic_decoder.cpp @@ -158,6 +158,7 @@ Graphics::PixelFormat FlicDecoder::FlicVideoTrack::getPixelFormat() const { #define FLI_SETPAL 4 #define FLI_SS2 7 +#define FLI_BLACK 13 #define FLI_BRUN 15 #define FLI_COPY 16 #define PSTAMP 18 @@ -234,6 +235,11 @@ void FlicDecoder::FlicVideoTrack::handleFrame() { case FLI_SS2: decodeDeltaFLC(data); break; + case FLI_BLACK: + _surface->fillRect(Common::Rect(0, 0, getWidth(), getHeight()), 0); + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); + break; case FLI_BRUN: decodeByteRun(data); break;