diff options
Diffstat (limited to 'backends')
117 files changed, 5184 insertions, 2597 deletions
diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp index 0caba25792..c503e6a536 100644 --- a/backends/events/default/default-events.cpp +++ b/backends/events/default/default-events.cpp @@ -93,7 +93,8 @@ DefaultEventManager::DefaultEventManager(OSystem *boss) : _boss(boss), _buttonState(0), _modifierState(0), - _shouldQuit(false) { + _shouldQuit(false), + _shouldRTL(false) { assert(_boss); @@ -200,6 +201,9 @@ DefaultEventManager::~DefaultEventManager() { _boss->unlockMutex(_timeMutex); _boss->unlockMutex(_recorderMutex); + if (!artificialEventQueue.empty()) + artificialEventQueue.clear(); + if (_playbackFile != NULL) { delete _playbackFile; } @@ -349,7 +353,11 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { uint32 time = _boss->getMillis(); bool result; - result = _boss->pollEvent(event); + if (!artificialEventQueue.empty()) { + event = artificialEventQueue.pop(); + result = true; + } else + result = _boss->pollEvent(event); if (_recordMode != kPassthrough) { @@ -375,7 +383,6 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { switch (event.type) { case Common::EVENT_KEYDOWN: _modifierState = event.kbd.flags; - // init continuous event stream // not done on PalmOS because keyboard is emulated and keyup is not generated #if !defined(PALMOS_MODE) @@ -384,7 +391,41 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { _currentKeyDown.flags = event.kbd.flags; _keyRepeatTime = time + kKeyRepeatInitialDelay; #endif + // Global Main Menu + // FIXME: F6 is not the best trigger, it conflicts with some games!!! + if (event.kbd.keycode == Common::KEYCODE_F6) { + if (g_engine && !g_engine->isPaused()) { + Common::Event menuEvent; + menuEvent.type = Common::EVENT_MAINMENU; + + // FIXME: GSoC RTL branch passes the F6 key event to the + // engine, and also enqueues a EVENT_MAINMENU. For now, + // we just drop the key event and return an EVENT_MAINMENU + // instead. This way, we don't have to add special cases + // to engines (like it was the case for LURE in the RTL branch). + // + // However, this has other consequences, possibly negative ones. + // Like, what happens with key repeat for the trigger key? + + //pushEvent(menuEvent); + event = menuEvent; + + // FIXME: Since now we do not push another MAINMENU event onto + // our event stack, the GMM would never open, so we have to do + // that here. Of course when the engine would handle MAINMENU + // as an event now and open up the GMM itself it would open the + // menu twice. + if (g_engine && !g_engine->isPaused()) + g_engine->mainMenuDialog(); + + if (_shouldQuit) + event.type = Common::EVENT_QUIT; + else if (_shouldRTL) + event.type = Common::EVENT_RTL; + } + } break; + case Common::EVENT_KEYUP: _modifierState = event.kbd.flags; if (event.kbd.keycode == _currentKeyDown.keycode) { @@ -401,6 +442,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { _mousePos = event.mouse; _buttonState |= LBUTTON; break; + case Common::EVENT_LBUTTONUP: _mousePos = event.mouse; _buttonState &= ~LBUTTON; @@ -410,11 +452,26 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { _mousePos = event.mouse; _buttonState |= RBUTTON; break; + case Common::EVENT_RBUTTONUP: _mousePos = event.mouse; _buttonState &= ~RBUTTON; break; + case Common::EVENT_MAINMENU: + if (g_engine && !g_engine->isPaused()) + g_engine->mainMenuDialog(); + + if (_shouldQuit) + event.type = Common::EVENT_QUIT; + else if (_shouldRTL) + event.type = Common::EVENT_RTL; + break; + + case Common::EVENT_RTL: + _shouldRTL = true; + break; + case Common::EVENT_QUIT: if (ConfMan.getBool("confirm_exit")) { if (g_engine) @@ -425,6 +482,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { g_engine->pauseEngine(false); } else _shouldQuit = true; + break; default: @@ -447,4 +505,14 @@ bool DefaultEventManager::pollEvent(Common::Event &event) { return result; } +void DefaultEventManager::pushEvent(Common::Event event) { + + // If already received an EVENT_QUIT, don't add another one + if (event.type == Common::EVENT_QUIT) { + if (!_shouldQuit) + artificialEventQueue.push(event); + } else + artificialEventQueue.push(event); +} + #endif // !defined(DISABLE_DEFAULT_EVENTMANAGER) diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h index 98dcd4b3de..b2cd1354cc 100644 --- a/backends/events/default/default-events.h +++ b/backends/events/default/default-events.h @@ -48,6 +48,7 @@ class DefaultEventManager : public Common::EventManager { int _buttonState; int _modifierState; bool _shouldQuit; + bool _shouldRTL; class RandomSourceRecord { public: @@ -107,6 +108,7 @@ public: ~DefaultEventManager(); virtual bool pollEvent(Common::Event &event); + virtual void pushEvent(Common::Event event); virtual void registerRandomSource(Common::RandomSource &rnd, const char *name); virtual void processMillis(uint32 &millis); @@ -114,6 +116,8 @@ public: virtual int getButtonState() const { return _buttonState; } virtual int getModifierState() const { return _modifierState; } virtual int shouldQuit() const { return _shouldQuit; } + virtual int shouldRTL() const { return _shouldRTL; } + virtual void resetRTL() { _shouldRTL = false; } }; #endif diff --git a/backends/fs/abstract-fs.cpp b/backends/fs/abstract-fs.cpp new file mode 100644 index 0000000000..6daad7152a --- /dev/null +++ b/backends/fs/abstract-fs.cpp @@ -0,0 +1,40 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "backends/fs/abstract-fs.h" + +const char *AbstractFilesystemNode::lastPathComponent(const Common::String &str, const char sep) { + // TODO: Get rid of this eventually! Use Common::lastPathComponent instead + if(str.empty()) + return ""; + + const char *start = str.c_str(); + const char *cur = start + str.size() - 2; + + while (cur >= start && *cur != sep) { + --cur; + } + + return cur + 1; +} diff --git a/backends/fs/abstract-fs.h b/backends/fs/abstract-fs.h index 97de40a2fc..b3a652f2ae 100644 --- a/backends/fs/abstract-fs.h +++ b/backends/fs/abstract-fs.h @@ -43,22 +43,21 @@ typedef Common::Array<AbstractFilesystemNode *> AbstractFSList; */ class AbstractFilesystemNode { protected: - friend class FilesystemNode; - typedef Common::String String; - typedef FilesystemNode::ListMode ListMode; + friend class Common::FilesystemNode; + typedef Common::FilesystemNode::ListMode ListMode; /** - * Returns the child node with the given name. If no child with this name - * exists, returns 0. When called on a non-directory node, it should - * handle this gracefully by returning 0. + * Returns the child node with the given name. When called on a non-directory + * node, it should handle this gracefully by returning 0. + * When called with a name not matching any of the files/dirs contained in this + * directory, a valid node shold be returned, which returns 'false' upon calling + * the exists() method. The idea is that this node can then still can be used to + * create a new file via the openForWriting() method. * * Example: * Calling getChild() for a node with path "/foo/bar" using name="file.txt", * would produce a new node with "/foo/bar/file.txt" as path. * - * @note This function will append a separator char (\ or /) to the end of the - * path if needed. - * * @note Handling calls on non-dir nodes gracefully makes it possible to * switch to a lazy type detection scheme in the future. * @@ -72,6 +71,19 @@ protected: */ virtual AbstractFilesystemNode *getParent() const = 0; + /** + * Returns the last component of a given path. + * + * Examples: + * /foo/bar.txt would return /bar.txt + * /foo/bar/ would return /bar/ + * + * @param str String containing the path. + * @param sep character used to separate path components + * @return Pointer to the first char of the last component inside str. + */ + static const char *lastPathComponent(const Common::String &str, const char sep); + public: /** * Destructor. @@ -149,9 +161,26 @@ public: */ virtual bool isWritable() const = 0; - /* TODO: - bool isFile(); - */ + + /** + * Creates a SeekableReadStream instance corresponding to the file + * referred by this node. This assumes that the node actually refers + * to a readable file. If this is not the case, 0 is returned. + * + * @return pointer to the stream object, 0 in case of a failure + */ + virtual Common::SeekableReadStream *openForReading() = 0; + + /** + * Creates a WriteStream instance corresponding to the file + * referred by this node. This assumes that the node actually refers + * to a readable file. If this is not the case, 0 is returned. + * + * @return pointer to the stream object, 0 in case of a failure + */ + virtual Common::WriteStream *openForWriting() = 0; }; + + #endif //BACKENDS_ABSTRACT_FS_H diff --git a/backends/fs/amigaos4/amigaos4-fs-factory.cpp b/backends/fs/amigaos4/amigaos4-fs-factory.cpp index af843b7c78..2b0b2f1908 100644 --- a/backends/fs/amigaos4/amigaos4-fs-factory.cpp +++ b/backends/fs/amigaos4/amigaos4-fs-factory.cpp @@ -26,8 +26,6 @@ #include "backends/fs/amigaos4/amigaos4-fs-factory.h" #include "backends/fs/amigaos4/amigaos4-fs.cpp" -DECLARE_SINGLETON(AmigaOSFilesystemFactory); - AbstractFilesystemNode *AmigaOSFilesystemFactory::makeRootFileNode() const { return new AmigaOSFilesystemNode(); } @@ -36,7 +34,7 @@ AbstractFilesystemNode *AmigaOSFilesystemFactory::makeCurrentDirectoryFileNode() return new AmigaOSFilesystemNode(); } -AbstractFilesystemNode *AmigaOSFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *AmigaOSFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new AmigaOSFilesystemNode(path); } #endif diff --git a/backends/fs/amigaos4/amigaos4-fs-factory.h b/backends/fs/amigaos4/amigaos4-fs-factory.h index 58a7dcd372..03af6e95b9 100644 --- a/backends/fs/amigaos4/amigaos4-fs-factory.h +++ b/backends/fs/amigaos4/amigaos4-fs-factory.h @@ -25,7 +25,6 @@ #ifndef AMIGAOS_FILESYSTEM_FACTORY_H #define AMIGAOS_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,11 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class AmigaOSFilesystemFactory : public FilesystemFactory, public Common::Singleton<AmigaOSFilesystemFactory> { +class AmigaOSFilesystemFactory : public FilesystemFactory { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - AmigaOSFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*AMIGAOS_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/amigaos4/amigaos4-fs.cpp b/backends/fs/amigaos4/amigaos4-fs.cpp index 5bf57ddf34..d517121dc0 100644 --- a/backends/fs/amigaos4/amigaos4-fs.cpp +++ b/backends/fs/amigaos4/amigaos4-fs.cpp @@ -36,8 +36,8 @@ #endif #include "common/util.h" -#include "engines/engine.h" #include "backends/fs/abstract-fs.h" +#include "backends/fs/stdiostream.h" #define ENTER() /* debug(6, "Enter") */ #define LEAVE() /* debug(6, "Leave") */ @@ -52,8 +52,8 @@ const uint32 kExAllBufferSize = 40960; // TODO: is this okay for sure? class AmigaOSFilesystemNode : public AbstractFilesystemNode { protected: BPTR _pFileLock; - String _sDisplayName; - String _sPath; + Common::String _sDisplayName; + Common::String _sPath; bool _bIsDirectory; bool _bIsValid; @@ -74,9 +74,9 @@ public: /** * Creates a AmigaOSFilesystemNode for a given path. * - * @param path String with the path the new node should point to. + * @param path Common::String with the path the new node should point to. */ - AmigaOSFilesystemNode(const String &p); + AmigaOSFilesystemNode(const Common::String &p); /** * FIXME: document this constructor. @@ -96,17 +96,20 @@ public: virtual ~AmigaOSFilesystemNode(); virtual bool exists() const; - virtual String getDisplayName() const { return _sDisplayName; }; - virtual String getName() const { return _sDisplayName; }; - virtual String getPath() const { return _sPath; }; + virtual Common::String getDisplayName() const { return _sDisplayName; }; + virtual Common::String getName() const { return _sDisplayName; }; + virtual Common::String getPath() const { return _sPath; }; virtual bool isDirectory() const { return _bIsDirectory; }; virtual bool isReadable() const; virtual bool isWritable() const; - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); + /** * Creates a list with all the volumes present in the root node. */ @@ -116,7 +119,7 @@ public: /** * Returns the last component of a given path. * - * @param str String containing the path. + * @param str Common::String containing the path. * @return Pointer to the first char of the last component inside str. */ const char *lastPathComponent(const Common::String &str) { @@ -148,10 +151,10 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode() { LEAVE(); } -AmigaOSFilesystemNode::AmigaOSFilesystemNode(const String &p) { +AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) { ENTER(); - int len = 0, offset = p.size(); + int offset = p.size(); //assert(offset > 0); @@ -161,7 +164,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const String &p) { } _sPath = p; - _sDisplayName = lastPathComponent(_sPath); + _sDisplayName = ::lastPathComponent(_sPath); _pFileLock = 0; _bIsDirectory = false; @@ -299,14 +302,14 @@ bool AmigaOSFilesystemNode::exists() const { return nodeExists; } -AbstractFilesystemNode *AmigaOSFilesystemNode::getChild(const String &n) const { +AbstractFilesystemNode *AmigaOSFilesystemNode::getChild(const Common::String &n) const { ENTER(); if (!_bIsDirectory) { debug(6, "Not a directory"); return 0; } - String newPath(_sPath); + Common::String newPath(_sPath); if (_sPath.lastChar() != '/') newPath += '/'; @@ -368,10 +371,10 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b struct ExAllData *ead = data; do { - if ((mode == FilesystemNode::kListAll) || - (EAD_IS_DRAWER(ead) && (mode == FilesystemNode::kListDirectoriesOnly)) || - (EAD_IS_FILE(ead) && (mode == FilesystemNode::kListFilesOnly))) { - String full_path = _sPath; + if ((mode == Common::FilesystemNode::kListAll) || + (EAD_IS_DRAWER(ead) && (mode == Common::FilesystemNode::kListDirectoriesOnly)) || + (EAD_IS_FILE(ead) && (mode == Common::FilesystemNode::kListFilesOnly))) { + Common::String full_path = _sPath; full_path += (char*)ead->ed_Name; BPTR lock = IDOS->Lock((STRPTR)full_path.c_str(), SHARED_LOCK); @@ -566,4 +569,12 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const { return myList; } +Common::SeekableReadStream *AmigaOSFilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} + +Common::WriteStream *AmigaOSFilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); +} + #endif //defined(__amigaos4__) diff --git a/backends/fs/ds/ds-fs-factory.cpp b/backends/fs/ds/ds-fs-factory.cpp index 2eae2f2403..5c8c3f45f8 100644 --- a/backends/fs/ds/ds-fs-factory.cpp +++ b/backends/fs/ds/ds-fs-factory.cpp @@ -45,7 +45,7 @@ AbstractFilesystemNode *DSFilesystemFactory::makeCurrentDirectoryFileNode() cons } } -AbstractFilesystemNode *DSFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *DSFilesystemFactory::makeFileNodePath(const Common::String &path) const { if (DS::isGBAMPAvailable()) { return new DS::GBAMPFileSystemNode(path); } else { diff --git a/backends/fs/ds/ds-fs-factory.h b/backends/fs/ds/ds-fs-factory.h index bff21a309d..67e0076b78 100644 --- a/backends/fs/ds/ds-fs-factory.h +++ b/backends/fs/ds/ds-fs-factory.h @@ -35,11 +35,9 @@ */ class DSFilesystemFactory : public FilesystemFactory, public Common::Singleton<DSFilesystemFactory> { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; protected: DSFilesystemFactory() {}; diff --git a/backends/fs/ds/ds-fs.cpp b/backends/fs/ds/ds-fs.cpp index cffe4c118d..911702316d 100644 --- a/backends/fs/ds/ds-fs.cpp +++ b/backends/fs/ds/ds-fs.cpp @@ -24,6 +24,7 @@ #include "common/util.h" //#include <NDS/ARM9/console.h> //basic print funcionality #include "backends/fs/ds/ds-fs.h" +#include "backends/fs/stdiostream.h" #include "dsmain.h" #include "fat/gba_nds_fat.h" @@ -55,7 +56,7 @@ DSFileSystemNode::DSFileSystemNode() { } } -DSFileSystemNode::DSFileSystemNode(const String& path) { +DSFileSystemNode::DSFileSystemNode(const Common::String& path) { // consolePrintf("--%s ",path.c_str()); char disp[128]; @@ -70,7 +71,7 @@ DSFileSystemNode::DSFileSystemNode(const String& path) { strcpy(disp, pathStr + lastSlash + 1); - _displayName = String(disp); + _displayName = Common::String(disp); _path = path; // _isValid = true; // _isDirectory = false; @@ -98,7 +99,7 @@ DSFileSystemNode::DSFileSystemNode(const String& path) { // consolePrintf("%s - Found: %d, Dir: %d\n", pathStr, _isValid, _isDirectory); } -DSFileSystemNode::DSFileSystemNode(const String& path, bool isDir) { +DSFileSystemNode::DSFileSystemNode(const Common::String& path, bool isDir) { // consolePrintf("--%s ",path.c_str()); char disp[128]; @@ -112,7 +113,7 @@ DSFileSystemNode::DSFileSystemNode(const String& path, bool isDir) { strcpy(disp, pathStr + lastSlash + 1); - _displayName = String(disp); + _displayName = Common::String(disp); _path = path; _isValid = true; _isDirectory = isDir; @@ -167,10 +168,10 @@ bool DSFileSystemNode::getChildren(AbstractFSList &dirList, ListMode mode, bool _zipFile->getFileName(n); // consolePrintf("file: %s\n", n); - if ( (_zipFile->isDirectory() && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)) ) - || (!_zipFile->isDirectory() && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll)) ) ) + if ( (_zipFile->isDirectory() && ((mode == Common::FilesystemNode::kListDirectoriesOnly) || (mode == Common::FilesystemNode::kListAll)) ) + || (!_zipFile->isDirectory() && ((mode == Common::FilesystemNode::kListFilesOnly) || (mode == Common::FilesystemNode::kListAll)) ) ) { - DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + String(n), _zipFile->isDirectory()); + DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + Common::String(n), _zipFile->isDirectory()); dsfsn->_isDirectory = _zipFile->isDirectory(); dirList.push_back((dsfsn)); } @@ -195,7 +196,7 @@ AbstractFilesystemNode* DSFileSystemNode::getParent() const { } } - p = new DSFileSystemNode(String(path, lastSlash)); + p = new DSFileSystemNode(Common::String(path, lastSlash)); ((DSFileSystemNode *) (p))->_isDirectory = true; } else { p = new DSFileSystemNode(); @@ -204,6 +205,14 @@ AbstractFilesystemNode* DSFileSystemNode::getParent() const { return p; } +Common::SeekableReadStream *DSFileSystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} + +Common::WriteStream *DSFileSystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); +} + ////////////////////////////////////////////////////////////////////////// // GBAMPFileSystemNode - File system using GBA Movie Player and CF card // ////////////////////////////////////////////////////////////////////////// @@ -216,7 +225,7 @@ GBAMPFileSystemNode::GBAMPFileSystemNode() { _path = "mp:/"; } -GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path) { +GBAMPFileSystemNode::GBAMPFileSystemNode(const Common::String& path) { // consolePrintf("'%s'",path.c_str()); char disp[128]; @@ -245,13 +254,13 @@ GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path) { } // consolePrintf("Path: %s (%d)\n", check, success); - _displayName = String(disp); + _displayName = Common::String(disp); _path = path; _isValid = success == FT_FILE; _isDirectory = success == FT_DIR; } -GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path, bool isDirectory) { +GBAMPFileSystemNode::GBAMPFileSystemNode(const Common::String& path, bool isDirectory) { // consolePrintf("'%s'",path.c_str()); char disp[128]; @@ -265,7 +274,7 @@ GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path, bool isDirectory) { strcpy(disp, pathStr + lastSlash + 1); - _displayName = String(disp); + _displayName = Common::String(disp); _path = path; _isValid = true; _isDirectory = isDirectory; @@ -313,8 +322,8 @@ bool GBAMPFileSystemNode::getChildren(AbstractFSList& dirList, ListMode mode, bo while (entryType != TYPE_NO_MORE) { - if ( ((entryType == TYPE_DIR) && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll))) - || ((entryType == TYPE_FILE) && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll))) ) { + if ( ((entryType == TYPE_DIR) && ((mode == Common::FilesystemNode::kListDirectoriesOnly) || (mode == Common::FilesystemNode::kListAll))) + || ((entryType == TYPE_FILE) && ((mode == Common::FilesystemNode::kListFilesOnly) || (mode == Common::FilesystemNode::kListAll))) ) { GBAMPFileSystemNode* dsfsn; consolePrintf("Fname: %s\n", fname); @@ -322,9 +331,9 @@ bool GBAMPFileSystemNode::getChildren(AbstractFSList& dirList, ListMode mode, bo if (strcmp(fname, ".") && strcmp(fname, "..")) { if (!strcmp(path, "/")) { - dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String(fname), entryType == TYPE_DIR); + dsfsn = new GBAMPFileSystemNode("mp:" + Common::String(path) + Common::String(fname), entryType == TYPE_DIR); } else { - dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String("/") + String(fname), entryType == TYPE_DIR); + dsfsn = new GBAMPFileSystemNode("mp:" + Common::String(path) + Common::String("/") + Common::String(fname), entryType == TYPE_DIR); } // dsfsn->_isDirectory = entryType == DIR; @@ -358,7 +367,7 @@ AbstractFilesystemNode* GBAMPFileSystemNode::getParent() const { } } - p = new GBAMPFileSystemNode(String(path, lastSlash)); + p = new GBAMPFileSystemNode(Common::String(path, lastSlash)); p->_isDirectory = true; } else { p = new GBAMPFileSystemNode(); @@ -367,6 +376,14 @@ AbstractFilesystemNode* GBAMPFileSystemNode::getParent() const { return p; } +Common::SeekableReadStream *GBAMPFileSystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} + +Common::WriteStream *GBAMPFileSystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); +} + // Stdio replacements #define MAX_FILE_HANDLES 32 @@ -399,6 +416,7 @@ FILE* std_fopen(const char* name, const char* mode) { if (DS::isGBAMPAvailable()) { FAT_chdir("/"); + // Turn all back slashes into forward slashes for gba_nds_fat char* p = realName; while (*p) { if (*p == '\\') *p = '/'; @@ -422,8 +440,12 @@ FILE* std_fopen(const char* name, const char* mode) { // Allocate a file handle int r = 0; - while (handle[r].used) r++; + while (handle[r].used) { + r++; + assert(r < MAX_FILE_HANDLES); + } +#ifdef GBA_SRAM_SAVE if (strchr(mode, 'w')) { // consolePrintf("Writing %s\n", realName); handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, true); @@ -431,6 +453,7 @@ FILE* std_fopen(const char* name, const char* mode) { // consolePrintf("Reading %s\n", realName); handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, false); } +#endif if (handle[r].sramFile) { handle[r].used = true; @@ -512,69 +535,6 @@ size_t std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) { return bytes / size; } return numItems; - -/* int item = 0; - u8* data = (u8 *) ptr; - while ((item < numItems) && (!FAT_feof((FAT_FILE *) handle))) { - - - int bytes = 0; - while ((bytes < size) && (!FAT_feof((FAT_FILE *) handle))) { - *data++ = FAT_fgetc((FAT_FILE *) handle); - bytes++; - } - - item++; - - } - - return item; -*/ - int items = 0; - - //for (int r = 0; r < numItems; r++) { - if (!std_feof(handle)) { -/* for (int t = 0; t < size; t++) { - if (feof(handle)) eof = true; - *(((char *) (ptr)) + r * size + t) = getc(handle); - }*/ - int left = size * numItems; - int bytesRead = -1; - - while ((left > 0) && (!FAT_feof((FAT_FILE *) handle))) { - int amount = left > 8192? 8192: left; -// do { - bytesRead = FAT_fread((void *) ptr, 1, amount, (FAT_FILE *) handle); -/* if (bytesRead == 0) { - consolePrintf("Pos:%d items:%d num:%d amount:%d read:%d\n", ftell(handle), items, numItems, amount, bytesRead); - left++; - - int pos = ftell(handle); - - fseek(handle, 0, SEEK_SET); - int c = getc(handle); - fseek(handle, pos - 1024, SEEK_SET); - fread(ptr, 1024, 1, handle); - swiWaitForVBlank(); - //while (true); - } - - } while (bytesRead == 0); -*/ - left -= bytesRead; - ptr = ((char *) (ptr)) + bytesRead; - } - - items = numItems - (left / size); - -// FAT_fread((void *) ptr, size, 1, ((int) (handle)) - 1); -// ptr = ((char *) (ptr)) + size; - } -// } - -// consolePrintf("...done %d \n", items) - - return items; } if (handle->sramFile) { @@ -641,10 +601,6 @@ size_t std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) { } } -void std_fprintf(FILE* handle, const char* fmt, ...) { - consolePrintf(fmt); -} - bool std_feof(FILE* handle) { // consolePrintf("feof "); @@ -660,42 +616,10 @@ bool std_feof(FILE* handle) { return handle->pos >= handle->size; } -void std_fflush(FILE* handle) { +int std_fflush(FILE* handle) { //FIXME: not implemented? // consolePrintf("fflush "); -} - -char* std_fgets(char* str, int size, FILE* file) { -// consolePrintf("fgets file=%d ", file); - - if (DS::isGBAMPAvailable()) { - char* s = str; - while ((*s++ = std_getc(file)) >= 32) { -// consolePrintf("%d ", *s); - } - *s = 0; - -// consolePrintf("Read:%s\n", str); - - return str; - } - - if (file->sramFile) { - file->pos--; - int p = -1; - do { - file->pos++; - p++; - file->sramFile->read((char *) &str[p], 1); -// consolePrintf("%d,", str[p]); - } while ((str[p] >= 32) && (!std_feof(file)) && (p < size)); - str[p + 1] = 0; - file->pos++; -// consolePrintf("Read:%s\n", str); - return str; - } - - return NULL; + return 0; } long int std_ftell(FILE* handle) { @@ -731,92 +655,20 @@ int std_fseek(FILE* handle, long int offset, int whence) { return 0; } -void std_clearerr(FILE* handle) { +int std_ferror(FILE* handle) { //FIXME: not implemented? -// consolePrintf("clearerr "); -} - -int std_getc(FILE* handle) { - if (DS::isGBAMPAvailable()) { - char c; - FAT_fread(&c, 1, 1, (FAT_FILE *) handle); - - return c; - } - -// consolePrintf("fgetc "); - return 0; // Not supported yet +// consolePrintf("ferror "); + return 0; } -char* std_getcwd(char* dir, int dunno) { -// consolePrintf("getcwd "); - dir[0] = '\0'; - return dir; // Not supported yet +void std_clearerr(FILE* handle) { + //FIXME: not implemented? +// consolePrintf("clearerr "); } -void std_cwd(char* dir) { - char buffer[128]; - strcpy(buffer, dir); - char* realName = buffer; - - if (DS::isGBAMPAvailable()) { - if ((strlen(dir) >= 4) && (dir[0] == 'm') && (dir[1] == 'p') && (dir[2] == ':') && (dir[3] == '/')) { - realName += 4; - } - - // consolePrintf("Real cwd:%d\n", realName); - - char* p = realName; - while (*p) { - if (*p == '\\') *p = '/'; - p++; - } - - // consolePrintf("Real cwd:%d\n", realName); - FAT_chdir(realName); - } else { - if ((strlen(dir) >= 4) && (dir[0] == 'd') && (dir[1] == 's') && (dir[2] == ':') && (dir[3] == '/')) { - realName += 4; - } - - char* p = realName; - while (*p) { - if (*p == '\\') *p = '/'; - p++; - } - - strcpy(currentDir, realName); - if (*(currentDir + strlen(currentDir) - 1) == '/') { - *(currentDir + strlen(currentDir) - 1) = '\0'; - } -// consolePrintf("CWD: %s\n", currentDir); - } +void std_fprintf(FILE* handle, const char* fmt, ...) { + consolePrintf(fmt); } -int std_ferror(FILE* handle) { - return 0; -} } // namespace DS - -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/' && *cur != '\\') { - --cur; - } - - return cur + 1; -} - diff --git a/backends/fs/ds/ds-fs.h b/backends/fs/ds/ds-fs.h index 9ac453aca9..36e7bc9824 100644 --- a/backends/fs/ds/ds-fs.h +++ b/backends/fs/ds/ds-fs.h @@ -41,12 +41,10 @@ namespace DS { */ class DSFileSystemNode : public AbstractFilesystemNode { protected: - typedef class Common::String String; - static ZipFile* _zipFile; - String _displayName; - String _path; + Common::String _displayName; + Common::String _path; bool _isDirectory; bool _isValid; @@ -61,7 +59,7 @@ public: * * @param path String with the path the new node should point to. */ - DSFileSystemNode(const String &path); + DSFileSystemNode(const Common::String &path); /** * Creates a DSFilesystemNode for a given path. @@ -69,7 +67,7 @@ public: * @param path String with the path the new node should point to. * @param path true if path is a directory, false otherwise. */ - DSFileSystemNode(const String& path, bool isDir); + DSFileSystemNode(const Common::String& path, bool isDir); /** * Copy constructor. @@ -77,9 +75,9 @@ public: DSFileSystemNode(const DSFileSystemNode *node); virtual bool exists() const { return true; } //FIXME: this is just a stub - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; } virtual bool isReadable() const { return true; } //FIXME: this is just a stub virtual bool isWritable() const { return true; } //FIXME: this is just a stub @@ -89,9 +87,12 @@ public: */ virtual AbstractFilesystemNode *clone() const { return new DSFileSystemNode(this); } virtual AbstractFilesystemNode *getChild(const Common::String& name) const; - virtual bool getChildren(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly, bool hidden = false) const; + virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); + /** * Returns the zip file this node points to. * TODO: check this documentation. @@ -107,10 +108,8 @@ public: */ class GBAMPFileSystemNode : public AbstractFilesystemNode { protected: - typedef class Common::String String; - - String _displayName; - String _path; + Common::String _displayName; + Common::String _path; bool _isDirectory; bool _isValid; @@ -125,7 +124,7 @@ public: * * @param path String with the path the new node should point to. */ - GBAMPFileSystemNode(const String &path); + GBAMPFileSystemNode(const Common::String &path); /** * Creates a DSFilesystemNode for a given path. @@ -133,7 +132,7 @@ public: * @param path String with the path the new node should point to. * @param path true if path is a directory, false otherwise. */ - GBAMPFileSystemNode(const String &path, bool isDirectory); + GBAMPFileSystemNode(const Common::String &path, bool isDirectory); /** * Copy constructor. @@ -141,9 +140,9 @@ public: GBAMPFileSystemNode(const GBAMPFileSystemNode *node); virtual bool exists() const { return _isValid || _isDirectory; } - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; } virtual bool isReadable() const { return true; } //FIXME: this is just a stub virtual bool isWritable() const { return true; } //FIXME: this is just a stub @@ -153,8 +152,11 @@ public: */ virtual AbstractFilesystemNode *clone() const { return new GBAMPFileSystemNode(this); } virtual AbstractFilesystemNode *getChild(const Common::String& name) const; - virtual bool getChildren(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly, bool hidden = false) const; + virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; + + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); }; struct fileHandle { @@ -179,15 +181,14 @@ struct fileHandle { // Please do not remove any of these prototypes that appear not to be required. FILE* std_fopen(const char* name, const char* mode); void std_fclose(FILE* handle); -int std_getc(FILE* handle); size_t std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle); size_t std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle); bool std_feof(FILE* handle); long int std_ftell(FILE* handle); int std_fseek(FILE* handle, long int offset, int whence); void std_clearerr(FILE* handle); -void std_cwd(char* dir); -void std_fflush(FILE* handle); +int std_fflush(FILE* handle); +int std_ferror(FILE* handle); } //namespace DS diff --git a/backends/fs/palmos/palmos-fs-factory.cpp b/backends/fs/palmos/palmos-fs-factory.cpp index 8699a9788b..bbc1639897 100644 --- a/backends/fs/palmos/palmos-fs-factory.cpp +++ b/backends/fs/palmos/palmos-fs-factory.cpp @@ -36,7 +36,7 @@ AbstractFilesystemNode *PalmOSFilesystemFactory::makeCurrentDirectoryFileNode() return new PalmOSFilesystemNode(); } -AbstractFilesystemNode *PalmOSFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *PalmOSFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new PalmOSFilesystemNode(path); } #endif diff --git a/backends/fs/palmos/palmos-fs-factory.h b/backends/fs/palmos/palmos-fs-factory.h index 3ea8b5fe47..f778aa89ef 100644 --- a/backends/fs/palmos/palmos-fs-factory.h +++ b/backends/fs/palmos/palmos-fs-factory.h @@ -35,11 +35,9 @@ */ class PalmOSFilesystemFactory : public FilesystemFactory, public Common::Singleton<PalmOSFilesystemFactory> { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; protected: PalmOSFilesystemFactory() {}; diff --git a/backends/fs/palmos/palmos-fs.cpp b/backends/fs/palmos/palmos-fs.cpp index 5edb6c2d26..7c415aa320 100644 --- a/backends/fs/palmos/palmos-fs.cpp +++ b/backends/fs/palmos/palmos-fs.cpp @@ -28,6 +28,7 @@ #include "globals.h" #include "backends/fs/abstract-fs.h" +#include "backends/fs/stdiostream.h" /** * Implementation of the ScummVM file system API based on PalmOS VFS API. @@ -36,8 +37,8 @@ */ class PalmOSFilesystemNode : public AbstractFilesystemNode { protected: - String _displayName; - String _path; + Common::String _displayName; + Common::String _path; bool _isDirectory; bool _isValid; bool _isPseudoRoot; @@ -51,22 +52,25 @@ public: /** * Creates a POSIXFilesystemNode for a given path. * - * @param path String with the path the new node should point to. + * @param path Common::String with the path the new node should point to. */ - PalmOSFilesystemNode(const String &p); + PalmOSFilesystemNode(const Common::String &p); virtual bool exists() const { return _isValid; } - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; } virtual bool isReadable() const { return true; } //FIXME: this is just a stub virtual bool isWritable() const { return true; } //FIXME: this is just a stub - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); + private: /** * Adds a single WindowsFilesystemNode to a given list. @@ -74,44 +78,20 @@ private: * * @param list List to put the file entry node in. * @param mode Mode to use while adding the file entry to the list. - * @param base String with the directory being listed. + * @param base Common::String with the directory being listed. * @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find. */ static void addFile(AbstractFSList &list, ListMode mode, const Char *base, FileInfoType* find_data); }; -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} - void PalmOSFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, FileInfoType* find_data) { PalmOSFilesystemNode entry; bool isDir; isDir = (find_data->attributes & vfsFileAttrDirectory); - if ((!isDir && mode == FilesystemNode::kListDirectoriesOnly) || - (isDir && mode == FilesystemNode::kListFilesOnly)) + if ((!isDir && mode == Common::FilesystemNode::kListDirectoriesOnly) || + (isDir && mode == Common::FilesystemNode::kListFilesOnly)) return; entry._isDirectory = isDir; @@ -136,9 +116,9 @@ PalmOSFilesystemNode::PalmOSFilesystemNode() { _isPseudoRoot = false; } -PalmOSFilesystemNode::PalmOSFilesystemNode(const String &p) { +PalmOSFilesystemNode::PalmOSFilesystemNode(const Common::String &p) { _path = p; - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '/'); UInt32 attr; FileRef handle; @@ -159,10 +139,10 @@ PalmOSFilesystemNode::PalmOSFilesystemNode(const String &p) { _isPseudoRoot = false; } -AbstractFilesystemNode *PalmOSFilesystemNode::getChild(const String &n) const { +AbstractFilesystemNode *PalmOSFilesystemNode::getChild(const Common::String &n) const { assert(_isDirectory); - String newPath(_path); + Common::String newPath(_path); if (_path.lastChar() != '/') newPath += '/'; newPath += n; @@ -215,17 +195,25 @@ AbstractFilesystemNode *PalmOSFilesystemNode::getParent() const { if (!_isPseudoRoot) { const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); p = new PalmOSFilesystemNode(); - p->_path = String(start, end - start); + p->_path = Common::String(start, end - start); p->_isValid = true; p->_isDirectory = true; - p->_displayName = lastPathComponent(p->_path); + p->_displayName = lastPathComponent(p->_path, '/'); p->_isPseudoRoot =(p->_path == "/"); } return p; } +Common::SeekableReadStream *PalmOSFilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} + +Common::WriteStream *PalmOSFilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); +} + #endif // PALMOS_MODE diff --git a/backends/fs/posix/posix-fs-factory.cpp b/backends/fs/posix/posix-fs-factory.cpp index 0a1160ff8f..cbfb69b76a 100644 --- a/backends/fs/posix/posix-fs-factory.cpp +++ b/backends/fs/posix/posix-fs-factory.cpp @@ -26,19 +26,18 @@ #include "backends/fs/posix/posix-fs-factory.h" #include "backends/fs/posix/posix-fs.cpp" -DECLARE_SINGLETON(POSIXFilesystemFactory); - AbstractFilesystemNode *POSIXFilesystemFactory::makeRootFileNode() const { - return new POSIXFilesystemNode(); + return new POSIXFilesystemNode("/"); } AbstractFilesystemNode *POSIXFilesystemFactory::makeCurrentDirectoryFileNode() const { char buf[MAXPATHLEN]; getcwd(buf, MAXPATHLEN); - return new POSIXFilesystemNode(buf, true); + return new POSIXFilesystemNode(buf); } -AbstractFilesystemNode *POSIXFilesystemFactory::makeFileNodePath(const String &path) const { - return new POSIXFilesystemNode(path, true); +AbstractFilesystemNode *POSIXFilesystemFactory::makeFileNodePath(const Common::String &path) const { + assert(!path.empty()); + return new POSIXFilesystemNode(path); } #endif diff --git a/backends/fs/posix/posix-fs-factory.h b/backends/fs/posix/posix-fs-factory.h index d8eecda6ef..c697679814 100644 --- a/backends/fs/posix/posix-fs-factory.h +++ b/backends/fs/posix/posix-fs-factory.h @@ -25,7 +25,6 @@ #ifndef POSIX_FILESYSTEM_FACTORY_H #define POSIX_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,10 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class POSIXFilesystemFactory : public FilesystemFactory, public Common::Singleton<POSIXFilesystemFactory> { -public: - typedef Common::String String; - +class POSIXFilesystemFactory : public FilesystemFactory { virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - POSIXFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*POSIX_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/posix/posix-fs.cpp b/backends/fs/posix/posix-fs.cpp index 10782a9057..8dca78d82a 100644 --- a/backends/fs/posix/posix-fs.cpp +++ b/backends/fs/posix/posix-fs.cpp @@ -24,85 +24,20 @@ #if defined(UNIX) -#include "backends/fs/abstract-fs.h" +#include "backends/fs/posix/posix-fs.h" +#include "backends/fs/stdiostream.h" +#include "common/algorithm.h" -#ifdef MACOSX -#include <sys/types.h> -#endif #include <sys/param.h> #include <sys/stat.h> #include <dirent.h> #include <stdio.h> -#include <unistd.h> -/** - * Implementation of the ScummVM file system API based on POSIX. - * - * Parts of this class are documented in the base interface class, AbstractFilesystemNode. - */ -class POSIXFilesystemNode : public AbstractFilesystemNode { -protected: - Common::String _displayName; - Common::String _path; - bool _isDirectory; - bool _isValid; - -public: - /** - * Creates a POSIXFilesystemNode with the root node as path. - */ - POSIXFilesystemNode(); - - /** - * Creates a POSIXFilesystemNode for a given path. - * - * @param path String with the path the new node should point to. - * @param verify true if the isValid and isDirectory flags should be verified during the construction. - */ - POSIXFilesystemNode(const Common::String &path, bool verify); - - virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; } - virtual Common::String getDisplayName() const { return _displayName; } - virtual Common::String getName() const { return _displayName; } - virtual Common::String getPath() const { return _path; } - virtual bool isDirectory() const { return _isDirectory; } - virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } - virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } - - virtual AbstractFilesystemNode *getChild(const Common::String &n) const; - virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; - virtual AbstractFilesystemNode *getParent() const; - -private: - /** - * Tests and sets the _isValid and _isDirectory flags, using the stat() function. - */ - virtual void setFlags(); -}; - -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } +#ifdef __OS2__ +#define INCL_DOS +#include <os2.h> +#endif - return cur + 1; -} void POSIXFilesystemNode::setFlags() { struct stat st; @@ -111,15 +46,7 @@ void POSIXFilesystemNode::setFlags() { _isDirectory = _isValid ? S_ISDIR(st.st_mode) : false; } -POSIXFilesystemNode::POSIXFilesystemNode() { - // The root dir. - _path = "/"; - _displayName = _path; - _isValid = true; - _isDirectory = true; -} - -POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p, bool verify) { +POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p) { assert(p.size() > 0); // Expand "~/" to the value of the HOME env variable @@ -134,30 +61,85 @@ POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p, bool verify) { } else { _path = p; } - - _displayName = lastPathComponent(_path); - - if (verify) { - setFlags(); + +#ifdef __OS2__ + // On OS/2, 'X:/' is a root of drive X, so we should not remove that last + // slash. + if (!(_path.size() == 3 && _path.hasSuffix(":/"))) +#endif + // Normalize the path (that is, remove unneeded slashes etc.) + _path = Common::normalizePath(_path, '/'); + _displayName = Common::lastPathComponent(_path, '/'); + + // TODO: should we turn relative paths into absolute ones? + // Pro: Ensures the "getParent" works correctly even for relative dirs. + // Contra: The user may wish to use (and keep!) relative paths in his + // config file, and converting relative to absolute paths may hurt him... + // + // An alternative approach would be to change getParent() to work correctly + // if "_path" is the empty string. +#if 0 + if (!_path.hasPrefix("/")) { + char buf[MAXPATHLEN+1]; + getcwd(buf, MAXPATHLEN); + strcat(buf, "/"); + _path = buf + _path; } +#endif + // TODO: Should we enforce that the path is absolute at this point? + //assert(_path.hasPrefix("/")); + + setFlags(); } AbstractFilesystemNode *POSIXFilesystemNode::getChild(const Common::String &n) const { - // FIXME: Pretty lame implementation! We do no error checking to speak - // of, do not check if this is a special node, etc. + assert(!_path.empty()); assert(_isDirectory); + + // Make sure the string contains no slashes + assert(!n.contains('/')); + // We assume here that _path is already normalized (hence don't bother to call + // Common::normalizePath on the final path). Common::String newPath(_path); if (_path.lastChar() != '/') newPath += '/'; newPath += n; - return new POSIXFilesystemNode(newPath, true); + return makeNode(newPath); } bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { assert(_isDirectory); +#ifdef __OS2__ + if (_path == "/") { + // Special case for the root dir: List all DOS drives + ULONG ulDrvNum; + ULONG ulDrvMap; + + DosQueryCurrentDisk(&ulDrvNum, &ulDrvMap); + + for (int i = 0; i < 26; i++) { + if (ulDrvMap & 1) { + char drive_root[] = "A:/"; + drive_root[0] += i; + + POSIXFilesystemNode *entry = new POSIXFilesystemNode(); + entry->_isDirectory = true; + entry->_isValid = true; + entry->_path = drive_root; + entry->_displayName = "[" + Common::String(drive_root, 2) + "]"; + myList.push_back(entry); + } + + ulDrvMap >>= 1; + } + + return true; + } +#endif + DIR *dirp = opendir(_path.c_str()); struct dirent *dp; @@ -175,12 +157,12 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo continue; } - Common::String newPath(_path); - if (newPath.lastChar() != '/') - newPath += '/'; - newPath += dp->d_name; - - POSIXFilesystemNode entry(newPath, false); + // Start with a clone of this node, with the correct path set + POSIXFilesystemNode entry(*this); + entry._displayName = dp->d_name; + if (_path.lastChar() != '/') + entry._path += '/'; + entry._path += entry._displayName; #if defined(SYSTEM_NOT_SUPPORTING_D_TYPE) /* TODO: d_type is not part of POSIX, so it might not be supported @@ -215,13 +197,10 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo continue; // Honor the chosen mode - if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) || - (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) + if ((mode == Common::FilesystemNode::kListFilesOnly && entry._isDirectory) || + (mode == Common::FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) continue; - if (entry._isDirectory) - entry._path += "/"; - myList.push_back(new POSIXFilesystemNode(entry)); } closedir(dirp); @@ -231,12 +210,39 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo AbstractFilesystemNode *POSIXFilesystemNode::getParent() const { if (_path == "/") - return 0; + return 0; // The filesystem root has no parent + +#ifdef __OS2__ + if (_path.size() == 3 && _path.hasSuffix(":/")) + // This is a root directory of a drive + return makeNode("/"); // return a virtual root for a list of drives +#endif const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = start + _path.size(); + + // Strip of the last component. We make use of the fact that at this + // point, _path is guaranteed to be normalized + while (end > start && *(end-1) != '/') + end--; + + if (end == start) { + // This only happens if we were called with a relative path, for which + // there simply is no parent. + // TODO: We could also resolve this by assuming that the parent is the + // current working directory, and returning a node referring to that. + return 0; + } + + return makeNode(Common::String(start, end)); +} + +Common::SeekableReadStream *POSIXFilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} - return new POSIXFilesystemNode(Common::String(start, end - start), true); +Common::WriteStream *POSIXFilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); } #endif //#if defined(UNIX) diff --git a/backends/fs/posix/posix-fs.h b/backends/fs/posix/posix-fs.h new file mode 100644 index 0000000000..e09e433e05 --- /dev/null +++ b/backends/fs/posix/posix-fs.h @@ -0,0 +1,86 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#ifndef POSIX_FILESYSTEM_H +#define POSIX_FILESYSTEM_H + +#include "backends/fs/abstract-fs.h" + +#ifdef MACOSX +#include <sys/types.h> +#endif +#include <unistd.h> + +/** + * Implementation of the ScummVM file system API based on POSIX. + * + * Parts of this class are documented in the base interface class, AbstractFilesystemNode. + */ +class POSIXFilesystemNode : public AbstractFilesystemNode { +protected: + Common::String _displayName; + Common::String _path; + bool _isDirectory; + bool _isValid; + + virtual AbstractFilesystemNode *makeNode(const Common::String &path) const { + return new POSIXFilesystemNode(path); + } + + /** + * Plain constructor, for internal use only (hence protected). + */ + POSIXFilesystemNode() : _isDirectory(false), _isValid(false) {} + +public: + /** + * Creates a POSIXFilesystemNode for a given path. + * + * @param path the path the new node should point to. + */ + POSIXFilesystemNode(const Common::String &path); + + virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } + virtual bool isDirectory() const { return _isDirectory; } + virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } + virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } + + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; + virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; + virtual AbstractFilesystemNode *getParent() const; + + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); + +private: + /** + * Tests and sets the _isValid and _isDirectory flags, using the stat() function. + */ + virtual void setFlags(); +}; + +#endif /*POSIX_FILESYSTEM_H*/ diff --git a/backends/fs/ps2/ps2-fs-factory.cpp b/backends/fs/ps2/ps2-fs-factory.cpp index ce3b4a5eaf..e96671ee0a 100644 --- a/backends/fs/ps2/ps2-fs-factory.cpp +++ b/backends/fs/ps2/ps2-fs-factory.cpp @@ -36,7 +36,7 @@ AbstractFilesystemNode *Ps2FilesystemFactory::makeCurrentDirectoryFileNode() con return new Ps2FilesystemNode(); } -AbstractFilesystemNode *Ps2FilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *Ps2FilesystemFactory::makeFileNodePath(const Common::String &path) const { // return new Ps2FilesystemNode(path); Ps2FilesystemNode *nf = new Ps2FilesystemNode(path, true); diff --git a/backends/fs/ps2/ps2-fs-factory.h b/backends/fs/ps2/ps2-fs-factory.h index 416024c905..432cf467c3 100644 --- a/backends/fs/ps2/ps2-fs-factory.h +++ b/backends/fs/ps2/ps2-fs-factory.h @@ -35,11 +35,9 @@ */ class Ps2FilesystemFactory : public FilesystemFactory, public Common::Singleton<Ps2FilesystemFactory> { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; protected: Ps2FilesystemFactory() {}; diff --git a/backends/fs/ps2/ps2-fs.cpp b/backends/fs/ps2/ps2-fs.cpp index 782e97b959..3d7656e9f0 100644 --- a/backends/fs/ps2/ps2-fs.cpp +++ b/backends/fs/ps2/ps2-fs.cpp @@ -23,6 +23,7 @@ */ #include "backends/fs/abstract-fs.h" +#include "backends/fs/stdiostream.h" #include <kernel.h> #include <stdio.h> #include <stdlib.h> @@ -47,8 +48,8 @@ class Ps2FilesystemNode : public AbstractFilesystemNode { friend class Ps2FilesystemFactory; protected: - String _displayName; - String _path; + Common::String _displayName; + Common::String _path; bool _isDirectory; bool _isRoot; @@ -65,10 +66,10 @@ public: /** * Creates a PS2FilesystemNode for a given path. * - * @param path String with the path the new node should point to. + * @param path Common::String with the path the new node should point to. */ - Ps2FilesystemNode(const String &path); - Ps2FilesystemNode(const String &path, bool verify); + Ps2FilesystemNode(const Common::String &path); + Ps2FilesystemNode(const Common::String &path, bool verify); /** * Copy constructor. @@ -77,9 +78,9 @@ public: virtual bool exists(void) const; - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; @@ -95,32 +96,13 @@ public: } virtual AbstractFilesystemNode *clone() const { return new Ps2FilesystemNode(this); } - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; -}; - -/** - * Returns the last component of a given path. - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if (str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/' && *cur != ':') { - --cur; - } - - printf("romeo : lastPathComponent = %s\n", cur + 1); - return cur + 1; -} + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); +}; Ps2FilesystemNode::Ps2FilesystemNode() { _isDirectory = true; @@ -129,12 +111,12 @@ Ps2FilesystemNode::Ps2FilesystemNode() { _path = ""; } -Ps2FilesystemNode::Ps2FilesystemNode(const String &path) { +Ps2FilesystemNode::Ps2FilesystemNode(const Common::String &path) { _path = path; _isDirectory = true; if (strcmp(path.c_str(), "") == 0) { _isRoot = true; - _displayName = String("PlayStation 2"); + _displayName = Common::String("PlayStation 2"); } else { _isRoot = false; const char *dsplName = NULL, *pos = path.c_str(); @@ -142,18 +124,18 @@ Ps2FilesystemNode::Ps2FilesystemNode(const String &path) { if (*pos++ == '/') dsplName = pos; if (dsplName) - _displayName = String(dsplName); + _displayName = Common::String(dsplName); else _displayName = getDeviceDescription(path.c_str()); } } -Ps2FilesystemNode::Ps2FilesystemNode(const String &path, bool verify) { +Ps2FilesystemNode::Ps2FilesystemNode(const Common::String &path, bool verify) { _path = path; if (strcmp(path.c_str(), "") == 0) { _isRoot = true; /* root is always a dir*/ - _displayName = String("PlayStation 2"); + _displayName = Common::String("PlayStation 2"); _isDirectory = true; } else { _isRoot = false; @@ -163,7 +145,7 @@ Ps2FilesystemNode::Ps2FilesystemNode(const String &path, bool verify) { dsplName = pos; if (dsplName) { - _displayName = String(dsplName); + _displayName = Common::String(dsplName); if (verify) _isDirectory = getDirectoryFlag(path.c_str()); else @@ -228,7 +210,7 @@ bool Ps2FilesystemNode::getDirectoryFlag(const char *path) { return false; } -AbstractFilesystemNode *Ps2FilesystemNode::getChild(const String &n) const { +AbstractFilesystemNode *Ps2FilesystemNode::getChild(const Common::String &n) const { if (!_isDirectory) return NULL; @@ -306,9 +288,9 @@ bool Ps2FilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hi while ((dreadRes = fio.dread(fd, &dirent)) > 0) { if (dirent.name[0] == '.') continue; // ignore '.' and '..' - if (((mode == FilesystemNode::kListDirectoriesOnly) && (dirent.stat.mode & FIO_S_IFDIR)) || - ((mode == FilesystemNode::kListFilesOnly) && !(dirent.stat.mode & FIO_S_IFDIR)) || - (mode == FilesystemNode::kListAll)) { + if (((mode == Common::FilesystemNode::kListDirectoriesOnly) && (dirent.stat.mode & FIO_S_IFDIR)) || + ((mode == Common::FilesystemNode::kListFilesOnly) && !(dirent.stat.mode & FIO_S_IFDIR)) || + (mode == Common::FilesystemNode::kListAll)) { dirEntry._isDirectory = (bool)(dirent.stat.mode & FIO_S_IFDIR); dirEntry._isRoot = false; @@ -344,7 +326,7 @@ AbstractFilesystemNode *Ps2FilesystemNode::getParent() const { } if (slash) - return new Ps2FilesystemNode(String(_path.c_str(), slash - _path.c_str())); + return new Ps2FilesystemNode(Common::String(_path.c_str(), slash - _path.c_str())); else return new Ps2FilesystemNode(); } @@ -359,3 +341,10 @@ char *Ps2FilesystemNode::getDeviceDescription(const char *path) const { return "Harddisk"; } +Common::SeekableReadStream *Ps2FilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} + +Common::WriteStream *Ps2FilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); +} diff --git a/backends/fs/psp/psp-fs-factory.cpp b/backends/fs/psp/psp-fs-factory.cpp index 87f0e0f587..a38462f02a 100644 --- a/backends/fs/psp/psp-fs-factory.cpp +++ b/backends/fs/psp/psp-fs-factory.cpp @@ -36,7 +36,7 @@ AbstractFilesystemNode *PSPFilesystemFactory::makeCurrentDirectoryFileNode() con return new PSPFilesystemNode(); } -AbstractFilesystemNode *PSPFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *PSPFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new PSPFilesystemNode(path, true); } #endif diff --git a/backends/fs/psp/psp-fs-factory.h b/backends/fs/psp/psp-fs-factory.h index ffa934755f..abf03d288e 100644 --- a/backends/fs/psp/psp-fs-factory.h +++ b/backends/fs/psp/psp-fs-factory.h @@ -35,11 +35,9 @@ */ class PSPFilesystemFactory : public FilesystemFactory, public Common::Singleton<PSPFilesystemFactory> { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; protected: PSPFilesystemFactory() {}; diff --git a/backends/fs/psp/psp-fs.cpp b/backends/fs/psp/psp-fs.cpp index 3fe6060928..13cd63903b 100644 --- a/backends/fs/psp/psp-fs.cpp +++ b/backends/fs/psp/psp-fs.cpp @@ -26,6 +26,7 @@ #include "engines/engine.h" #include "backends/fs/abstract-fs.h" +#include "backends/fs/stdiostream.h" #include <sys/stat.h> #include <unistd.h> @@ -39,8 +40,8 @@ */ class PSPFilesystemNode : public AbstractFilesystemNode { protected: - String _displayName; - String _path; + Common::String _displayName; + Common::String _path; bool _isDirectory; bool _isValid; @@ -53,47 +54,26 @@ public: /** * Creates a PSPFilesystemNode for a given path. * - * @param path String with the path the new node should point to. + * @param path Common::String with the path the new node should point to. * @param verify true if the isValid and isDirectory flags should be verified during the construction. */ PSPFilesystemNode(const Common::String &p, bool verify); virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; } - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; } virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; -}; - -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); +}; PSPFilesystemNode::PSPFilesystemNode() { _isDirectory = true; @@ -106,7 +86,7 @@ PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) { assert(p.size() > 0); _path = p; - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '/'); _isValid = true; _isDirectory = true; @@ -117,12 +97,12 @@ PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) { } } -AbstractFilesystemNode *PSPFilesystemNode::getChild(const String &n) const { +AbstractFilesystemNode *PSPFilesystemNode::getChild(const Common::String &n) const { // FIXME: Pretty lame implementation! We do no error checking to speak // of, do not check if this is a special node, etc. assert(_isDirectory); - String newPath(_path); + Common::String newPath(_path); if (_path.lastChar() != '/') newPath += '/'; newPath += n; @@ -157,8 +137,8 @@ bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool entry._path += "/"; // Honor the chosen mode - if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) || - (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) + if ((mode == Common::FilesystemNode::kListFilesOnly && entry._isDirectory) || + (mode == Common::FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) continue; myList.push_back(new PSPFilesystemNode(entry)); @@ -176,9 +156,17 @@ AbstractFilesystemNode *PSPFilesystemNode::getParent() const { return 0; const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); + + return new PSPFilesystemNode(Common::String(start, end - start), false); +} + +Common::SeekableReadStream *PSPFilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} - return new PSPFilesystemNode(String(start, end - start), false); +Common::WriteStream *PSPFilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); } #endif //#ifdef __PSP__ diff --git a/backends/fs/stdiostream.cpp b/backends/fs/stdiostream.cpp new file mode 100644 index 0000000000..3b0de253ab --- /dev/null +++ b/backends/fs/stdiostream.cpp @@ -0,0 +1,161 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/fs/stdiostream.h" + +#include <errno.h> + +#if defined(MACOSX) || defined(IPHONE) +#include "CoreFoundation/CoreFoundation.h" +#endif + + +#ifdef __PLAYSTATION2__ + // for those replaced fopen/fread/etc functions + typedef unsigned long uint64; + typedef signed long int64; + #include "backends/platform/ps2/fileio.h" + + #define fopen(a, b) ps2_fopen(a, b) + #define fclose(a) ps2_fclose(a) + #define fseek(a, b, c) ps2_fseek(a, b, c) + #define ftell(a) ps2_ftell(a) + #define feof(a) ps2_feof(a) + #define fread(a, b, c, d) ps2_fread(a, b, c, d) + #define fwrite(a, b, c, d) ps2_fwrite(a, b, c, d) + + //#define fprintf ps2_fprintf // used in common/util.cpp + //#define fflush(a) ps2_fflush(a) // used in common/util.cpp + + //#define fgetc(a) ps2_fgetc(a) // not used + //#define fgets(a, b, c) ps2_fgets(a, b, c) // not used + //#define fputc(a, b) ps2_fputc(a, b) // not used + //#define fputs(a, b) ps2_fputs(a, b) // not used + + //#define fsize(a) ps2_fsize(a) // not used -- and it is not a standard function either +#endif + +#ifdef __DS__ + + // These functions replace the standard library functions of the same name. + // As this header is included after the standard one, I have the chance to #define + // all of these to my own code. + // + // A #define is the only way, as redefinig the functions would cause linker errors. + + // These functions need to be #undef'ed, as their original definition + // in devkitarm is done with #includes (ugh!) + #undef feof + #undef clearerr + //#undef getc + //#undef ferror + + #include "backends/fs/ds/ds-fs.h" + + + // Only functions used in the ScummVM source have been defined here! + #define fopen(name, mode) DS::std_fopen(name, mode) + #define fclose(handle) DS::std_fclose(handle) + #define fread(ptr, size, items, file) DS::std_fread(ptr, size, items, file) + #define fwrite(ptr, size, items, file) DS::std_fwrite(ptr, size, items, file) + #define feof(handle) DS::std_feof(handle) + #define ftell(handle) DS::std_ftell(handle) + #define fseek(handle, offset, whence) DS::std_fseek(handle, offset, whence) + #define clearerr(handle) DS::std_clearerr(handle) + #define fflush(file) DS::std_fflush(file) + #define ferror(handle) DS::std_ferror(handle) + +#endif + +StdioStream::StdioStream(void *handle) : _handle(handle) { + assert(handle); +} + +StdioStream::~StdioStream() { + fclose((FILE *)_handle); +} + +bool StdioStream::err() const { + return ferror((FILE *)_handle) != 0; +} + +void StdioStream::clearErr() { + clearerr((FILE *)_handle); +} + +bool StdioStream::eos() const { + return feof((FILE *)_handle) != 0; +} + +int32 StdioStream::pos() const { + return ftell((FILE *)_handle); +} + +int32 StdioStream::size() const { + int32 oldPos = ftell((FILE *)_handle); + fseek((FILE *)_handle, 0, SEEK_END); + int32 length = ftell((FILE *)_handle); + fseek((FILE *)_handle, oldPos, SEEK_SET); + + return length; +} + +bool StdioStream::seek(int32 offs, int whence) { + return fseek((FILE *)_handle, offs, whence) == 0; +} + +uint32 StdioStream::read(void *ptr, uint32 len) { + return fread((byte *)ptr, 1, len, (FILE *)_handle); +} + +uint32 StdioStream::write(const void *ptr, uint32 len) { + return fwrite(ptr, 1, len, (FILE *)_handle); +} + +bool StdioStream::flush() { + return fflush((FILE *)_handle) == 0; +} + +StdioStream *StdioStream::makeFromPath(const Common::String &path, bool writeMode) { + FILE *handle = fopen(path.c_str(), writeMode ? "wb" : "rb"); + +#ifdef __amigaos4__ + // + // Work around for possibility that someone uses AmigaOS "newlib" build + // with SmartFileSystem (blocksize 512 bytes), leading to buffer size + // being only 512 bytes. "Clib2" sets the buffer size to 8KB, resulting + // smooth movie playback. This forces the buffer to be enough also when + // using "newlib" compile on SFS. + // + if (handle && !writeMode) { + setvbuf(handle, NULL, _IOFBF, 8192); + } +#endif + + + if (handle) + return new StdioStream(handle); + return 0; +} diff --git a/backends/fs/stdiostream.h b/backends/fs/stdiostream.h new file mode 100644 index 0000000000..3d44062d7f --- /dev/null +++ b/backends/fs/stdiostream.h @@ -0,0 +1,62 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef BACKENDS_FS_STDIOSTREAM_H +#define BACKENDS_FS_STDIOSTREAM_H + +#include "common/scummsys.h" +#include "common/noncopyable.h" +#include "common/stream.h" +#include "common/str.h" + +class StdioStream : public Common::SeekableReadStream, public Common::WriteStream, public Common::NonCopyable { +protected: + /** File handle to the actual file. */ + void *_handle; + +public: + /** + * Given a path, invokes fopen on that path and wrap the result in a + * StdioStream instance. + */ + static StdioStream *makeFromPath(const Common::String &path, bool writeMode); + + StdioStream(void *handle); + virtual ~StdioStream(); + + bool err() const; + void clearErr(); + bool eos() const; + + virtual uint32 write(const void *dataPtr, uint32 dataSize); + virtual bool flush(); + + virtual int32 pos() const; + virtual int32 size() const; + bool seek(int32 offs, int whence = SEEK_SET); + uint32 read(void *dataPtr, uint32 dataSize); +}; + +#endif diff --git a/backends/fs/symbian/symbian-fs-factory.cpp b/backends/fs/symbian/symbian-fs-factory.cpp index 0a1bd62134..c31dfb594a 100644 --- a/backends/fs/symbian/symbian-fs-factory.cpp +++ b/backends/fs/symbian/symbian-fs-factory.cpp @@ -26,8 +26,6 @@ #include "backends/fs/symbian/symbian-fs-factory.h" #include "backends/fs/symbian/symbian-fs.cpp" -DECLARE_SINGLETON(SymbianFilesystemFactory); - AbstractFilesystemNode *SymbianFilesystemFactory::makeRootFileNode() const { return new SymbianFilesystemNode(true); } @@ -38,7 +36,7 @@ AbstractFilesystemNode *SymbianFilesystemFactory::makeCurrentDirectoryFileNode() return new SymbianFilesystemNode(path); } -AbstractFilesystemNode *SymbianFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *SymbianFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new SymbianFilesystemNode(path); } #endif diff --git a/backends/fs/symbian/symbian-fs-factory.h b/backends/fs/symbian/symbian-fs-factory.h index 502fba2930..ef5a231e72 100644 --- a/backends/fs/symbian/symbian-fs-factory.h +++ b/backends/fs/symbian/symbian-fs-factory.h @@ -25,7 +25,6 @@ #ifndef SYMBIAN_FILESYSTEM_FACTORY_H #define SYMBIAN_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,11 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class SymbianFilesystemFactory : public FilesystemFactory, public Common::Singleton<SymbianFilesystemFactory> { +class SymbianFilesystemFactory : public FilesystemFactory { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - SymbianFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*SYMBIAN_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/symbian/symbian-fs.cpp b/backends/fs/symbian/symbian-fs.cpp index 85fc58179a..1c6d8435a9 100644 --- a/backends/fs/symbian/symbian-fs.cpp +++ b/backends/fs/symbian/symbian-fs.cpp @@ -24,12 +24,16 @@ #if defined (__SYMBIAN32__) #include "backends/fs/abstract-fs.h" +#include "backends/fs/symbian/symbianstream.h" +#include "backends/platform/symbian/src/symbianos.h" #include <dirent.h> #include <eikenv.h> #include <f32file.h> #include <bautils.h> +#define KDriveLabelSize 30 + /** * Implementation of the ScummVM file system API based on POSIX. * @@ -37,12 +41,11 @@ */ class SymbianFilesystemNode : public AbstractFilesystemNode { protected: - String _displayName; - String _path; - bool _isDirectory; - bool _isValid; - bool _isPseudoRoot; - + Common::String _displayName; + Common::String _path; + TBool _isDirectory; + TBool _isValid; + TBool _isPseudoRoot; public: /** * Creates a SymbianFilesystemNode with the root node as path. @@ -54,57 +57,36 @@ public: /** * Creates a SymbianFilesystemNode for a given path. * - * @param path String with the path the new node should point to. + * @param path Common::String with the path the new node should point to. */ - SymbianFilesystemNode(const String &path); + SymbianFilesystemNode(const Common::String &path); virtual bool exists() const { TFileName fname; - TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size()); + TPtrC8 ptr((const unsigned char*) _path.c_str(), _path.size()); fname.Copy(ptr); - TBool fileExists = BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), fname); + TBool fileExists = BaflUtils::FileExists(static_cast<OSystem_SDL_Symbian*> (g_system)->FsSession(), fname); return fileExists; } - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; } virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } //FIXME: this is just a stub virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } //FIXME: this is just a stub - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; -}; -/** - * Returns the last component of a given path. - * - * Examples: - * c:\foo\bar.txt would return "\bar.txt" - * c:\foo\bar\ would return "\bar\" - * - * @param str Path to obtain the last component from. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '\\') { - --cur; - } - - return cur + 1; -} + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); +}; /** * Fixes the path by changing all slashes to backslashes. * - * @param path String with the path to be fixed. + * @param path Common::String with the path to be fixed. */ static void fixFilePath(Common::String& aPath){ TInt len = aPath.size(); @@ -118,54 +100,47 @@ static void fixFilePath(Common::String& aPath){ SymbianFilesystemNode::SymbianFilesystemNode(bool aIsRoot) { _path = ""; - _isValid = true; - _isDirectory = true; + _isValid = ETrue; + _isDirectory = ETrue; _isPseudoRoot = aIsRoot; _displayName = "Root"; } -SymbianFilesystemNode::SymbianFilesystemNode(const String &path) { +SymbianFilesystemNode::SymbianFilesystemNode(const Common::String &path) { if (path.size() == 0) - _isPseudoRoot = true; + _isPseudoRoot = ETrue; else - _isPseudoRoot = false; + _isPseudoRoot = EFalse; _path = path; fixFilePath(_path); - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '\\'); TEntry fileAttribs; TFileName fname; TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size()); fname.Copy(ptr); - if (CEikonEnv::Static()->FsSession().Entry(fname, fileAttribs) == KErrNone) { - _isValid = true; + if (static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession().Entry(fname, fileAttribs) == KErrNone) { + _isValid = ETrue; _isDirectory = fileAttribs.IsDir(); } else { - _isValid = false; - _isDirectory = false; + _isValid = ETrue; + _isDirectory = EFalse; } } -AbstractFilesystemNode *SymbianFilesystemNode::getChild(const String &n) const { +AbstractFilesystemNode *SymbianFilesystemNode::getChild(const Common::String &n) const { assert(_isDirectory); - String newPath(_path); + Common::String newPath(_path); if (_path.lastChar() != '\\') newPath += '\\'; - newPath += n; - TPtrC8 ptr((const unsigned char*) newPath.c_str(), newPath.size()); - TFileName fname; - fname.Copy(ptr); - TBool isFolder = EFalse; - BaflUtils::IsFolder(CEikonEnv::Static()->FsSession(), fname, isFolder); - if (!isFolder) - return 0; + newPath += n; return new SymbianFilesystemNode(newPath); } @@ -177,19 +152,19 @@ bool SymbianFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b if (_isPseudoRoot) { // Drives enumeration - RFs fs = CEikonEnv::Static()->FsSession(); + RFs& fs = static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(); TInt driveNumber; TChar driveLetter; TUint driveLetterValue; TVolumeInfo volumeInfo; - TBuf8<30> driveLabel8; - TBuf8<30> driveString8; + TBuf8<KDriveLabelSize> driveLabel8; + TBuf8<KDriveLabelSize> driveString8; for (driveNumber=EDriveA; driveNumber<=EDriveZ; driveNumber++) { TInt err = fs.Volume(volumeInfo, driveNumber); if (err != KErrNone) continue; - if (fs.DriveToChar(driveNumber,driveLetter) != KErrNone) + if (fs.DriveToChar(driveNumber, driveLetter) != KErrNone) continue; driveLetterValue = driveLetter; @@ -205,40 +180,46 @@ bool SymbianFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b sprintf(path,"%c:\\", driveNumber+'A'); SymbianFilesystemNode entry(false); - entry._displayName = (char*)driveString8.PtrZ(); // drive_name - entry._isDirectory = true; - entry._isValid = true; - entry._isPseudoRoot = false; + entry._displayName = (char*) driveString8.PtrZ(); // drive_name + entry._isDirectory = ETrue; + entry._isValid = ETrue; + entry._isPseudoRoot = EFalse; entry._path = path; myList.push_back(new SymbianFilesystemNode(entry)); } } else { - TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size()); + TPtrC8 ptr((const unsigned char*) _path.c_str(), _path.size()); TFileName fname; - fname.Copy(ptr); TBuf8<256>nameBuf; CDir* dirPtr; - if (CEikonEnv::Static()->FsSession().GetDir(fname,KEntryAttNormal|KEntryAttDir,0,dirPtr)==KErrNone) { + fname.Copy(ptr); + + if (_path.lastChar() != '\\') + fname.Append('\\'); + + if (static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession().GetDir(fname, KEntryAttNormal|KEntryAttDir, 0, dirPtr) == KErrNone) { CleanupStack::PushL(dirPtr); TInt cnt=dirPtr->Count(); for (TInt loop=0;loop<cnt;loop++) { TEntry fileentry=(*dirPtr)[loop]; nameBuf.Copy(fileentry.iName); - SymbianFilesystemNode entry(false); - entry._isPseudoRoot = false; + SymbianFilesystemNode entry(EFalse); + entry._isPseudoRoot = EFalse; - entry._displayName =(char*)nameBuf.PtrZ(); + entry._displayName =(char*) nameBuf.PtrZ(); entry._path = _path; - entry._path +=(char*)nameBuf.PtrZ(); + + if (entry._path.lastChar() != '\\') + entry._path+= '\\'; + + entry._path +=(char*) nameBuf.PtrZ(); entry._isDirectory = fileentry.IsDir(); // Honor the chosen mode - if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) || - (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) + if ((mode == Common::FilesystemNode::kListFilesOnly && entry._isDirectory) || + (mode == Common::FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) continue; - - if (entry._isDirectory) - entry._path += "\\"; + myList.push_back(new SymbianFilesystemNode(entry)); } CleanupStack::PopAndDestroy(dirPtr); @@ -254,21 +235,30 @@ AbstractFilesystemNode *SymbianFilesystemNode::getParent() const { // Root node is its own parent. Still we can't just return this // as the GUI code will call delete on the old node. if (!_isPseudoRoot && _path.size() > 3) { - p = new SymbianFilesystemNode(false); + p = new SymbianFilesystemNode(EFalse); const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '\\'); - p->_path = String(start, end - start); - p->_isValid = true; - p->_isDirectory = true; - p->_displayName = lastPathComponent(p->_path); + p->_path = Common::String(start, end - start); + p->_isValid = ETrue; + p->_isDirectory = ETrue; + p->_displayName = lastPathComponent(p->_path, '\\'); } else { - p = new SymbianFilesystemNode(true); + p = new SymbianFilesystemNode(ETrue); } return p; } +Common::SeekableReadStream *SymbianFilesystemNode::openForReading() { + return SymbianStdioStream::makeFromPath(getPath().c_str(), false); +} + +Common::WriteStream *SymbianFilesystemNode::openForWriting() { + return SymbianStdioStream::makeFromPath(getPath().c_str(), true); +} #endif //#if defined (__SYMBIAN32__) + + diff --git a/backends/fs/symbian/symbianstream.cpp b/backends/fs/symbian/symbianstream.cpp new file mode 100644 index 0000000000..5944cab892 --- /dev/null +++ b/backends/fs/symbian/symbianstream.cpp @@ -0,0 +1,274 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/scummsys.h" +#include "backends/fs/symbian/symbianstream.h" +#include "common/system.h" +#include "backends/platform/symbian/src/symbianos.h" + +#include <f32file.h> + +#define KInputBufferLength 128 + +// Symbian libc file functionality in order to provide shared file handles +class TSymbianFileEntry { +public: + RFile _fileHandle; + char _inputBuffer[KInputBufferLength]; + TInt _inputBufferLen; + TInt _inputPos; + TInt _lastError; + TBool _eofReached; +}; + +TSymbianFileEntry* CreateSymbianFileEntry(const char* name, const char* mode) { + TSymbianFileEntry* fileEntry = new TSymbianFileEntry; + fileEntry->_inputPos = KErrNotFound; + fileEntry->_lastError = 0; + fileEntry->_eofReached = EFalse; + + if (fileEntry != NULL) { + TInt modeLen = strlen(mode); + + TPtrC8 namePtr((unsigned char*) name, strlen(name)); + TFileName tempFileName; + tempFileName.Copy(namePtr); + + TInt fileMode = EFileRead; + + if (mode[0] == 'a') + fileMode = EFileWrite; + + if (!((modeLen > 1 && mode[1] == 'b') || (modeLen > 2 && mode[2] == 'b'))) { + fileMode |= EFileStreamText; + } + + if ((modeLen > 1 && mode[1] == '+') || (modeLen > 2 && mode[2] == '+')) { + fileMode = fileMode| EFileWrite; + } + + fileMode = fileMode| EFileShareAny; + + switch(mode[0]) { + case 'a': + if (fileEntry->_fileHandle.Open(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { + if (fileEntry->_fileHandle.Create(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { + delete fileEntry; + fileEntry = NULL; + } + } + break; + case 'r': + if (fileEntry->_fileHandle.Open(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { + delete fileEntry; + fileEntry = NULL; + } + break; + + case 'w': + if (fileEntry->_fileHandle.Replace(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) { + delete fileEntry; + fileEntry = NULL; + } + break; + } + } + return fileEntry; +} + +size_t ReadData(const void* ptr, size_t size, size_t numItems, TSymbianFileEntry* handle) { + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); + TUint32 totsize = size*numItems; + TPtr8 pointer ( (unsigned char*) ptr, totsize); + + // Nothing cached and we want to load at least KInputBufferLength bytes + if (totsize >= KInputBufferLength) { + TUint32 totLength = 0; + if (entry->_inputPos != KErrNotFound) { + TPtr8 cacheBuffer( (unsigned char*) entry->_inputBuffer+entry->_inputPos, entry->_inputBufferLen - entry->_inputPos, KInputBufferLength); + pointer.Append(cacheBuffer); + entry->_inputPos = KErrNotFound; + totLength+=pointer.Length(); + pointer.Set(totLength+(unsigned char*) ptr, 0, totsize-totLength); + } + + entry->_lastError = entry->_fileHandle.Read(pointer); + + totLength+=pointer.Length(); + + pointer.Set((unsigned char*) ptr, totLength, totsize); + + } else { + // Nothing in buffer + if (entry->_inputPos == KErrNotFound) { + TPtr8 cacheBuffer( (unsigned char*) entry->_inputBuffer, KInputBufferLength); + entry->_lastError = entry->_fileHandle.Read(cacheBuffer); + + if (cacheBuffer.Length() >= totsize) { + pointer.Copy(cacheBuffer.Left(totsize)); + entry->_inputPos = totsize; + entry->_inputBufferLen = cacheBuffer.Length(); + } else { + pointer.Copy(cacheBuffer); + entry->_inputPos = KErrNotFound; + } + + } else { + TPtr8 cacheBuffer( (unsigned char*) entry->_inputBuffer, entry->_inputBufferLen, KInputBufferLength); + + if (entry->_inputPos+totsize < entry->_inputBufferLen) { + pointer.Copy(cacheBuffer.Mid(entry->_inputPos, totsize)); + entry->_inputPos+=totsize; + } else { + + pointer.Copy(cacheBuffer.Mid(entry->_inputPos, entry->_inputBufferLen-entry->_inputPos)); + cacheBuffer.SetLength(0); + entry->_lastError = entry->_fileHandle.Read(cacheBuffer); + + if (cacheBuffer.Length() >= totsize-pointer.Length()) { + TUint32 restSize = totsize-pointer.Length(); + pointer.Append(cacheBuffer.Left(restSize)); + entry->_inputPos = restSize; + entry->_inputBufferLen = cacheBuffer.Length(); + } else { + pointer.Append(cacheBuffer); + entry->_inputPos = KErrNotFound; + } + } + } + } + + if((numItems * size) != pointer.Length() && entry->_lastError == KErrNone) { + entry->_eofReached = ETrue; + } + + return pointer.Length() / size; +} + +SymbianStdioStream::SymbianStdioStream(void *handle) : _handle(handle) { + assert(handle); +} + +SymbianStdioStream::~SymbianStdioStream() { + ((TSymbianFileEntry*)(_handle))->_fileHandle.Close(); + + delete (TSymbianFileEntry*)(_handle); +} + +bool SymbianStdioStream::err() const { + return ((TSymbianFileEntry*)(_handle))->_lastError != 0; +} + +void SymbianStdioStream::clearErr() { + ((TSymbianFileEntry*)(_handle))->_lastError = 0; + ((TSymbianFileEntry*)(_handle))->_eofReached = 0; +} + +bool SymbianStdioStream::eos() const { + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(_handle)); + + return entry->_eofReached != 0; +} + +int32 SymbianStdioStream::pos() const { + TInt pos = 0; + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(_handle)); + + entry->_lastError = entry->_fileHandle.Seek(ESeekCurrent, pos); + if (entry->_lastError == KErrNone && entry->_inputPos != KErrNotFound) { + pos += (entry->_inputPos - entry->_inputBufferLen); + } + + return pos; +} + +int32 SymbianStdioStream::size() const { + + TInt length = 0; + ((TSymbianFileEntry*)(_handle))->_fileHandle.Size(length); + + return length; +} + +bool SymbianStdioStream::seek(int32 offs, int whence) { + assert(_handle); + + TSeek seekMode = ESeekStart; + TInt pos = offs; + TSymbianFileEntry* entry = ((TSymbianFileEntry*)(_handle)); + + switch (whence) { + case SEEK_SET: + seekMode = ESeekStart; + break; + case SEEK_CUR: + seekMode = ESeekCurrent; + if (entry->_inputPos != KErrNotFound) { + pos += (entry->_inputPos - entry->_inputBufferLen); + } + break; + case SEEK_END: + seekMode = ESeekEnd; + break; + + } + + entry->_inputPos = KErrNotFound; + entry->_eofReached = EFalse; + entry->_fileHandle.Seek(seekMode, pos); + + return true; // FIXME: Probably should return a value based on what _fileHandle.Seek returns +} + +uint32 SymbianStdioStream::read(void *ptr, uint32 len) { + return (uint32)ReadData((byte *)ptr, 1, len, (TSymbianFileEntry *)_handle); +} + +uint32 SymbianStdioStream::write(const void *ptr, uint32 len) { + TPtrC8 pointer( (unsigned char*) ptr, len); + + ((TSymbianFileEntry*)(_handle))->_inputPos = KErrNotFound; + ((TSymbianFileEntry*)(_handle))->_lastError = ((TSymbianFileEntry*)(_handle))->_fileHandle.Write(pointer); + ((TSymbianFileEntry*)(_handle))->_eofReached = EFalse; + + if (((TSymbianFileEntry*)(_handle))->_lastError == KErrNone) { + return len; + } + + return 0; +} + +bool SymbianStdioStream::flush() { + ((TSymbianFileEntry*)(_handle))->_fileHandle.Flush(); + return true; +} + +SymbianStdioStream *SymbianStdioStream::makeFromPath(const Common::String &path, bool writeMode) { + void *handle = CreateSymbianFileEntry(path.c_str(), writeMode ? "wb" : "rb"); + if (handle) + return new SymbianStdioStream(handle); + return 0; +} + diff --git a/backends/fs/symbian/symbianstream.h b/backends/fs/symbian/symbianstream.h new file mode 100644 index 0000000000..d783856687 --- /dev/null +++ b/backends/fs/symbian/symbianstream.h @@ -0,0 +1,62 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: $ + * $Id: $ + * + */ + +#ifndef BACKENDS_FS_SYMBIANSTDIOSTREAM_H +#define BACKENDS_FS_SYMBIANSTDIOSTREAM_H + +#include "common/scummsys.h" +#include "common/noncopyable.h" +#include "common/stream.h" +#include "common/str.h" + +class SymbianStdioStream : public Common::SeekableReadStream, public Common::WriteStream, public Common::NonCopyable { +protected: + /** File handle to the actual file. */ + void *_handle; + +public: + /** + * Given a path, invokes fopen on that path and wrap the result in a + * StdioStream instance. + */ + static SymbianStdioStream *makeFromPath(const Common::String &path, bool writeMode); + + SymbianStdioStream(void *handle); + virtual ~SymbianStdioStream(); + + bool err() const; + void clearErr(); + bool eos() const; + + virtual uint32 write(const void *dataPtr, uint32 dataSize); + virtual bool flush(); + + virtual int32 pos() const; + virtual int32 size() const; + bool seek(int32 offs, int whence = SEEK_SET); + uint32 read(void *dataPtr, uint32 dataSize); +}; + +#endif diff --git a/backends/fs/wii/wii-fs-factory.cpp b/backends/fs/wii/wii-fs-factory.cpp index 9839858dd5..69086a95f1 100644 --- a/backends/fs/wii/wii-fs-factory.cpp +++ b/backends/fs/wii/wii-fs-factory.cpp @@ -42,7 +42,7 @@ AbstractFilesystemNode *WiiFilesystemFactory::makeCurrentDirectoryFileNode() con return new WiiFilesystemNode(); } -AbstractFilesystemNode *WiiFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *WiiFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new WiiFilesystemNode(path, true); } #endif diff --git a/backends/fs/wii/wii-fs-factory.h b/backends/fs/wii/wii-fs-factory.h index 24badee330..36867a392c 100644 --- a/backends/fs/wii/wii-fs-factory.h +++ b/backends/fs/wii/wii-fs-factory.h @@ -33,11 +33,9 @@ */ class WiiFilesystemFactory : public FilesystemFactory, public Common::Singleton<WiiFilesystemFactory> { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; protected: WiiFilesystemFactory() {}; diff --git a/backends/fs/wii/wii-fs.cpp b/backends/fs/wii/wii-fs.cpp index e6d0cf4c7e..a620df5471 100644 --- a/backends/fs/wii/wii-fs.cpp +++ b/backends/fs/wii/wii-fs.cpp @@ -23,6 +23,7 @@ #if defined(__WII__) #include "backends/fs/abstract-fs.h" +#include "backends/fs/stdiostream.h" #include <sys/dir.h> @@ -37,8 +38,8 @@ */ class WiiFilesystemNode : public AbstractFilesystemNode { protected: - String _displayName; - String _path; + Common::String _displayName; + Common::String _path; bool _isDirectory, _isReadable, _isWritable; public: @@ -50,51 +51,30 @@ public: /** * Creates a WiiFilesystemNode for a given path. * - * @param path String with the path the new node should point to. + * @param path Common::String with the path the new node should point to. * @param verify true if the isValid and isDirectory flags should be verified during the construction. */ - WiiFilesystemNode(const String &path, bool verify); + WiiFilesystemNode(const Common::String &path, bool verify); virtual bool exists() const; - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; } virtual bool isReadable() const { return _isReadable; } virtual bool isWritable() const { return _isWritable; } - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); + private: virtual void setFlags(); }; -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} - void WiiFilesystemNode::setFlags() { struct stat st; @@ -118,12 +98,12 @@ WiiFilesystemNode::WiiFilesystemNode() { setFlags(); } -WiiFilesystemNode::WiiFilesystemNode(const String &p, bool verify) { +WiiFilesystemNode::WiiFilesystemNode(const Common::String &p, bool verify) { assert(p.size() > 0); _path = p; - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '/'); if (verify) setFlags(); @@ -134,10 +114,10 @@ bool WiiFilesystemNode::exists() const { return stat(_path.c_str (), &st) == 0; } -AbstractFilesystemNode *WiiFilesystemNode::getChild(const String &n) const { +AbstractFilesystemNode *WiiFilesystemNode::getChild(const Common::String &n) const { assert(_isDirectory); - String newPath(_path); + Common::String newPath(_path); if (newPath.lastChar() != '/') newPath += '/'; newPath += n; @@ -160,15 +140,15 @@ bool WiiFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) continue; - String newPath(_path); + Common::String newPath(_path); if (newPath.lastChar() != '/') newPath += '/'; newPath += filename; bool isDir = S_ISDIR(st.st_mode); - if ((mode == FilesystemNode::kListFilesOnly && isDir) || - (mode == FilesystemNode::kListDirectoriesOnly && !isDir)) + if ((mode == Common::FilesystemNode::kListFilesOnly && isDir) || + (mode == Common::FilesystemNode::kListDirectoriesOnly && !isDir)) continue; if (isDir) @@ -187,9 +167,17 @@ AbstractFilesystemNode *WiiFilesystemNode::getParent() const { return 0; const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); + + return new WiiFilesystemNode(Common::String(start, end - start), true); +} + +Common::SeekableReadStream *WiiFilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} - return new WiiFilesystemNode(String(start, end - start), true); +Common::WriteStream *WiiFilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); } #endif //#if defined(__WII__) diff --git a/backends/fs/windows/windows-fs-factory.cpp b/backends/fs/windows/windows-fs-factory.cpp index 7fbf4f7fff..ed273bb746 100644 --- a/backends/fs/windows/windows-fs-factory.cpp +++ b/backends/fs/windows/windows-fs-factory.cpp @@ -26,8 +26,6 @@ #include "backends/fs/windows/windows-fs-factory.h" #include "backends/fs/windows/windows-fs.cpp" -DECLARE_SINGLETON(WindowsFilesystemFactory); - AbstractFilesystemNode *WindowsFilesystemFactory::makeRootFileNode() const { return new WindowsFilesystemNode(); } @@ -36,7 +34,7 @@ AbstractFilesystemNode *WindowsFilesystemFactory::makeCurrentDirectoryFileNode() return new WindowsFilesystemNode("", true); } -AbstractFilesystemNode *WindowsFilesystemFactory::makeFileNodePath(const String &path) const { +AbstractFilesystemNode *WindowsFilesystemFactory::makeFileNodePath(const Common::String &path) const { return new WindowsFilesystemNode(path, false); } #endif diff --git a/backends/fs/windows/windows-fs-factory.h b/backends/fs/windows/windows-fs-factory.h index 0745b286a8..3c7b80942d 100644 --- a/backends/fs/windows/windows-fs-factory.h +++ b/backends/fs/windows/windows-fs-factory.h @@ -25,7 +25,6 @@ #ifndef WINDOWS_FILESYSTEM_FACTORY_H #define WINDOWS_FILESYSTEM_FACTORY_H -#include "common/singleton.h" #include "backends/fs/fs-factory.h" /** @@ -33,19 +32,11 @@ * * Parts of this class are documented in the base interface class, FilesystemFactory. */ -class WindowsFilesystemFactory : public FilesystemFactory, public Common::Singleton<WindowsFilesystemFactory> { +class WindowsFilesystemFactory : public FilesystemFactory { public: - typedef Common::String String; - virtual AbstractFilesystemNode *makeRootFileNode() const; virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const; - virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const; - -protected: - WindowsFilesystemFactory() {}; - -private: - friend class Common::Singleton<SingletonBaseType>; + virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const; }; #endif /*WINDOWS_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/windows/windows-fs.cpp b/backends/fs/windows/windows-fs.cpp index 2105317a96..c59c7dbe71 100644 --- a/backends/fs/windows/windows-fs.cpp +++ b/backends/fs/windows/windows-fs.cpp @@ -24,24 +24,17 @@ #ifdef WIN32 -#ifdef ARRAYSIZE -#undef ARRAYSIZE -#endif -#ifdef _WIN32_WCE #include <windows.h> // winnt.h defines ARRAYSIZE, but we want our own one... #undef ARRAYSIZE +#ifdef _WIN32_WCE #undef GetCurrentDirectory #endif #include "backends/fs/abstract-fs.h" +#include "backends/fs/stdiostream.h" #include <io.h> #include <stdio.h> #include <stdlib.h> -#ifndef _WIN32_WCE -#include <windows.h> -// winnt.h defines ARRAYSIZE, but we want our own one... -#undef ARRAYSIZE -#endif #include <tchar.h> // F_OK, R_OK and W_OK are not defined under MSVC, so we define them here @@ -66,8 +59,8 @@ */ class WindowsFilesystemNode : public AbstractFilesystemNode { protected: - String _displayName; - String _path; + Common::String _displayName; + Common::String _path; bool _isDirectory; bool _isPseudoRoot; bool _isValid; @@ -89,23 +82,26 @@ public: * path=c:\foo\bar.txt, currentDir=true -> current directory * path=NULL, currentDir=true -> current directory * - * @param path String with the path the new node should point to. + * @param path Common::String with the path the new node should point to. * @param currentDir if true, the path parameter will be ignored and the resulting node will point to the current directory. */ - WindowsFilesystemNode(const String &path, const bool currentDir); + WindowsFilesystemNode(const Common::String &path, const bool currentDir); virtual bool exists() const { return _access(_path.c_str(), F_OK) == 0; } - virtual String getDisplayName() const { return _displayName; } - virtual String getName() const { return _displayName; } - virtual String getPath() const { return _path; } + virtual Common::String getDisplayName() const { return _displayName; } + virtual Common::String getName() const { return _displayName; } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return _isDirectory; } virtual bool isReadable() const { return _access(_path.c_str(), R_OK) == 0; } virtual bool isWritable() const { return _access(_path.c_str(), W_OK) == 0; } - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; virtual AbstractFilesystemNode *getParent() const; + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); + private: /** * Adds a single WindowsFilesystemNode to a given list. @@ -113,7 +109,7 @@ private: * * @param list List to put the file entry node in. * @param mode Mode to use while adding the file entry to the list. - * @param base String with the directory being listed. + * @param base Common::String with the directory being listed. * @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find. */ static void addFile(AbstractFSList &list, ListMode mode, const char *base, WIN32_FIND_DATA* find_data); @@ -121,7 +117,7 @@ private: /** * Converts a Unicode string to Ascii format. * - * @param str String to convert from Unicode to Ascii. + * @param str Common::String to convert from Unicode to Ascii. * @return str in Ascii format. */ static char *toAscii(TCHAR *str); @@ -129,36 +125,12 @@ private: /** * Converts an Ascii string to Unicode format. * - * @param str String to convert from Ascii to Unicode. + * @param str Common::String to convert from Ascii to Unicode. * @return str in Unicode format. */ static const TCHAR* toUnicode(const char *str); }; -/** - * Returns the last component of a given path. - * - * Examples: - * c:\foo\bar.txt would return "\bar.txt" - * c:\foo\bar\ would return "\bar\" - * - * @param str Path to obtain the last component from. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '\\') { - --cur; - } - - return cur + 1; -} - void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, WIN32_FIND_DATA* find_data) { WindowsFilesystemNode entry; char *asciiName = toAscii(find_data->cFileName); @@ -170,8 +142,8 @@ void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const c isDirectory = (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? true : false); - if ((!isDirectory && mode == FilesystemNode::kListDirectoriesOnly) || - (isDirectory && mode == FilesystemNode::kListFilesOnly)) + if ((!isDirectory && mode == Common::FilesystemNode::kListDirectoriesOnly) || + (isDirectory && mode == Common::FilesystemNode::kListFilesOnly)) return; entry._isDirectory = isDirectory; @@ -222,7 +194,7 @@ WindowsFilesystemNode::WindowsFilesystemNode() { #endif } -WindowsFilesystemNode::WindowsFilesystemNode(const String &p, const bool currentDir) { +WindowsFilesystemNode::WindowsFilesystemNode(const Common::String &p, const bool currentDir) { if (currentDir) { char path[MAX_PATH]; GetCurrentDirectory(MAX_PATH, path); @@ -232,7 +204,7 @@ WindowsFilesystemNode::WindowsFilesystemNode(const String &p, const bool current _path = p; } - _displayName = lastPathComponent(_path); + _displayName = lastPathComponent(_path, '\\'); // Check whether it is a directory, and whether the file actually exists DWORD fileAttribs = GetFileAttributes(toUnicode(_path.c_str())); @@ -251,10 +223,10 @@ WindowsFilesystemNode::WindowsFilesystemNode(const String &p, const bool current _isPseudoRoot = false; } -AbstractFilesystemNode *WindowsFilesystemNode::getChild(const String &n) const { +AbstractFilesystemNode *WindowsFilesystemNode::getChild(const Common::String &n) const { assert(_isDirectory); - String newPath(_path); + Common::String newPath(_path); if (_path.lastChar() != '\\') newPath += '\\'; newPath += n; @@ -322,17 +294,25 @@ AbstractFilesystemNode *WindowsFilesystemNode::getParent() const { WindowsFilesystemNode *p = new WindowsFilesystemNode(); if (_path.size() > 3) { const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '\\'); p = new WindowsFilesystemNode(); - p->_path = String(start, end - start); + p->_path = Common::String(start, end - start); p->_isValid = true; p->_isDirectory = true; - p->_displayName = lastPathComponent(p->_path); + p->_displayName = lastPathComponent(p->_path, '\\'); p->_isPseudoRoot = false; } return p; } +Common::SeekableReadStream *WindowsFilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} + +Common::WriteStream *WindowsFilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); +} + #endif //#ifdef WIN32 diff --git a/backends/midi/seq.cpp b/backends/midi/seq.cpp index 57a5a1ea32..9e86181674 100644 --- a/backends/midi/seq.cpp +++ b/backends/midi/seq.cpp @@ -28,7 +28,7 @@ * both the QuickTime support and (vkeybd http://www.alsa-project.org/~iwai/alsa.html) */ -#if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) +#if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) && !defined(__MINT__) #include "common/util.h" #include "sound/musicplugin.h" diff --git a/backends/midi/stmidi.cpp b/backends/midi/stmidi.cpp new file mode 100644 index 0000000000..addb23c6bd --- /dev/null +++ b/backends/midi/stmidi.cpp @@ -0,0 +1,155 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Raw MIDI output for the Atari ST line of computers. + * Based on the ScummVM SEQ & CoreMIDI drivers. + * Atari code by Keith Scroggins + * We, unfortunately, could not use the SEQ driver because the /dev/midi under + * FreeMiNT (and hence in libc) is considered to be a serial port for machine + * access. So, we just use OS calls then to send the data to the MIDI ports + * directly. The current implementation is sending 1 byte at a time because + * in most cases we are only sending up to 3 bytes, I believe this saves a few + * cycles. I might change so sysex messages are sent the other way later. + */ + +#if defined __MINT__ + +#include <osbind.h> +#include "sound/mpu401.h" +#include "common/util.h" +#include "sound/musicplugin.h" + +class MidiDriver_STMIDI : public MidiDriver_MPU401 { +public: + MidiDriver_STMIDI() : _isOpen (false) { } + int open(); + void close(); + void send(uint32 b); + void sysEx(const byte *msg, uint16 length); + +private: + bool _isOpen; +}; + +int MidiDriver_STMIDI::open() { + if ((_isOpen) && (!Bcostat(4))) + return MERR_ALREADY_OPEN; + warning("ST Midi Port Open"); + _isOpen = true; + return 0; +} + +void MidiDriver_STMIDI::close() { + MidiDriver_MPU401::close(); + _isOpen = false; +} + +void MidiDriver_STMIDI::send(uint32 b) { + + byte status_byte = (b & 0x000000FF); + byte first_byte = (b & 0x0000FF00) >> 8; + byte second_byte = (b & 0x00FF0000) >> 16; + +// warning("ST MIDI Packet sent"); + + switch (b & 0xF0) { + case 0x80: // Note Off + case 0x90: // Note On + case 0xA0: // Polyphonic Key Pressure + case 0xB0: // Controller + case 0xE0: // Pitch Bend + Bconout(3, status_byte); + Bconout(3, first_byte); + Bconout(3, second_byte); + break; + case 0xC0: // Program Change + case 0xD0: // Aftertouch + Bconout(3, status_byte); + Bconout(3, first_byte); + break; + default: + fprintf(stderr, "Unknown : %08x\n", (int)b); + break; + } +} + +void MidiDriver_STMIDI::sysEx (const byte *msg, uint16 length) { + if (length > 254) { + warning ("Cannot send SysEx block - data too large"); + return; + } + + const byte *chr = msg; + warning("Sending SysEx Message"); + + Bconout(3, '0xF0'); + for (; length; --length, ++chr) { + Bconout(3,((unsigned char) *chr & 0x7F)); + } + Bconout(3, '0xF7'); +} + +// Plugin interface + +class StMidiMusicPlugin : public MusicPluginObject { +public: + const char *getName() const { + return "STMIDI"; + } + + const char *getId() const { + return "stmidi"; + } + + MusicDevices getDevices() const; + PluginError createInstance(Audio::Mixer *mixer, MidiDriver **mididriver) + const; +}; + +MusicDevices StMidiMusicPlugin::getDevices() const { + MusicDevices devices; + // TODO: Return a different music type depending on the configuration + // TODO: List the available devices + devices.push_back(MusicDevice(this, "", MT_GM)); + return devices; +} + +PluginError StMidiMusicPlugin::createInstance(Audio::Mixer *mixer, MidiDriver **mididriver) const { + *mididriver = new MidiDriver_STMIDI(); + + return kNoError; +} + +MidiDriver *MidiDriver_STMIDI_create(Audio::Mixer *mixer) { + MidiDriver *mididriver; + + StMidiMusicPlugin p; + p.createInstance(mixer, &mididriver); + + return mididriver; +} + +//#if PLUGIN_ENABLED_DYNAMIC(STMIDI) + //REGISTER_PLUGIN_DYNAMIC(STMIDI, PLUGIN_TYPE_MUSIC, StMidiMusicPlugin); +//#else + REGISTER_PLUGIN_STATIC(STMIDI, PLUGIN_TYPE_MUSIC, StMidiMusicPlugin); +//#endif + +#endif diff --git a/backends/module.mk b/backends/module.mk index 6642a3a281..8944e9a3db 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -1,6 +1,8 @@ MODULE := backends MODULE_OBJS := \ + fs/abstract-fs.o \ + fs/stdiostream.o \ fs/amigaos4/amigaos4-fs-factory.o \ fs/ds/ds-fs-factory.o \ fs/palmos/palmos-fs-factory.o \ @@ -17,6 +19,7 @@ MODULE_OBJS := \ midi/coremidi.o \ midi/quicktime.o \ midi/seq.o \ + midi/stmidi.o \ midi/timidity.o \ midi/dmedia.o \ midi/windows.o \ diff --git a/backends/platform/dc/dc-fs.cpp b/backends/platform/dc/dc-fs.cpp index f4dc4037df..c4f1d76f10 100644 --- a/backends/platform/dc/dc-fs.cpp +++ b/backends/platform/dc/dc-fs.cpp @@ -24,6 +24,7 @@ #include "dc.h" #include "backends/fs/abstract-fs.h" +#include "backends/fs/stdiostream.h" #include <ronin/cdfs.h> #include <stdio.h> @@ -34,75 +35,50 @@ * * Parts of this class are documented in the base interface class, AbstractFilesystemNode. */ - -/* A file */ class RoninCDFileNode : public AbstractFilesystemNode { protected: - String _path; - static const char *lastPathComponent(const Common::String &str); + Common::String _path; public: - RoninCDFileNode(const String &path) : _path(path) {}; + RoninCDFileNode(const Common::String &path) : _path(path) {}; virtual bool exists() const { return true; } - virtual String getName() const { return lastPathComponent(_path); } - virtual String getPath() const { return _path; } + virtual Common::String getName() const { return lastPathComponent(_path, '/'); } + virtual Common::String getPath() const { return _path; } virtual bool isDirectory() const { return false; } virtual bool isReadable() const { return true; } virtual bool isWritable() const { return false; } - virtual AbstractFilesystemNode *getChild(const String &n) const { return NULL; } + virtual AbstractFilesystemNode *getChild(const Common::String &n) const { return NULL; } virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const { return false; } virtual AbstractFilesystemNode *getParent() const; + virtual Common::SeekableReadStream *openForReading(); + virtual Common::WriteStream *openForWriting(); + static AbstractFilesystemNode *makeFileNodePath(const Common::String &path); }; /* A directory */ class RoninCDDirectoryNode : public RoninCDFileNode { public: - RoninCDDirectoryNode(const String &path) : RoninCDFileNode(path) {}; + RoninCDDirectoryNode(const Common::String &path) : RoninCDFileNode(path) {}; virtual bool isDirectory() const { return true; } - virtual AbstractFilesystemNode *getChild(const String &n) const; + virtual AbstractFilesystemNode *getChild(const Common::String &n) const; virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; }; /* A file/directory which does not exist */ class RoninCDNonexistingNode : public RoninCDFileNode { public: - RoninCDNonexistingNode(const String &path) : RoninCDFileNode(path) {}; + RoninCDNonexistingNode(const Common::String &path) : RoninCDFileNode(path) {}; virtual bool exists() const { return false; } virtual bool isReadable() const { return false; } }; -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *RoninCDFileNode::lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } - - return cur + 1; -} - -AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String &path) -{ +AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String &path) { assert(path.size() > 0); int fd; @@ -110,18 +86,16 @@ AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String & if ((fd = open(path.c_str(), O_RDONLY)) >= 0) { close(fd); return new RoninCDFileNode(path); - } - else if ((fd = open(path.c_str(), O_DIR|O_RDONLY)) >= 0) { + } else if ((fd = open(path.c_str(), O_DIR|O_RDONLY)) >= 0) { close(fd); return new RoninCDDirectoryNode(path); - } - else { + } else { return NULL; } } -AbstractFilesystemNode *RoninCDDirectoryNode::getChild(const String &n) const { - String newPath(_path); +AbstractFilesystemNode *RoninCDDirectoryNode::getChild(const Common::String &n) const { + Common::String newPath(_path); if (_path.lastChar() != '/') newPath += '/'; newPath += n; @@ -139,20 +113,20 @@ bool RoninCDDirectoryNode::getChildren(AbstractFSList &myList, ListMode mode, bo // ... loop over dir entries using readdir while ((dp = readdir(dirp)) != NULL) { - String newPath(_path); + Common::String newPath(_path); if (newPath.lastChar() != '/') newPath += '/'; newPath += dp->d_name; if (dp->d_size < 0) { // Honor the chosen mode - if (mode == FilesystemNode::kListFilesOnly) + if (mode == Common::FilesystemNode::kListFilesOnly) continue; myList.push_back(new RoninCDDirectoryNode(newPath+"/")); } else { // Honor the chosen mode - if (mode == FilesystemNode::kListDirectoriesOnly) + if (mode == Common::FilesystemNode::kListDirectoriesOnly) continue; myList.push_back(new RoninCDFileNode(newPath)); @@ -168,9 +142,18 @@ AbstractFilesystemNode *RoninCDFileNode::getParent() const { return 0; const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = lastPathComponent(_path, '/'); + + return new RoninCDDirectoryNode(Common::String(start, end - start)); +} + + +Common::SeekableReadStream *RoninCDFileNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} - return new RoninCDDirectoryNode(String(start, end - start)); +Common::WriteStream *RoninCDFileNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); } AbstractFilesystemNode *OSystem_Dreamcast::makeRootFileNode() const { diff --git a/backends/platform/dc/selector.cpp b/backends/platform/dc/selector.cpp index 91c851506f..a4a53e0f65 100644 --- a/backends/platform/dc/selector.cpp +++ b/backends/platform/dc/selector.cpp @@ -146,12 +146,12 @@ struct Dir { char name[252]; char deficon[256]; - FilesystemNode node; + Common::FilesystemNode node; }; static Game the_game; -static bool isIcon(const FilesystemNode &entry) +static bool isIcon(const Common::FilesystemNode &entry) { int l = entry.getDisplayName().size(); if (l>4 && !strcasecmp(entry.getDisplayName().c_str()+l-4, ".ICO")) @@ -198,14 +198,14 @@ static int findGames(Game *games, int max) { Dir *dirs = new Dir[MAX_DIR]; int curr_game = 0, curr_dir = 0, num_dirs = 1; - dirs[0].node = FilesystemNode(""); + dirs[0].node = Common::FilesystemNode(""); while (curr_game < max && curr_dir < num_dirs) { strncpy(dirs[curr_dir].name, dirs[curr_dir].node.getPath().c_str(), 252); dirs[curr_dir].name[251] = '\0'; dirs[curr_dir].deficon[0] = '\0'; - FSList files, fslist; - dirs[curr_dir++].node.getChildren(fslist, FilesystemNode::kListAll); - for (FSList::const_iterator entry = fslist.begin(); entry != fslist.end(); + Common::FSList files, fslist; + dirs[curr_dir++].node.getChildren(fslist, Common::FilesystemNode::kListAll); + for (Common::FSList::const_iterator entry = fslist.begin(); entry != fslist.end(); ++entry) { if (entry->isDirectory()) { if (num_dirs < MAX_DIR && strcasecmp(entry->getDisplayName().c_str(), diff --git a/backends/platform/dc/vmsave.cpp b/backends/platform/dc/vmsave.cpp index 6ab8fc4558..d17e1f6213 100644 --- a/backends/platform/dc/vmsave.cpp +++ b/backends/platform/dc/vmsave.cpp @@ -269,14 +269,15 @@ class InVMSave : public Common::InSaveFile { private: char *buffer; int _pos, _size; + bool _eos; uint32 read(void *buf, uint32 cnt); - void skip(uint32 offset); - void seek(int32 offs, int whence); + bool skip(uint32 offset); + bool seek(int32 offs, int whence); public: InVMSave() - : _pos(0), buffer(NULL) + : _pos(0), buffer(NULL), _eos(false) { } ~InVMSave() @@ -285,9 +286,10 @@ public: delete[] buffer; } - bool eos() const { return _pos >= _size; } - uint32 pos() const { return _pos; } - uint32 size() const { return _size; } + bool eos() const { return _eos; } + void clearErr() { _eos = false; } + int32 pos() const { return _pos; } + int32 size() const { return _size; } bool readSaveGame(const char *filename) { return ::readSaveGame(buffer, _size, filename); } @@ -312,8 +314,8 @@ public: ~OutVMSave(); - bool ioFailed() const { return iofailed; } - void clearIOFailed() { iofailed = false; } + bool err() const { return iofailed; } + void clearErr() { iofailed = false; } void finalize(); }; @@ -370,6 +372,7 @@ uint32 InVMSave::read(void *buf, uint32 cnt) int nbyt = cnt; if (_pos + nbyt > _size) { cnt = (_size - _pos); + _eos = true; nbyt = cnt; } if (nbyt) @@ -378,15 +381,16 @@ uint32 InVMSave::read(void *buf, uint32 cnt) return cnt; } -void InVMSave::skip(uint32 offset) +bool InVMSave::skip(uint32 offset) { int nbyt = offset; if (_pos + nbyt > _size) nbyt = (_size - _pos); _pos += nbyt; + return true; } -void InVMSave::seek(int32 offs, int whence) +bool InVMSave::seek(int32 offs, int whence) { switch(whence) { case SEEK_SET: @@ -403,6 +407,8 @@ void InVMSave::seek(int32 offs, int whence) _pos = 0; else if (_pos > _size) _pos = _size; + _eos = false; + return true; } uint32 OutVMSave::write(const void *buf, uint32 cnt) diff --git a/backends/platform/ds/arm7/Makefile b/backends/platform/ds/arm7/Makefile index 55db7f8cad..82637845db 100644 --- a/backends/platform/ds/arm7/Makefile +++ b/backends/platform/ds/arm7/Makefile @@ -107,7 +107,7 @@ MAPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.map))) export OFILES := $(MAPFILES:.map=.o) $(RAWFILES:.raw=.o) $(PALFILES:.pal=.o) $(BINFILES:.bin=.o) $(PCXFILES:.pcx=.o)\ $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) -I- -I$(CURDIR)/../commoninclude\ +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) -Iquote -I$(CURDIR)/../commoninclude\ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include/nds)\ -I$(CURDIR)/$(BUILD) -I$(CURDIR)/source/libcartreset diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp index bee39f1efe..d252ed44de 100644 --- a/backends/platform/ds/arm7/source/main.cpp +++ b/backends/platform/ds/arm7/source/main.cpp @@ -233,7 +233,7 @@ void DummyHandler() { REG_IF = REG_IF; } -uint16 powerManagerWrite(uint32 command, u32 data, bool enable) { +void powerManagerWrite(uint32 command, u32 data, bool enable) { uint16 result; SerialWaitBusy(); @@ -261,9 +261,6 @@ uint16 powerManagerWrite(uint32 command, u32 data, bool enable) { REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz; REG_SPIDATA = enable? (result | data): (result & ~data); SerialWaitBusy(); - - // FIXME: This function should either return something, or have a comment - // explaining why it is valid for it to not return something. :-) } /* diff --git a/backends/platform/ds/arm9/dist/readme_ds.txt b/backends/platform/ds/arm9/dist/readme_ds.txt new file mode 100644 index 0000000000..f77da418c9 --- /dev/null +++ b/backends/platform/ds/arm9/dist/readme_ds.txt @@ -0,0 +1,840 @@ + + + + The official port of ScummVM + to the Nintendo DS handheld console + by Neil Millstone (agentq) + http://scummvm.drunkencoders.com +------------------------------------------------------------------------ +Visit the main ScummVM website <http://www.scummvm.org> + + + + + Contents + ------------------------------------------------------------------------ + + + + * What's New? + * What is ScummVM DS? + * Features + * Screenshots + * How to Get ScummVM DS Onto Your DS - Simple Explanation + o Using a CF/SD/Mini SD/Micro SD card reader and a DLDI driver + o Instructions for specific card readers + * What to do if saving doesn't work or your card gets corruped - + force SRAM saves + * How to use ScummVM DS + * Game Specific Controls + * DS Options Screen + * Which games are compatible with ScummVM DS + * Predictive dictionary for Sierra AGI games + * Converting your CD audio + * Converting speech to MP3 format + * Frequently Asked Questions + * Downloads + * Contributors + * Donations and Getting Help + * Building from Sources + + + + What's New? + ------------------------------------------------------------------------ + +ScummVM DS 0.12.0 + + * New games supported: Lure of the Temptress, Nippon Safes, Lost in Time. + * New laptop-style trackpad input method. Uses relative movement when you + drag on the touch screen. + * New option which allows you to drag to hover, tap the touch screen to + click, and double tap the screen to right click. + * Reorganised DS Options screen into three tabs for clearer navigation + * New top screen scaling options let you choose the scaling factor used + on startup. + * The usual round of bug fixes. + + +ScummVM DS 0.11.1 + + * Bugfix release - No new DS port features + + +ScummVM DS 0.11.0 + + * New games supported: Elvira 1 and 2, Waxworks (Amiga version) + * Software scaler for improved image quality. Turn it on using the DS options + screen (press select during the game). Thanks to Tramboi and Robin Watts for + this feature! + * Function keys added to virtual keyboard (used in AGI games) + * Plenty of bug fixes + + What is ScummVM DS? + ------------------------------------------------------------------------ + +ScummVM DS is a part of the ScummVM project. The ScummVM project is an +attempt to re-engineer many classic point and click adventure games of the +80s and 90s to run on modern computer hardware. Technology has changed a +lot since these games were written, and so ScummVM attempts to replicate the +gameplay of the original games in exacting details, without any of the original +code that the game ran on. ScummVM needs a copy of the original game, in order +to take the graphics, sound, and scripts that made the game work. + +ScummVM is written in such a way that it can be 'ported' from one type of +machine to another, and ScummVM DS is a port of ScummVM to the Nintendo DS +handheld games console. + + + Features + ------------------------------------------------------------------------ + + * Runs nearly all of Lucasarts' SCUMM games up to and including Sam + & Max Hit the Road + * Runs many non-Lucasarts point-and-click adventures too + * Supports sound + * Provides a GUI to change settings and choose games + * Supports using the DS touch screen for controls + * Suports saving games to compatible flash cards + * All games run at pretty much full speed + + + + + + How to Get ScummVM DS Onto Your DS - Simple Explanation + ------------------------------------------------------------------------ + +Nintendo don't want you to run ScummVM on your DS. They control +which companies can make games on the DS, and there is an expensive +process to go through in order to be licenced. Having to pay for +this would prevent me from giving away ScummVM for free. + +So, the result is that to run ScummVM on your DS you'll need an +unofficial card reader. There are many of these, and all are different. +Popular models at the time of writing are the R4DS and the M3DS Real, +but many different models work. You need to buy one of these, and at +MicroSD card to go with it. + +There are also slot-2 card readers which fit into the bottom slot on +your DS, usually used for Game Boy Advance games. These are less common +these days, and although they have certain advantages, the details of +these are beyond the scope of this website. Information on these is +quite easy to find by searching. + +Once you have your card reader and a MicroSD card, you will also need +a copy of the game you want to run. ScummVM can run a large variety +of games, but you must own a real boxed copy of the game. These games +are still under copyright, and it is illegal to copy them from a friend +or download them from the Internet without paying. The exception to +this are the three Revolution Software games. These are 'Beneath a +Steel Sky', 'Lure of the Temptress' and 'Flight of the Amazon Queen'. +Revolution have kindly allowed us to give these games away for free. +You can download them from the main ScummVM site at +<http://www.scummvm.org/downloads.php> + +NOTE: Previous version of ScummVM DS supported a method which used a +zip file to run games on unsupported flash card readers. This method +is no longer supported. + + + How to Get ScummVM DS Onto Your DS - Using a CF/SD/Mini SD/Micro + SD card reader and a DLDI driver + ------------------------------------------------------------------------ + +ScummVM DS needs something called a DLDI driver to run on each make +and model of card reader. Many modern card readers (R4DS, M3 DS Real) +handle this autmatically and for those, you don't have to do anything. +Just running ScummVM on the card will handle this step for you. +For others, you will need to follow the steps in this section before +ScummVM DS will work. + +All DS card readers are different in the way that they work. In order to +support many different card readers, ScummVM DS uses a DLDI driver installed +into the ScummVM DS code. This is done using a program called DLDITool +which you can download and run on your computer. Each DLDI driver is +designed to tell ScummVM DS how to use a specific type of card reader. +These drivers can be used with any homebrew program which supports the +DLDI interface. + +While each card reader should work with these instructions, there are +some exceptions. Please read the card reader notes +section to see if there is any specific information about your card reader. + +Here is what you need to do: + + * Visit the DLDI page <http://dldi.drunkencoders.com/> and + download the executable for DLDITool for your operating system + (versions are available for Windows, Linux, and MacOS) + * Download the DLDI for your card reader. This is the big table at + the top of the page. The first column marked DLDI is the one you + want. You should get a single file with a .dldi extension. + * Extract DLDITool into a folder, and put the DLDI of your choice in + the same folder. + * If you're using the command line version of DLDITool enter the + following at a command prompt: + + dlditool <dldiname> <scummvm nds name> + + + If you're using the Windows GUI version, double click on + dlditool32.exe, select your card reader from the box, drag your + ScummVM binaries (either the .nds, or the .ds.gba version + depending on your card reader. I think only Supercards use the + .ds.gba files) into the lower box, then click patch. + + Either way, you should see 'Patched Successfully'. If you don't, + you're doing something wrong. + + You need to patch one of the builds labeled A - F depending on + which game you want to run. See the table on the ScummVM DS + website to see which games are supported by which build. + + * Put the patched .nds or .ds.gba files on your flash card. If + you're using the Supercard, you will need to use the .ds.gba + files, but rename them to .nds. + * Put your game data in any folder on the card. Do NOT use a zip file. + * Boot up your DS and run ScummVM. + * Click 'Add Game', browse to the folder with your game data, click + 'Choose', then 'OK'. Click 'Start' to run the game. + +If your copy of ScummVM DS has been successfully patched, you will get a +message on the top screen that looks like this: + + DLDI Device: + GBA Movie Player (Compact Flash) + +The message should show the name of your card reader. If it is wrong, +you have used the wrong DLDI file. + +If you haven't patched your .nds file, you will get the following message + + DLDI Driver not patched! + DLDI Initialise failed. + +In this case, you've made a mistake following the above instructions, or +have patched the wrong file. + +You may also see the following message: + + DLDI Device: + GBA Movie Player (Compact Flash) + DLDI Initialise failed. + +In this case, the driver did not start up correctly. The driver is +probably broken, or you've used the wrong one for your card reader. + +In the case of the Supercard, M3 Lite and DS Link, there are several +drivers available. You might want to try one of the others. + +This version of ScummVM DS will run on any card reader that has a DLDI +driver available. If yours doesn't, you need to pressure your card +reader manufacturer to release one. + +DO NOT EMAIL ME TO ASK ME TO CREATE A DRIVER FOR YOUR CARD READER, I +CANNOT DO THIS. + + + How to Get ScummVM DS Onto Your DS - Instructions for specific + card readers + ------------------------------------------------------------------------ + + * *GBAMP CF:* You need to upload replacement firmware to your card + reader before it will work. You can download the firmware program + here <http://chishm.drunkencoders.com/NDSMP/index.html>. Name your + .nds file _BOOT_MP.nds. + * *M3 CF/SD:* Copy the .nds file to your card with the M3 Game + Manager in order to avoid an annoying message when you boot your + M3. Use the default options to copy the file. Be sure to press 'A' + in the M3 browser to start the .nds file, and not 'Start', or it + won't work. + * *M3 CF/SD:* Copy the .nds file to your card with the M3 Game + Manager in order to avoid an annoying message when you boot your + M3. Use the default options to copy the file. Be sure to press 'A' + in the M3 browser to start the .nds file, and not 'Start', or it + won't work. + * *Supercard CF/SD (slot-2):* Use the .ds.gba files to run ScummVM + on the Supercard. Other than that, just follow the instructions as + normal. + * *Supercard Lite (slot-2):* It has been reported that only the + standard Supercard driver and the Moonshell version work with + ScummVM DS. + * *Datel Max Media Dock: * If you haven't already, upgrade your + firmware to the latest version. The firmware that came with my Max + Media Dock was unable to run ScummVM DS at all. Click here to + visit Datel's support page and download the latest firmware + <http://us.codejunkies.com/mpds/support.htm> + * *NinjaDS*: There are firmware upgrades for this device, but for + me, ScummVM DS ran straight out of the box. Visit this page + <http://www.ninjads.com/news.html> to download the latest firmware + if you want. If you have installed FlashMe on your DS, it will + make your DS crash on boot when the NinjaDS is inserted. You can + hold the 'select' button during boot to disable FlashMe, which + will allow the NinjaDS to work. Due to this, it is not recommended + to install FlashMe if you use a NinjaDS. + * *EZ-Flash*: This card reader uses .ds.gba files from the ScummVM + archive. Rename them to .nds before patching them with the DLDI + patcher. + * *R4DS*: If you upgrade the firmware for your R4DS to version 1.10 + or later, the card will autmatically DLDI patch the game, meaning + you don't have to use dlditool to patch the .NDS file. This makes + things a lot easier! + * *M3DS Real*: This card autmatically DLDI patches the game, meaning + that you do not need to do this yourself. + + + + Which games are compatible with ScummVM DS? + ------------------------------------------------------------------------ + +I'm glad you asked. Here is a list of the compatible games in version +0.12.0. Demo versions of the games listed should work too. + +Flight of the Amazon Queen, Beneath a Steel Sky, and Lure of the +Temptress have generously been released as freeware by the original +authors, Revolution Software <http://www.revolution.co.uk/>. This is a +great thing and we should support Revolution for being so kind to us. +You can download the game data from the official ScummVM download page +<http://www.scummvm.org/downloads.php>. + +The other games on this list are commercial, and still under copyright, +which means downloading them without paying for it is illegal. You can +probably find a second-hand copy on eBay. Please don't email me to ask +for a copy, as I am unable to send it to you. + +Game Build Notes + +Manic Mansion A + +Zak McKracken and the Alien Mindbenders A + +Indiana Jones and the Last Crusade A + +Loom A + +Passport to Adventure A + +The Secret of Monkey Island A + +Monkey Island 2: LeChuck's Revenge A + +Indiana Jones and the Fate of Atlantis A + +Day of the Tentacle A + +Sam & Max Hit the Road A Some slowdown in a few scenes + when MP3 audio is enabled + +Bear Stormin' (DOS) A + +Fatty Bear's Birthday Surprise (DOS) A + +Fatty Bear's Fun Pack (DOS) A + +Putt-Putt's Fun Pack (DOS) A + +Putt-Putt Goes to the Moon (DOS) A + +Putt-Putt Joins the Parade (DOS) A Can sometimes crash due to low memory + +Beneath a Steel Sky B + +Flight of the Amazon Queen B + +Simon the Sorcerer 1 C Zoomed view does not follow the + speaking character +Simon the Sorcerer 2 C Zoomed view does not follow the + speaking character +Elvira 1 C + +Elvira 2 C + +Waxworks (Amiga version) C + +Gobliiins D + +Gobliins 2 D + +Goblins 3 D + +Ween: The Prophecy D + +Bargon Attack D + +Lost in Time D + +Future Wars D + +All Sierra AGI games. +For a complete list, see this page +<http://wiki.scummvm.org/index.php/AGI> D + +Inherit the Earth E + +The Legend of Kyrandia F Zoomed view does not follow the + speaking character + +Lure of the Temptress G + +Nippon Safes G + +There is no support for Full Throttle, The Dig, or The Curse of Monkey +Island because of memory issues. There simply is not enough RAM on the +DS to run these games. Sorry. Also there is no support for Windows Humongous +Entertainment games. The extra code required to make this work uses up +too much RAM. + + + What to do when saving doesn't work or your card gets corrupted - + forcing SRAM Saves + ------------------------------------------------------------------------ + +This method only works for cards which use the Game Boy Advance slot on the +bottom of your DS. + +If ScummVM DS cannot save games to your SD card, or it causes corruption +when it does, you can force it to use GBA SRAM to save the game. This +uses your flash cart reader's GBA features to save the game to a .sav or +.dat file (depending on the reader). Only slot-2 devices can use SRAM saves, +and only ones with support for GBA games. + +If you want to use SRAM save, just create a text file called scummvm.ini +(or scummvmb.ini, scummvmc.ini for builds B or C) in the root of your +card which contains the following: + +[ds] +forcesramsave=true + +When you boot your game, ScummVM DS will not save games to your SD card +directly, instead it will save to GBA SRAM. On most cards, you need to +transfer the data to your SD card by rebooting and using your card +reader's boot-up menu. Using this method, around four saves can me made. + +One disadvantage of forcing SRAM saves is that your settings won't be +saved. You can add games manually to the ini file so that you don't have +to select them on each boot. Just add a section like the following on +for each game on your card. + +[monkey2] +description=Monkey Island 2: LeChuck's Revenge (English/DOS) +path=mp:/MONKEY2 + + + How to Use ScummVM + ------------------------------------------------------------------------ + +Once you've booted up ScummVM, you'll see the start up screen. + + 1. Tap the 'Add' button with the pen, then browse to the folder + containing your game data. Once you have clicked on your folder, you will + not see any files inside. This is normal, as the folder selector only shows + folders! + + 2. Click the 'Choose' button. + + 3. You will get some options for the game. You can usually just click 'Ok' to + this. + + 4. Now click on the name of the game you want to play from the list and + click 'Start'. Your game will start! + +You can use the B button to skip cutscenes, and the select button to +show an options menu which will let you tweak the DS contols, including +switch between scaled and unscaled video modes. The text is clearer in +the unscaled mode, but the whole game doesn't fit on the screen. To +scroll around, hold either shoulder button and use the D-pad or drag the +screen around with the stylus. Even in scaled mode, a small amount is +missing from the top and bottom of the screen. You can scroll around to +see those areas. The top screen shows a zoomed-in view. This scrolls +around to focus on the character who's speaking, and also follows where +the pen touches the screen. You can change the zoom level by holding one +of the shoulder buttons and pressing B to zoom in and A to zoom out. + +Press the start button for the in-game menu where you can load or save +your game (this works in Lucasarts games, other games vary). Saves will +write directly to your flash card. You can choose the folder where they +are stored using the GUI that appears when you boot up. If you're using +a GBA Flash Cartridge, or an unsupported flash card adaptor, you will be +using GBA SRAM to save your game. Four or five save game will fit in +save RAM. If you save more games than will fit, a warning will appear on +the top screen. When you turn your DS off, the new save will be lost, +and only the first ones you saved will be present. + +Many of the games use both mouse buttons. Usually the right button often +performs the default action on any object you click on. To simulate this +with the DS pen, you can switch the input into one of three modes. Press +left on the D-pad to enable the left mouse button. Press right on the +D-pad to enable the right mouse button. Press up on the D-pad to enable +hover mode. In this mode, you won't click on anything, just hover the +mouse cursor over it. This lets you pick out active objects in the scene. + +An icon on the top screen will show you which mode you're in. + +In hover mode, there are some additional controls. While holding the pen +on the screen, tapping D-pad left or D-pad right (or A/Y in left handed +mode) will click the left or right mouse button. + +There is an alternative method of control which doesn't require you to +change modes with the D-pad. Press 'Select' to bring up the DS options, +and choose 'Tap for left click, double tap for right click'. In this +mode, you can quickly tap the screen to left click the mouse, and tap twice +to right click the mouse. + + +Here is a complete list of controls in right-handed mode (the default +setting): +Key Usage +Pad Left Left mouse button +Pad Right Right mouse button +Pad Up Hover mouse (no mouse button) +Pad Down Skip dialogue line (for some Lucasarts games), Show inventory + (for Beneath a Steel Sky), Show active objects (for Simon the Sorceror) +Start Pause/game menu (works in some games) +Select DS Options +B Skip cutscenes +A Swap main screen and zoomed screen +Y Show/Hide debug console +X Show/Hide on-screen keyboard +L + D-pad or L + Pen Scroll touch screen view +L + B Zoom in +L + A Zoom out + + + +And here's left-handed mode: +Key Usage +Y Left mouse button +A Right mouse button +X Hover mouse (no mouse button) +B Skip dialogue line (for some Lucasarts games), Show inventory (for + Beneath a Steel Sky), Show active objects (for Simon the Sorceror) +Start Pause/game menu (works in some games) +Select DS Options +D-pad down Skip cutscenes +D-pad up Swap main screen and zoomed screen +D-pad left Show/Hide debug console +D-pad right Show/Hide on-screen keyboard +R + D-pad or R + Pen Scroll touch screen view +R + D-pad down Zoom in +R + d-pad right Zoom out + + + + Game-specific controls + ------------------------------------------------------------------------ + + * Sam and Max Hit the Road: The current cursor mode is displayed on + the top screen. Use d-pad right to switch mode. + * Indiana Jones games: If you get into a fight, press Select, and + check the box marked 'Use Indy Fighting Controls'. + Return to the game, then use the following controls to fight: + + D-pad left: move left + D-pad right: move right + D-pad up: guard up + D-pad down: guard down + Y: guard middle + X: Punch high + A: Punch middle + B: Punch low + Left shoulder: Fight towards the left + Right shoulder: Fight towards the right + + The icon on the top screen shows which way you're currently + facing. Remember to turn the option off when the fight ends, or + the normal controls won't work! + * Beneath a Steel Sky: Press D-pad down to show your inventory. + * Simon the Sorcerer 1/2: Press D-pad down to show active objects. + * AGI games: Press Start to show the menu bar. + * Bargon Attack: Press Start to hit F1 when you need to start the + game. Use the on-screen keyboard (hit X) to press other function keys. + + + DS Options Screen + ------------------------------------------------------------------------ + +Pressing the 'select' button during any game to show the DS options +screen. This screen shows options specific to the Nintendo DS version +of ScummVM. + +Controls tab + +Indy Fight Controls - Enable fighting controls for the Indiana Jones +games. See 'Game Specific Controls' for more information. + +Left handed Mode - Switch the controls on the D-pad with the controls +on the A/B/X/Y buttons. + +Show mouse cursor - Shows the game's mouse cursor on the bottom screen. + +Snap to edges - makes it easier for the mouse controls to reach the edges +of the screen. Useful for Beneath a Steel Sky and Goblins 3. + +Touch X offset - if your screen doesn't perform properly, this setting +allows you to adjust when the cursor appears left or right relative to +the screen's measured touch position. + +Touch Y offset - if your screen doesn't perform properly, this setting +allows you to adjust when the cursor appears higher or lower relative to +the screen's measured touch position. + +Use Laptop Trackpad-style cursor control - In this mode, use the lower +screen to drag the cursor around, a bit like using a trackpad on a laptop. +When this option is enabled, the following option is also enabled. + +Tap for left click, double tap for right click - In this mode, you can +quickly tap on the screen to left click the mouse, or quickly +double tap on the screen to right click the mouse. If you find clicking +or double-clicking difficult, try and make a firmer touch on the screen, +and keep the pen down for longer. + +Sensitivity - this bar adjusts the speed of cursor movement when laptop +trackpad-style cursor control is enabled (see above). + +Graphics Tab + +Scaling options: + +Three scaling options are available for the main screen. + +Harware Scale - Scales using the DS hardware scaler using a flicker method. +Produces lower quality graphics but doesn't slow the game down. + +Software Scale - Scales using the CPU. A much higher quality image is +produced, but at the expense of speed in some games. + +Unscaled - Allows you to see the graphics as originaly displayed. This +doesn't fit on the DS screen, but you can scroll the screen around by holding +the left shoulder button and using the D-pad or touch screen. + +Top screen zoom - These three options control the zoom level of the top +screen when ScummVM is started up. Changing this option will set the zoom +to the specified level immediately. + +Initial top screen scale: + +This option controls the scaling level of the zoomed screen. In ScummVM +DS, one screen shows a zoomed-in view of the action, and this option controls +how zoomed in it is. You can also adjust this in the game by holding L and +pressing A/B. + +General Tab + +High Quality Audio - Enhance the sound quality, at the expense of some +slowdown during some games. + +Disable power off - ScummVM DS turns the power off when the game quits. +This option disables that feature. + + + + + + + Auto completion dictionary for Sierra AGI games + ------------------------------------------------------------------------ + +If you are playing a Sierra AGI game, you will be using the on-screen +keyboard quite a lot (press X to show it). To reduce the amount you have +to type, the game can automatically complete long words for you. To use +this feature, simply copy the PRED.DIC file from the ScummVM DS archive +into your game folder on your card. Now, when you use the keyboard, +possible words will be shown underneith it. To type one of those words, +simply double click on it with your stylus. + + + Converting your CD audio + ------------------------------------------------------------------------ + +ScummVM supports playing CD audio for specific games which came with +music stored as standard music CD tracks. To use this music in ScummVM +DS, they need to be ripped from the CD and stored in a specific format. +This can only be done for the CD versions of certain games, such as +Monkey Island 1, Loom, and Gobliiins. All the floppy games and CD games +that didn't have CD audio tracks for music don't require any conversion, +and will work unmodified on ScummVM DS. MP3 audio files for CD music are +not supported. + +Cdex can do the conversion very well and I recommend using it to convert +your audio files, although any CD ripping software can be used, so feel +free to use your favourite program. The format you need to use is +IMA-ADPCM 4-bit Mono. You may use any sample rate. All other formats +will be rejected, including uncompressed WAV files. + +Now I will to describe how to rip your CD tracks with Cdex, which can be +found here: Cdex Homepage <http://sourceforge.net/projects/cdexos/>. +Other software can be used to create IMA ADPCM files under Linux or +MacOS. + +To set this up in Cdex, select Settings from the Options menu. On the +Encoder tab, select 'WAV Output Encoder'. Under 'Encoder Options', +choose the following: + + Format: WAV + Compression: IMA ADPCM + Samplerate: 22050 Hz + Channels: Mono + On the fly encoding: On + +Next, go to the 'Filenames' tab and select the folder you want to save +your Wav files to. Under 'Filename format', enter 'track%3'. This should +name your WAV files in the correct way. Click OK. + +Now select all the tracks on your CD, and click 'Extract CD tracks to a +compressed audio file'. Cdex should rip all the audio off your CD. + +Now all you have to do is copy the newly created WAV files into the same +directory that your other game data is stored on your CompactFlash card. +Next time your run ScummVM DS, it should play with music! + +*Important Note:* Do not select 'Extract CD tracks to a WAV file'. This +creates uncompressed WAVs only. You want 'Extract CD tracks to a +compressed audio file'. + + + Converting Speech files to MP3 format + ------------------------------------------------------------------------ + +ScummVM supports playing back speech for talkie games in MP3 format. +Unfortunately, the DS CPU is not quite up to the task, and MP3 audio +will sometimes cause slowdown in your game. However, if your flash card +isn't big enough to fit the audio files on, you will have no choice! + +To convert your audio you will need a copy of the ScummVM Tools package +<http://sourceforge.net/project/showfiles.php?group_id=37116&package_id=67433>. +You will also need a copy of the LAME MP3 encoder +<http://www.free-codecs.com/Lame_Encoder_download.htm>. + +Once this is all installed and set up, the process to encode your audio +varies from game to game, but the Lucasarts games can all be compressed +using the following command line: + +compress_scumm_sou --mp3 monster.sou + +This produces a monster.so3 file which you can copy to your flash card +and replaces the original monster.sou. Ogg format (monster.sog) and flac +format files are not currently supported by ScummVM DS, and it is +unlikely they will ever be supported. There is no way to convert .sog or +.so3 files back to .sou files. Just dig out your original CD and copy +the file from that. + + + Frequently Asked Questions + ------------------------------------------------------------------------ + +I get a lot of email about ScummVM DS. Nearly all of them are exactly +the same. Here I'm going to try and answer the questions that everybody +asks me in the hope that I will spend less time answering questions that +are clearly in the documentation and more time helping people who have a +real problem or have discovered a real bug. + +*Q:* I can't see the bottom line of inventory items in Day of the +Tentacle, Monkey Island 2, or a few other games! What do I do? +*A:* Hold down the left shoulder button and use D-pad (or the touch +screen) to scroll the screen around. + +*Q:* I dont see a menu when I press Start in Flight of the Amazon Queen +or Simon the Sorcerer. Is ScummVM broken? +*A:* No. To save in Simon the Sorcerer, click 'use', then click on the +postcard in your inventory. In Flight of the Amazon Queen, click 'use', +then click on the journal in your inventory. + +*Q:* Why does ScummVM crash when I play Monkey Island 1? +*A:* This happens when MP3 audio tracks are present from the PC version +of ScummVM. Delete the MP3 tracks and reencode them to ADPCM WAV files +as described in the CD audio section. + +*Q:* When will you support my Mini/Micro SD card reader? I want it! +Pretty please? +*A:* ScummVM uses DLDI drivers. If your card reader manufacturer doesn't +provide a driver, there is nothing I can do about it. The people to ask +are the card reader manufacturers themselves. + +*Q:* Can't you use the extra RAM in the M3/Supercard or the official +Opera Expansion Pack to support more games like The Dig and Full +Throttle? DS Linux has done it, so why can't you? +*A:* Not at the moment. The extra RAM has certain differences to the +build in RAM which makes it difficult to use for general programs. As +ScummVM DS is an official port, the changes to the ScummVM code base +must be minimal to avoid making the code difficult to read for other +users. I do have plans to work on this some time in the future, but +don't nag me about when it'll be done. If and when there's progress with +this, I will post on the ScummVM forums about it. + + +*Q:* ScummVM DS turns off my DS when I hit 'Quit' in the game or quit +from the frontend. Why doesn't it return to the menu? +*A:* Due to bugs in the ScummVM codebase, many of the ScummVM games +cannot quit cleanly leaving the machine in the same state as when it +started. You will notice that no other versions of ScummVM can quit back +to the menu either. This will be fixed at some time in the future. + + + + + Contributors + ------------------------------------------------------------------------ + +ScummVM DS uses chishm's GBA Movie Player FAT driver. +The CPU scaler is by Tramboi and Robin Watts +The ARM code was optimised by Robin Watts +Thanks to highpass for the ScummVM DS icons. +Thanks to zhevon for the Sam & Max cursor code. +Thanks to theNinjaBunny for the M3 Adaptor guide on this site. +Thanks also to everyone on the GBADev Forums. + +This program was brought to you by caffiene, sugar, and late nights. + + + Donations and Getting Help + ------------------------------------------------------------------------ + +If you have problems getting ScummVM to work on your hardware, please +read the FAQ first. /Please/ don't ask me questions which are +answered in the FAQ, I get many emails about this program each day, and +I can't help the people who really need help if I'm answering the same +question all the time which is already answered on this page. Other than +that, feel free to post on the ScummVM DS forum <http://forums.scummvm.org> +for help. Please do your research first though. There is no way of +running this on an out-of-the box DS without extra hardware. Most of +these things are fairly inexpensive though. + +If you want to contact me, please email me on scummvm at millstone dot +demon dot co dot uk. + +If you want to help with the development of ScummVM DS, great! Download +the source code and get building. There are plenty of things left to do. + +You can also help by making a donation if you've particularly enjoyed +ScummVM DS. This uses Paypal, and is completely secure. There's no +pressure though, ScummVM DS is completely free. This is just for those +who would like to make a contribution to further development. + + + + Building from Sources + ------------------------------------------------------------------------ + +ScummVM is an open source project. This means that anyone is free to +take the source code to the project and make their own additions and fixes, +contributing them back to the authors for consideration for the next version. + +To build ScummVM DS from source, it's probably better to checkout the +latest version of the code from the ScummVM SVN repository. The ScummVM +Sourceforge.net homepage <http://sourceforge.net/projects/scummvm> has +all the information about how to do this. + +By default, ScummVM DS expects to find libmad, an MP3 compressor library +targeted for the ARM platform. If you don't have this, you must disable +libmad support by opening 'backends/platform/ds/arm9/makefile' and +commenting out the line which says USE_MAD = 1. + +Then, enter the 'backends/platform/ds' folder and type: +make SCUMM_BUILD=a + +The executable nds file will build inside 'backends/platform/ds/arm9/SCUMMVM-A'. + +For other builds, substitute the letters b - g in the above line. + + + diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index 7472a32218..e74bcf28da 100644 --- a/backends/platform/ds/arm9/makefile +++ b/backends/platform/ds/arm9/makefile @@ -8,25 +8,29 @@ libndsdir = $(DEVKITPRO)/libnds # Select the build by setting SCUMM_BUILD to a,b,c,d,e,f or g. # Anything else gets build a. -ifeq ($(SCUMM_BUILD),g) +ifeq ($(SCUMM_BUILD),h) + DS_BUILD_H = 1 + else + ifeq ($(SCUMM_BUILD),g) DS_BUILD_G = 1 -else - ifeq ($(SCUMM_BUILD),f) + else + ifeq ($(SCUMM_BUILD),f) DS_BUILD_F = 1 - else - ifeq ($(SCUMM_BUILD),e) - DS_BUILD_E = 1 else - ifeq ($(SCUMM_BUILD),d) - DS_BUILD_D = 1 + ifeq ($(SCUMM_BUILD),e) + DS_BUILD_E = 1 else - ifeq ($(SCUMM_BUILD),c) - DS_BUILD_C = 1 + ifeq ($(SCUMM_BUILD),d) + DS_BUILD_D = 1 else - ifeq ($(SCUMM_BUILD),b) - DS_BUILD_B = 1 + ifeq ($(SCUMM_BUILD),c) + DS_BUILD_C = 1 else + ifeq ($(SCUMM_BUILD),b) + DS_BUILD_B = 1 + else DS_BUILD_A = 1 + endif endif endif endif @@ -67,7 +71,12 @@ endif # NOTE: The header and libs for the debugger is assumed to be in the libnds # folder. -VPATH = $(srcdir) +vpath %.h $(srcdir) +vpath %.cpp $(srcdir) +vpath %.c $(srcdir) +vpath %.m $(srcdir) +vpath %.asm $(srcdir) +vpath %.s $(srcdir) # Command to build libmad is: # ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork' @@ -75,8 +84,8 @@ VPATH = $(srcdir) # I actually had to use # ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork' LDFLAGS='C:/Progra~1/devkitpro/libnds/lib/libnds9.a' --disable-shared --disable-debugging -USE_ARM_SOUND_ASM = 1 ARM = 1 +USE_ARM_SOUND_ASM = 1 USE_ARM_COSTUME_ASM = 1 ifdef DS_BUILD_A @@ -135,6 +144,13 @@ ifdef DS_BUILD_G BUILD=scummvm-G endif +ifdef DS_BUILD_H + DEFINES = -DDS_NON_SCUMM_BUILD -DDS_BUILD_H + LOGO = logog.bmp + ENABLE_PARALLACTION = STATIC_PLUGIN + BUILD=scummvm-H +endif + ARM7BIN := -7 $(CURDIR)/../../arm7/arm7.bin ICON := -b ../../../logo.bmp "ScummVM;By Neil Millstone;" @@ -147,6 +163,7 @@ CFLAGS = -Wno-multichar -Wall\ -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\ -mthumb-interwork -DUSE_ARM_COSTUME_ASM=1 + # -ffast-math ifdef USE_DEBUGGER @@ -160,7 +177,7 @@ ifdef USE_PROFILER endif CXXFLAGS= $(CFLAGS) -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-reorder \ - -fno-exceptions -fno-rtti -mthumb-interwork + -fno-exceptions -fno-rtti -mthumb-interwork -ffunction-sections -fdata-sections # -mthumb @@ -180,12 +197,12 @@ ifdef USE_MAD endif -LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -Wl,--wrap,time -mno-fpu -Wl,-Map,map.txt +LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -Wl,--wrap,time -mno-fpu -Wl,-Map,map.txt -Wl,--gc-sections -INCLUDES= -I./ -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/common -I$(portdir)/source \ - -I$(portdir)/data -I$(libndsdir)/include -I$(portdir)/../commoninclude\ - -I$(libndsdir)/include -I$(libndsdir)/include/nds -I$(srcdir)/engines -I$(portdir)/source/mad\ - -I$(portdir)/source/libcartreset -include $(srcdir)/common/scummsys.h +INCLUDES= -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/engines \ + -I$(portdir)/data -I$(portdir)/../commoninclude \ + -I$(portdir)/source -I$(portdir)/source/mad -I$(portdir)/source/libcartreset \ + -I$(libndsdir)/include -include $(srcdir)/common/scummsys.h LIBS = -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9 @@ -232,7 +249,8 @@ endif DATA_OBJS := $(portdir)/data/icons.o $(portdir)/data/keyboard.o $(portdir)/data/keyboard_pal.o $(portdir)/data/default_font.o $(portdir)/data/8x8font_tga.o -COMPRESSOR_OBJS := $(portdir)/source/compressor/lz.o +COMPRESSOR_OBJS := +#$(portdir)/source/compressor/lz.o FAT_OBJS := $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o\ $(portdir)/source/fat/io_fcsr.o $(portdir)/source/fat/io_m3cf.o\ @@ -252,14 +270,15 @@ FAT_OBJS := $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o # $(portdir)/source/fat/io_sd_common.o $(portdir)/source/fat/io_scsd_s.o \ # $(portdir)/source/fat/io_sc_common.o $(portdir)/source/fat/io_sd_common.o -LIBCARTRESET_OBJS := $(portdir)/source/libcartreset/cartreset.o +LIBCARTRESET_OBJS := +#$(portdir)/source/libcartreset/cartreset.o # Files in this list will be optimisied for speed, otherwise they will be optimised for space OPTLIST := actor.cpp ds_main.cpp osystem_ds.cpp blitters.cpp fmopl.cpp rate.cpp mixer.cpp isomap.cpp image.cpp gfx.cpp sprite.cpp actor_path.cpp actor_walk.cpp #OPTLIST := # Compiler options for files which should be optimised for speed -OPT_SPEED := -O2 +OPT_SPEED := -O3 # Compiler options for files which should be optimised for space OPT_SIZE := -Os @@ -281,7 +300,7 @@ ndsall: include $(srcdir)/Makefile.common semiclean: - $(RM) $(portdir)/source/dsoptions.o $(portdir)/source/dsmain.o $(FAT_OBJS) $(DATA_OBJS) $(portdir)/source/wordcompletion.o + $(RM) $(portdir)/source/dsoptions.o $(portdir)/source/dsmain.o $(FAT_OBJS) $(DATA_OBJS) $(portdir)/source/wordcompletion.o $(portdir)/source/dsoptions.o clean: $(RM) $(OBJS) $(EXECUTABLE) @@ -333,36 +352,17 @@ endef ############## # Replacement rule for the one in makefile.common ############## -ifndef HAVE_GCC3 -# If you use GCC, disable the above and enable this for intelligent -# dependency tracking. -#.cpp.o: -%.o:%.cpp - $(MKDIR) $(*D)/$(DEPDIR) - $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o -# $(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d - $(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d" - $(RM) "$(*D)/$(DEPDIR)/$(*F).d2" -else -# If you even have GCC 3.x, you can use this build rule, which is safer; the above -# rule can get you into a bad state if you Ctrl-C at the wrong moment. -# Also, with this GCC inserts additional dummy rules for the involved headers, -# which ensures a smooth compilation even if said headers become obsolete. -#.cpp.o: -%.o:%.cpp +%.o: %.cpp # echo !!!!!!!!!!!! $(notdir $<) # ifeq ( $(notdir $<), $(findstring $(notdir $<), $(OPTLIST)) ) # OPTFLAG=-O3 # else # OPTFLAG=-Os # endif - # export OPTFLAG = ; # echo !!!!!!!! $(OPTFLAG) - $(MKDIR) $(*D)/$(DEPDIR) $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(if $(findstring $(notdir $<), $(OPTLIST)), $(OPT_SPEED), $(OPT_SIZE)) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o -endif #--------------------------------------------------------------------------------- @@ -412,6 +412,7 @@ endif padbin 16 $(basename $@).ds.gba #--------------------------------------------------------------------------------- +# FIXME: The following rule hardcodes the input & output filename -- shouldn't it use $< and $@ instead? %.bin: %.elf $(OBJCOPY) -S scummvm.elf scummvm-stripped.elf $(OBJCOPY) -O binary scummvm-stripped.elf scummvm.bin @@ -419,4 +420,3 @@ endif #%.o: %.s # $(MKDIR) $(*D)/$(DEPDIR) # $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o - diff --git a/backends/platform/ds/arm9/source/blitters_arm.s b/backends/platform/ds/arm9/source/blitters_arm.s index 5f7df298b4..48ec316675 100644 --- a/backends/platform/ds/arm9/source/blitters_arm.s +++ b/backends/platform/ds/arm9/source/blitters_arm.s @@ -20,149 +20,12 @@ @ @ @author Robin Watts (robin@wss.co.uk) - .global asmDrawStripToScreen - .global asmCopy8Col .global Rescale_320x256xPAL8_To_256x256x1555 .global Rescale_320x256x1555_To_256x256x1555 .section .itcm,"ax", %progbits .align 2 .code 32 - @ ARM implementation of asmDrawStripToScreen. - @ - @ C prototype would be: - @ - @ extern "C" void asmDrawStripToScreen(int height, - @ int width, - @ byte const *text, - @ byte const *src, - @ byte *dst, - @ int vsPitch, - @ int vsScreenWidth, - @ int textSurfacePitch); - @ - @ In addition, we assume that text, src and dst are all word (4 byte) - @ aligned. This is the same assumption that the old 'inline' version - @ made. -asmDrawStripToScreen: - @ r0 = height - @ r1 = width - @ r2 = text - @ r3 = src - MOV r12,r13 - STMFD r13!,{r4-r7,r9-r11,R14} - LDMIA r12,{r4,r5,r6,r7} - @ r4 = dst - @ r5 = vsPitch - @ r6 = vmScreenWidth - @ r7 = textSurfacePitch - - CMP r0,#0 @ If height<=0 - MOVLE r0,#1 @ height=1 - CMP r1,#4 @ If width<4 - BLT end @ return - - @ Width &= ~4 ? What's that about then? Width &= ~3 I could have - @ understood... - BIC r1,r1,#4 - - SUB r5,r5,r1 @ vsPitch -= width - SUB r6,r6,r1 @ vmScreenWidth -= width - SUB r7,r7,r1 @ textSurfacePitch -= width - MOV r10,#253 - ORR r10,r10,r10,LSL #8 - ORR r10,r10,r10,LSL #16 @ r10 = mask -yLoop: - MOV r14,r1 @ r14 = width -xLoop: - LDR r12,[r2],#4 @ r12 = [text] - LDR r11,[r3],#4 @ r11 = [src] - CMP r12,r10 - BNE singleByteCompare - SUBS r14,r14,#4 - STR r11,[r4], #4 @ r4 = [dst] - BGT xLoop - - ADD r2,r2,r7 @ text += textSurfacePitch - ADD r3,r3,r5 @ src += vsPitch - ADD r4,r4,r6 @ dst += vmScreenWidth - SUBS r0,r0,#1 - BGT yLoop - LDMFD r13!,{r4-r7,r9-r11,PC} - -singleByteCompare: - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - STR r12,[r4],#4 - SUBS r14,r14,#4 - BGT xLoop - - ADD r2,r2,r7 @ text += textSurfacePitch - ADD r3,r3,r5 @ src += vsPitch - ADD r4,r4,r6 @ dst += vmScreenWidth - SUBS r0,r0,#1 - BGT yLoop -end: - LDMFD r13!,{r4-r7,r9-r11,PC} - - - @ ARM implementation of asmCopy8Col - @ - @ C prototype would be: - @ - @ extern "C" void asmCopy8Col(byte *dst, - @ int dstPitch, - @ const byte *src, - @ int height); - @ - @ In addition, we assume that src and dst are both word (4 byte) - @ aligned. This is the same assumption that the old 'inline' version - @ made. -asmCopy8Col: - @ r0 = dst - @ r1 = dstPitch - @ r2 = src - @ r3 = height - STMFD r13!,{r14} - SUB r1,r1,#4 - - TST r3,#1 - ADDNE r3,r3,#1 - BNE roll2 -yLoop2: - LDR r12,[r2],#4 - LDR r14,[r2],r1 - STR r12,[r0],#4 - STR r14,[r0],r1 -roll2: - LDR r12,[r2],#4 - LDR r14,[r2],r1 - SUBS r3,r3,#2 - STR r12,[r0],#4 - STR r14,[r0],r1 - BNE yLoop2 - - LDMFD r13!,{PC} - - @ ARM implementation of Rescale_320x256x1555_To_256x256x1555 @ @ C prototype would be: diff --git a/backends/platform/ds/arm9/source/cdaudio.h b/backends/platform/ds/arm9/source/cdaudio.h index d237569bb7..d1897d3e5d 100644 --- a/backends/platform/ds/arm9/source/cdaudio.h +++ b/backends/platform/ds/arm9/source/cdaudio.h @@ -20,7 +20,7 @@ * */ - #ifndef _CDAUDIO_H_ +#ifndef _CDAUDIO_H_ #define _CDAUDIO_H_ namespace DS { diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index f4706807f7..872a196e9b 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -65,6 +65,8 @@ //#define USE_LIBCARTRESET #include <nds.h> +#include <nds/registers_alt.h> +#include <nds/arm9/exceptions.h> //#include <ARM9/console.h> //basic print funcionality @@ -75,13 +77,10 @@ #include "icons_raw.h" #include "fat/gba_nds_fat.h" #include "fat/disc_io.h" -#include "common/config-manager.h" -#include "engines/scumm/scumm.h" #include "keyboard_raw.h" #include "keyboard_pal_raw.h" #define V16(a, b) ((a << 12) | b) #include "touchkeyboard.h" -#include "registers_alt.h" //#include "compact_flash.h" #include "dsoptions.h" #ifdef USE_DEBUGGER @@ -96,6 +95,26 @@ #endif #include "backends/fs/ds/ds-fs.h" +extern "C" u32 getExceptionAddress( u32 opcodeAddress, u32 thumbState); +extern const char __itcm_start[]; +static const char *registerNames[] = + { "r0","r1","r2","r3","r4","r5","r6","r7", + "r8 ","r9 ","r10","r11","r12","sp ","lr ","pc " }; + +/* +extern "C" void* __real_malloc(size_t size); + +extern "C" void* __wrap_malloc(size_t size) { + void* res = __real_malloc(size); + if (res) { + return res; + } else { + consolePrintf("Failed alloc %d\n", size); + return NULL; + } +} +*/ + namespace DS { // From console.c in NDSLib @@ -168,7 +187,7 @@ bool displayModeIs8Bit = false; u8 gameID; bool snapToBorder = false; -bool consoleEnable = true; +bool consoleEnable = false; bool gameScreenSwap = false; bool isCpuScalerEnabled(); //#define HEAVY_LOGGING @@ -197,6 +216,13 @@ int mouseHotspotX, mouseHotspotY; bool cursorEnable = false; bool mouseCursorVisible = true; bool rightButtonDown = false; +bool touchPadStyle = false; +int touchPadSensitivity = 8; +bool tapScreenClicks = true; + +int tapCount = 0; +int tapTimeout = 0; +int tapComplete = 0; // Dragging int dragStartX, dragStartY; @@ -213,7 +239,14 @@ int gameHeight = 200; // Scale bool twoHundredPercentFixedScale = false; bool cpuScalerEnable = false; -#define NUM_SUPPORTED_GAMES 20 + + // 100 256 + // 150 192 + // 200 128 + + // (256 << 8) / scale + + #ifdef USE_PROFILER int hBlankCount = 0; @@ -221,6 +254,7 @@ int hBlankCount = 0; u8* scalerBackBuffer = NULL; +#define NUM_SUPPORTED_GAMES 21 gameListType gameList[NUM_SUPPORTED_GAMES] = { // Unknown game - use normal SCUMM controls @@ -248,6 +282,7 @@ gameListType gameList[NUM_SUPPORTED_GAMES] = { {"elvira2", CONT_SIMON}, {"elvira1", CONT_SIMON}, {"waxworks", CONT_SIMON}, + {"parallaction", CONT_NIPPON}, }; gameListType* currentGame = NULL; @@ -260,6 +295,7 @@ bool penHeld; bool penReleased; bool penDownLastFrame; s32 penX, penY; +s32 penDownX, penDownY; int keysDownSaved; int keysReleasedSaved; int keysChangedSaved; @@ -299,9 +335,41 @@ void setCpuScalerEnable(bool enable) { cpuScalerEnable = enable; } +void setTrackPadStyleEnable(bool enable) { + touchPadStyle = enable; +} + +void setTapScreenClicksEnable(bool enable) { + tapScreenClicks = enable; +} + +void setGameScreenSwap(bool enable) { + gameScreenSwap = enable; +} + +void setSensitivity(int sensitivity) { + touchPadSensitivity = sensitivity; +} + +void setTopScreenZoom(int percentage) { + // 100 256 + // 150 192 + // 200 128 + + // (256 << 8) / scale + + s32 scale = (percentage << 8) / 100; + subScreenScale = (256 * 256) / scale; + +// consolePrintf("Scale is %d %%\n", percentage); +} // return (ConfMan.hasKey("cpu_scaler", "ds") && ConfMan.getBool("cpu_scaler", "ds")); +controlType getControlType() { + return currentGame->control; +} + //plays an 8 bit mono sample at 11025Hz void playSound(const void* data, u32 length, bool loop, bool adpcm, int rate) @@ -429,14 +497,14 @@ void initGame() { consolePrintf("initing game..."); #endif - static bool firstTime = true; +// static bool firstTime = true; setOptions(); //strcpy(gameName, ConfMan.getActiveDomain().c_str()); strcpy(gameName, ConfMan.get("gameid").c_str()); - consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]); +// consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]); currentGame = &gameList[0]; // Default game @@ -447,16 +515,12 @@ void initGame() { } } - if (firstTime) { +/* if (firstTime) { firstTime = false; - if (ConfMan.hasKey("22khzaudio", "ds") && ConfMan.getBool("22khzaudio", "ds")) { - startSound(22050, 8192); - } else { - startSound(11025, 4096); - } } +*/ #ifdef HEAVY_LOGGING consolePrintf("done\n"); #endif @@ -631,7 +695,7 @@ void checkSleepMode() { void setShowCursor(bool enable) { - if (currentGame->control == CONT_SCUMM_SAMNMAX) + if ((currentGame) && (currentGame->control == CONT_SCUMM_SAMNMAX)) { if (cursorEnable) { sprites[1].attribute[0] = ATTR0_BMP | 150; @@ -654,23 +718,28 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX, mouseHotspotX = hotspotX; mouseHotspotY = hotspotY; + //consolePrintf("Set cursor icon %d, %d\n", w, h); + { int off = 128*64; memset(SPRITE_GFX + off, 0, 32 * 32 * 2); memset(SPRITE_GFX_SUB + off, 0, 32 * 32 * 2); + for (uint y=0; y<h; y++) { for (uint x=0; x<w; x++) { int color = icon[y*w+x]; + + //consolePrintf("%d:%d ", color, OSystem_DS::instance()->getDSPaletteEntry(color)); if (color == keycolor) { SPRITE_GFX[off+(y)*32+x] = 0x0000; // black background SPRITE_GFX_SUB[off+(y)*32+x] = 0x0000; // black background } else { - SPRITE_GFX[off+(y)*32+x] = BG_PALETTE[color] | 0x8000; - SPRITE_GFX_SUB[off+(y)*32+x] = BG_PALETTE[color] | 0x8000; + SPRITE_GFX[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000; + SPRITE_GFX_SUB[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000; } } } @@ -733,6 +802,7 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX, sprites[1].attribute[1] = ATTR1_SIZE_64 | pos; sprites[1].attribute[2] = ATTR2_ALPHA(1) | 176; } + } @@ -745,6 +815,7 @@ void displayMode16Bit() { u16 buffer[32 * 32 * 2]; + releaseAllKeys(); if (displayModeIs8Bit) { // static int test = 0; @@ -1109,7 +1180,7 @@ void setKeyboardEnable(bool en) { } else { - + DS::releaseAllKeys(); // Restore the palette that the keyboard has used for (int r = 0; r < 256; r++) { BG_PALETTE_SUB[r] = BG_PALETTE[r]; @@ -1157,6 +1228,194 @@ bool getIsDisplayMode8Bit() { return displayModeIs8Bit; } +void doScreenTapMode(OSystem_DS* system) +{ + Common::Event event; + static bool left = false, right = false; + + if (left) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + left = false; + } + + if (right) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + right = false; + } + + + if (tapComplete == 1) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + tapComplete = 0; + left = true; + } else if (tapComplete == 2) { + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + tapComplete = 0; + right = true; + } + + + if (getKeysDown() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + if (getKeysReleased() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + + if (getKeysDown() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + if (getKeysReleased() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + event.type = Common::EVENT_MOUSEMOVE; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); +} + +void doButtonSelectMode(OSystem_DS* system) +{ + Common::Event event; + + + if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { + event.type = Common::EVENT_MOUSEMOVE; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + //consolePrintf("x=%d y=%d \n", getPenX(), getPenY()); + } + + static bool leftButtonDown = false; + static bool rightButtonDown = false; + + if (getPenReleased() && (leftButtonDown || rightButtonDown)) { + if (leftButtonDown) { + event.type = Common::EVENT_LBUTTONUP; + } else { + event.type = Common::EVENT_RBUTTONUP; + } + + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + + if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) { + if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { + if ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit)) { + event.type = Common::EVENT_LBUTTONDOWN; + leftButtonDown = true; + } else { + event.type = Common::EVENT_RBUTTONDOWN; + rightButtonDown = true; + } + + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + } else { + // In hover mode, D-pad left and right click the mouse when the pen is on the screen + + if (getPenHeld()) { + if (getKeysDown() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + if (getKeysReleased() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + + if (getKeysDown() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + if (getKeysReleased() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + } + } + + if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (!getIndyFightState()) && (!getKeyboardEnable())) { + + if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) { + if (getKeysDown() & KEY_LEFT) { + mouseMode = MOUSE_LEFT; + } + + if (rightButtonDown) + { + Common::Event event; + event.mouse = Common::Point(getPenX(), getPenY()); + event.type = Common::EVENT_RBUTTONUP; + system->addEvent(event); + rightButtonDown = false; + } + + + if (getKeysDown() & KEY_RIGHT) { + if ((currentGame->control != CONT_SCUMM_SAMNMAX) && (currentGame->control != CONT_FUTURE_WARS) && (currentGame->control != CONT_GOBLINS)) { + mouseMode = MOUSE_RIGHT; + } else { + // If we're playing sam and max, click and release the right mouse + // button to change verb + Common::Event event; + + if (currentGame->control == CONT_FUTURE_WARS) { + event.mouse = Common::Point(320 - 128, 200 - 128); + event.type = Common::EVENT_MOUSEMOVE; + system->addEvent(event); + } else { + event.mouse = Common::Point(getPenX(), getPenY()); + } + + rightButtonDown = true; + + + event.type = Common::EVENT_RBUTTONDOWN; + system->addEvent(event); + + //event.type = Common::EVENT_RBUTTONUP; + //system->addEvent(event); + } + } + + + + if (getKeysDown() & KEY_UP) { + mouseMode = MOUSE_HOVER; + } + } + } +} + void addEventsToQueue() { #ifdef HEAVY_LOGGING consolePrintf("addEventsToQueue\n"); @@ -1286,54 +1545,6 @@ void addEventsToQueue() { } - if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) { - if (getKeysDown() & KEY_LEFT) { - mouseMode = MOUSE_LEFT; - } - - if (rightButtonDown) - { - Common::Event event; - event.mouse = Common::Point(getPenX(), getPenY()); - event.type = Common::EVENT_RBUTTONUP; - system->addEvent(event); - rightButtonDown = false; - } - - - if (getKeysDown() & KEY_RIGHT) { - if ((currentGame->control != CONT_SCUMM_SAMNMAX) && (currentGame->control != CONT_FUTURE_WARS) && (currentGame->control != CONT_GOBLINS)) { - mouseMode = MOUSE_RIGHT; - } else { - // If we're playing sam and max, click and release the right mouse - // button to change verb - Common::Event event; - - if (currentGame->control == CONT_FUTURE_WARS) { - event.mouse = Common::Point(320 - 128, 200 - 128); - event.type = Common::EVENT_MOUSEMOVE; - system->addEvent(event); - } else { - event.mouse = Common::Point(getPenX(), getPenY()); - } - - rightButtonDown = true; - - - event.type = Common::EVENT_RBUTTONDOWN; - system->addEvent(event); - - //event.type = Common::EVENT_RBUTTONUP; - //system->addEvent(event); - } - } - - - - if (getKeysDown() & KEY_UP) { - mouseMode = MOUSE_HOVER; - } - } @@ -1359,52 +1570,13 @@ void addEventsToQueue() { if (!keyboardEnable) { - if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { - event.type = Common::EVENT_MOUSEMOVE; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - //consolePrintf("x=%d y=%d \n", getPenX(), getPenY()); + if ((tapScreenClicks) && (getIsDisplayMode8Bit())) + { + doScreenTapMode(system); } - - if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) { - if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { - event.type = ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit))? Common::EVENT_LBUTTONDOWN: Common::EVENT_RBUTTONDOWN; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - - if (getPenReleased()) { - event.type = mouseMode == MOUSE_LEFT? Common::EVENT_LBUTTONUP: Common::EVENT_RBUTTONUP; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - } else { - // In hover mode, D-pad left and right click the mouse when the pen is on the screen - - if (getPenHeld()) { - if (getKeysDown() & KEY_LEFT) { - event.type = Common::EVENT_LBUTTONDOWN; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - if (getKeysReleased() & KEY_LEFT) { - event.type = Common::EVENT_LBUTTONUP; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - - - if (getKeysDown() & KEY_RIGHT) { - event.type = Common::EVENT_RBUTTONDOWN; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - if (getKeysReleased() & KEY_RIGHT) { - event.type = Common::EVENT_RBUTTONUP; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - } + else + { + doButtonSelectMode(system); } if (((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R)) || (indyFightState)) && (displayModeIs8Bit)) { @@ -1537,8 +1709,8 @@ void triggerIcon(int imageNum) { void setIcon(int num, int x, int y, int imageNum, int flags, bool enable) { - sprites[num].attribute[0] = ATTR0_BMP | (enable? y: 192) | (!enable? ATTR0_DISABLED: 0); - sprites[num].attribute[1] = ATTR1_SIZE_32 | x | flags; + sprites[num].attribute[0] = ATTR0_BMP | (enable? (y & 0xFF): 192) | (!enable? ATTR0_DISABLED: 0); + sprites[num].attribute[1] = ATTR1_SIZE_32 | (x & 0x1FF) | flags; sprites[num].attribute[2] = ATTR2_ALPHA(1)| (imageNum * 16); } @@ -1552,28 +1724,30 @@ void updateStatus() { int offs; if (displayModeIs8Bit) { - switch (mouseMode) { - case MOUSE_LEFT: { - offs = 1; - break; - } - case MOUSE_RIGHT: { - offs = 2; - break; - } - case MOUSE_HOVER: { - offs = 0; - break; - } - default: { - // Nothing! - offs = 0; - break; + if (!tapScreenClicks) { + switch (mouseMode) { + case MOUSE_LEFT: { + offs = 1; + break; + } + case MOUSE_RIGHT: { + offs = 2; + break; + } + case MOUSE_HOVER: { + offs = 0; + break; + } + default: { + // Nothing! + offs = 0; + break; + } } + + setIcon(0, 208, 150, offs, 0, true); } - setIcon(0, 208, 150, offs, 0, true); - if (indyFightState) { setIcon(1, (190 - 32), 150, 3, (indyFightRight? 0: ATTR1_FLIP_X), true); // consolePrintf("%d\n", indyFightRight); @@ -1631,7 +1805,7 @@ void setMainScreenScroll(int x, int y) { BG3_CX = x + (((frameCount & 1) == 0)? 64: 0); BG3_CY = y; - if (!gameScreenSwap) { + if ((!gameScreenSwap) || (touchPadStyle)) { touchX = x >> 8; touchY = y >> 8; } @@ -1660,7 +1834,7 @@ void setMainScreenScale(int x, int y) { BG3_YDY = y; } - if (!gameScreenSwap) { + if ((!gameScreenSwap) || (touchPadStyle)) { touchScX = x; touchScY = y; } @@ -1676,7 +1850,7 @@ void setZoomedScreenScroll(int x, int y, bool shake) { touchY = y >> 8; } else */{ - if (gameScreenSwap) { + if ((gameScreenSwap) && (!touchPadStyle)) { touchX = x >> 8; touchY = y >> 8; } @@ -1696,7 +1870,7 @@ void setZoomedScreenScale(int x, int y) { } else */{ - if (gameScreenSwap) { + if ((gameScreenSwap) && (!touchPadStyle)) { touchScX = x; touchScY = y; } @@ -1757,18 +1931,22 @@ void VBlankHandler(void) { frameCount++; - if ((cursorEnable) && (mouseCursorVisible)) - { + if ((cursorEnable) && (mouseCursorVisible)) { if (!keyboardEnable) { storedMouseX = penX; storedMouseY = penY; } - setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true); - } - else - { + if (gameScreenSwap) { + setIcon(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true); + setIconMain(3, 0, 0, 0, 0, false); + } else { + setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true); + setIcon(3, 0, 0, 0, 0, false); + } + } else { setIconMain(3, 0, 0, 0, 0, false); + setIcon(3, 0, 0, 0, 0, false); } @@ -1826,7 +2004,7 @@ void VBlankHandler(void) { SUB_BG3_YDX = 0; SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);*/ - static int ratio = ( 320 << 8) / SCUMM_GAME_WIDTH; + static int ratio = (320 << 8) / SCUMM_GAME_WIDTH; bool zooming = false; @@ -1851,8 +2029,12 @@ void VBlankHandler(void) { subScreenWidth = 256 >> 1; subScreenHeight = 192 >> 1; } else { - subScreenWidth = (((SCUMM_GAME_HEIGHT * 256) / 192) * subScreenScale) >> 8; - subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8; +// subScreenWidth = (((SCUMM_GAME_HEIGHT * 256) / 192) * subScreenScale) >> 8; +// subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8; + + + subScreenWidth = (256 * subScreenScale) >> 8; + subScreenHeight = (192 * subScreenScale) >> 8; if ( ((subScreenWidth) > 256 - 8) && ((subScreenWidth) < 256 + 8) ) { subScreenWidth = 256; @@ -2215,43 +2397,141 @@ void penUpdate() { // if (getKeysHeld() & KEY_L) consolePrintf("%d, %d penX=%d, penY=%d tz=%d\n", IPC->touchXpx, IPC->touchYpx, penX, penY, IPC->touchZ1); - if ((penDownFrames > 1)) { // Is this right? Dunno, but it works for me. + bool penDownThisFrame = (IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0); + bool firstFrame = penDownFrames == 2; + static bool moved = false; - if ((penHeld)) { - penHeld = true; - penDown = false; + if ((tapScreenClicks) && (!getKeyboardEnable()) && (getIsDisplayMode8Bit())) { - if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) { - penX = IPC->touchXpx + touchXOffset; - penY = IPC->touchYpx + touchYOffset; + if ((tapTimeout >= 0)) { + tapTimeout++; + + if (((tapTimeout > 15) || (tapCount == 2)) && (tapCount > 0)) { + tapComplete = tapCount; + tapCount = 0; +// consolePrintf("Taps: %d\n", tapComplete); } + } - } else { - penDown = true; - penHeld = true; - penDownSaved = true; + - //if ( (ABS(penX - IPC->touchXpx) < 10) && (ABS(penY - IPC->touchYpx) < 10) ) { - if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) { - penX = IPC->touchXpx; - penY = IPC->touchYpx; + if ((penHeld) && (!penDownThisFrame)) { + if ((touchPadStyle) || (moved) || (tapCount == 1)) { + if ((penDownFrames > 0) && (penDownFrames < 6) && ((tapTimeout == -1) || (tapTimeout > 2))) { + tapCount++; + tapTimeout = 0; +// consolePrintf("Tap! %d\n", penDownFrames); + moved = false; + } } - //} } + } - } else { - if (penHeld) { - penReleased = true; - penReleasedSaved = true; + + + if ((touchPadStyle) && (getIsDisplayMode8Bit())) { + + if ((penDownFrames > 0)) { + + + if ((penHeld)) { + + if (penDownThisFrame) + { + if (penDownFrames >= 2) { + int diffX = IPC->touchXpx - penDownX; + int diffY = IPC->touchYpx - penDownY; + + int speed = ABS(diffX) + ABS(diffY); + + if ((ABS(diffX) < 35) && (ABS(diffY) < 35)) + { + + if (speed >= 8) + { + diffX *= ((speed >> 3) * touchPadSensitivity) >> 3; + diffY *= ((speed >> 3) * touchPadSensitivity) >> 3; + } + + penX += diffX; + penY += diffY; + if (penX > 255) penX = 255; + if (penX < 0) penX = 0; + if (penY > 191) penY = 191; + if (penY < 0) penY = 0; + } + +// consolePrintf("x: %d y: %d\n", IPC->touchYpx - penDownY, IPC->touchYpx - penDownY); + penDownX = IPC->touchXpx; + penDownY = IPC->touchYpx; + + } + } + else + { + } + + + } else { + penDown = true; + penHeld = true; + penDownSaved = true; + + // First frame, so save pen positions + if (penDownThisFrame) { + penDownX = IPC->touchXpx; + penDownY = IPC->touchYpx; + } + } + } else { - penReleased = false; + if (penHeld) { + penReleased = true; + penReleasedSaved = true; + } else { + penReleased = false; + } + + penDown = false; + penHeld = false; } + } else { + if ((penDownFrames > 1)) { // Is this right? Dunno, but it works for me. + + if ((penHeld)) { + penHeld = true; + penDown = false; + } else { + penDown = true; + penHeld = true; + penDownSaved = true; + } + + if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) { + penX = IPC->touchXpx + touchXOffset; + penY = IPC->touchYpx + touchYOffset; + moved = true; + } + - penDown = false; - penHeld = false; + + } else { + if (penHeld) { + penReleased = true; + penReleasedSaved = true; + } else { + penReleased = false; + } + + penDown = false; + penHeld = false; + } + + } + if ((IPC->touchZ1 > 0) || ((penDownFrames == 2)) ) { penDownLastFrame = true; penDownFrames++; @@ -2259,7 +2539,6 @@ void penUpdate() { penDownLastFrame = false; penDownFrames = 0; } - } int leftHandedSwap(int keys) { @@ -2346,8 +2625,7 @@ int getPenX() { int x = ((penX * touchScX) >> 8) + touchX; x = x < 0? 0: (x > gameWidth - 1? gameWidth - 1: x); - if (snapToBorder) - { + if (snapToBorder) { if (x < 8) x = 0; if (x > gameWidth - 8) x = gameWidth - 1; } @@ -2359,8 +2637,7 @@ int getPenY() { int y = ((penY * touchScY) >> 8) + touchY; y = y < 0? 0: (y > gameHeight - 1? gameHeight - 1: y); - if (snapToBorder) - { + if (snapToBorder) { if (y < 8) y = 0; if (y > gameHeight - 8) y = gameHeight - 1; } @@ -2377,6 +2654,8 @@ GLvector getPenPos() { return v; } +#ifdef GBA_SRAM_SAVE + void formatSramOption() { consolePrintf("The following files are present in save RAM:\n"); DSSaveFileManager::instance()->listFiles(); @@ -2398,7 +2677,7 @@ void formatSramOption() { } } } - +#endif void setIndyFightState(bool st) { indyFightState = st; @@ -2496,8 +2775,6 @@ struct cardTranslate { char dldiId[5]; }; -#define NUM_CARD_READERS 7 - cardTranslate cardReaderTable[] = { {DEVICE_TYPE_M3SD, DEVICE_M3SD, "M3SD"}, {DEVICE_TYPE_M3CF, DEVICE_M3CF, "M3CF"}, @@ -2519,13 +2796,13 @@ void reboot() { consolePrintf("DLDI Device ID: %s\n", id); - for (int r = 0; r < NUM_CARD_READERS; r++) { + for (int r = 0; r < ARRAYSIZE(cardReaderTable); r++) { if (!stricmp(id, cardReaderTable[r].dldiId)) { deviceType = cardReaderTable[r].cartResetId; } } } else { - for (int r = 0; r < NUM_CARD_READERS; r++) { + for (int r = 0; r < ARRAYSIZE(cardReaderTable); r++) { if (disc_getDeviceId() == cardReaderTable[r].svmId) { deviceType = cardReaderTable[r].cartResetId; } @@ -2573,13 +2850,66 @@ void powerOff() { ///////////////// -int main(void) -{ + +void dsExceptionHandler() { + consolePrintf("Blue screen of death"); + setExceptionHandler(NULL); + + + u32 currentMode = getCPSR() & 0x1f; + u32 thumbState = ((*(u32*)0x027FFD90) & 0x20); + + u32 codeAddress, exceptionAddress = 0; + + int offset = 8; + + if ( currentMode == 0x17 ) { + consolePrintf("\x1b[10Cdata abort!\n\n"); + codeAddress = exceptionRegisters[15] - offset; + if ( (codeAddress > 0x02000000 && codeAddress < 0x02400000) || + (codeAddress > (u32)__itcm_start && codeAddress < (u32)(__itcm_start + 32768)) ) + exceptionAddress = getExceptionAddress( codeAddress, thumbState); + else + exceptionAddress = codeAddress; + + } else { + if (thumbState) + offset = 2; + else + offset = 4; + consolePrintf("\x1b[5Cundefined instruction!\n\n"); + codeAddress = exceptionRegisters[15] - offset; + exceptionAddress = codeAddress; + } + + consolePrintf(" pc: %08X addr: %08X\n\n",codeAddress,exceptionAddress); + + int i; + for ( i=0; i < 8; i++ ) { + consolePrintf( " %s: %08X %s: %08X\n", + registerNames[i], exceptionRegisters[i], + registerNames[i+8],exceptionRegisters[i+8]); + } +// u32 *stack = (u32 *)exceptionRegisters[13]; +// for ( i=0; i<10; i++ ) { +// consolePrintf( "\x1b[%d;2H%08X: %08X %08X", i + 14, (u32)&stack[i*2],stack[i*2], stack[(i*2)+1] ); +// } + + memoryReport(); + + while(1); +} + + + + +int main(void) { soundCallback = NULL; initHardware(); + setExceptionHandler(dsExceptionHandler); #ifdef USE_DEBUGGER for (int r = 0; r < 150; r++) { @@ -2663,36 +2993,33 @@ int main(void) consolePrintf("-------------------------------\n"); consolePrintf("ScummVM DS\n"); consolePrintf("Ported by Neil Millstone\n"); - consolePrintf("Version 0.11.1 beta2"); + consolePrintf("Version 0.13.0 SVN "); #if defined(DS_BUILD_A) consolePrintf("build A\n"); consolePrintf("Lucasarts SCUMM games (SCUMM)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_B) consolePrintf("build B\n"); consolePrintf("BASS, QUEEN\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_C) consolePrintf("build C\n"); consolePrintf("Simon/Elvira/Waxworks (AGOS)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_D) consolePrintf("build D\n"); consolePrintf("AGI, CINE, GOB\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_E) consolePrintf("build E\n"); consolePrintf("Inherit the Earth (SAGA)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_F) consolePrintf("build F\n"); consolePrintf("The Legend of Kyrandia (KYRA)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_G) - consolePrintf("build F\n"); - consolePrintf("Lure of the Temptress (LURE)\n"); - consolePrintf("-------------------------------\n"); + consolePrintf("build G\n"); + consolePrintf("Lure of the Tempress (LURE)\n"); +#elif defined(DS_BUILD_H) + consolePrintf("build H\n"); + consolePrintf("Nippon Safes (PARALLATION)\n"); #endif + consolePrintf("-------------------------------\n"); consolePrintf("L/R + D-pad/pen: Scroll view\n"); consolePrintf("D-pad left: Left mouse button\n"); consolePrintf("D-pad right: Right mouse button\n"); @@ -2808,9 +3135,11 @@ int main(void) g_system = new OSystem_DS(); assert(g_system); +#ifdef GBA_SRAM_SAVE if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) { formatSramOption(); } +#endif IPC->adpcm.semaphore = false; @@ -2831,6 +3160,8 @@ int main(void) const char *argv[] = {"/scummvmds", "--config=scummvmf.ini"}; #elif defined(DS_BUILD_G) const char *argv[] = {"/scummvmds", "--config=scummvmg.ini"}; +#elif defined(DS_BUILD_H) + const char *argv[] = {"/scummvmds", "--config=scummvmh.ini"}; #endif while (1) { diff --git a/backends/platform/ds/arm9/source/dsmain.h b/backends/platform/ds/arm9/source/dsmain.h index 43258b5c5d..ab74554917 100644 --- a/backends/platform/ds/arm9/source/dsmain.h +++ b/backends/platform/ds/arm9/source/dsmain.h @@ -38,7 +38,8 @@ enum controlType { CONT_SIMON, CONT_FUTURE_WARS, CONT_AGI, - CONT_GOBLINS + CONT_GOBLINS, + CONT_NIPPON, }; struct gameListType { @@ -56,6 +57,7 @@ int getPenX(); int getPenY(); GLvector getPenPos(); void consumePenEvents(); +controlType getControlType(); // Pad reading int getKeysHeld(); @@ -64,6 +66,8 @@ int getKeysDown(); int getKeysReleased(); void consumeKeys(); int leftHandedSwap(int keys); +void setGameScreenSwap(bool enable); +void setSensitivity(int sensitivity); // Video void displayMode8Bit(); // Switch to 8-bit mode5 @@ -81,6 +85,7 @@ u16* getScalerBuffer(); void setTalkPos(int x, int y); void setTopScreenTarget(int x, int y); void set200PercentFixedScale(bool on); +void setTopScreenZoom(int percentage); // Timers void setTimerCallback(OSystem_DS::TimerProc proc, int interval); // Setup a callback function at a regular interval @@ -88,7 +93,9 @@ int getMillis(); // Return the current runtime in milliseconds void doTimerCallback(); // Call callback function if required // Sound -void doSoundCallback(); // Call function if sound buffers need more data +void doSoundCallback(); +void startSound(int freq, int buffer); // Start sound hardware +// Call function if sound buffers need more data void playSound(const void* data, u32 length, bool loop, bool adpcm = false, int rate = 22050); // Start a sound void stopSound(int channel); int getSoundFrequency(); @@ -131,6 +138,8 @@ void setIndyFightState(bool st); bool getIndyFightState(); bool isCpuScalerEnabled(); void setCpuScalerEnable(bool enable); +void setTrackPadStyleEnable(bool enable); +void setTapScreenClicksEnable(bool enable); // Display bool getIsDisplayMode8Bit(); diff --git a/backends/platform/ds/arm9/source/dsoptions.cpp b/backends/platform/ds/arm9/source/dsoptions.cpp index edb9c70580..2dbc4b842b 100644 --- a/backends/platform/ds/arm9/source/dsoptions.cpp +++ b/backends/platform/ds/arm9/source/dsoptions.cpp @@ -25,6 +25,7 @@ #include "gui/dialog.h" #include "gui/newgui.h" #include "gui/ListWidget.h" +#include "gui/TabWidget.h" #include "osystem_ds.h" #include "engines/scumm/scumm.h" #include "touchkeyboard.h" @@ -41,8 +42,67 @@ namespace Scumm { namespace DS { -DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { - addButton(this, 10, 175, "Close", GUI::kCloseCmd, 'C'); +DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(0, 0, 320 - 10, 230 - 40) { + + addButton(this, 10, 170, "Close", GUI::kCloseCmd, 'C'); + _tab = new GUI::TabWidget(this, 5, 5, 300, 230 - 20 - 40 - 10); + + _tab->addTab("Controls"); + + _leftHandedCheckbox = new GUI::CheckboxWidget(_tab, 5, 5, 130, 20, "Left handed mode", 0, 'L'); + _indyFightCheckbox = new GUI::CheckboxWidget(_tab, 5, 20, 140, 20, "Indy fight controls", 0, 'I'); + _showCursorCheckbox = new GUI::CheckboxWidget(_tab, 150, 5, 130, 20, "Show mouse cursor", 0, 'T'); + _snapToBorderCheckbox = new GUI::CheckboxWidget(_tab, 150, 20, 130, 20, "Snap to edges", 0, 'T'); + + new GUI::StaticTextWidget(_tab, 20, 35, 100, 15, "Touch X Offset", GUI::kTextAlignLeft); + _touchX = new GUI::SliderWidget(_tab, 130, 35, 130, 12, 1); + _touchX->setMinValue(-8); + _touchX->setMaxValue(+8); + _touchX->setValue(0); + _touchX->setFlags(GUI::WIDGET_CLEARBG); + + new GUI::StaticTextWidget(_tab, 20, 50, 100, 15, "Touch Y Offset", GUI::kTextAlignLeft); + _touchY = new GUI::SliderWidget(_tab, 130, 50, 130, 12, 2); + _touchY->setMinValue(-8); + _touchY->setMaxValue(+8); + _touchY->setValue(0); + _touchY->setFlags(GUI::WIDGET_CLEARBG); + + new GUI::StaticTextWidget(_tab, 130 + 65 - 10, 65, 20, 15, "0", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(_tab, 130 + 130 - 10, 65, 20, 15, "8", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(_tab, 130 - 20, 65, 20, 15, "-8", GUI::kTextAlignCenter); + + + _touchPadStyle = new GUI::CheckboxWidget(_tab, 5, 80, 270, 20, "Use laptop trackpad-style cursor control", 0x20000001, 'T'); + _screenTaps = new GUI::CheckboxWidget(_tab, 5, 95, 285, 20, "Tap for left click, double tap right click", 0x20000002, 'T'); + + _sensitivityLabel = new GUI::StaticTextWidget(_tab, 20, 110, 110, 15, "Sensitivity", GUI::kTextAlignLeft); + _sensitivity = new GUI::SliderWidget(_tab, 130, 110, 130, 12, 1); + _sensitivity->setMinValue(4); + _sensitivity->setMaxValue(16); + _sensitivity->setValue(8); + _sensitivity->setFlags(GUI::WIDGET_CLEARBG); + + _tab->addTab("Graphics"); + + new GUI::StaticTextWidget(_tab, 5, 70, 180, 15, "Initial top screen scale:", GUI::kTextAlignLeft); + + _100PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 85, 230, 20, "100%", 0x30000001, 'T'); + _150PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 100, 230, 20, "150%", 0x30000002, 'T'); + _200PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 115, 230, 20, "200%", 0x30000003, 'T'); + + new GUI::StaticTextWidget(_tab, 5, 5, 180, 15, "Main screen scaling:", GUI::kTextAlignLeft); + + _hardScaler = new GUI::CheckboxWidget(_tab, 5, 20, 270, 20, "Hardware scale (fast, but low quality)", 0x10000001, 'T'); + _cpuScaler = new GUI::CheckboxWidget(_tab, 5, 35, 270, 20, "Software scale (good quality, but slower)", 0x10000002, 'S'); + _unscaledCheckbox = new GUI::CheckboxWidget(_tab, 5, 50, 270, 20, "Unscaled (you must scroll left and right)", 0x10000003, 'S'); + + _tab->addTab("General"); + + _highQualityAudioCheckbox = new GUI::CheckboxWidget(_tab, 5, 5, 250, 20, "High quality audio (slower) (reboot)", 0, 'T'); + _disablePowerOff = new GUI::CheckboxWidget(_tab, 5, 20, 200, 20, "Disable power off", 0, 'T'); + + _tab->setActiveTab(0); _radioButtonMode = false; @@ -52,46 +112,17 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { } #endif - new GUI::StaticTextWidget(this, 90, 10, 130, 15, "ScummVM DS Options", GUI::kTextAlignCenter); +// new GUI::StaticTextWidget(this, 90, 10, 130, 15, "ScummVM DS Options", GUI::kTextAlignCenter); - _leftHandedCheckbox = new GUI::CheckboxWidget(this, 5, 70, 130, 20, "Left handed mode", 0, 'L'); - _indyFightCheckbox = new GUI::CheckboxWidget(this, 5, 40, 200, 20, "Indy fighting controls", 0, 'I'); - _twoHundredPercentCheckbox = new GUI::CheckboxWidget(this, 5, 55, 230, 20, "Zoomed screen at fixed 200% zoom", 0, 'T'); - _highQualityAudioCheckbox = new GUI::CheckboxWidget(this, 5, 25, 250, 20, "High quality audio (slower) (reboot)", 0, 'T'); - _disablePowerOff = new GUI::CheckboxWidget(this, 5, 85, 130, 20, "Disable power off", 0, 'T'); - _showCursorCheckbox = new GUI::CheckboxWidget(this, 5, 100, 130, 20, "Show mouse cursor", 0, 'T'); //#ifdef ALLOW_CPU_SCALER // _cpuScaler = new GUI::CheckboxWidget(this, 160, 115, 90, 20, "CPU scaler", 0, 'T'); //#endif - new GUI::StaticTextWidget(this, 180, 70, 130, 15, "Main screen:", GUI::kTextAlignLeft); - - _hardScaler = new GUI::CheckboxWidget(this, 140, 85, 170, 20, "Hardware scale (fast)", 0x10000001, 'T'); - _cpuScaler = new GUI::CheckboxWidget(this, 140, 100, 170, 20, "Software scale (quality)", 0x10000002, 'S'); - _unscaledCheckbox = new GUI::CheckboxWidget(this, 140, 115, 170, 20, "Unscaled", 0x10000003, 'S'); - _snapToBorderCheckbox = new GUI::CheckboxWidget(this, 5, 115, 120, 20, "Snap to border", 0, 'T'); - new GUI::StaticTextWidget(this, 20, 145, 110, 15, "Touch X Offset", GUI::kTextAlignLeft); - _touchX = new GUI::SliderWidget(this, 130, 145, 130, 12, 1); - _touchX->setMinValue(-8); - _touchX->setMaxValue(+8); - _touchX->setValue(0); - _touchX->setFlags(GUI::WIDGET_CLEARBG); - - new GUI::StaticTextWidget(this, 20, 160, 110, 15, "Touch Y Offset", GUI::kTextAlignLeft); - _touchY = new GUI::SliderWidget(this, 130, 160, 130, 12, 2); - _touchY->setMinValue(-8); - _touchY->setMaxValue(+8); - _touchY->setValue(0); - _touchY->setFlags(GUI::WIDGET_CLEARBG); - - new GUI::StaticTextWidget(this, 130 + 65 - 10, 175, 20, 15, "0", GUI::kTextAlignCenter); - new GUI::StaticTextWidget(this, 130 + 130 - 10, 175, 20, 15, "8", GUI::kTextAlignCenter); - new GUI::StaticTextWidget(this, 130 - 10, 175, 20, 15, "-8", GUI::kTextAlignCenter); #ifdef DS_SCUMM_BUILD _delDialog = new Scumm::SaveLoadChooser("Delete game:", "Delete", false, Scumm::g_scumm); @@ -125,10 +156,36 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { _unscaledCheckbox->setState(false); } - if (ConfMan.hasKey("twohundredpercent", "ds")) { - _twoHundredPercentCheckbox->setState(ConfMan.getBool("twohundredpercent", "ds")); + + if (ConfMan.hasKey("topscreenzoom", "ds")) { + + _100PercentCheckbox->setState(false); + _150PercentCheckbox->setState(false); + _200PercentCheckbox->setState(false); + + switch (ConfMan.getInt("topscreenzoom", "ds")) + { + case 100: { + _100PercentCheckbox->setState(true); + break; + } + + case 150: { + _150PercentCheckbox->setState(true); + break; + } + + case 200: { + _200PercentCheckbox->setState(true); + break; + } + } + + } else if (ConfMan.hasKey("twohundredpercent", "ds")) { + _200PercentCheckbox->setState(ConfMan.getBool("twohundredpercent", "ds")); } else { - _twoHundredPercentCheckbox->setState(false); + // No setting + _150PercentCheckbox->setState(true); } if (ConfMan.hasKey("22khzaudio", "ds")) { @@ -165,6 +222,29 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { _touchY->setValue(0); } + if (ConfMan.hasKey("sensitivity", "ds")) { + _sensitivity->setValue(ConfMan.getInt("sensitivity", "ds")); + } else { + _sensitivity->setValue(8); + } + + if (ConfMan.hasKey("touchpad", "ds")) { + _touchPadStyle->setState(ConfMan.getBool("touchpad", "ds")); + } else { + _touchPadStyle->setState(0); + } + + if (ConfMan.hasKey("screentaps", "ds")) { + _screenTaps->setState(ConfMan.getBool("screentaps", "ds")); + } else { + _screenTaps->setState(0); + } + + _screenTaps->setEnabled(!_touchPadStyle->getState()); + _sensitivity->setEnabled(_touchPadStyle->getState()); + _sensitivityLabel->setEnabled(_touchPadStyle->getState()); + _sensitivityLabel->draw(); + if (!_cpuScaler->getState() && !_unscaledCheckbox->getState()) { _hardScaler->setState(true); } @@ -180,7 +260,7 @@ DSOptionsDialog::~DSOptionsDialog() { void DSOptionsDialog::updateConfigManager() { ConfMan.setBool("lefthanded", _leftHandedCheckbox->getState(), "ds"); ConfMan.setBool("unscaled", _unscaledCheckbox->getState(), "ds"); - ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds"); +// ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds"); ConfMan.setBool("22khzaudio", _highQualityAudioCheckbox->getState(), "ds"); ConfMan.setBool("disablepoweroff", _disablePowerOff->getState(), "ds"); #ifdef ALLOW_CPU_SCALER @@ -190,6 +270,24 @@ void DSOptionsDialog::updateConfigManager() { ConfMan.setInt("yoffset", _touchY->getValue(), "ds"); ConfMan.setBool("showcursor", _showCursorCheckbox->getState(), "ds"); ConfMan.setBool("snaptoborder", _snapToBorderCheckbox->getState(), "ds"); + ConfMan.setBool("touchpad", _touchPadStyle->getState(), "ds"); + ConfMan.setBool("screentaps", _screenTaps->getState(), "ds"); + ConfMan.setInt("sensitivity", _sensitivity->getValue(), "ds"); + + u32 zoomLevel = 150; + + if (_100PercentCheckbox->getState()) { + zoomLevel = 100; + } else if (_150PercentCheckbox->getState()) { + zoomLevel = 150; + } else if (_200PercentCheckbox->getState()) { + zoomLevel = 200; + } + + consolePrintf("Saved zoom: %d\n", zoomLevel); + + ConfMan.setInt("topscreenzoom", zoomLevel, "ds"); + DS::setOptions(); } @@ -227,6 +325,70 @@ void DSOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint } + if ((!guard) && (_radioButtonMode)) + { + guard = true; + + if ((sender == _touchPadStyle) && (cmd == 0x20000001)) { + + if (_touchPadStyle->getState()) { + // Swap screens when turning on trackpad style, it feels + // much more natural! + DS::setGameScreenSwap(true); + + _screenTaps->setState(true); + _screenTaps->setEnabled(false); + _screenTaps->draw(); + _sensitivity->setEnabled(true); + _sensitivityLabel->setEnabled(true); + _sensitivityLabel->draw(); + _sensitivity->draw(); + } else { + DS::setGameScreenSwap(false); + + _screenTaps->setEnabled(true); + _screenTaps->setState(false); + _screenTaps->draw(); + _sensitivity->setEnabled(false); + _sensitivityLabel->setEnabled(false); + _sensitivityLabel->draw(); + _sensitivity->draw(); + } + } + + guard = false; + } + + if ((!guard) && (_radioButtonMode)) { + + guard = true; + + if (cmd == 0x30000001) { + _100PercentCheckbox->setState(true); + _150PercentCheckbox->setState(false); + _200PercentCheckbox->setState(false); + DS::setTopScreenZoom(100); + } + + if (cmd == 0x30000002) { + _100PercentCheckbox->setState(false); + _150PercentCheckbox->setState(true); + _200PercentCheckbox->setState(false); + DS::setTopScreenZoom(150); + } + + if (cmd == 0x30000003) { + _100PercentCheckbox->setState(false); + _150PercentCheckbox->setState(false); + _200PercentCheckbox->setState(true); + DS::setTopScreenZoom(200); + } + + guard = false; + + } + + if (cmd == GUI::kCloseCmd) { updateConfigManager(); close(); @@ -297,6 +459,8 @@ void showOptionsDialog() { } void setOptions() { + static bool firstLoad = true; + ConfMan.addGameDomain("ds"); if (ConfMan.hasKey("lefthanded", "ds")) { @@ -327,10 +491,16 @@ void setOptions() { DS::setUnscaledMode(false); } - if (ConfMan.hasKey("twohundredpercent", "ds")) { - DS::set200PercentFixedScale(ConfMan.getBool("twohundredpercent", "ds")); - } else { - DS::set200PercentFixedScale(false); + if (firstLoad) { + if (ConfMan.hasKey("topscreenzoom", "ds")) { + DS::setTopScreenZoom(ConfMan.getInt("topscreenzoom", "ds")); + } else { + if (ConfMan.hasKey("twohundredpercent", "ds")) { + DS::setTopScreenZoom(200); + } else { + DS::setTopScreenZoom(150); + } + } } if (ConfMan.hasKey("xoffset", "ds")) { @@ -345,6 +515,12 @@ void setOptions() { DS::setTouchXOffset(0); } + if (ConfMan.hasKey("sensitivity", "ds")) { + DS::setSensitivity(ConfMan.getInt("sensitivity", "ds")); + } else { + DS::setSensitivity(8); + } + #ifdef ALLOW_CPU_SCALER if (ConfMan.hasKey("cpu_scaler", "ds")) { DS::setCpuScalerEnable(ConfMan.getBool("cpu_scaler", "ds")); @@ -353,6 +529,33 @@ void setOptions() { } #endif + if (ConfMan.hasKey("screentaps", "ds")) { + DS::setTapScreenClicksEnable(ConfMan.getBool("screentaps", "ds")); + } else { + DS::setTapScreenClicksEnable(false); + } + + if (ConfMan.hasKey("touchpad", "ds")) { + bool enable = ConfMan.getBool("touchpad", "ds"); + + DS::setTrackPadStyleEnable(enable); + + if ((enable) and (firstLoad)) { + // If we've just booted up, want to swap screens when trackpad mode is in use + // but not every time we enter the options dialog. + DS::setGameScreenSwap(true); + } + + if (enable) { + DS::setTapScreenClicksEnable(true); + } + + } else { + DS::setTrackPadStyleEnable(false); + } + + + firstLoad = false; } } diff --git a/backends/platform/ds/arm9/source/dsoptions.h b/backends/platform/ds/arm9/source/dsoptions.h index 9cfa785ca8..e3ab2f55e0 100644 --- a/backends/platform/ds/arm9/source/dsoptions.h +++ b/backends/platform/ds/arm9/source/dsoptions.h @@ -30,6 +30,7 @@ #include "gui/object.h" #include "gui/widget.h" #include "gui/dialog.h" +#include "gui/TabWidget.h" #include "scumm/dialogs.h" namespace DS { @@ -45,11 +46,18 @@ protected: void togglePause(); void updateConfigManager(); + GUI::TabWidget* _tab; + + GUI::StaticTextWidget* _sensitivityLabel; + GUI::SliderWidget* _touchX; GUI::SliderWidget* _touchY; + GUI::SliderWidget* _sensitivity; GUI::CheckboxWidget* _leftHandedCheckbox; GUI::CheckboxWidget* _unscaledCheckbox; - GUI::CheckboxWidget* _twoHundredPercentCheckbox; + GUI::CheckboxWidget* _100PercentCheckbox; + GUI::CheckboxWidget* _150PercentCheckbox; + GUI::CheckboxWidget* _200PercentCheckbox; GUI::CheckboxWidget* _indyFightCheckbox; GUI::CheckboxWidget* _highQualityAudioCheckbox; GUI::CheckboxWidget* _disablePowerOff; @@ -59,6 +67,9 @@ protected: GUI::CheckboxWidget* _hardScaler; GUI::CheckboxWidget* _cpuScaler; + GUI::CheckboxWidget* _touchPadStyle; + GUI::CheckboxWidget* _screenTaps; + #ifdef DS_SCUMM_BUILD Scumm::SaveLoadChooser* _delDialog; #endif diff --git a/backends/platform/ds/arm9/source/gbampsave.cpp b/backends/platform/ds/arm9/source/gbampsave.cpp index 9c8af81a6e..a53ab9739d 100644 --- a/backends/platform/ds/arm9/source/gbampsave.cpp +++ b/backends/platform/ds/arm9/source/gbampsave.cpp @@ -54,8 +54,8 @@ bool GBAMPSaveFile::eos() const { return DS::std_feof(handle); } -void GBAMPSaveFile::skip(uint32 bytes) { - DS::std_fseek(handle, bytes, SEEK_CUR); +bool GBAMPSaveFile::skip(uint32 bytes) { + return DS::std_fseek(handle, bytes, SEEK_CUR) == 0; } void GBAMPSaveFile::flushSaveBuffer() { @@ -67,11 +67,11 @@ void GBAMPSaveFile::flushSaveBuffer() { } } -uint32 GBAMPSaveFile::pos() const { +int32 GBAMPSaveFile::pos() const { return DS::std_ftell(handle); } -uint32 GBAMPSaveFile::size() const { +int32 GBAMPSaveFile::size() const { int position = pos(); DS::std_fseek(handle, 0, SEEK_END); int size = DS::std_ftell(handle); @@ -79,8 +79,8 @@ uint32 GBAMPSaveFile::size() const { return size; } -void GBAMPSaveFile::seek(int32 pos, int whence) { - DS::std_fseek(handle, pos, whence); +bool GBAMPSaveFile::seek(int32 pos, int whence) { + return DS::std_fseek(handle, pos, whence) == 0; } @@ -155,11 +155,13 @@ GBAMPSaveFile* GBAMPSaveFileManager::openSavefile(char const* name, bool saveOrL sprintf(fileSpec, "%s/%s", getSavePath(), name); } -// consolePrintf(fileSpec); +// consolePrintf("Opening the file: %s\n", fileSpec); GBAMPSaveFile* sf = new GBAMPSaveFile(fileSpec, saveOrLoad); if (sf->isOpen()) { +// consolePrintf("Ok"); return sf; } else { +// consolePrintf("Fail"); delete sf; return NULL; } @@ -192,8 +194,29 @@ Common::StringList GBAMPSaveFileManager::listSavefiles(const char *pattern) { enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 }; char name[256]; - DS::std_cwd((char*)getSavePath()); //TODO : Check this suspicious const-cast -// consolePrintf("Save path: '%s', pattern: '%s'\n", getSavePath(),pattern); + { + char dir[128]; + strcpy(dir, getSavePath()); + char *realName = dir; + + if ((strlen(dir) >= 4) && (dir[0] == 'm') && (dir[1] == 'p') && (dir[2] == ':') && (dir[3] == '/')) { + realName += 4; + } + + // consolePrintf("Real cwd:%d\n", realName); + + char* p = realName; + while (*p) { + if (*p == '\\') *p = '/'; + p++; + } + + // consolePrintf("Real cwd:%d\n", realName); + FAT_chdir(realName); + + } + +// consolePrintf("Save path: '%s', pattern: '%s'\n", getSavePath(), pattern); int fileType = FAT_FindFirstFileLFN(name); @@ -206,7 +229,7 @@ Common::StringList GBAMPSaveFileManager::listSavefiles(const char *pattern) { FAT_GetLongFilename(name); - for (int r = 0; r < strlen(name); r++) { + for (int r = 0; name[r] != 0; r++) { name[r] = tolower(name[r]); } diff --git a/backends/platform/ds/arm9/source/gbampsave.h b/backends/platform/ds/arm9/source/gbampsave.h index d0cbc68bfd..6ddc4fd964 100644 --- a/backends/platform/ds/arm9/source/gbampsave.h +++ b/backends/platform/ds/arm9/source/gbampsave.h @@ -43,11 +43,11 @@ public: virtual uint32 write(const void *buf, uint32 size); virtual bool eos() const; - virtual void skip(uint32 bytes); + virtual bool skip(uint32 bytes); - virtual uint32 pos() const; - virtual uint32 size() const; - virtual void seek(int32 pos, int whence); + virtual int32 pos() const; + virtual int32 size() const; + virtual bool seek(int32 pos, int whence); void flushSaveBuffer(); diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp index 79b0c5390b..5ddcb50b15 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.cpp +++ b/backends/platform/ds/arm9/source/osystem_ds.cpp @@ -41,7 +41,8 @@ OSystem_DS* OSystem_DS::_instance = NULL; OSystem_DS::OSystem_DS() - : eventNum(0), lastPenFrame(0), queuePos(0), _mixer(NULL), _timer(NULL), _frameBufferExists(false) + : eventNum(0), lastPenFrame(0), queuePos(0), _mixer(NULL), _timer(NULL), _frameBufferExists(false), + _disableCursorPalette(true), _graphicsEnable(true) { // eventNum = 0; // lastPenFrame = 0; @@ -71,7 +72,13 @@ void OSystem_DS::initBackend() { _timer = new DSTimerManager(); DS::setTimerCallback(&OSystem_DS::timerHandler, 10); - _mixer->setOutputRate(11025 /*DS::getSoundFrequency()*/); + if (ConfMan.hasKey("22khzaudio", "ds") && ConfMan.getBool("22khzaudio", "ds")) { + DS::startSound(22050, 8192); + } else { + DS::startSound(11025, 4096); + } + + _mixer->setOutputRate(DS::getSoundFrequency()); _mixer->setReady(true); OSystem::initBackend(); @@ -79,7 +86,7 @@ void OSystem_DS::initBackend() { bool OSystem_DS::hasFeature(Feature f) { // consolePrintf("hasfeature\n"); - return (f == kFeatureVirtualKeyboard); + return (f == kFeatureVirtualKeyboard) || (f == kFeatureCursorHasPalette); } void OSystem_DS::setFeatureState(Feature f, bool enable) { @@ -107,7 +114,7 @@ bool OSystem_DS::setGraphicsMode(int mode) { } bool OSystem_DS::setGraphicsMode(const char *name) { -// consolePrintf("Set gfx mode %s\n", name); + consolePrintf("Set gfx mode %s\n", name); return true; } @@ -116,8 +123,15 @@ int OSystem_DS::getGraphicsMode() const { } void OSystem_DS::initSize(uint width, uint height) { -// consolePrintf("Set gfx mode %d x %d\n", width, height); - DS::setGameSize(width, height); + // For Lost in Time, the title screen is displayed in 640x400. + // In order to support this game, the screen mode is set, but + // all draw calls are ignored until the game switches to 320x200. + if ((width == 640) && (height == 400)) { + _graphicsEnable = false; + } else { + _graphicsEnable = true; + DS::setGameSize(width, height); + } } int16 OSystem_DS::getHeight() { @@ -129,9 +143,8 @@ int16 OSystem_DS::getWidth() { } void OSystem_DS::setPalette(const byte *colors, uint start, uint num) { -// consolePrintf("Set palette %d, %d colours\n", start, num); -//return; - if (!DS::getIsDisplayMode8Bit()) return; +// consolePrintf("Setpal %d, %d\n", start, num); + for (unsigned int r = start; r < start + num; r++) { int red = *colors; int green = *(colors + 1); @@ -141,17 +154,44 @@ void OSystem_DS::setPalette(const byte *colors, uint start, uint num) { green >>= 3; blue >>= 3; - if (r != 255) +// if (r != 255) { - BG_PALETTE[r] = red | (green << 5) | (blue << 10); - if (!DS::getKeyboardEnable()) { - BG_PALETTE_SUB[r] = red | (green << 5) | (blue << 10); + u16 paletteValue = red | (green << 5) | (blue << 10); + + if (DS::getIsDisplayMode8Bit()) { + BG_PALETTE[r] = paletteValue; + if (!DS::getKeyboardEnable()) { + BG_PALETTE_SUB[r] = paletteValue; + } } + + _palette[r] = paletteValue; } -// if (num == 16) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue); + // if (num == 255) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue); + + colors += 4; + } +} + +void OSystem_DS::setCursorPalette(const byte *colors, uint start, uint num) { + +// consolePrintf("Cursor palette set: start: %d, cols: %d\n", start, num); + for (unsigned int r = start; r < start + num; r++) { + int red = *colors; + int green = *(colors + 1); + int blue = *(colors + 2); + + red >>= 3; + green >>= 3; + blue >>= 3; + u16 paletteValue = red | (green << 5) | (blue << 10); + _cursorPalette[r] = paletteValue; + colors += 4; } + + _disableCursorPalette = false; } bool OSystem_DS::grabRawScreen(Graphics::Surface* surf) { @@ -184,9 +224,11 @@ void OSystem_DS::grabPalette(unsigned char *colors, uint start, uint num) { } +#define MISALIGNED16(ptr) (((u32) (ptr) & 1) != 0) + void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { -// consolePrintf("Copy rect %d, %d %d, %d ", x, y, w, h); - + //consolePrintf("Copy rect %d, %d %d, %d ", x, y, w, h); + if (!_graphicsEnable) return; if (w <= 1) return; if (h < 0) return; if (!DS::getIsDisplayMode8Bit()) return; @@ -195,6 +237,9 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int s32 stride; u16* bgSub = (u16 *) BG_GFX_SUB; + // The DS video RAM doesn't support 8-bit writes because Nintendo wanted + // to save a few pennies/euro cents on the hardware. + if (_frameBufferExists) { bg = (u16 *) _framebuffer.pixels; stride = _framebuffer.pitch; @@ -203,46 +248,117 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int stride = DS::get8BitBackBufferStride(); } - u16* src = (u16 *) buf; - - if (DS::getKeyboardEnable()) { - + if (((pitch & 1) != 0) || ((w & 1) != 0) || (((int) (buf) & 1) != 0)) { + + // Something is misaligned, so we have to use the slow but sure method + + int by = 0; + for (int dy = y; dy < y + h; dy++) { - u16* dest = bg + (dy * (stride >> 1)) + (x >> 1); - - DC_FlushRange(src, w << 1); - DC_FlushRange(dest, w << 1); - dmaCopyHalfWords(3, src, dest, w); - - src += pitch >> 1; + u8* dest = ((u8 *) (bg)) + (dy * stride) + x; + u8* destSub = ((u8 *) (bgSub)) + (dy * 512) + x; + u8* src = (u8 *) buf + (pitch * by); + + u32 dx; + + u32 pixelsLeft = w; + + if (MISALIGNED16(dest)) { + // Read modify write + + dest--; + u16 mix = *((u16 *) dest); + + mix = (mix & 0x00FF) | (*src++ << 8); + + *dest = mix; + *destSub = mix; + + dest += 2; + destSub += 2; + pixelsLeft--; + } + + // We can now assume dest is aligned + u16* dest16 = (u16 *) dest; + u16* destSub16 = (u16 *) destSub; + + for (dx = 0; dx < pixelsLeft; dx+=2) { + u16 mix; + + mix = *src + (*(src + 1) << 8); + *dest16++ = mix; + *destSub16++ = mix; + src += 2; + } + + pixelsLeft -= dx; + + // At the end we may have one pixel left over + + if (pixelsLeft != 0) { + u16 mix = *dest16; + + mix = (mix & 0x00FF) | ((*src++) << 8); + + *dest16 = mix; + *destSub16 = mix; + } + + by++; + } - + +// consolePrintf("Slow method used!\n"); + + } else { - for (int dy = y; dy < y + h; dy++) { - u16* dest1 = bg + (dy * (stride >> 1)) + (x >> 1); - u16* dest2 = bgSub + (dy << 8) + (x >> 1); + + // Stuff is aligned to 16-bit boundaries, so it's safe to do DMA. + + u16* src = (u16 *) buf; + + if (DS::getKeyboardEnable()) { + + for (int dy = y; dy < y + h; dy++) { + u16* dest = bg + (dy * (stride >> 1)) + (x >> 1); - DC_FlushRange(src, w << 1); - DC_FlushRange(dest1, w << 1); - DC_FlushRange(dest2, w << 1); - - dmaCopyHalfWords(3, src, dest1, w); - dmaCopyHalfWords(3, src, dest2, w); - - src += pitch >> 1; - } - } + DC_FlushRange(src, w << 1); + DC_FlushRange(dest, w << 1); + dmaCopyHalfWords(3, src, dest, w); -// consolePrintf("Done\n"); + while (dmaBusy(3)); + + src += pitch >> 1; + } + + } else { + for (int dy = y; dy < y + h; dy++) { + u16* dest1 = bg + (dy * (stride >> 1)) + (x >> 1); + u16* dest2 = bgSub + (dy << 8) + (x >> 1); + + DC_FlushRange(src, w << 1); + DC_FlushRange(dest1, w << 1); + DC_FlushRange(dest2, w << 1); + + dmaCopyHalfWords(3, src, dest1, w); - + if ((!_frameBufferExists) || (buf == _framebuffer.pixels)) { + dmaCopyHalfWords(2, src, dest2, w); + } + while (dmaBusy(2) || dmaBusy(3)); + + src += pitch >> 1; + } + } + } +// consolePrintf("Done\n"); } void OSystem_DS::updateScreen() { - if ((_frameBufferExists) && (DS::getIsDisplayMode8Bit())) - { + if ((_frameBufferExists) && (DS::getIsDisplayMode8Bit())) { _frameBufferExists = false; // Copy temp framebuffer back to screen @@ -253,6 +369,12 @@ void OSystem_DS::updateScreen() { DS::doSoundCallback(); // DS::doTimerCallback(); DS::addEventsToQueue(); + + // Force back buffer usage for Nippon Safes, as it doesn't double buffer it's output + if (DS::getControlType() == DS::CONT_NIPPON) { + OSystem_DS::instance()->lockScreen(); + OSystem_DS::instance()->unlockScreen(); + } } void OSystem_DS::setShakePos(int shakeOffset) { @@ -334,7 +456,21 @@ void OSystem_DS::warpMouse(int x, int y) { } void OSystem_DS::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetCursorScale) { - DS::setCursorIcon(buf, w, h, keycolor, hotspotX, hotspotY); + if ((w > 0) && (w < 64) && (h > 0) && (h < 64)) + { + memcpy(_cursorImage, buf, w * h); + _cursorW = w; + _cursorH = h; + _cursorHotX = hotspotX; + _cursorHotY = hotspotY; + _cursorKey = keycolor; + _cursorScale = targetCursorScale; + refreshCursor(); + } +} + +void OSystem_DS::refreshCursor() { + DS::setCursorIcon(_cursorImage, _cursorW, _cursorH, _cursorKey, _cursorHotX, _cursorHotY); } void OSystem_DS::addEvent(Common::Event& e) { @@ -489,7 +625,11 @@ Common::SaveFileManager* OSystem_DS::getSavefileManager() { if (DS::isGBAMPAvailable() && (!forceSram)) { return &mpSaveManager; } else { +#ifdef GBA_SRAM_SAVE return &saveManager; +#else + return NULL; +#endif } } diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h index 8c8d661ad8..16c8f41491 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.h +++ b/backends/platform/ds/arm9/source/osystem_ds.h @@ -52,17 +52,32 @@ protected: Common::Event eventQueue[96]; int queuePos; +#ifdef GBA_SRAM_SAVE DSSaveFileManager saveManager; +#endif GBAMPSaveFileManager mpSaveManager; DSAudioMixer* _mixer; DSTimerManager* _timer; Graphics::Surface _framebuffer; bool _frameBufferExists; - + bool _graphicsEnable; static OSystem_DS* _instance; + + u16 _palette[256]; + u16 _cursorPalette[256]; + + u8 _cursorImage[64 * 64]; + uint _cursorW; + uint _cursorH; + int _cursorHotX; + int _cursorHotY; + byte _cursorKey; + int _cursorScale; + Graphics::Surface* createTempFrameBuffer(); + bool _disableCursorPalette; public: typedef void (*SoundProc)(byte *buf, int len); @@ -159,7 +174,16 @@ public: virtual void clearAutoComplete(); virtual void setCharactersEntered(int count); + u16 getDSPaletteEntry(u32 entry) { return _palette[entry]; } + u16 getDSCursorPaletteEntry(u32 entry) { return !_disableCursorPalette? _cursorPalette[entry]: _palette[entry]; } + + virtual void setCursorPalette(const byte *colors, uint start, uint num); + + virtual void disableCursorPalette(bool dis) { _disableCursorPalette = dis; refreshCursor(); } + FilesystemFactory *getFilesystemFactory(); + + void refreshCursor(); }; static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { diff --git a/backends/platform/ds/arm9/source/portdefs.h b/backends/platform/ds/arm9/source/portdefs.h index de7a5795f5..16f3d8cc9b 100644 --- a/backends/platform/ds/arm9/source/portdefs.h +++ b/backends/platform/ds/arm9/source/portdefs.h @@ -81,7 +81,10 @@ void consolePrintf(const char* s, ...); #define ITCM_DATA __attribute__((section(".itcm"))) - +// Since I can't change the engine at the moment (post lockdown) this define can go here. +// This define changes the mouse-relative motion which doesn't make sense on a touch screen to +// a more conventional form of input where the menus can be clicked on. +#define LURE_CLICKABLE_MENUS //#include "common/array.h" //#include "common/str.h" diff --git a/backends/platform/ds/arm9/source/ramsave.cpp b/backends/platform/ds/arm9/source/ramsave.cpp index be355ce76f..a9f4e3d2fc 100644 --- a/backends/platform/ds/arm9/source/ramsave.cpp +++ b/backends/platform/ds/arm9/source/ramsave.cpp @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ - // Save in order 1,2,3,4,larger 2,5 +#ifdef GBA_SRAM_SAVE + + #include "ramsave.h" #include "nds.h" #include "compressor/lz.h" @@ -64,6 +66,7 @@ DSSaveFile::DSSaveFile(SCUMMSave* s, bool compressed, u8* data) { } isTempFile = false; + eosReached = false; } DSSaveFile::~DSSaveFile() { @@ -167,11 +170,13 @@ int DSSaveFile::saveToSaveRAM(vu8* address) { void DSSaveFile::reset() { ptr = 0; + eosReached = false; } uint32 DSSaveFile::read(void *buf, uint32 size) { if (ptr + size > save.size) { size = save.size - ptr; + eosReached = true; if (size < 0) size = 0; } memcpy(buf, saveData + ptr, size); @@ -181,15 +186,15 @@ uint32 DSSaveFile::read(void *buf, uint32 size) { return size; } -uint32 DSSaveFile::pos() const { +int32 DSSaveFile::pos() const { return ptr; } -uint32 DSSaveFile::size() const { +int32 DSSaveFile::size() const { return save.size; } -void DSSaveFile::seek(int32 pos, int whence) { +bool DSSaveFile::seek(int32 pos, int whence) { switch (whence) { case SEEK_SET: { ptr = pos; @@ -204,15 +209,22 @@ void DSSaveFile::seek(int32 pos, int whence) { break; } } + eosReached = false; + return true; } bool DSSaveFile::eos() const { - return ptr >= (int) save.size; + return eosReached; } -void DSSaveFile::skip(uint32 bytes) { +void DSSaveFile::clearErr() { + eosReached = false; +} + +bool DSSaveFile::skip(uint32 bytes) { ptr = ptr + bytes; if (ptr > (int) save.size) ptr = save.size; + return true; } uint32 DSSaveFile::write(const void *buf, uint32 size) { @@ -227,7 +239,7 @@ uint32 DSSaveFile::write(const void *buf, uint32 size) { return size; } -bool DSSaveFile::matches(char* prefix, int num) { +bool DSSaveFile::matches(const char *prefix, int num) { char str[16]; if (isValid()) { sprintf(str, "%s%02d", prefix, num); @@ -241,7 +253,7 @@ bool DSSaveFile::matches(char* prefix, int num) { } } -bool DSSaveFile::matches(char* filename) { +bool DSSaveFile::matches(const char *filename) { if (isValid()) { return !strcmp(save.name, filename); } else { @@ -522,3 +534,5 @@ int DSSaveFileManager::getExtraData() { return 0; } } + +#endif diff --git a/backends/platform/ds/arm9/source/ramsave.h b/backends/platform/ds/arm9/source/ramsave.h index f919da18db..034e957b7f 100644 --- a/backends/platform/ds/arm9/source/ramsave.h +++ b/backends/platform/ds/arm9/source/ramsave.h @@ -52,6 +52,7 @@ class DSSaveFile : public Common::InSaveFile, public Common::OutSaveFile { SCUMMSave* origHeader; bool isOpenFlag; bool isTempFile; + bool eosReached; public: DSSaveFile(); @@ -62,11 +63,12 @@ public: bool isOpen() const { return isOpenFlag; } virtual bool eos() const; - virtual void skip(uint32 size); + virtual void clearErr(); + virtual bool skip(uint32 size); - virtual uint32 pos() const; - virtual uint32 size() const; - virtual void seek(int32 pos, int whence); + virtual int32 pos() const; + virtual int32 size() const; + virtual bool seek(int32 pos, int whence); uint32 read(void *buf, uint32 size); uint32 write(const void *buf, uint32 size); @@ -76,8 +78,8 @@ public: bool isValid() { return save.isValid; } bool isTemp() { return isTempFile; } - bool matches(char* prefix, int num); - bool matches(char* filename); + bool matches(const char *prefix, int num); + bool matches(const char *filename); void clearData(); void compress(); diff --git a/backends/platform/ds/arm9/source/touchkeyboard.cpp b/backends/platform/ds/arm9/source/touchkeyboard.cpp index 11832f4e3a..85f80fac92 100644 --- a/backends/platform/ds/arm9/source/touchkeyboard.cpp +++ b/backends/platform/ds/arm9/source/touchkeyboard.cpp @@ -402,6 +402,23 @@ void createKeyEvent(int keyNum, Common::Event& event) } } +void releaseAllKeys() { + for (int r = 0; r < DS_NUM_KEYS; r++) { + if (keys[r].pressed) { + DS::setKeyHighlight(r, false); + + OSystem_DS* system = OSystem_DS::instance(); + + Common::Event event; + createKeyEvent(r, event); + event.type = Common::EVENT_KEYUP; + system->addEvent(event); + + keys[r].pressed = false; + } + } +} + void addKeyboardEvents() { bool resetShift = false; @@ -446,7 +463,7 @@ void addKeyboardEvents() { // consolePrintf("Key: %d\n", r); if ((keys[r].character == Common::KEYCODE_INVALID)) { // Close button - DS::closed = true; + //DS::closed = true; } else { createKeyEvent(r, event); } @@ -492,9 +509,14 @@ void addKeyboardEvents() { OSystem_DS* system = OSystem_DS::instance(); Common::Event event; - createKeyEvent(r, event); - event.type = Common::EVENT_KEYUP; - system->addEvent(event); + if ((keys[r].character == Common::KEYCODE_INVALID)) { + // Close button + DS::closed = true; + } else { + createKeyEvent(r, event); + event.type = Common::EVENT_KEYUP; + system->addEvent(event); + } keys[r].pressed = false; diff --git a/backends/platform/ds/arm9/source/touchkeyboard.h b/backends/platform/ds/arm9/source/touchkeyboard.h index 8a5fc728ce..91efbc1e9a 100644 --- a/backends/platform/ds/arm9/source/touchkeyboard.h +++ b/backends/platform/ds/arm9/source/touchkeyboard.h @@ -40,6 +40,7 @@ bool getKeyboardClosed(); void addAutoComplete(char* word); void clearAutoComplete(); void setCharactersEntered(int count); +void releaseAllKeys(); } diff --git a/backends/platform/ds/logog.bmp b/backends/platform/ds/logog.bmp Binary files differnew file mode 100644 index 0000000000..9c194d3f82 --- /dev/null +++ b/backends/platform/ds/logog.bmp diff --git a/backends/platform/ds/makefile b/backends/platform/ds/makefile index 3fb19e939c..a9fbb13637 100644 --- a/backends/platform/ds/makefile +++ b/backends/platform/ds/makefile @@ -36,3 +36,23 @@ allbuilds: make all SCUMM_BUILD=f make semiclean make all SCUMM_BUILD=g + make semiclean + make all SCUMM_BUILD=h + +allbuildssafe: + make clean SCUMM_BUILD=a + make all SCUMM_BUILD=a + make clean SCUMM_BUILD=b + make all SCUMM_BUILD=b + make clean SCUMM_BUILD=c + make all SCUMM_BUILD=c + make clean SCUMM_BUILD=d + make all SCUMM_BUILD=d + make clean SCUMM_BUILD=e + make all SCUMM_BUILD=e + make clean SCUMM_BUILD=f + make all SCUMM_BUILD=f + make clean SCUMM_BUILD=g + make all SCUMM_BUILD=g + make clean SCUMM_BUILD=h + make all SCUMM_BUILD=h diff --git a/backends/platform/iphone/iphone_keyboard.m b/backends/platform/iphone/iphone_keyboard.m index bd4948e30a..fda481933d 100644 --- a/backends/platform/iphone/iphone_keyboard.m +++ b/backends/platform/iphone/iphone_keyboard.m @@ -54,8 +54,7 @@ @implementation SoftKeyboard - (id)initWithFrame:(CGRect)frame { - //self = [super initWithFrame:frame]; - self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)]; + self = [super initWithFrame:frame]; inputDelegate = nil; inputView = [[TextInputHandler alloc] initWithKeyboard:self]; return self; diff --git a/backends/platform/iphone/iphone_main.m b/backends/platform/iphone/iphone_main.m index b01e9f3f34..6b709b0803 100644 --- a/backends/platform/iphone/iphone_main.m +++ b/backends/platform/iphone/iphone_main.m @@ -79,10 +79,7 @@ int main(int argc, char** argv) { - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // hide the status bar [UIHardware _setStatusBarHeight:0.0f]; - //[self setStatusBarMode:2 orientation:0 duration:0.0f fenceID:0]; - - //[self setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; - [self setStatusBarHidden:YES animated:YES]; + [self setStatusBarHidden:YES animated:NO]; _window = [[UIWindow alloc] initWithContentRect: [UIHardware fullScreenApplicationContentRect]]; [_window retain]; @@ -103,9 +100,13 @@ int main(int argc, char** argv) { - (void)applicationResume:(GSEventRef)event { [self removeApplicationBadge]; - [UIHardware _setStatusBarHeight:0.0f]; - [self setStatusBarHidden:YES animated:YES]; [_view applicationResume]; + + // Workaround, need to "hide" and unhide the statusbar to properly remove it, + // since the Springboard has put it back without apparently flagging our application. + [self setStatusBarHidden:NO animated:NO]; // hide status bar + [UIHardware _setStatusBarHeight:0.0f]; + [self setStatusBarHidden:YES animated:NO]; // hide status bar } - (void)deviceOrientationChanged:(GSEvent *)event { diff --git a/backends/platform/iphone/iphone_video.m b/backends/platform/iphone/iphone_video.m index 89f159c1d9..910f14ab58 100644 --- a/backends/platform/iphone/iphone_video.m +++ b/backends/platform/iphone/iphone_video.m @@ -169,10 +169,6 @@ bool getLocalMouseCoords(CGPoint *point) { nil ]; - if (_screenSurface != nil) { - //[[sharedInstance _layer] removeSublayer: screenLayer]; - } - //("Allocating surface: %d\n", allocSize); _screenSurface = CoreSurfaceBufferCreate((CFDictionaryRef)dict); //printf("Surface created.\n"); @@ -205,10 +201,13 @@ bool getLocalMouseCoords(CGPoint *point) { [screenLayer setFrame: _screenRect]; } else { float ratio = (float)_height / (float)_width; - _screenRect = CGRectMake(0, 0, _fullWidth, _fullWidth * ratio); + int height = _fullWidth * ratio; + //printf("Making rect (%u, %u)\n", _fullWidth, height); + _screenRect = CGRectMake(0, 0, _fullWidth - 1, height - 1); [screenLayer setFrame: _screenRect]; - CGRect keyFrame = CGRectMake(0.0f, _screenRect.size.height, _fullWidth, _fullHeight - _screenRect.size.height); + //CGRect keyFrame = CGRectMake(0.0f, _screenRect.size.height, _fullWidth, _fullHeight - _screenRect.size.height); + CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f); if (_keyboardView == nil) { _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame]; [_keyboardView setInputDelegate:self]; @@ -250,9 +249,6 @@ bool getLocalMouseCoords(CGPoint *point) { [self lock]; id event = [_events objectAtIndex: 0]; - if (event == nil) { - return nil; - } [_events removeObjectAtIndex: 0]; [self unlock]; diff --git a/backends/platform/iphone/osys_iphone.cpp b/backends/platform/iphone/osys_iphone.cpp index 3d5571cf3a..521e91a87e 100644 --- a/backends/platform/iphone/osys_iphone.cpp +++ b/backends/platform/iphone/osys_iphone.cpp @@ -56,24 +56,27 @@ const OSystem::GraphicsMode OSystem_IPHONE::s_supportedGraphicsModes[] = { AQCallbackStruct OSystem_IPHONE::s_AudioQueue; SoundProc OSystem_IPHONE::s_soundCallback = NULL; void *OSystem_IPHONE::s_soundParam = NULL; -bool OSystem_IPHONE::s_is113OrHigher = false; OSystem_IPHONE::OSystem_IPHONE() : _savefile(NULL), _mixer(NULL), _timer(NULL), _offscreen(NULL), _overlayVisible(false), _overlayBuffer(NULL), _fullscreen(NULL), _mouseHeight(0), _mouseWidth(0), _mouseBuf(NULL), _lastMouseTap(0), _secondaryTapped(false), _lastSecondaryTap(0), _screenOrientation(kScreenOrientationFlippedLandscape), - _needEventRestPeriod(false), _mouseClickAndDragEnabled(false), + _needEventRestPeriod(false), _mouseClickAndDragEnabled(false), _touchpadModeEnabled(false), _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), - _mouseDirty(false), _timeSuspended(0) + _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1) + { _queuedInputEvent.type = (Common::EventType)0; _lastDrawnMouseRect = Common::Rect(0, 0, 0, 0); + + _fsFactory = new POSIXFilesystemFactory(); } OSystem_IPHONE::~OSystem_IPHONE() { AudioQueueDispose(s_AudioQueue.queue, true); + delete _fsFactory; delete _savefile; delete _mixer; delete _timer; @@ -665,8 +668,8 @@ bool OSystem_IPHONE::pollEvent(Common::Event &event) { float xUnit, yUnit; if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit)) { - int x; - int y; + int x = 0; + int y = 0; switch (_screenOrientation) { case kScreenOrientationPortrait: x = (int)(xUnit * _screenWidth); @@ -684,334 +687,436 @@ bool OSystem_IPHONE::pollEvent(Common::Event &event) { switch ((InputEvent)eventType) { case kInputMouseDown: - //printf("Mouse down at (%u, %u)\n", x, y); - - // Workaround: kInputMouseSecondToggled isn't always sent when the - // secondary finger is lifted. Need to make sure we get out of that mode. - _secondaryTapped = false; - - warpMouse(x, y); - // event.type = Common::EVENT_MOUSEMOVE; - // event.mouse.x = _mouseX; - // event.mouse.y = _mouseY; - - if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; - return true; - } else { - _lastMouseDown = curTime; - } - return false; + if (!handleEvent_mouseDown(event, x, y)) + return false; break; - case kInputMouseUp: - //printf("Mouse up at (%u, %u)\n", x, y); - if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; - } else { - if (curTime - _lastMouseDown < 250) { - event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; - - _queuedInputEvent.type = Common::EVENT_LBUTTONUP; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; - _lastMouseTap = curTime; - _needEventRestPeriod = true; - } else - return false; - } + case kInputMouseUp: + if (!handleEvent_mouseUp(event, x, y)) + return false; break; + case kInputMouseDragged: - //printf("Mouse dragged at (%u, %u)\n", x, y); - if (_secondaryTapped) { - if (_gestureStartX == -1 || _gestureStartY == -1) { - return false; - } - - int vecX = (x - _gestureStartX); - int vecY = (y - _gestureStartY); - int lengthSq = vecX * vecX + vecY * vecY; - //printf("Lengthsq: %u\n", lengthSq); - - if (lengthSq > 15000) { // Long enough gesture to react upon. - _gestureStartX = -1; - _gestureStartY = -1; - - float vecLength = sqrt(lengthSq); - float vecXNorm = vecX / vecLength; - float vecYNorm = vecY / vecLength; - - //printf("Swipe vector: (%.2f, %.2f)\n", vecXNorm, vecYNorm); - - if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm > 0.75) { - // Swipe down - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; - - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_F5; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_F5; - _needEventRestPeriod = true; - } else if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm < -0.75) { - // Swipe up - _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; - const char *dialogMsg; - if (_mouseClickAndDragEnabled) - dialogMsg = "Mouse-click-and-drag mode enabled."; - else - dialogMsg = "Mouse-click-and-drag mode disabled."; - GUI::TimedMessageDialog dialog(dialogMsg, 1500); - dialog.runModal(); - return false; - } else if (vecXNorm > 0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) { - // Swipe right - // _secondaryTapped = !_secondaryTapped; - // _gestureStartX = x; - // _gestureStartY = y; - // - // GUI::TimedMessageDialog dialog("Forcing toggle of pressed state.", 1500); - // dialog.runModal(); - return false; - } else if (vecXNorm < -0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) { - // Swipe left - return false; - } else - return false; - } else - return false; - } else { - event.type = Common::EVENT_MOUSEMOVE; - event.mouse.x = x; - event.mouse.y = y; - warpMouse(x, y); - } + if (!handleEvent_mouseDragged(event, x, y)) + return false; break; + case kInputMouseSecondToggled: _secondaryTapped = !_secondaryTapped; //printf("Mouse second at (%u, %u). State now %s.\n", x, y, _secondaryTapped ? "on" : "off"); if (_secondaryTapped) { - _lastSecondaryDown = curTime; - _gestureStartX = x; - _gestureStartY = y; - if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; - - _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; - } - else + if (!handleEvent_secondMouseDown(event, x, y)) return false; } else { - if (curTime - _lastSecondaryDown < 250 ) { - if (curTime - _lastSecondaryTap < 250 && !_overlayVisible) { - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; - - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; - _needEventRestPeriod = true; - _lastSecondaryTap = 0; - } else if (!_mouseClickAndDragEnabled) { - event.type = Common::EVENT_RBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; - _queuedInputEvent.type = Common::EVENT_RBUTTONUP; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; - _lastSecondaryTap = curTime; - _needEventRestPeriod = true; - } - } - if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_RBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; - } - } - break; - case kInputOrientationChanged: - //printf("Orientation: %i", (int)xUnit); - - ScreenOrientation newOrientation; - switch ((int)xUnit) { - case 1: - newOrientation = kScreenOrientationPortrait; - break; - case 3: - newOrientation = kScreenOrientationLandscape; - break; - case 4: - newOrientation = kScreenOrientationFlippedLandscape; - break; - default: + if (!handleEvent_secondMouseUp(event, x, y)) return false; } + break; - - if (_screenOrientation != newOrientation) { - _screenOrientation = newOrientation; - if (_screenOrientation != kScreenOrientationPortrait) - iPhone_initSurface(_screenHeight, _screenWidth, true); - else - iPhone_initSurface(_screenWidth, _screenHeight, false); - - dirtyFullScreen(); - updateScreen(); - } + case kInputOrientationChanged: + handleEvent_orientationChanged((int)xUnit); + return false; break; case kInputApplicationSuspended: suspendLoop(); + return false; break; - case kInputKeyPressed: { - int keyPressed = (int)xUnit; - int ascii = keyPressed; - //printf("key: %i\n", keyPressed); - - // We remap some of the iPhone keyboard keys. - // The first ten here are the row of symbols below the numeric keys. - switch (keyPressed) { - case 45: - keyPressed = Common::KEYCODE_F1; - ascii = Common::ASCII_F1; - break; - case 47: - keyPressed = Common::KEYCODE_F2; - ascii = Common::ASCII_F2; - break; - case 58: - keyPressed = Common::KEYCODE_F3; - ascii = Common::ASCII_F3; - break; - case 59: - keyPressed = Common::KEYCODE_F4; - ascii = Common::ASCII_F4; - break; - case 40: - keyPressed = Common::KEYCODE_F5; - ascii = Common::ASCII_F5; - break; - case 41: - keyPressed = Common::KEYCODE_F6; - ascii = Common::ASCII_F6; - break; - case 36: - keyPressed = Common::KEYCODE_F7; - ascii = Common::ASCII_F7; - break; - case 38: - keyPressed = Common::KEYCODE_F8; - ascii = Common::ASCII_F8; - break; - case 64: - keyPressed = Common::KEYCODE_F9; - ascii = Common::ASCII_F9; - break; - case 34: - keyPressed = Common::KEYCODE_F10; - ascii = Common::ASCII_F10; - break; - case 10: - keyPressed = Common::KEYCODE_RETURN; - ascii = Common::ASCII_RETURN; - break; - } - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; + case kInputKeyPressed: + handleEvent_keyPressed(event, (int)xUnit); + break; - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii; - _needEventRestPeriod = true; + case kInputSwipe: + if (!handleEvent_swipe(event, (int)xUnit)) + return false; break; - } - case kInputSwipe: { - Common::KeyCode keycode = Common::KEYCODE_INVALID; - switch (_screenOrientation) { - case kScreenOrientationPortrait: - switch ((UIViewSwipeDirection)xUnit) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_UP; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_DOWN; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_RIGHT; - break; - default: - return false; - } - break; - case kScreenOrientationLandscape: - switch ((UIViewSwipeDirection)xUnit) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_RIGHT; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_DOWN; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_UP; - break; - default: - return false; - } - break; - case kScreenOrientationFlippedLandscape: - switch ((UIViewSwipeDirection)xUnit) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_RIGHT; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_UP; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_DOWN; - break; - default: - return false; - } - break; - } + default: + break; + } + + return true; + } + return false; +} + +bool OSystem_IPHONE::handleEvent_mouseDown(Common::Event &event, int x, int y) { + printf("Mouse down at (%u, %u)\n", x, y); + + // Workaround: kInputMouseSecondToggled isn't always sent when the + // secondary finger is lifted. Need to make sure we get out of that mode. + _secondaryTapped = false; + + if (_touchpadModeEnabled) { + _lastPadX = x; + _lastPadY = y; + } else + warpMouse(x, y); + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + return true; + } else { + _lastMouseDown = getMillis(); + } + return false; +} + +bool OSystem_IPHONE::handleEvent_mouseUp(Common::Event &event, int x, int y) { + //printf("Mouse up at (%u, %u)\n", x, y); + + if (_secondaryTapped) { + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, x, y)) + return false; + } + else if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + } else { + if (getMillis() - _lastMouseDown < 250) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + + _queuedInputEvent.type = Common::EVENT_LBUTTONUP; + _queuedInputEvent.mouse.x = _mouseX; + _queuedInputEvent.mouse.y = _mouseY; + _lastMouseTap = getMillis(); + _needEventRestPeriod = true; + } else + return false; + } + + return true; +} + +bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, int y) { + _lastSecondaryDown = getMillis(); + _gestureStartX = x; + _gestureStartY = y; + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + + _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.mouse.x = _mouseX; + _queuedInputEvent.mouse.y = _mouseY; + } + else + return false; + + return true; +} + +bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int y) { + int curTime = getMillis(); + + if (curTime - _lastSecondaryDown < 400 ) { + //printf("Right tap!\n"); + if (curTime - _lastSecondaryTap < 400 && !_overlayVisible) { + //printf("Right escape!\n"); + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + _needEventRestPeriod = true; + _lastSecondaryTap = 0; + } else if (!_mouseClickAndDragEnabled) { + //printf("Rightclick!\n"); + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedInputEvent.mouse.x = _mouseX; + _queuedInputEvent.mouse.y = _mouseY; + _lastSecondaryTap = curTime; + _needEventRestPeriod = true; + } else { + //printf("Right nothing!\n"); + return false; + } + } + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + } + + return true; +} + +bool OSystem_IPHONE::handleEvent_mouseDragged(Common::Event &event, int x, int y) { + if (_lastDragPosX == x && _lastDragPosY == y) + return false; + + _lastDragPosX = x; + _lastDragPosY = y; + + //printf("Mouse dragged at (%u, %u)\n", x, y); + if (_secondaryTapped) { + if (_gestureStartX == -1 || _gestureStartY == -1) { + return false; + } + + int vecX = (x - _gestureStartX); + int vecY = (y - _gestureStartY); + int lengthSq = vecX * vecX + vecY * vecY; + //printf("Lengthsq: %u\n", lengthSq); + + if (lengthSq > 15000) { // Long enough gesture to react upon. + _gestureStartX = -1; + _gestureStartY = -1; + + float vecLength = sqrt(lengthSq); + float vecXNorm = vecX / vecLength; + float vecYNorm = vecY / vecLength; + + //printf("Swipe vector: (%.2f, %.2f)\n", vecXNorm, vecYNorm); - event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; + if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm > 0.75) { + // Swipe down event.type = Common::EVENT_KEYDOWN; _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_F5; _needEventRestPeriod = true; - break; - } + } else if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm < -0.75) { + // Swipe up + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) + dialogMsg = "Mouse-click-and-drag mode enabled."; + else + dialogMsg = "Mouse-click-and-drag mode disabled."; + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; - default: - break; + } else if (vecXNorm > 0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = "Touchpad mode enabled."; + else + dialogMsg = "Touchpad mode disabled."; + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + + } else if (vecXNorm < -0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) { + // Swipe left + return false; + } else + return false; + } else + return false; + } else { + int mouseNewPosX; + int mouseNewPosY; + if (_touchpadModeEnabled ) { + int deltaX = _lastPadX - x; + int deltaY = _lastPadY - y; + _lastPadX = x; + _lastPadY = y; + + mouseNewPosX = (int)(_mouseX - deltaX / 0.5f); + mouseNewPosY = (int)(_mouseY - deltaY / 0.5f); + + if (mouseNewPosX < 0) + mouseNewPosX = 0; + else if (mouseNewPosX > _screenWidth) + mouseNewPosX = _screenWidth; + + if (mouseNewPosY < 0) + mouseNewPosY = 0; + else if (mouseNewPosY > _screenHeight) + mouseNewPosY = _screenHeight; + + } else { + mouseNewPosX = x; + mouseNewPosY = y; } + + event.type = Common::EVENT_MOUSEMOVE; + event.mouse.x = mouseNewPosX; + event.mouse.y = mouseNewPosY; + warpMouse(mouseNewPosX, mouseNewPosY); + } + + return true; +} - return true; +void OSystem_IPHONE::handleEvent_orientationChanged(int orientation) { + //printf("Orientation: %i\n", orientation); + + ScreenOrientation newOrientation; + switch (orientation) { + case 1: + newOrientation = kScreenOrientationPortrait; + break; + case 3: + newOrientation = kScreenOrientationLandscape; + break; + case 4: + newOrientation = kScreenOrientationFlippedLandscape; + break; + default: + return; } - return false; + + + if (_screenOrientation != newOrientation) { + _screenOrientation = newOrientation; + if (_screenOrientation != kScreenOrientationPortrait) + iPhone_initSurface(_screenHeight, _screenWidth, true); + else + iPhone_initSurface(_screenWidth, _screenHeight, false); + + dirtyFullScreen(); + updateScreen(); + } +} + +void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPressed) { + int ascii = keyPressed; + //printf("key: %i\n", keyPressed); + + // We remap some of the iPhone keyboard keys. + // The first ten here are the row of symbols below the numeric keys. + switch (keyPressed) { + case 45: + keyPressed = Common::KEYCODE_F1; + ascii = Common::ASCII_F1; + break; + case 47: + keyPressed = Common::KEYCODE_F2; + ascii = Common::ASCII_F2; + break; + case 58: + keyPressed = Common::KEYCODE_F3; + ascii = Common::ASCII_F3; + break; + case 59: + keyPressed = Common::KEYCODE_F4; + ascii = Common::ASCII_F4; + break; + case 40: + keyPressed = Common::KEYCODE_F5; + ascii = Common::ASCII_F5; + break; + case 41: + keyPressed = Common::KEYCODE_F6; + ascii = Common::ASCII_F6; + break; + case 36: + keyPressed = Common::KEYCODE_F7; + ascii = Common::ASCII_F7; + break; + case 38: + keyPressed = Common::KEYCODE_F8; + ascii = Common::ASCII_F8; + break; + case 64: + keyPressed = Common::KEYCODE_F9; + ascii = Common::ASCII_F9; + break; + case 34: + keyPressed = Common::KEYCODE_F10; + ascii = Common::ASCII_F10; + break; + case 10: + keyPressed = Common::KEYCODE_RETURN; + ascii = Common::ASCII_RETURN; + break; + } + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii; + _needEventRestPeriod = true; +} + +bool OSystem_IPHONE::handleEvent_swipe(Common::Event &event, int direction) { + Common::KeyCode keycode = Common::KEYCODE_INVALID; + switch (_screenOrientation) { + case kScreenOrientationPortrait: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_RIGHT; + break; + default: + return false; + } + break; + case kScreenOrientationLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_UP; + break; + default: + return false; + } + break; + case kScreenOrientationFlippedLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_DOWN; + break; + default: + return false; + } + break; + } + + event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _needEventRestPeriod = true; + + return true; } void OSystem_IPHONE::suspendLoop() { @@ -1020,16 +1125,17 @@ void OSystem_IPHONE::suspendLoop() { float xUnit, yUnit; uint32 startTime = getMillis(); - AudioQueueStop(s_AudioQueue.queue, true); - + stopSoundsystem(); + while (!done) { if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit)) if ((InputEvent)eventType == kInputApplicationResumed) done = true; usleep(100000); } + + startSoundsystem(); - AudioQueueStart(s_AudioQueue.queue, NULL); _timeSuspended += getMillis() - startTime; } @@ -1107,7 +1213,10 @@ void OSystem_IPHONE::setupMixer() { s_soundCallback = mixCallback; s_soundParam = this; + startSoundsystem(); +} +void OSystem_IPHONE::startSoundsystem() { s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE; s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM; s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; @@ -1147,6 +1256,17 @@ void OSystem_IPHONE::setupMixer() { _mixer->setReady(true); } +void OSystem_IPHONE::stopSoundsystem() { + AudioQueueStop(s_AudioQueue.queue, true); + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueDispose(s_AudioQueue.queue, true); + _mixer->setReady(false); +} + int OSystem_IPHONE::getOutputSampleRate() const { return AUDIO_SAMPLE_RATE; } @@ -1196,29 +1316,6 @@ const char* OSystem_IPHONE::getConfigPath() { return SCUMMVM_PREFS_PATH; } -void OSystem_IPHONE::migrateApp() { - // Migrate to the new 1.1.3 directory structure, if needed. - - FilesystemNode file("/var/mobile"); - if (file.exists() && file.isDirectory()) { - // We have 1.1.3 or above. - s_is113OrHigher = true; - file = FilesystemNode(SCUMMVM_ROOT_PATH); - if (!file.exists()) { - system("mkdir " SCUMMVM_ROOT_PATH); - system("mkdir " SCUMMVM_SAVE_PATH); - - // Copy over the prefs file - system("cp " SCUMMVM_OLD_PREFS_PATH " " SCUMMVM_PREFS_PATH); - - file = FilesystemNode(SCUMMVM_OLD_SAVE_PATH); - // Copy over old savegames to the new directory. - if (file.exists() && file.isDirectory()) - system("cp " SCUMMVM_OLD_SAVE_PATH "/* " SCUMMVM_SAVE_PATH "/"); - } - } -} - void iphone_main(int argc, char *argv[]) { //OSystem_IPHONE::migrateApp(); @@ -1239,6 +1336,8 @@ void iphone_main(int argc, char *argv[]) { system("mkdir " SCUMMVM_ROOT_PATH); system("mkdir " SCUMMVM_SAVE_PATH); + chdir("/var/mobile/"); + g_system = OSystem_IPHONE_create(); assert(g_system); diff --git a/backends/platform/iphone/osys_iphone.h b/backends/platform/iphone/osys_iphone.h index c058686c8c..a9a3ddad65 100644 --- a/backends/platform/iphone/osys_iphone.h +++ b/backends/platform/iphone/osys_iphone.h @@ -35,14 +35,12 @@ #include <AudioToolbox/AudioQueue.h> #define AUDIO_BUFFERS 3 -#define WAVE_BUFFER_SIZE 8192 +#define WAVE_BUFFER_SIZE 2048 #define AUDIO_SAMPLE_RATE 44100 #define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM" #define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames" -#define SCUMMVM_OLD_SAVE_PATH "/var/root/.scummvm" #define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences" -#define SCUMMVM_OLD_PREFS_PATH "/var/root/.scummvmrc" typedef void (*SoundProc)(void *param, byte *buf, int len); typedef int (*TimerProc)(int interval); @@ -61,7 +59,6 @@ protected: static AQCallbackStruct s_AudioQueue; static SoundProc s_soundCallback; static void *s_soundParam; - static bool s_is113OrHigher; Common::SaveFileManager *_savefile; Audio::MixerImpl *_mixer; @@ -97,6 +94,11 @@ protected: long _lastSecondaryTap; int _gestureStartX, _gestureStartY; bool _mouseClickAndDragEnabled; + bool _touchpadModeEnabled; + int _lastPadX; + int _lastPadY; + int _lastDragPosX; + int _lastDragPosY; int _timerCallbackNext; int _timerCallbackTimer; @@ -106,6 +108,8 @@ protected: ScreenOrientation _screenOrientation; bool _fullScreenIsDirty; + FilesystemFactory *_fsFactory; + public: OSystem_IPHONE(); @@ -161,7 +165,7 @@ public: virtual void quit(); - FilesystemFactory *getFilesystemFactory() { return &POSIXFilesystemFactory::instance(); } + FilesystemFactory *getFilesystemFactory() { return _fsFactory; } virtual void getTimeAndDate(struct tm &t) const; virtual void setWindowCaption(const char *caption); @@ -170,7 +174,9 @@ public: virtual Audio::Mixer *getMixer(); virtual Common::TimerManager *getTimerManager(); - static void migrateApp(); + void startSoundsystem(); + void stopSoundsystem(); + static const char* getConfigPath(); protected: @@ -182,6 +188,18 @@ protected: void suspendLoop(); static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); static int timerHandler(int t); + + bool handleEvent_swipe(Common::Event &event, int direction); + void handleEvent_keyPressed(Common::Event &event, int keyPressed); + void handleEvent_orientationChanged(int orientation); + + bool handleEvent_mouseDown(Common::Event &event, int x, int y); + bool handleEvent_mouseUp(Common::Event &event, int x, int y); + + bool handleEvent_secondMouseDown(Common::Event &event, int x, int y); + bool handleEvent_secondMouseUp(Common::Event &event, int x, int y); + + bool handleEvent_mouseDragged(Common::Event &event, int x, int y); }; #endif diff --git a/backends/platform/null/null.cpp b/backends/platform/null/null.cpp index 463e9d7b2d..610f1d3a42 100644 --- a/backends/platform/null/null.cpp +++ b/backends/platform/null/null.cpp @@ -50,13 +50,12 @@ #include "backends/fs/windows/windows-fs-factory.h" #endif - - class OSystem_NULL : public OSystem { protected: Common::SaveFileManager *_savefile; Audio::MixerImpl *_mixer; Common::TimerManager *_timer; + FilesystemFactory *_fsFactory; timeval _startTime; public: @@ -133,12 +132,23 @@ OSystem_NULL::OSystem_NULL() { _savefile = 0; _mixer = 0; _timer = 0; + + #if defined(__amigaos4__) + _fsFactory = new AmigaOSFilesystemFactory(); + #elif defined(UNIX) + _fsFactory = new POSIXFilesystemFactory(); + #elif defined(WIN32) + _fsFactory = new WindowsFilesystemFactory(); + #else + #error Unknown and unsupported FS backend + #endif } OSystem_NULL::~OSystem_NULL() { delete _savefile; delete _mixer; delete _timer; + delete _fsFactory; } void OSystem_NULL::initBackend() { @@ -194,11 +204,11 @@ void OSystem_NULL::initSize(uint width, uint height) { } int16 OSystem_NULL::getHeight() { - return 320; + return 200; } int16 OSystem_NULL::getWidth() { - return 200; + return 320; } void OSystem_NULL::setPalette(const byte *colors, uint start, uint num) { @@ -327,18 +337,9 @@ void OSystem_NULL::getTimeAndDate(struct tm &t) const { } FilesystemFactory *OSystem_NULL::getFilesystemFactory() { - #if defined(__amigaos4__) - return &AmigaOSFilesystemFactory::instance(); - #elif defined(UNIX) - return &POSIXFilesystemFactory::instance(); - #elif defined(WIN32) - return &WindowsFilesystemFactory::instance(); - #else - #error Unknown and unsupported backend in OSystem_NULL::getFilesystemFactory - #endif + return _fsFactory; } - OSystem *OSystem_NULL_create() { return new OSystem_NULL(); } diff --git a/backends/platform/ps2/rawsavefile.cpp b/backends/platform/ps2/rawsavefile.cpp index 03270ea9ce..aa3cc57fe7 100644 --- a/backends/platform/ps2/rawsavefile.cpp +++ b/backends/platform/ps2/rawsavefile.cpp @@ -31,6 +31,7 @@ RawReadFile::RawReadFile(McAccess *mcAccess) { _size = -1; _pos = 0; _buf = NULL; + _eof = false; } RawReadFile::~RawReadFile(void) { @@ -79,12 +80,16 @@ int RawReadFile::bufSeek(int ofs, int whence) { _pos = 0; else if (_pos > _size) _pos = _size; + + _eof = false; return _pos; } int RawReadFile::bufRead(void *dest, int size) { - if (_pos + size > _size) + if (_pos + size > _size) { size = _size - _pos; + _eof = true; + } memcpy(dest, _buf + _pos, size); _pos += size; return size; @@ -94,7 +99,13 @@ int RawReadFile::bufSize(void) const { return _size; } +bool RawReadFile::bufEof(void) const { + return _eof; +} +void RawReadFile::bufClearErr(void) const { + _eof = false; +} RawWriteFile::RawWriteFile(McAccess *mcAccess) { _mcAccess = mcAccess; diff --git a/backends/platform/ps2/rawsavefile.h b/backends/platform/ps2/rawsavefile.h index b638d106ab..8e0dba4ab9 100644 --- a/backends/platform/ps2/rawsavefile.h +++ b/backends/platform/ps2/rawsavefile.h @@ -40,11 +40,14 @@ public: int bufTell(void) const; int bufSeek(int ofs, int whence); int bufSize(void) const; + bool bufEof(void) const; + void bufClearErr(void); protected: McAccess *_mcAccess; int _size; uint8 *_buf; int _pos; + bool _eof; }; class RawWriteFile { diff --git a/backends/platform/ps2/savefile.cpp b/backends/platform/ps2/savefile.cpp index 5ee724cd3f..bfcaf0f57f 100644 --- a/backends/platform/ps2/savefile.cpp +++ b/backends/platform/ps2/savefile.cpp @@ -71,7 +71,7 @@ uint32 AutoSaveFile::write(const void *ptr, uint32 size) { UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess *mcAccess) : RawReadFile(mcAccess) { _screen = screen; - _ioFailed = true; + _err = true; if (bufOpen(filename)) { if ((_size > 8) && (*(uint32 *)_buf == UCL_MAGIC)) { @@ -82,13 +82,13 @@ UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess free(_buf); _buf = decBuf; _size = resSize; - _ioFailed = false; + _err = false; _pos = 0; } else free(decBuf); } } - if (_ioFailed) { + if (_err) { if (_buf) free(_buf); _buf = NULL; @@ -100,36 +100,39 @@ UclInSaveFile::~UclInSaveFile(void) { _screen->wantAnim(false); } -bool UclInSaveFile::ioFailed(void) const { - return _ioFailed; +bool UclInSaveFile::err(void) const { + return _err; } -void UclInSaveFile::clearIOFailed(void) { - _ioFailed = false; +void UclInSaveFile::clearErr(void) { + _err = false; + bufClearErr(); } bool UclInSaveFile::eos(void) const { - return bufTell() == bufSize(); + return bufEof(); } -uint32 UclInSaveFile::pos(void) const { +int32 UclInSaveFile::pos(void) const { return bufTell(); } -uint32 UclInSaveFile::size(void) const { +int32 UclInSaveFile::size(void) const { return bufSize(); } -void UclInSaveFile::seek(int pos, int whence) { +bool UclInSaveFile::seek(int pos, int whence) { bufSeek(pos, whence); + return true; } uint32 UclInSaveFile::read(void *ptr, uint32 size) { return (uint32)bufRead(ptr, (int)size); } -void UclInSaveFile::skip(uint32 offset) { +bool UclInSaveFile::skip(uint32 offset) { bufSeek(offset, SEEK_CUR); + return true; } UclOutSaveFile::UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc) : RawWriteFile(mc) { @@ -137,7 +140,7 @@ UclOutSaveFile::UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dSc _system = system; strcpy(_fileName, filename); - _ioFailed = !bufOpen(filename); + _err = !bufOpen(filename); _wasFlushed = false; } @@ -146,7 +149,7 @@ UclOutSaveFile::~UclOutSaveFile(void) { if (_pos != 0) { printf("Engine didn't call SaveFile::flush()\n"); flush(); - if (ioFailed()) { + if (err()) { // unable to save to memory card and it's too late to return an error code to the engine _system->msgPrintf(5000, "!WARNING!\nCan't write to memory card.\nGame was NOT saved."); printf("~UclOutSaveFile: Flush failed!\n"); @@ -160,20 +163,20 @@ uint32 UclOutSaveFile::write(const void *ptr, uint32 size) { return size; } -bool UclOutSaveFile::ioFailed(void) const { - return _ioFailed; +bool UclOutSaveFile::err(void) const { + return _err; } -void UclOutSaveFile::clearIOFailed(void) { - _ioFailed = false; +void UclOutSaveFile::clearErr(void) { + _err = false; } -void UclOutSaveFile::flush(void) { +bool UclOutSaveFile::flush(void) { if (_pos != 0) { if (_wasFlushed) { printf("Multiple calls to UclOutSaveFile::flush!\n"); - _ioFailed = true; - return; + _err = true; + return false; } uint32 compSize = _pos * 2; uint8 *compBuf = (uint8*)memalign(64, compSize + 8); @@ -188,11 +191,12 @@ void UclOutSaveFile::flush(void) { _pos = compSize + 8; if (!bufFlush()) { printf("UclOutSaveFile::flush failed!\n"); - _ioFailed = true; + _err = true; removeFile(); } _wasFlushed = true; } + return true; } /* ----------------------------------------- Glue Classes for POSIX Memory Card Access ----------------------------------------- */ @@ -216,11 +220,11 @@ uint32 Ps2McReadFile::write(const void *src, uint32 len) { return 0; } -uint32 Ps2McReadFile::tell(void) { +int32 Ps2McReadFile::tell(void) { return bufTell(); } -uint32 Ps2McReadFile::size(void) { +int32 Ps2McReadFile::size(void) { return bufSize(); } @@ -253,11 +257,11 @@ uint32 Ps2McWriteFile::write(const void *src, uint32 len) { return len; } -uint32 Ps2McWriteFile::tell(void) { +int32 Ps2McWriteFile::tell(void) { return bufTell(); } -uint32 Ps2McWriteFile::size(void) { +int32 Ps2McWriteFile::size(void) { return bufTell(); } @@ -267,6 +271,3 @@ int Ps2McWriteFile::seek(int32 offset, int origin) { return 0; } -bool Ps2McWriteFile::eof(void) { - return true; -} diff --git a/backends/platform/ps2/savefile.h b/backends/platform/ps2/savefile.h index 4832b8c3fe..0c0cf922f4 100644 --- a/backends/platform/ps2/savefile.h +++ b/backends/platform/ps2/savefile.h @@ -41,14 +41,14 @@ public: UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc); virtual ~UclOutSaveFile(void); virtual uint32 write(const void *ptr, uint32 size); - virtual void flush(void); - virtual bool ioFailed(void) const; - virtual void clearIOFailed(void); + virtual bool flush(void); + virtual bool err(void) const; + virtual void clearErr(void); private: OSystem_PS2 *_system; Gs2dScreen *_screen; - bool _ioFailed, _wasFlushed; + bool _err, _wasFlushed; char _fileName[128]; }; @@ -58,16 +58,16 @@ public: virtual ~UclInSaveFile(void); virtual bool eos(void) const; virtual uint32 read(void *ptr, uint32 size); - virtual bool ioFailed(void) const; - virtual void clearIOFailed(void); - virtual void skip(uint32 offset); + virtual bool err(void) const; + virtual void clearErr(void); + virtual bool skip(uint32 offset); - virtual uint32 pos(void) const; - virtual uint32 size(void) const; - virtual void seek(int pos, int whence = SEEK_SET); + virtual int32 pos(void) const; + virtual int32 size(void) const; + virtual bool seek(int pos, int whence = SEEK_SET); private: Gs2dScreen *_screen; - bool _ioFailed; + bool _err; }; class AutoSaveFile : public Common::OutSaveFile { @@ -75,9 +75,9 @@ public: AutoSaveFile(Ps2SaveFileManager *saveMan, const char *filename); ~AutoSaveFile(void); virtual uint32 write(const void *ptr, uint32 size); - virtual void flush(void) {} - virtual bool ioFailed(void) { return false; }; - virtual void clearIOFailed(void) {} + virtual bool flush(void) {} + virtual bool err(void) const { return false; } + virtual void clearErr(void) {} private: Ps2SaveFileManager *_saveMan; char _fileName[256]; @@ -95,8 +95,8 @@ public: virtual bool open(const char *name); virtual uint32 read(void *dest, uint32 len); virtual uint32 write(const void *src, uint32 len); - virtual uint32 tell(void); - virtual uint32 size(void); + virtual int32 tell(void); + virtual int32 size(void); virtual int seek(int32 offset, int origin); virtual bool eof(void); }; @@ -108,10 +108,9 @@ public: virtual bool open(const char *name); virtual uint32 read(void *dest, uint32 len); virtual uint32 write(const void *src, uint32 len); - virtual uint32 tell(void); - virtual uint32 size(void); + virtual int32 tell(void); + virtual int32 size(void); virtual int seek(int32 offset, int origin); - virtual bool eof(void); }; #endif // __PS2_SAVEFILE__ diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index 6e9b5980d4..69be0abcb2 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -98,7 +98,20 @@ OSystem_PSP::~OSystem_PSP() { void OSystem_PSP::initBackend() { - _savefile = new DefaultSaveFileManager(); + _savefile = new DefaultSaveFileManager("ms0:/scummvm_savegames"); + + const char *savePath = _savefile->getSavePath().c_str(); + + //check if the save directory exists + SceUID fd = sceIoDopen(savePath); + if (fd < 0) { + //No? then let's create it. + sceIoMkdir(savePath, 0777); + } else { + //it exists, so close it again. + sceIoDclose(fd); + } + _timer = new DefaultTimerManager(); setTimerCallback(&timer_handler, 10); diff --git a/backends/platform/psp/osys_psp_gu.cpp b/backends/platform/psp/osys_psp_gu.cpp index 7e36fe6db0..1aa3bcd438 100644 --- a/backends/platform/psp/osys_psp_gu.cpp +++ b/backends/platform/psp/osys_psp_gu.cpp @@ -94,19 +94,23 @@ OSystem_PSP_GU::OSystem_PSP_GU() { //decompress keyboard data uLongf kbdSize = KBD_DATA_SIZE; keyboard_letters = (unsigned char *)memalign(16, KBD_DATA_SIZE); - assert(Z_OK == uncompress((Bytef *)keyboard_letters, &kbdSize, (const Bytef *)keyboard_letters_compressed, size_keyboard_letters_compressed)); - + if (!uncompress((Bytef *)keyboard_letters, &kbdSize, (const Bytef *)keyboard_letters_compressed, size_keyboard_letters_compressed)) + error("OSystem_PSP_GU: uncompressing keyboard_letters failed"); + kbdSize = KBD_DATA_SIZE; keyboard_letters_shift = (unsigned char *)memalign(16, KBD_DATA_SIZE); - assert(Z_OK == uncompress((Bytef *)keyboard_letters_shift, &kbdSize, (const Bytef *)keyboard_letters_shift_compressed, size_keyboard_letters_shift_compressed)); + if (!uncompress((Bytef *)keyboard_letters_shift, &kbdSize, (const Bytef *)keyboard_letters_shift_compressed, size_keyboard_letters_shift_compressed)) + error("OSystem_PSP_GU: uncompressing keyboard_letters_shift failed"); kbdSize = KBD_DATA_SIZE; keyboard_symbols = (unsigned char *)memalign(16, KBD_DATA_SIZE); - assert(Z_OK == uncompress((Bytef *)keyboard_symbols, &kbdSize, (const Bytef *)keyboard_symbols_compressed, size_keyboard_symbols_compressed)); + if (!uncompress((Bytef *)keyboard_symbols, &kbdSize, (const Bytef *)keyboard_symbols_compressed, size_keyboard_symbols_compressed)) + error("OSystem_PSP_GU: uncompressing keyboard_symbols failed"); kbdSize = KBD_DATA_SIZE; keyboard_symbols_shift = (unsigned char *)memalign(16, KBD_DATA_SIZE); - assert(Z_OK == uncompress((Bytef *)keyboard_symbols_shift, &kbdSize, (const Bytef *)keyboard_symbols_shift_compressed, size_keyboard_symbols_shift_compressed)); + if (!uncompress((Bytef *)keyboard_symbols_shift, &kbdSize, (const Bytef *)keyboard_symbols_shift_compressed, size_keyboard_symbols_shift_compressed)) + error("OSystem_PSP_GU: uncompressing keyboard_symbols_shift failed"); _keyboardVisible = false; _clut = (unsigned short*)(((unsigned int)clut256)|0x40000000); diff --git a/backends/platform/psp/portdefs.h b/backends/platform/psp/portdefs.h index af772230d7..1708a70c74 100644 --- a/backends/platform/psp/portdefs.h +++ b/backends/platform/psp/portdefs.h @@ -43,7 +43,6 @@ #include "trace.h" -#define SCUMMVM_SAVEPATH "ms0:/scummvm_savegames" #define BREAKPOINT asm("break\n") diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp index d2ed59efbe..94ef63488d 100644 --- a/backends/platform/psp/psp_main.cpp +++ b/backends/platform/psp/psp_main.cpp @@ -122,16 +122,6 @@ int main(void) { SetupCallbacks(); - //check if the save directory exists - SceUID fd = sceIoDopen(SCUMMVM_SAVEPATH); - if (fd < 0) { - //No? then let's create it. - sceIoMkdir(SCUMMVM_SAVEPATH, 0777); - } else { - //it exists, so close it again. - sceIoDclose(fd); - } - static char *argv[] = { "scummvm", NULL }; static int argc = sizeof(argv)/sizeof(char *)-1; diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 5c3b87309d..9a6f294a55 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -32,9 +32,9 @@ #endif #include "backends/platform/sdl/sdl.h" +#include "common/archive.h" #include "common/config-manager.h" #include "common/events.h" -#include "common/file.h" #include "common/util.h" #include "backends/saves/default/default-saves.h" @@ -72,6 +72,9 @@ #define DEFAULT_CONFIG_FILE "scummvm.ini" #endif +#if defined(MACOSX) || defined(IPHONE) +#include "CoreFoundation/CoreFoundation.h" +#endif static Uint32 timer_handler(Uint32 interval, void *param) { @@ -196,6 +199,7 @@ OSystem_SDL::OSystem_SDL() _soundMutex(0), _soundCond(0), _soundThread(0), _soundThreadIsRunning(false), _soundThreadShouldQuit(false), #endif + _fsFactory(0), _savefile(0), _mixer(0), _timer(0), @@ -213,6 +217,19 @@ OSystem_SDL::OSystem_SDL() memset(&_mouseCurState, 0, sizeof(_mouseCurState)); _inited = false; + + + #if defined(__amigaos4__) + _fsFactory = new AmigaOSFilesystemFactory(); + #elif defined(UNIX) + _fsFactory = new POSIXFilesystemFactory(); + #elif defined(WIN32) + _fsFactory = new WindowsFilesystemFactory(); + #elif defined(__SYMBIAN32__) + // Do nothing since its handled by the Symbian SDL inheritance + #else + #error Unknown and unsupported FS backend + #endif } OSystem_SDL::~OSystem_SDL() { @@ -254,19 +271,42 @@ Common::SaveFileManager *OSystem_SDL::getSavefileManager() { } FilesystemFactory *OSystem_SDL::getFilesystemFactory() { - #if defined(__amigaos4__) - return &AmigaOSFilesystemFactory::instance(); - #elif defined(UNIX) - return &POSIXFilesystemFactory::instance(); - #elif defined(WIN32) - return &WindowsFilesystemFactory::instance(); - #elif defined(__SYMBIAN32__) - // Do nothing since its handled by the Symbian SDL inheritance - #else - #error Unknown and unsupported backend in OSystem_SDL::getFilesystemFactory - #endif + assert(_fsFactory); + return _fsFactory; +} + +void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, uint priority) { + +#ifdef DATA_PATH + // Add the global DATA_PATH to the directory search list + // FIXME: We use depth = 4 for now, to match the old code. May want to change that + Common::FilesystemNode dataNode(DATA_PATH); + if (dataNode.exists() && dataNode.isDirectory()) { + Common::ArchivePtr dataArchive(new Common::FSDirectory(dataNode, 4)); + s.add(DATA_PATH, dataArchive, priority); + } +#endif + +#if defined(MACOSX) || defined(IPHONE) + // Get URL of the Resource directory of the .app bundle + CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (fileUrl) { + // Try to convert the URL to an absolute path + UInt8 buf[MAXPATHLEN]; + if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { + // Success: Add it to the search path + Common::String bundlePath((const char *)buf); + Common::ArchivePtr bundleArchive(new Common::FSDirectory(bundlePath)); + s.add("__OSX_BUNDLE__", bundleArchive, priority); + } + CFRelease(fileUrl); + } + +#endif + } + static Common::String getDefaultConfigFileName() { char configFile[MAXPATHLEN]; #if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) @@ -292,20 +332,19 @@ static Common::String getDefaultConfigFileName() { CreateDirectory(configFile, NULL); strcat(configFile, "\\" DEFAULT_CONFIG_FILE); - if (fopen(configFile, "r") == NULL) { + FILE *tmp = NULL; + if ((tmp = fopen(configFile, "r")) == NULL) { // Check windows directory char oldConfigFile[MAXPATHLEN]; GetWindowsDirectory(oldConfigFile, MAXPATHLEN); strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE); - if (fopen(oldConfigFile, "r")) { - printf("The default location of the config file (scummvm.ini) in ScummVM has changed,\n"); - printf("under Windows NT4/2000/XP/Vista. You may want to consider moving your config\n"); - printf("file from the old default location:\n"); - printf("%s\n", oldConfigFile); - printf("to the new default location:\n"); - printf("%s\n\n", configFile); + if ((tmp = fopen(oldConfigFile, "r"))) { strcpy(configFile, oldConfigFile); + + fclose(tmp); } + } else { + fclose(tmp); } } else { // Check windows directory @@ -334,23 +373,13 @@ static Common::String getDefaultConfigFileName() { } Common::SeekableReadStream *OSystem_SDL::openConfigFileForReading() { - Common::File *confFile = new Common::File(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + Common::FilesystemNode file(getDefaultConfigFileName()); + return file.openForReading(); } Common::WriteStream *OSystem_SDL::openConfigFileForWriting() { - Common::DumpFile *confFile = new Common::DumpFile(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + Common::FilesystemNode file(getDefaultConfigFileName()); + return file.openForWriting(); } void OSystem_SDL::setWindowCaption(const char *caption) { @@ -435,15 +464,21 @@ void OSystem_SDL::quit() { } void OSystem_SDL::setupIcon() { - int w, h, ncols, nbytes, i; - unsigned int rgba[256], icon[32 * 32]; - unsigned char mask[32][4]; + int x, y, w, h, ncols, nbytes, i; + unsigned int rgba[256]; + unsigned int *icon; sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes); - if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { - warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes); + if ((w > 512) || (h > 512) || (ncols > 255) || (nbytes > 1)) { + warning("Could not load the built-in icon (%d %d %d %d)", w, h, ncols, nbytes); + return; + } + icon = (unsigned int*)malloc(w*h*sizeof(unsigned int)); + if (!icon) { + warning("Could not allocate temp storage for the built-in icon"); return; } + for (i = 0; i < ncols; i++) { unsigned char code; char color[32]; @@ -457,26 +492,27 @@ void OSystem_SDL::setupIcon() { sscanf(color + 1, "%06x", &col); col |= 0xFF000000; } else { - warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); + warning("Could not load the built-in icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); + free(icon); return; } rgba[code] = col; } - memset(mask, 0, sizeof(mask)); - for (h = 0; h < 32; h++) { - const char *line = scummvm_icon[1 + ncols + h]; - for (w = 0; w < 32; w++) { - icon[w + 32 * h] = rgba[(int)line[w]]; - if (rgba[(int)line[w]] & 0xFF000000) { - mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); - } + for (y = 0; y < h; y++) { + const char *line = scummvm_icon[1 + ncols + y]; + for (x = 0; x < w; x++) { + icon[x + w * y] = rgba[(int)line[x]]; } } - SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); - SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask); + SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, w, h, 32, w * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); + if (!sdl_surf) { + warning("SDL_CreateRGBSurfaceFrom(icon) failed"); + } + SDL_WM_SetIcon(sdl_surf, NULL); SDL_FreeSurface(sdl_surf); + free(icon); } OSystem::MutexRef OSystem_SDL::createMutex(void) { @@ -515,7 +551,7 @@ void OSystem_SDL::mixerProducerThread() { // Generate samples and put them into the next buffer nextSoundBuffer = _activeSoundBuf ^ 1; _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize); - + // Swap buffers _activeSoundBuf = nextSoundBuffer; } @@ -559,7 +595,7 @@ void OSystem_SDL::deinitThreadedMixer() { SDL_CondBroadcast(_soundCond); SDL_WaitThread(_soundThread, NULL); - // Kill the mutex & cond variables. + // Kill the mutex & cond variables. // Attention: AT this point, the mixer callback must not be running // anymore, else we will crash! SDL_DestroyMutex(_soundMutex); @@ -582,10 +618,10 @@ void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) { // Lock mutex, to ensure our data is not overwritten by the producer thread SDL_LockMutex(this_->_soundMutex); - + // Copy data from the current sound buffer memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len); - + // Unlock mutex and wake up the produced thread SDL_UnlockMutex(this_->_soundMutex); SDL_CondSignal(this_->_soundCond); @@ -645,7 +681,7 @@ void OSystem_SDL::setupMixer() { // even if it didn't. Probably only happens for "weird" rates, though. _samplesPerSec = obtained.freq; debug(1, "Output sample rate: %d Hz", _samplesPerSec); - + // Tell the mixer that we are ready and start the sound processing _mixer->setOutputRate(_samplesPerSec); _mixer->setReady(true); diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 1c1381ec5c..1cc0acbc29 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -209,6 +209,7 @@ public: virtual Common::SaveFileManager *getSavefileManager(); virtual FilesystemFactory *getFilesystemFactory(); + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, uint priority = 0); virtual Common::SeekableReadStream *openConfigFileForReading(); virtual Common::WriteStream *openConfigFileForWriting(); @@ -400,14 +401,13 @@ protected: void deinitThreadedMixer(); #endif - + FilesystemFactory *_fsFactory; Common::SaveFileManager *_savefile; Audio::MixerImpl *_mixer; SDL_TimerID _timerID; Common::TimerManager *_timer; - protected: void addDirtyRgnAuto(const byte *buf); void makeChecksums(const byte *buf); diff --git a/backends/platform/symbian/AdaptAllMMPs.pl b/backends/platform/symbian/AdaptAllMMPs.pl index b576bb3993..d7b5642f1c 100644 --- a/backends/platform/symbian/AdaptAllMMPs.pl +++ b/backends/platform/symbian/AdaptAllMMPs.pl @@ -27,7 +27,7 @@ chdir("../../../"); "mmp/scummvm_sword1.mmp", "mmp/scummvm_sword2.mmp", "mmp/scummvm_touche.mmp", - + "mmp/scummvm_tinsel.mmp", # Target Platform Project Files "S60/ScummVM_S60.mmp", @@ -83,6 +83,9 @@ my @excludes_graphics = ( "iff.cpp" ); +my @excludes_gui = ( +); + # the USE_ARM_* defines not parsed correctly, exclude manually: my @excludes_scumm = ( ".*ARM.*", # the *ARM.s files are added in .mpp files based on WINS/ARM build! @@ -95,7 +98,7 @@ my @excludes_scumm = ( #arseModule(mmpStr, dirStr, ifdefArray, [exclusionsArray]) ParseModule("_base", "base", \@section_empty); # now in ./TRG/ScummVM_TRG.mmp, these never change anyways... ParseModule("_base", "common", \@section_empty); -ParseModule("_base", "gui", \@section_empty); +ParseModule("_base", "gui", \@section_empty, \@excludes_gui); ParseModule("_base", "graphics", \@section_empty, \@excludes_graphics); ParseModule("_base", "sound", \@section_empty, \@excludes_snd); @@ -103,22 +106,23 @@ chdir("engines/"); ParseModule("_scumm", "scumm", \@sections_scumm, \@excludes_scumm ); ParseModule("_queen", "queen", \@section_empty); ParseModule("_agos", "agos", \@section_empty); -ParseModule("_sky", "sky", \@section_empty); -ParseModule("_gob", "gob", \@section_empty); +ParseModule("_sky", "sky", \@section_empty); +ParseModule("_gob", "gob", \@section_empty); ParseModule("_saga", "saga", \@section_empty); ParseModule("_kyra", "kyra", \@section_empty); ParseModule("_sword1", "sword1", \@section_empty); ParseModule("_sword2", "sword2", \@section_empty); ParseModule("_lure", "lure", \@section_empty); ParseModule("_cine", "cine", \@section_empty); -ParseModule("_agi", "agi", \@section_empty); +ParseModule("_agi", "agi", \@section_empty); ParseModule("_touche", "touche", \@section_empty); ParseModule("_parallaction","parallaction",\@section_empty); ParseModule("_cruise", "cruise", \@section_empty); ParseModule("_drascula","drascula", \@section_empty); ParseModule("_igor", "igor", \@section_empty); ParseModule("_made", "made", \@section_empty); -ParseModule("_m4", "m4", \@section_empty); +ParseModule("_m4", "m4", \@section_empty); +ParseModule("_tinsel", "tinsel", \@section_empty); print " ======================================================================================= Done. Enjoy :P diff --git a/backends/platform/symbian/BuildPackageUpload_AllVersions.pl b/backends/platform/symbian/BuildPackageUpload_AllVersions.pl index 94edbf4fcf..ba8afe5084 100644 --- a/backends/platform/symbian/BuildPackageUpload_AllVersions.pl +++ b/backends/platform/symbian/BuildPackageUpload_AllVersions.pl @@ -443,6 +443,10 @@ my $header = " PrintMessage("Cleaning for $Target") if (!$ReallyQuiet); system("bldmake bldfiles > NUL 2> NUL"); PrintErrorMessage("'bldmake bldfiles' exited with value " . ($? >> 8)) if ($? >> 8); + + system("abld MAKEFILE $TargetName > NUL 2> NUL"); + PrintErrorMessage("'abld MAKEFILE $TargetName' exited with value " . ($? >> 8)) if ($? >> 8); + system("abld CLEAN $TargetName UREL > NUL 2> NUL"); PrintErrorMessage("'abld CLEAN $TargetName urel' exited with value " . ($? >> 8)) if ($? >> 8); # remove file so we are sure that after .lib generation we have a fresh copy! @@ -455,10 +459,10 @@ my $header = " my $OldSize = (-s $build_log_err); $Redirection = ($RedirectSTDERR ? "2>> $build_log_err" : ""); - system("abld BUILD $TargetName UREL $Redirection >> $build_log_out"); + system("abld TARGET $TargetName UREL $Redirection >> $build_log_out"); $OK = 0 if ($? >> 8); # print " STDERR: ".((-s $build_log_err)-$OldSize)." bytes output written to $build_log_err\n+--------------------------------------------------------------------------------------\n" if ($OldSize != (-s $build_log_err)); - PrintErrorMessage("'abld BUILD $TargetName UREL' exited with value " . ($? >> 8)) if ($? >> 8); + PrintErrorMessage("'abld TARGET $TargetName UREL' exited with value " . ($? >> 8)) if ($? >> 8); return 0 if (!$OK); # ABLD always returns ok :( grr PrintMessage("Done.") if (!$ReallyQuiet); @@ -475,7 +479,7 @@ my $header = " } else { - PrintErrorMessage("'abld BUILD $TargetName UREL' apparently failed."); + PrintErrorMessage("'abld TARGET $TargetName UREL' apparently failed."); if ($HaltOnError) { PrintErrorMessage("Halting on error as requested!"); diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl index 12e5f8f0c4..8ba743674d 100644 --- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl +++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl @@ -3,14 +3,15 @@ @WorkingEngines = qw( scumm agos sky queen gob saga drascula - kyra lure agi touche parallaction + kyra lure agi touche parallaction cine + cruise igor made m4 tinsel sword1 sword2 ); + @TestingEngines = qw( - cruise igor made m4 cine + ); - @BrokenEngines = qw( - sword1 - sword2 + + @BrokenEngines = qw( ); @EnablableEngines = (@WorkingEngines, @TestingEngines); @@ -29,20 +30,7 @@ # these are normally enabled for each variation #$DefaultFeatures = qw(zlib,mad); - $DefaultFeatures = qw(zlib,mad,tremor); - - - # you can use these below for speed & clarity or override with custom settings - $DefaultTopMacros = " - MACRO USE_ZLIB // LIB:zlib.lib - MACRO USE_MAD // LIB:libmad.lib - MACRO USE_TREMOR // LIB:libtremor.lib - "; - - $DefaultBottomMacros = " - MACRO DISABLE_SWORD1 // LIB:scummvm_sword1.lib - MACRO DISABLE_SWORD2 // LIB:scummvm_sword2.lib - "; + $DefaultFeatures = qw(zlib,mad,tremor); ################################################################################################################## ## @@ -186,6 +174,44 @@ # now you can add $VariationSets only built on this PC below this line :) } + elsif ($ENV{'COMPUTERNAME'} eq "EMBEDDEV-LAPE") ################################################################# + { + $Producer = "AnotherGuest"; + $RedirectSTDERR = 1; + $HaltOnError = 0; + $SkipExistingPackages = 1; + $ReallyQuiet = 1; + + #$FTP_Host = "host.com"; + #$FTP_User = "ag@host.com"; + #$FTP_Pass = "password"; + #$FTP_Dir = "cvsbuilds"; + + #$SDK_RootDirs{'UIQ2'}= "D:\\UIQ2"; + $SDK_RootDirs{'UIQ3'}= "G:\\UIQ3"; + #$SDK_RootDirs{'S60v1'}= "D:\\S60v1"; + #$SDK_RootDirs{'S60v2'}= "D:\\S60v2"; + $SDK_RootDirs{'S60v3'}= "G:\\S60_3rd_FP1"; + #$SDK_RootDirs{'S80'}= "D:\\S80"; + #$SDK_RootDirs{'S90'}= "D:\\S90"; + $ECompXL_BinDir= "D:\\ECompXL\\"; + if (0) # so we can turn them on/off easily + { +# $SDK_LibraryDirs{'ALL'}{'zlib.lib'} = "C:\\S\\zlib-1.2.2\\epoc"; +# $SDK_LibraryDirs{'ALL'}{'libmad.lib'} = "C:\\S\\libmad-0.15.1b\\group"; +# $SDK_LibraryDirs{'ALL'}{'libtremor.lib'}= "C:\\tremor\\epoc"; + $SDK_LibraryDirs{'UIQ2'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\UIQ"; + $SDK_LibraryDirs{'S60v1'}{'esdl.lib'} = $SDK_LibraryDirs{'S60v2'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S60"; + $SDK_LibraryDirs{'S80'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S80"; + $SDK_LibraryDirs{'S90'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S90"; + $SDK_LibraryDirs{'S60v3'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S60\\S60V3"; + $SDK_LibraryDirs{'UIQ3'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\UIQ\\UIQ3"; + #$SDK_LibraryDirs{'ALL'}{'libmpeg2.lib'} = "C:\\S\\mpeg2dec-0.4.0\\epoc"; + } + + # now you can add $VariationSets only built on this PC below this line :) + + } else ######################################################################################################### { print "ERROR: Computer name ".$ENV{'COMPUTERNAME'}." not recognized! Plz edit _LocalSettings.pl!"; @@ -245,15 +271,11 @@ } # below here you could specify weird & experimental combinations, non-ready engines - # a small version of the saga engine, because it is so big (no tremor,mad,zlib) - #$VariationSets{'ALL'}{'saga_mini'} = "saga"; + # Separate version for the broken sword engines (1&2) + $VariationSets{'ALL'}{'brokensword'} = "$DefaultFeatures sword1 sword2"; - # a smaller version of scumm without support for v7, v8 and HE games - #$VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm"; - - # maybe you feel lucky and want to test the sword engines? :P - #$VariationSets{'S60v2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2"; - #$VariationSets{'UIQ2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2"; + # Separate version for Scumm games (COMI) since memory usage might be high + $VariationSets{'ALL'}{'scumm'} = "$DefaultFeatures scumm scumm_7_8 he"; # for mega-fast-testing only plz! Warning: contains to engines! #$VariationSets{'ALL'}{'fast_empty'} = ""; diff --git a/backends/platform/symbian/README b/backends/platform/symbian/README index db46dae8de..1e011ec4a1 100644 --- a/backends/platform/symbian/README +++ b/backends/platform/symbian/README @@ -8,6 +8,18 @@ Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson $Id$ +Using parts of snprintf.c by +Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000 +Copyright © 1999,2000,2001,2002 Mark Martinec. All rights reserved. +under these conditions: +"Terms and conditions ... + +This program is free software; it is dual licensed, the terms of the "Frontier Artistic License" or +the "GNU General Public License" can be chosen at your discretion. +The chosen license then applies solely and in its entirety. +Both licenses come with this Kit." + + About ScummVM -------------- diff --git a/backends/platform/symbian/S60/ScummVM_S60.mmp.in b/backends/platform/symbian/S60/ScummVM_S60.mmp.in index 099b33ed95..35632d9c95 100644 --- a/backends/platform/symbian/S60/ScummVM_S60.mmp.in +++ b/backends/platform/symbian/S60/ScummVM_S60.mmp.in @@ -93,6 +93,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp SOURCE gui\Actions.cpp +SOURCE gui\Dialog.cpp // Special for graphics source graphics\iff.cpp diff --git a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg index bf3c69ae08..91649727df 100644 --- a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg +++ b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg @@ -16,7 +16,7 @@ ; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ; ; $URL:$ -; $Id:$ +; $Id$ ; ; @@ -28,7 +28,7 @@ ;&EN ; UID is the app's UID -#{"ScummVM S60v1"},(0x101f9b57),0,120,0 +#{"ScummVM S60v1"},(0x101f9b57),0,130,0 ; Platform type (0x101F6F88), 0, 0, 0, {"Series60ProductID"} diff --git a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg index 3f88ec918c..4547af0597 100644 --- a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg +++ b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg @@ -27,7 +27,7 @@ ;&EN ; UID is the app's UID -#{"ScummVM S60v2"},(0x101f9b57),0,120,0 +#{"ScummVM S60v2"},(0x101f9b57),0,130,0 ; Platform type (0x101F6F88), 0, 0, 0, {"Series60ProductID"} diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in index 8daf76138c..fae74a425a 100644 --- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in +++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in @@ -116,6 +116,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp SOURCE gui\Actions.cpp +SOURCE gui\Dialog.cpp // Special for graphics source graphics\iff.cpp diff --git a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg index 6bd1fbd047..1898ac1b58 100644 --- a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg +++ b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg @@ -34,7 +34,7 @@ :"ScummVM" ; UID is the app's UID -#{"ScummVM S60v3"},(0xA0000657),0,120,0 +#{"ScummVM S60v3"},(0xA0000657),0,13,0 ;Supports Series 60 v 3.0 [0x101F7961], 0, 0, 0, {"Series60ProductID"} @@ -63,7 +63,7 @@ "..\..\..\..\dists\engine-data\sky.cpt"-"c:\data\scummvm\sky.cpt" "..\..\..\..\dists\engine-data\igor.tbl"-"c:\data\scummvm\igor.tbl" "..\..\..\..\dists\engine-data\lure.dat"-"c:\data\scummvm\lure.dat" -"..\..\..\..\dists\engine-data\drascula.dat"-"c:\data\drascula.dat" +"..\..\..\..\dists\engine-data\drascula.dat"-"c:\data\scummvm\drascula.dat" ; Config/log files: 'empty' will automagically be removed on uninstall ""-"c:\data\scummvm\scummvm.ini",FILENULL diff --git a/backends/platform/symbian/S80/ScummVM_S80.mmp.in b/backends/platform/symbian/S80/ScummVM_S80.mmp.in index 95879dd2af..1c8076fdc3 100644 --- a/backends/platform/symbian/S80/ScummVM_S80.mmp.in +++ b/backends/platform/symbian/S80/ScummVM_S80.mmp.in @@ -91,6 +91,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp SOURCE gui\Actions.cpp +SOURCE gui\Dialog.cpp // Special for graphics source graphics\iff.cpp diff --git a/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg b/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg index 29e318a479..c6b3e6f82f 100644 --- a/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg +++ b/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg @@ -28,7 +28,7 @@ ;&EN ; UID is the app's UID -#{"ScummVM S80"},(0x101f9b57),0,120,0 +#{"ScummVM S80"},(0x101f9b57),0,130,0 ; Platform type -- disabled: seems to be causing trouble ;(0x101F8ED2), 0, 0, 0, {"Series80ProductID"} diff --git a/backends/platform/symbian/S90/Scummvm_S90.mmp.in b/backends/platform/symbian/S90/Scummvm_S90.mmp.in index 47a3d9a1d4..8ace71b190 100644 --- a/backends/platform/symbian/S90/Scummvm_S90.mmp.in +++ b/backends/platform/symbian/S90/Scummvm_S90.mmp.in @@ -91,6 +91,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp SOURCE gui\Actions.cpp +SOURCE gui\Dialog.cpp // Special for graphics source graphics\iff.cpp diff --git a/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg b/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg index 0173da7699..b578019979 100644 --- a/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg +++ b/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg @@ -28,7 +28,7 @@ ;&EN ; UID is the app's UID -#{"ScummVM S90"},(0x101f9b57),0,120,0 +#{"ScummVM S90"},(0x101f9b57),0,130,0 ; Platform type -- disabled: seems to be causing trouble ;(0x101FBE04), 0, 0, 0, {"Series90ProductID"} diff --git a/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in b/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in index e9dff7b94f..9fab248799 100644 --- a/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in +++ b/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in @@ -89,6 +89,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp SOURCE gui\Actions.cpp +SOURCE gui\Dialog.cpp // Special for graphics source graphics\iff.cpp diff --git a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg index aca927eadd..a8b02d4099 100644 --- a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg +++ b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg @@ -16,7 +16,7 @@ ; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ; ; $URL:$ -; $Id:$ +; $Id$ ; ; @@ -28,7 +28,7 @@ ;&EN ; UID is the app's UID -#{"ScummVM UIQ2"},(0x101f9b57),0,100,0 +#{"ScummVM UIQ2"},(0x101f9b57),0,130,0 ; Platform type (0x101F617B), 2, 0, 0, {"UIQ20ProductID"} diff --git a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg index ecca51bd26..2d08bd01b2 100644 --- a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg +++ b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg @@ -6,7 +6,7 @@ ;&EN ; UID is the app's UID -#{"ScummVM SE"},(0x101f9b57),0,110,0 +#{"ScummVM SE"},(0x101f9b57),0,130,0 ; Platform type (0x101F617B), 2, 0, 0, {"UIQ20ProductID"} diff --git a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in index cf3d0c1d7b..6053a72182 100644 --- a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in +++ b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in @@ -117,6 +117,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp SOURCE gui\Actions.cpp +SOURCE gui\Dialog.cpp // Special for graphics source graphics\iff.cpp diff --git a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg index 0883c88a21..cdeb83f192 100644 --- a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg +++ b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg @@ -32,7 +32,7 @@ :"ScummVM" ; UID is the app's UID -#{"ScummVM UIQ3"},(0xA0000657),0,120,0 +#{"ScummVM UIQ3"},(0xA0000657),0,13,0 ; ProductID for UIQ 3.0 ; Product/platform version UID, Major, Minor, Build, Product ID diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in index d1c8878d4b..3277e34ba3 100644 --- a/backends/platform/symbian/mmp/scummvm_base.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in @@ -85,7 +85,6 @@ SOURCEPATH ..\..\..\..\gui //SOURCE KeysDialog.cpp //SOURCE Actions.cpp - SOURCEPATH ..\..\..\..\sound //START_AUTO_OBJECTS_SOUND_// @@ -108,7 +107,8 @@ SOURCE backends\saves\savefile.cpp SOURCE backends\saves\default\default-saves.cpp SOURCE backends\saves\compressed\compressed-saves.cpp SOURCE engines\engine.cpp - - -// backend specific includes +SOURCE engines\dialogs.cpp +SOURCE backends\fs\abstract-fs.cpp +SOURCE backends\fs\symbian\symbianstream.cpp // backend specific includes + diff --git a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in new file mode 100644 index 0000000000..3f68ec086e --- /dev/null +++ b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in @@ -0,0 +1,56 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL + * Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System + * Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// +// EPOC MMP makefile project for ScummVM +// + +// *** Definitions + +TARGET scummvm_tinsel.lib +TARGETTYPE lib +OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp +OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char +ALWAYS_BUILD_AS_ARM + +//START_AUTO_MACROS_SLAVE// + +// empty base file, will be updated by Perl build scripts + +//STOP_AUTO_MACROS_SLAVE// + +// *** SOURCE files + +SOURCEPATH ..\..\..\..\engines\tinsel + +//START_AUTO_OBJECTS_TINSEL_// + + // empty base file, will be updated by Perl build scripts + +//STOP_AUTO_OBJECTS_TINSEL_// + +// *** Include paths + +USERINCLUDE ..\..\..\..\engines +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/src/SymbianActions.cpp b/backends/platform/symbian/src/SymbianActions.cpp index 60e402632f..e71b242329 100644 --- a/backends/platform/symbian/src/SymbianActions.cpp +++ b/backends/platform/symbian/src/SymbianActions.cpp @@ -153,7 +153,7 @@ void SymbianActions::initInstanceGame() { // Save - if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble) + if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble) _action_enabled[ACTION_SAVE] = false; else { _action_enabled[ACTION_SAVE] = true; diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index 0ce44d1704..23876c5ec1 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -24,10 +24,12 @@ #include <eikenv.h> // for CEikonEnv::Static() @ Symbian::FatalError() #include <sdlapp.h> // for CSDLApp::GetExecutablePathCStr() @ Symbian::GetExecutablePath() +#include <bautils.h> #include "backends/fs/symbian/symbian-fs-factory.h" #include "backends/platform/symbian/src/SymbianOS.h" #include "backends/platform/symbian/src/SymbianActions.h" +#include "backends/saves/default/default-saves.h" #include "common/config-manager.h" #include "common/events.h" #include "common/file.h" @@ -45,16 +47,7 @@ #define DEFAULT_CONFIG_FILE "scummvm.ini" - - -#define KInputBufferLength 128 -// Symbian libc file functionality in order to provide shared file handles -struct TSymbianFileEntry { - RFile iFileHandle; - char iInputBuffer[KInputBufferLength]; - TInt iInputBufferLen; - TInt iInputPos; -}; +#define DEFAULT_SAVE_PATH "Savegames" #define FILE void @@ -123,10 +116,6 @@ void OSystem_SDL_Symbian::setFeatureState(Feature f, bool enable) { } } -FilesystemFactory *OSystem_SDL_Symbian::getFilesystemFactory() { - return &SymbianFilesystemFactory::instance(); -} - static Common::String getDefaultConfigFileName() { char configFile[MAXPATHLEN]; strcpy(configFile, Symbian::GetExecutablePath()); @@ -135,36 +124,48 @@ static Common::String getDefaultConfigFileName() { } Common::SeekableReadStream *OSystem_SDL_Symbian::openConfigFileForReading() { - Common::File *confFile = new Common::File(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + Common::FilesystemNode file(getDefaultConfigFileName()); + return file.openForReading(); } Common::WriteStream *OSystem_SDL_Symbian::openConfigFileForWriting() { - Common::DumpFile *confFile = new Common::DumpFile(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + Common::FilesystemNode file(getDefaultConfigFileName()); + return file.openForWriting(); } - OSystem_SDL_Symbian::zoneDesc OSystem_SDL_Symbian::_zones[TOTAL_ZONES] = { { 0, 0, 320, 145 }, { 0, 145, 150, 55 }, { 150, 145, 170, 55 } }; OSystem_SDL_Symbian::OSystem_SDL_Symbian() :_channels(0),_stereo_mix_buffer(0) { + _RFs = &CEikonEnv::Static()->FsSession(); + _fsFactory = new SymbianFilesystemFactory(); } void OSystem_SDL_Symbian::initBackend() { + // First set the extrapath (for installed dat files etc) ConfMan.set("extrapath", Symbian::GetExecutablePath()); + + // Calculate the default savepath + Common::String savePath; + savePath = Symbian::GetExecutablePath(); + savePath += DEFAULT_SAVE_PATH "\\"; + _savefile = new DefaultSaveFileManager(savePath); + + // If savepath has not already been set then set it + if (!ConfMan.hasKey("savepath")) { + ConfMan.set("savepath", savePath); + + } + + // Ensure that the current set path (might have been altered by the user) exists + Common::String currentPath = ConfMan.get("savepath"); + TFileName fname; + TPtrC8 ptr((const unsigned char*)currentPath.c_str(),currentPath.size()); + fname.Copy(ptr); + BaflUtils::EnsurePathExistsL(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), fname); + ConfMan.setBool("FM_high_quality", false); #if !defined(S60) || defined(S60V3) // S60 has low quality as default ConfMan.setBool("FM_medium_quality", true); @@ -488,223 +489,60 @@ void OSystem_SDL_Symbian::initZones() { } } -FILE* symbian_fopen(const char* name, const char* mode) { - TSymbianFileEntry* fileEntry = new TSymbianFileEntry; - fileEntry->iInputPos = KErrNotFound; - - if (fileEntry != NULL) { - TInt modeLen = strlen(mode); - - TPtrC8 namePtr((unsigned char*) name, strlen(name)); - TFileName tempFileName; - tempFileName.Copy(namePtr); - - TInt fileMode = EFileRead; - - if (mode[0] == 'a') - fileMode = EFileWrite; - - if (!((modeLen > 1 && mode[1] == 'b') || (modeLen > 2 && mode[2] == 'b'))) { - fileMode |= EFileStreamText; - } - - if ((modeLen > 1 && mode[1] == '+') || (modeLen > 2 && mode[2] == '+')) { - fileMode = fileMode| EFileWrite; - } - - fileMode = fileMode| EFileShareAny; - - switch(mode[0]) { - case 'a': - if (fileEntry->iFileHandle.Open(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { - if (fileEntry->iFileHandle.Create(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { - delete fileEntry; - fileEntry = NULL; - } - } - break; - case 'r': - if (fileEntry->iFileHandle.Open(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { - delete fileEntry; - fileEntry = NULL; - } - break; - - case 'w': - if (fileEntry->iFileHandle.Replace(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) { - delete fileEntry; - fileEntry = NULL; - } - break; - } +RFs& OSystem_SDL_Symbian::FsSession() { + return *_RFs; +} + +// Symbian bsearch implementation is flawed +void* scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { + // Perform binary search + size_t lo = 0; + size_t hi = nmemb; + while (lo < hi) { + size_t mid = (lo + hi) / 2; + const void *p = ((const char *)base) + mid * size; + int tmp = (*compar)(key, p); + if (tmp < 0) + hi = mid; + else if (tmp > 0) + lo = mid + 1; + else + return (void *)p; } - return (FILE*) fileEntry; -} - -void symbian_fclose(FILE* handle) { - ((TSymbianFileEntry*)(handle))->iFileHandle.Close(); - delete (TSymbianFileEntry*)(handle); + return NULL; } -size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) { - TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); - TUint32 totsize = size*numItems; - TPtr8 pointer ( (unsigned char*) ptr, totsize); - - // Nothing cached and we want to load at least KInputBufferLength bytes - if(totsize >= KInputBufferLength) { - TUint32 totLength = 0; - if(entry->iInputPos != KErrNotFound) - { - TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer+entry->iInputPos, entry->iInputBufferLen - entry->iInputPos, KInputBufferLength); - pointer.Append(cacheBuffer); - entry->iInputPos = KErrNotFound; - totLength+=pointer.Length(); - pointer.Set(totLength+(unsigned char*) ptr, 0, totsize-totLength); - } - - entry->iFileHandle.Read(pointer); - totLength+=pointer.Length(); - - pointer.Set((unsigned char*) ptr, totLength, totsize); - - } - else { - // Nothing in buffer - if(entry->iInputPos == KErrNotFound) { - TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, KInputBufferLength); - entry->iFileHandle.Read(cacheBuffer); - - if(cacheBuffer.Length() >= totsize) { - pointer.Copy(cacheBuffer.Left(totsize)); - entry->iInputPos = totsize; - entry->iInputBufferLen = cacheBuffer.Length(); - } - else { - pointer.Copy(cacheBuffer); - entry->iInputPos = KErrNotFound; - } - - } - else { - TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, entry->iInputBufferLen, KInputBufferLength); - - if(entry->iInputPos+totsize < entry->iInputBufferLen) { - pointer.Copy(cacheBuffer.Mid(entry->iInputPos, totsize)); - entry->iInputPos+=totsize; - } - else { - - pointer.Copy(cacheBuffer.Mid(entry->iInputPos, entry->iInputBufferLen-entry->iInputPos)); - cacheBuffer.SetLength(0); - entry->iFileHandle.Read(cacheBuffer); - - if(cacheBuffer.Length() >= totsize-pointer.Length()) { - TUint32 restSize = totsize-pointer.Length(); - pointer.Append(cacheBuffer.Left(restSize)); - entry->iInputPos = restSize; - entry->iInputBufferLen = cacheBuffer.Length(); - } - else { - pointer.Append(cacheBuffer); - entry->iInputPos = KErrNotFound; - } - } - } - } - - return pointer.Length()/size; -} - -size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) { - TPtrC8 pointer( (unsigned char*) ptr, size*numItems); - - ((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound; - if (((TSymbianFileEntry*)(handle))->iFileHandle.Write(pointer) == KErrNone) { - return numItems; - } - - return 0; -} - -bool symbian_feof(FILE* handle) { - TInt pos = 0; - TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); - - if (entry->iFileHandle.Seek(ESeekCurrent, pos) == KErrNone) { - - TInt size = 0; - if (entry->iFileHandle.Size(size) == KErrNone) { - if(entry->iInputPos == KErrNotFound && pos == size) - return true; - - if(entry->iInputPos != KErrNotFound && pos == size && entry->iInputPos == entry->iInputBufferLen) - return true; - - return false; - } - } - return true; -} - -long int symbian_ftell(FILE* handle) { - TInt pos = 0; - TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); - - entry->iFileHandle.Seek(ESeekCurrent, pos); - if(entry->iInputPos != KErrNotFound) - { - pos+=(entry->iInputPos - entry->iInputBufferLen); - } - return pos; -} - -int symbian_fseek(FILE* handle, long int offset, int whence) { - - TSeek seekMode = ESeekStart; - TInt pos = offset; - TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle)); - - switch(whence) { - case SEEK_SET: - seekMode = ESeekStart; - break; - case SEEK_CUR: - seekMode = ESeekCurrent; - if(entry->iInputPos != KErrNotFound) { - pos+=(entry->iInputPos - entry->iInputBufferLen); - } - break; - case SEEK_END: - seekMode = ESeekEnd; - break; - - } - - entry->iInputPos = KErrNotFound; - - return entry->iFileHandle.Seek(seekMode, pos); -} - -void symbian_clearerr(FILE* /*handle*/) { +extern "C" +{ +// Include the snprintf and vsnprintf implementations as 'C' code +#include "vsnprintf.h" } /** Vibration support */ #ifdef USE_VIBRA_SE_PXXX void OSystem_SDL_Symbian::initializeVibration() { - _vibrationApi = SonyEricsson::CVibration::NewL(); +#ifdef UIQ3 +#else +#endif } void OSystem_SDL_Symbian::vibrationOn(int vibraLength) { - // initialize? +#ifdef UIQ3 + // initialize? if (!_vibrationApi) _vibrationApi = SonyEricsson::CVibration::NewL(); // do it! _vibrationApi->VibrationOn(1, 1, vibraLength); +#else + +#endif } void OSystem_SDL_Symbian::vibrationOff() { +#ifdef UIQ3 +#else _vibrationApi->VibrationOff(); +#endif } #endif // USE_SE_PXX_VIBRA diff --git a/backends/platform/symbian/src/SymbianOS.h b/backends/platform/symbian/src/SymbianOS.h index 68a6fb492f..03d7fb972c 100644 --- a/backends/platform/symbian/src/SymbianOS.h +++ b/backends/platform/symbian/src/SymbianOS.h @@ -27,12 +27,8 @@ #include "backends/platform/sdl/sdl.h" -/** Vibration support */ -#ifdef USE_VIBRA_SE_PXXX -#include <vibration.h> -#endif - #define TOTAL_ZONES 3 +class RFs; class OSystem_SDL_Symbian : public OSystem_SDL { public: @@ -62,6 +58,9 @@ public: // Overloaded from SDL_Commmon void quit(); + + // Returns reference to File session + RFs& FsSession(); protected: // // The mixer callback function, passed on to OSystem::setSoundCallback(). @@ -70,7 +69,6 @@ protected: // static void symbianMixCallback(void *s, byte *samples, int len); - virtual FilesystemFactory *getFilesystemFactory(); virtual Common::SeekableReadStream *openConfigFileForReading(); virtual Common::WriteStream *openConfigFileForWriting(); @@ -134,6 +132,7 @@ protected: } zoneDesc; static zoneDesc _zones[TOTAL_ZONES]; + RFs* _RFs; }; #endif diff --git a/backends/platform/symbian/src/main_features.inl b/backends/platform/symbian/src/main_features.inl deleted file mode 100644 index 30bbbea52c..0000000000 --- a/backends/platform/symbian/src/main_features.inl +++ /dev/null @@ -1,92 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL - * Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System - * Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer - * Copyright (C) 2005-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifdef USE_VIBRA_SE_PXXX - "Vibra " -#endif - "\n" - -// we want a list of supported engines visible in the program, -// because we also release special builds with only one engine -#ifdef ENABLE_SCUMM - "SCUMM " -#endif -#ifdef ENABLE_AGOS - "AGOS " -#endif -#ifdef ENABLE_SKY - "Sky " -#endif -#ifdef ENABLE_QUEEN - "Queen " -#endif -#ifdef ENABLE_GOB - "Gob " -#endif -#ifdef ENABLE_SAGA - "Saga " -#endif -#ifdef ENABLE_KYRA - "Kyra " -#endif -#ifdef ENABLE_SWORD1 - "Sword1 " -#endif -#ifdef ENABLE_SWORD2 - "Sword2 " -#endif -#ifdef ENABLE_CINE - "Cine " -#endif -#ifdef ENABLE_LURE - "Lure " -#endif -#ifdef ENABLE_AGI - "AGI " -#endif -#ifdef ENABLE_TOUCHE - "Touche " -#endif -#ifdef ENABLE_DRASCULA - "Drascula " -#endif -#ifdef ENABLE_IGOR - "Igor " -#endif -#ifdef ENABLE_PARALLACTION - "Parallaction " -#endif -#ifdef ENABLE_CRUISE - "Cruise " -#endif -#ifdef ENABLE_MADE - "MADE " -#endif -#ifdef ENABLE_M4 - "M4 " -#endif - - - - - - diff --git a/backends/platform/symbian/src/portdefs.h b/backends/platform/symbian/src/portdefs.h index 4577824b33..ab8333c986 100644 --- a/backends/platform/symbian/src/portdefs.h +++ b/backends/platform/symbian/src/portdefs.h @@ -35,9 +35,6 @@ #include <e32std.h> #include <math.h> -//#define DISABLE_SCALERS // we only need 1x -//#define DISABLE_HQ_SCALERS - #if defined(USE_TREMOR) && !defined(USE_VORBIS) #define USE_VORBIS // make sure this one is defined together with USE_TREMOR! #endif @@ -107,56 +104,35 @@ */ #elif defined (__WINS__) // WINS + extern "C" int symbian_snprintf(char *text, size_t maxlen, const char *fmt, ...); + extern "C" int symbian_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap); + #define snprintf(buf,len,args...) symbian_snprintf(buf,len,args) + #define vsnprintf(buf,len,format,valist) symbian_vsnprintf(buf,len,format,valist) - // let's just blatantly ignore this for now and just get it to work :P but does n't work from the debug function - int inline scumm_snprintf (char *str, unsigned long /*n*/, char const *fmt, ...) { - va_list args; - va_start(args, fmt); - vsprintf(str, fmt, args); - va_end(args); - return strlen(str); - } - - int inline scumm_vsnprintf (char *str, unsigned long /*n*/, char const *fmt, va_list valist) { - vsprintf(str, fmt, valist); - return strlen(str); - } - - #define snprintf scumm_snprintf - #define vsnprintf scumm_vsnprintf void* symbian_malloc (size_t _size); #define malloc symbian_malloc #else // GCCE and the rest - #define snprintf(buf,len,args...) sprintf(buf,args) - #define vsnprintf(buf,len,format,valist) vsprintf(buf,format,valist) + extern "C" int symbian_snprintf(char *text, size_t maxlen, const char *fmt, ...); + extern "C" int symbian_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap); + #define snprintf(buf,len,args...) symbian_snprintf(buf,len,args) + #define vsnprintf(buf,len,format,valist) symbian_vsnprintf(buf,len,format,valist) #endif #ifndef __WINS__ #define USE_ARM_GFX_ASM -#define ARM_USE_GFX_ASM #define USE_ARM_SMUSH_ASM #define USE_ARM_COSTUME_ASM #define USE_ARM_SOUND_ASM #endif -// somehow nobody has this function... -#define hypot(a, b) sqrt((a)*(a) + (b)*(b)) // Symbian bsearch implementation is flawed -void inline *scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { - size_t i; - - for (i=0; i < nmemb; i++) - if (compar(key, (void *)((size_t)base + size * i)) == 0) - return (void *)((size_t)base + size * i); - return NULL; -} -#define bsearch scumm_bsearch +void *scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); +#define bsearch scumm_bsearch // we cannot include SymbianOS.h everywhere, but this works too (functions code is in SymbianOS.cpp) namespace Symbian { extern void FatalError(const char *msg); extern char* GetExecutablePath(); -#define DYNAMIC_MODULES 1 } #endif diff --git a/backends/platform/symbian/src/vsnprintf.h b/backends/platform/symbian/src/vsnprintf.h new file mode 100644 index 0000000000..5ed04b1980 --- /dev/null +++ b/backends/platform/symbian/src/vsnprintf.h @@ -0,0 +1,668 @@ +/* + * This is the vsnprintf for scummvm/symbian implementation from the original snprintf.c, + * all support functions has been removed and vsnprintf renamed to symbian_vsnprintf + * snprintf.c - a portable implementation of snprintf + * According to the homepage this function could be licensed as either Frontier Aritistic or GPL. + * + * AUTHOR + * Mark Martinec <mark.martinec@ijs.si>, April 1999. + * + * Copyright 1999, Mark Martinec. All rights reserved. + * + * TERMS AND CONDITIONS + * This program is free software; you can redistribute it and/or modify + * it under the terms of the "Frontier Artistic License" which comes + * with this Kit. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the Frontier Artistic License for more details. + * + * You should have received a copy of the Frontier Artistic License + * with this Kit in the file named LICENSE.txt . + * If not, I'll be glad to provide one. + * + * FEATURES + * - careful adherence to specs regarding flags, field width and precision; + * - good performance for large string handling (large format, large + * argument or large paddings). Performance is similar to system's sprintf + * and in several cases significantly better (make sure you compile with + * optimizations turned on, tell the compiler the code is strict ANSI + * if necessary to give it more freedom for optimizations); + * - return value semantics per ISO/IEC 9899:1999 ("ISO C99"); + * - written in standard ISO/ANSI C - requires an ANSI C compiler. + * + * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES + * + * This snprintf only supports the following conversion specifiers: + * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) + * with flags: '-', '+', ' ', '0' and '#'. + * An asterisk is supported for field width as well as precision. + * + * Length modifiers 'h' (short int), 'l' (long int), + * and 'll' (long long int) are supported. + * NOTE: + * If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the + * length modifier 'll' is recognized but treated the same as 'l', + * which may cause argument value truncation! Defining + * SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also + * handles length modifier 'll'. long long int is a language extension + * which may not be portable. + * + * Conversion of numeric data (conversion specifiers d, u, o, x, X, p) + * with length modifiers (none or h, l, ll) is left to the system routine + * sprintf, but all handling of flags, field width and precision as well as + * c and s conversions is done very carefully by this portable routine. + * If a string precision (truncation) is specified (e.g. %.8s) it is + * guaranteed the string beyond the specified precision will not be referenced. + * + * Length modifiers h, l and ll are ignored for c and s conversions (data + * types wint_t and wchar_t are not supported). + * + * The following common synonyms for conversion characters are supported: + * - i is a synonym for d + * - D is a synonym for ld, explicit length modifiers are ignored + * - U is a synonym for lu, explicit length modifiers are ignored + * - O is a synonym for lo, explicit length modifiers are ignored + * The D, O and U conversion characters are nonstandard, they are supported + * for backward compatibility only, and should not be used for new code. + * + * The following is specifically NOT supported: + * - flag ' (thousands' grouping character) is recognized but ignored + * - numeric conversion specifiers: f, e, E, g, G and synonym F, + * as well as the new a and A conversion specifiers + * - length modifier 'L' (long double) and 'q' (quad - use 'll' instead) + * - wide character/string conversions: lc, ls, and nonstandard + * synonyms C and S + * - writeback of converted string length: conversion character n + * - the n$ specification for direct reference to n-th argument + * - locales + * + * It is permitted for str_m to be zero, and it is permitted to specify NULL + * pointer for resulting string argument if str_m is zero (as per ISO C99). + * + * The return value is the number of characters which would be generated + * for the given input, excluding the trailing null. If this value + * is greater or equal to str_m, not all characters from the result + * have been stored in str, output bytes beyond the (str_m-1) -th character + * are discarded. If str_m is greater than zero it is guaranteed + * the resulting string will be null-terminated. + * + * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1, + * but is different from some older and vendor implementations, + * and is also different from XPG, XSH5, SUSv2 specifications. + * For historical discussion on changes in the semantics and standards + * of snprintf see printf(3) man page in the Linux programmers manual. + * + * Routines asprintf and vasprintf return a pointer (in the ptr argument) + * to a buffer sufficiently large to hold the resulting string. This pointer + * should be passed to free(3) to release the allocated storage when it is + * no longer needed. If sufficient space cannot be allocated, these functions + * will return -1 and set ptr to be a NULL pointer. These two routines are a + * GNU C library extensions (glibc). + * + * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf, + * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1 + * characters into the allocated output string, the last character in the + * allocated buffer then gets the terminating null. If the formatted string + * length (the return value) is greater than or equal to the str_m argument, + * the resulting string was truncated and some of the formatted characters + * were discarded. These routines present a handy way to limit the amount + * of allocated memory to some sane value. + * + * AVAILABILITY + * http://www.ijs.si/software/snprintf/ + * + * REVISION HISTORY + * 1999-04 V0.9 Mark Martinec + * - initial version, some modifications after comparing printf + * man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10, + * and checking how Perl handles sprintf (differently!); + * 1999-04-09 V1.0 Mark Martinec <mark.martinec@ijs.si> + * - added main test program, fixed remaining inconsistencies, + * added optional (long long int) support; + * 1999-04-12 V1.1 Mark Martinec <mark.martinec@ijs.si> + * - support the 'p' conversion (pointer to void); + * - if a string precision is specified + * make sure the string beyond the specified precision + * will not be referenced (e.g. by strlen); + * 1999-04-13 V1.2 Mark Martinec <mark.martinec@ijs.si> + * - support synonyms %D=%ld, %U=%lu, %O=%lo; + * - speed up the case of long format string with few conversions; + * 1999-06-30 V1.3 Mark Martinec <mark.martinec@ijs.si> + * - fixed runaway loop (eventually crashing when str_l wraps + * beyond 2^31) while copying format string without + * conversion specifiers to a buffer that is too short + * (thanks to Edwin Young <edwiny@autonomy.com> for + * spotting the problem); + * - added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) + * to snprintf.h + * 2000-02-14 V2.0 (never released) Mark Martinec <mark.martinec@ijs.si> + * - relaxed license terms: The Artistic License now applies. + * You may still apply the GNU GENERAL PUBLIC LICENSE + * as was distributed with previous versions, if you prefer; + * - changed REVISION HISTORY dates to use ISO 8601 date format; + * - added vsnprintf (patch also independently proposed by + * Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01) + * 2000-06-27 V2.1 Mark Martinec <mark.martinec@ijs.si> + * - removed POSIX check for str_m<1; value 0 for str_m is + * allowed by ISO C99 (and GNU C library 2.1) - (pointed out + * on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie). + * Besides relaxed license this change in standards adherence + * is the main reason to bump up the major version number; + * - added nonstandard routines asnprintf, vasnprintf, asprintf, + * vasprintf that dynamically allocate storage for the + * resulting string; these routines are not compiled by default, + * see comments where NEED_V?ASN?PRINTF macros are defined; + * - autoconf contributed by Caolan McNamara + * 2000-10-06 V2.2 Mark Martinec <mark.martinec@ijs.si> + * - BUG FIX: the %c conversion used a temporary variable + * that was no longer in scope when referenced, + * possibly causing incorrect resulting character; + * - BUG FIX: make precision and minimal field width unsigned + * to handle huge values (2^31 <= n < 2^32) correctly; + * also be more careful in the use of signed/unsigned/size_t + * internal variables - probably more careful than many + * vendor implementations, but there may still be a case + * where huge values of str_m, precision or minimal field + * could cause incorrect behaviour; + * - use separate variables for signed/unsigned arguments, + * and for short/int, long, and long long argument lengths + * to avoid possible incompatibilities on certain + * computer architectures. Also use separate variable + * arg_sign to hold sign of a numeric argument, + * to make code more transparent; + * - some fiddling with zero padding and "0x" to make it + * Linux compatible; + * - systematically use macros fast_memcpy and fast_memset + * instead of case-by-case hand optimization; determine some + * breakeven string lengths for different architectures; + * - terminology change: 'format' -> 'conversion specifier', + * 'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")', + * 'alternative form' -> 'alternate form', + * 'data type modifier' -> 'length modifier'; + * - several comments rephrased and new ones added; + * - make compiler not complain about 'credits' defined but + * not used; + */ +/* ============================================= */ +/* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */ +/* ============================================= */ + +#define PORTABLE_SNPRINTF_VERSION_MAJOR 2 +#define PORTABLE_SNPRINTF_VERSION_MINOR 2 +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include <errno.h> +#ifdef isdigit +#undef isdigit +#endif +#define isdigit(c) ((c) >= '0' && (c) <= '9') + +#ifndef breakeven_point +# define breakeven_point 6 /* some reasonable one-size-fits-all value */ +#endif + +#define fast_memcpy(d,s,n) \ +{ register size_t nn = (size_t)(n); \ + if (nn >= breakeven_point) memcpy((d), (s), nn); \ + else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ + register char *dd; register const char *ss; \ +for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } } + +#define fast_memset(d,c,n) \ +{ register size_t nn = (size_t)(n); \ + if (nn >= breakeven_point) memset((d), (int)(c), nn); \ + else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ + register char *dd; register const int cc=(int)(c); \ +for (dd=(d); nn>0; nn--) *dd++ = cc; } } + + +/* declarations */ + +static char credits[] = "\n\ +@(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\ +@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\ +@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n"; +int symbian_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) { + + size_t str_l = 0; + const char *p = fmt; + + /* In contrast with POSIX, the ISO C99 now says + * that str can be NULL and str_m can be 0. + * This is more useful than the old: if (str_m < 1) return -1; */ + + if (!p) p = ""; + while (*p) { + if (*p != '%') { + /* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */ + /* but the following code achieves better performance for cases + * where format string is long and contains few conversions */ + const char *q = strchr(p+1,'%'); + size_t n = !q ? strlen(p) : (q-p); + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, p, (n>avail?avail:n)); + } + p += n; str_l += n; + } else { + const char *starting_p; + size_t min_field_width = 0, precision = 0; + int zero_padding = 0, precision_specified = 0, justify_left = 0; + int alternate_form = 0, force_sign = 0; + int space_for_positive = 1; /* If both the ' ' and '+' flags appear, + the ' ' flag should be ignored. */ + char length_modifier = '\0'; /* allowed values: \0, h, l, L */ + char tmp[32];/* temporary buffer for simple numeric->string conversion */ + + const char *str_arg; /* string address in case of string argument */ + size_t str_arg_l; /* natural field width of arg without padding + and sign */ + unsigned char uchar_arg; + /* unsigned char argument value - only defined for c conversion. + N.B. standard explicitly states the char argument for + the c conversion is unsigned */ + + size_t number_of_zeros_to_pad = 0; + /* number of zeros to be inserted for numeric conversions + as required by the precision or minimal field width */ + + size_t zero_padding_insertion_ind = 0; + /* index into tmp where zero padding is to be inserted */ + + char fmt_spec = '\0'; + /* current conversion specifier character */ + + str_arg = credits;/* just to make compiler happy (defined but not used)*/ + str_arg = NULL; + starting_p = p; p++; /* skip '%' */ + /* parse flags */ + while (*p == '0' || *p == '-' || *p == '+' || + *p == ' ' || *p == '#' || *p == '\'') { + switch (*p) { + case '0': zero_padding = 1; break; + case '-': justify_left = 1; break; + case '+': force_sign = 1; space_for_positive = 0; break; + case ' ': force_sign = 1; + /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */ + break; + case '#': alternate_form = 1; break; + case '\'': break; + } + p++; + } + /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */ + + /* parse field width */ + if (*p == '*') { + int j; + p++; j = va_arg(ap, int); + if (j >= 0) min_field_width = j; + else { min_field_width = -j; justify_left = 1; } + } else if (isdigit((int)(*p))) { + /* size_t could be wider than unsigned int; + make sure we treat argument like common implementations do */ + unsigned int uj = *p++ - '0'; + while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); + min_field_width = uj; + } + /* parse precision */ + if (*p == '.') { + p++; precision_specified = 1; + if (*p == '*') { + int j = va_arg(ap, int); + p++; + if (j >= 0) precision = j; + else { + precision_specified = 0; precision = 0; + /* NOTE: + * Solaris 2.6 man page claims that in this case the precision + * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page + * claim that this case should be treated as unspecified precision, + * which is what we do here. + */ + } + } else if (isdigit((int)(*p))) { + /* size_t could be wider than unsigned int; + make sure we treat argument like common implementations do */ + unsigned int uj = *p++ - '0'; + while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); + precision = uj; + } + } + /* parse 'h', 'l' and 'll' length modifiers */ + if (*p == 'h' || *p == 'l') { + length_modifier = *p; p++; + if (length_modifier == 'l' && *p == 'l') { /* double l = long long */ +#ifdef SNPRINTF_LONGLONG_SUPPORT + length_modifier = '2'; /* double l encoded as '2' */ +#else + length_modifier = 'l'; /* treat it as a single 'l' */ +#endif + p++; + } + } + fmt_spec = *p; + /* common synonyms: */ + switch (fmt_spec) { + case 'i': fmt_spec = 'd'; break; + case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; + case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; + case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; + default: break; + } + /* get parameter value, do initial processing */ + switch (fmt_spec) { + case '%': /* % behaves similar to 's' regarding flags and field widths */ + case 'c': /* c behaves similar to 's' regarding flags and field widths */ + case 's': + length_modifier = '\0'; /* wint_t and wchar_t not supported */ + /* the result of zero padding flag with non-numeric conversion specifier*/ + /* is undefined. Solaris and HPUX 10 does zero padding in this case, */ + /* Digital Unix and Linux does not. */ + zero_padding = 0; /* turn zero padding off for string conversions */ + str_arg_l = 1; + switch (fmt_spec) { + case '%': + str_arg = p; break; + case 'c': { + int j = va_arg(ap, int); + uchar_arg = (unsigned char) j; /* standard demands unsigned char */ + str_arg = (const char *) &uchar_arg; + break; + } + case 's': + str_arg = va_arg(ap, const char *); + if (!str_arg) str_arg_l = 0; + /* make sure not to address string beyond the specified precision !!! */ + else if (!precision_specified) str_arg_l = strlen(str_arg); + /* truncate string if necessary as requested by precision */ + else if (precision == 0) str_arg_l = 0; + else { + /* memchr on HP does not like n > 2^31 !!! */ + const char *q = (const char*) memchr(str_arg, '\0', + precision <= 0x7fffffff ? precision : 0x7fffffff); + str_arg_l = !q ? precision : (q-str_arg); + } + break; + default: break; + } + break; + case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': { + /* NOTE: the u, o, x, X and p conversion specifiers imply + the value is unsigned; d implies a signed value */ + + int arg_sign = 0; + /* 0 if numeric argument is zero (or if pointer is NULL for 'p'), + +1 if greater than zero (or nonzero for unsigned arguments), + -1 if negative (unsigned argument is never negative) */ + + int int_arg = 0; unsigned int uint_arg = 0; + /* only defined for length modifier h, or for no length modifiers */ + + long int long_arg = 0; unsigned long int ulong_arg = 0; + /* only defined for length modifier l */ + + void *ptr_arg = NULL; + /* pointer argument value -only defined for p conversion */ + +#ifdef SNPRINTF_LONGLONG_SUPPORT + long long int long_long_arg = 0; + unsigned long long int ulong_long_arg = 0; + /* only defined for length modifier ll */ +#endif + if (fmt_spec == 'p') { + /* HPUX 10: An l, h, ll or L before any other conversion character + * (other than d, i, u, o, x, or X) is ignored. + * Digital Unix: + * not specified, but seems to behave as HPUX does. + * Solaris: If an h, l, or L appears before any other conversion + * specifier (other than d, i, u, o, x, or X), the behavior + * is undefined. (Actually %hp converts only 16-bits of address + * and %llp treats address as 64-bit data which is incompatible + * with (void *) argument on a 32-bit system). + */ + length_modifier = '\0'; + ptr_arg = va_arg(ap, void *); + if (ptr_arg != NULL) arg_sign = 1; + } else if (fmt_spec == 'd') { /* signed */ + switch (length_modifier) { + case '\0': + case 'h': + /* It is non-portable to specify a second argument of char or short + * to va_arg, because arguments seen by the called function + * are not char or short. C converts char and short arguments + * to int before passing them to a function. + */ + int_arg = va_arg(ap, int); + if (int_arg > 0) arg_sign = 1; + else if (int_arg < 0) arg_sign = -1; + break; + case 'l': + long_arg = va_arg(ap, long int); + if (long_arg > 0) arg_sign = 1; + else if (long_arg < 0) arg_sign = -1; + break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': + long_long_arg = va_arg(ap, long long int); + if (long_long_arg > 0) arg_sign = 1; + else if (long_long_arg < 0) arg_sign = -1; + break; +#endif + } + } else { /* unsigned */ + switch (length_modifier) { + case '\0': + case 'h': + uint_arg = va_arg(ap, unsigned int); + if (uint_arg) arg_sign = 1; + break; + case 'l': + ulong_arg = va_arg(ap, unsigned long int); + if (ulong_arg) arg_sign = 1; + break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': + ulong_long_arg = va_arg(ap, unsigned long long int); + if (ulong_long_arg) arg_sign = 1; + break; +#endif + } + } + str_arg = tmp; str_arg_l = 0; + /* NOTE: + * For d, i, u, o, x, and X conversions, if precision is specified, + * the '0' flag should be ignored. This is so with Solaris 2.6, + * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. + */ + if (precision_specified) zero_padding = 0; + if (fmt_spec == 'd') { + if (force_sign && arg_sign >= 0) + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; + /* leave negative numbers for sprintf to handle, + to avoid handling tricky cases like (short int)(-32768) */ + } else if (alternate_form) { + if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) + { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } + /* alternate form should have no effect for p conversion, but ... */ + } + zero_padding_insertion_ind = str_arg_l; + if (!precision_specified) precision = 1; /* default precision is 1 */ + if (precision == 0 && arg_sign == 0 + ) { + /* converted to null string */ + /* When zero value is formatted with an explicit precision 0, + the resulting formatted string is empty (d, i, u, o, x, X, p). */ + } else { + char f[5]; int f_l = 0; + f[f_l++] = '%'; /* construct a simple format string for sprintf */ + if (!length_modifier) { } + else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; } + else f[f_l++] = length_modifier; + f[f_l++] = fmt_spec; f[f_l++] = '\0'; + if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg); + else if (fmt_spec == 'd') { /* signed */ + switch (length_modifier) { + case '\0': + case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break; + case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break; +#endif + } + } else { /* unsigned */ + switch (length_modifier) { + case '\0': + case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break; + case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break; +#endif + } + } + /* include the optional minus sign and possible "0x" + in the region before the zero padding insertion point */ + if (zero_padding_insertion_ind < str_arg_l && + tmp[zero_padding_insertion_ind] == '-') { + zero_padding_insertion_ind++; + } + if (zero_padding_insertion_ind+1 < str_arg_l && + tmp[zero_padding_insertion_ind] == '0' && + (tmp[zero_padding_insertion_ind+1] == 'x' || + tmp[zero_padding_insertion_ind+1] == 'X') ) { + zero_padding_insertion_ind += 2; + } + } + { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; + if (alternate_form && fmt_spec == 'o' + /* unless zero is already the first character */ + && !(zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '0') + ) { /* assure leading zero for alternate-form octal numbers */ + if (!precision_specified || precision < num_of_digits+1) { + /* precision is increased to force the first character to be zero, + except if a zero value is formatted with an explicit precision + of zero */ + precision = num_of_digits+1; precision_specified = 1; + } + } + /* zero padding to specified precision? */ + if (num_of_digits < precision) + number_of_zeros_to_pad = precision - num_of_digits; + } + /* zero padding to specified minimal field width? */ + if (!justify_left && zero_padding) { + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) number_of_zeros_to_pad += n; + } + break; + } + default: /* unrecognized conversion specifier, keep format string as-is*/ + zero_padding = 0; /* turn zero padding off for non-numeric convers. */ + justify_left = 1; min_field_width = 0; /* reset flags */ + /* discard the unrecognized conversion, just keep * + * the unrecognized conversion character */ + str_arg = p; str_arg_l = 0; + if (*p) str_arg_l++; /* include invalid conversion specifier unchanged + if not at end-of-string */ + break; + } + if (*p) p++; /* step over the just processed conversion specifier */ + /* insert padding to the left as requested by min_field_width; + this does not include the zero padding in case of numerical conversions*/ + if (!justify_left) { /* left padding with blank or zero */ + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n)); + } + str_l += n; + } + } + /* zero padding as requested by the precision or by the minimal field width + * for numeric conversions required? */ + if (number_of_zeros_to_pad <= 0) { + /* will not copy first part of numeric right now, * + * force it to be copied later in its entirety */ + zero_padding_insertion_ind = 0; + } else { + /* insert first part of numerics (sign or '0x') before zero padding */ + int n = zero_padding_insertion_ind; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, str_arg, (n>avail?avail:n)); + } + str_l += n; + } + /* insert zero padding as requested by the precision or min field width */ + n = number_of_zeros_to_pad; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, '0', (n>avail?avail:n)); + } + str_l += n; + } + } + /* insert formatted string + * (or as-is conversion specifier for unknown conversions) */ + { int n = str_arg_l - zero_padding_insertion_ind; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind, + (n>avail?avail:n)); + } + str_l += n; + } + } + /* insert right padding */ + if (justify_left) { /* right blank padding to the field width */ + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, ' ', (n>avail?avail:n)); + } + str_l += n; + } + } + } + } + if (str_m > 0) { /* make sure the string is null-terminated + even at the expense of overwriting the last character + (shouldn't happen, but just in case) */ + str[str_l <= str_m-1 ? str_l : str_m-1] = '\0'; + } + /* Return the number of characters formatted (excluding trailing null + * character), that is, the number of characters that would have been + * written to the buffer if it were large enough. + * + * The value of str_l should be returned, but str_l is of unsigned type + * size_t, and snprintf is int, possibly leading to an undetected + * integer overflow, resulting in a negative return value, which is illegal. + * Both XSH5 and ISO C99 (at least the draft) are silent on this issue. + * Should errno be set to EOVERFLOW and EOF returned in this case??? + */ + return (int) str_l; +} + +int symbian_snprintf(char *text, size_t maxlen, const char *fmt, ...) { + va_list ap; + int retval; + + va_start(ap, fmt); + retval = symbian_vsnprintf(text, maxlen, fmt, ap); + va_end(ap); + + return retval; +} diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp index 3626c4c10b..7f78517762 100644 --- a/backends/platform/wince/CEActionsPocket.cpp +++ b/backends/platform/wince/CEActionsPocket.cpp @@ -147,7 +147,7 @@ void CEActionsPocket::initInstanceGame() { _key_action[POCKET_ACTION_PAUSE].setKey(VK_SPACE); _action_enabled[POCKET_ACTION_PAUSE] = true; // Save - if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble) + if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble) _action_enabled[POCKET_ACTION_SAVE] = false; else if (is_queen) { _action_enabled[POCKET_ACTION_SAVE] = true; diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp index 87f73f5a66..0c4113cc0c 100644 --- a/backends/platform/wince/CEActionsSmartphone.cpp +++ b/backends/platform/wince/CEActionsSmartphone.cpp @@ -130,7 +130,7 @@ void CEActionsSmartphone::initInstanceGame() { // Initialize keys for different actions // Save - if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble) + if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble) _action_enabled[SMARTPHONE_ACTION_SAVE] = false; else if (is_queen) { _action_enabled[SMARTPHONE_ACTION_SAVE] = true; diff --git a/backends/platform/wince/CELauncherDialog.cpp b/backends/platform/wince/CELauncherDialog.cpp index edfdad84b3..7e306be114 100644 --- a/backends/platform/wince/CELauncherDialog.cpp +++ b/backends/platform/wince/CELauncherDialog.cpp @@ -72,10 +72,10 @@ void CELauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 d } } -void CELauncherDialog::automaticScanDirectory(const FilesystemNode &node) { +void CELauncherDialog::automaticScanDirectory(const Common::FilesystemNode &node) { // First check if we have a recognized game in the current directory - FSList files; - node.getChildren(files, FilesystemNode::kListFilesOnly); + Common::FSList files; + node.getChildren(files, Common::FilesystemNode::kListFilesOnly); // detect GameList candidates(EngineMan.detectGames(files)); // insert @@ -85,9 +85,9 @@ void CELauncherDialog::automaticScanDirectory(const FilesystemNode &node) { addGameToConf(result); } // Then recurse on the subdirectories - FSList dirs; - node.getChildren(dirs, FilesystemNode::kListDirectoriesOnly); - for (FSList::const_iterator currentDir = dirs.begin(); currentDir != dirs.end(); ++currentDir) + Common::FSList dirs; + node.getChildren(dirs, Common::FilesystemNode::kListDirectoriesOnly); + for (Common::FSList::const_iterator currentDir = dirs.begin(); currentDir != dirs.end(); ++currentDir) automaticScanDirectory(*currentDir); } diff --git a/backends/platform/wince/CELauncherDialog.h b/backends/platform/wince/CELauncherDialog.h index 55d177bcb8..a5f3fd0d43 100644 --- a/backends/platform/wince/CELauncherDialog.h +++ b/backends/platform/wince/CELauncherDialog.h @@ -36,7 +36,7 @@ public: virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); protected: void addGame(); - void automaticScanDirectory(const FilesystemNode &node); + void automaticScanDirectory(const Common::FilesystemNode &node); }; typedef GUI::LauncherDialog GUILauncherDialog; diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile index 4400d50e3a..9f040bbed1 100644 --- a/backends/platform/wince/Makefile +++ b/backends/platform/wince/Makefile @@ -45,8 +45,8 @@ ENABLE_DRASCULA = STATIC_PLUGIN USE_MAD = 1 USE_MPEG2 = 1 -USE_TREMOR = 1 -#USE_TREMOLO = 1 +#USE_TREMOR = 1 +USE_TREMOLO = 1 USE_FLAC = 1 USE_ZLIB = 1 @@ -139,7 +139,7 @@ LIBS += -ltremorce endif ifdef USE_TREMOLO -DEFINES += -DUSE_TREMOR -DUSE_VORBIS +DEFINES += -DUSE_TREMOR -DUSE_VORBIS -DUSE_TREMOLO INCLUDES += -Ilibs/include/tremolo LIBS += -llibTremolo endif diff --git a/backends/platform/wince/README-WinCE.txt b/backends/platform/wince/README-WinCE.txt index f4cb00dcfa..86c627d764 100644 --- a/backends/platform/wince/README-WinCE.txt +++ b/backends/platform/wince/README-WinCE.txt @@ -1,29 +1,28 @@ ScummVM Windows CE FAQ Last updated: $Date$ -Release version: 0.11.0 +Release version: 0.12.0 ------------------------------------------------------------------------ New in this version ------------------- -0.11.0 -- Redesigned 'Free Look' action (Pocket PCs) -In order to accommodate for the requirements of the lure engine, the -usage characteristics of the 'Free Look' action have been improved. The -new behavior is available for use in all engines, but is is *strongly* -recommended for at least when playing 'Lure of the Temptress'. By using -the new scheme, when in 'Free Look' mode, it is now possible to enter -left clicks by clicking a second time near the current location of the -mouse pointer. Left and Right clicks at the current point location -are also available by using the respective actions' bound key. +0.12.0: +- Improved SMUSH support (deprecated 'Smush_force_redraw' option) +No skipped frames in Full Throttle action sequences. The 'Smush_force_redraw' +option is not needed/honored anymore. -- Reduced optimization build -The ScummVM executable has grown quite large, prohibiting some devices -from running memory demanding games (or any games at all). Code -optimization level has been reduced to offset the growth of the executable. -Games run slightly slower. This will be addressed before next release. +- Fixed MultiFuntion key in Full Throttle -- Several bugfixes +- Improved sound output +Fixed a long standing bug which led to distorted sound output in all games. + +- Switched to faster ogg vorbis library +Robin Watts' libTremolo is used for ogg vorbis (tremor) replay. Info patch +by Lostech. + +- New right click through double tap inhibiting option +Check out the 'no_doubletap_rightclick' option if double-tapping as a right +click input method annoys you. Patch by spookypeanut. ------------------------------------------------------------------------ @@ -109,10 +108,10 @@ and report your success ... How do I install ScummVM for Windows CE ? ----------------------------------------- -Simple! Unpack the release package on your desktop pc, then copy all its contents -to a folder on your device. Typically, you should at least have scummvm.exe, -modern.ini and modern.zip in the same directory. Finally, upload your beloved games -and fire it up :-) +Simple! Unpack the release package on your desktop pc, then copy all its +contents to a folder on your device. Typically, you should at least have +scummvm.exe, modern.ini and modern.zip in the same directory. Finally, upload +your beloved games and fire it up :-) Some devices (like Pocket PC 2000) require GAPI to be present. @@ -184,18 +183,19 @@ The following actions are available : * Right click : acts as a right mouse button click * Cursor : hide or display the mouse cursor * Free look : go in or out of free-look mode. In this mode, you can tap - the screen to look for interesting locations without walking. - Cling a second time near the pointer's location equals to left click. + the screen to look for interesting locations without + walking. Click a second time near the pointer's location + equals to a left click. * Zoom up : magnify the upper part of the screen for 640x480 games rendered on a QVGA device. * Zoom down : magnify the lower part of the screen for 640x480 games rendered on a QVGA device. - * Multi Function : this key performs a different function depending on the game - : Full Throttle -> win an action sequence (cheat) - : Fate of Atlantis -> sucker punch (cheat) - : Bargon -> F1 (start the game) - : All AGI games -> bring up the predictive input dialog - * Bind keys : map a key action to a device button + * Multi Function : performs a different function depending on the game : + Full Throttle -> win an action sequence (cheat) + Fate of Atlantis -> sucker punch (cheat) + Bargon -> F1 (start the game) + All AGI games -> bring up the predictive input dialog + * Bind keys map a key action to a device button * Up,Down,Left : Right, : emulate mouse/stylus behavior Left Click : @@ -245,11 +245,11 @@ the list of available actions for Smartphones: * Skip : skip a non interactive sequence, the current dialog or behaves like the ESC key on a regular keyboard * Zone : switch between the 3 different mouse zones - * Multi Function : this key performs a different function depending on the game - : Full Throttle -> win an action sequence (cheat) - : Fate of Atlantis -> sucker punch (cheat) - : Bargon -> F1 (start the game) - : All AGI games -> bring up the predictive input dialog + * Multi Function : performs a different function depending on the game + Full Throttle -> win an action sequence (cheat) + Fate of Atlantis -> sucker punch (cheat) + Bargon -> F1 (start the game) + All AGI games -> bring up the predictive input dialog * Bind keys : map a key action to a device button * Keyboard : hide or display the virtual keyboard * Rotate : rotate the screen (also rotates dpad keys) @@ -287,32 +287,34 @@ Some parameters are specific to this port : Game specific sections (f.e. [monkey2]) - performance options - * high_sample_rate bool Desktop quality (22 kHz) sound output if set. - 11 kHz otherwise. The default is 11 kHz. - If you have a fast device, you can set this to - true to enjoy better sound effects and music. + * high_sample_rate bool Desktop quality (22 kHz) sound output if + set. The default is 11 kHz. + If you have a fast device, you can set this + to true to enjoy better sound effects and + music. * FM_high_quality bool Desktop quality FM synthesis if set. Lower - quality otherwise. The default is low quality. - You can change this if you have a fast device. - * sound_thread_priority int Set the priority of the sound thread (0, 1, 2). - Depending on the release, this is set to 1 - internally (above normal). If you get sound - stuttering try setting this to a higher value. + quality otherwise. The default is low + quality. You can change this if you have a + fast device. + * sound_thread_priority int Set the priority of the sound thread (0, 1, + 2). Depending on the release, this is set + to 1 internally (above normal). + If you get sound stuttering try setting + this to a higher value. Set to 0 if your device is fast enough or if - you prefer better audio/video synchronization. - * Smush_force_redraw int Force a Smush frame redraw every X missed - frames. Mainly used for Full Throttle action - sequences. Setting it lower gives more - priority to screen redraws. Setting it higher - gives more priority to stylus/keyboard input. - The default is 30. + you prefer better audio/video sync. Game specific sections (f.e. [monkey2]) - game options - * landscape int 0: Portrait, 1: Landscape, 2: Inverse Landscape - You can also use this in the [scummvm] section - in QVGA Pocket PCs to display the launcher in - landscape, for example, at startup. + * landscape int 0: Portrait, 1: Landscape, + 2: Inverse Landscape. + You can also use this in the [scummvm] + section to display the launcher in landscape + for example, at startup. + * no_doubletap_rightclick int 1: Turn off the default behavior of + simulating a right-click when the screen is + double-tapped. + [scummvm] section - keys definition @@ -335,18 +337,18 @@ You can tweak these parameters to customize how the cursor is handled. consider being repeated. * repeatX int Number of key repeat events before changing horizontal cursor behaviour. - * stepX1 int Horizontal cursor offset value when the key is - not repeated. - * stepX2 int Horizontal cursor offset value when the key is - repeated less than repeatX. - * stepX3 int Horizontal cursor offset value when the key is - repeated more than repeatX. + * stepX1 int Horizontal cursor offset value when the key + is not repeated. + * stepX2 int Horizontal cursor offset value when the key + is repeated less than repeatX. + * stepX3 int Horizontal cursor offset value when the key + is repeated more than repeatX. * repeatY int Number of key repeat events before changing - vertical cursor behaviour. + vertical cursor behavior. * stepY1 int Vertical cursor offset value when the key is not repeated. - * stepY2 int Horizontal cursor offset value when the key is - repeated less than repeatY. + * stepY2 int Horizontal cursor offset value when the key + is repeated less than repeatY. * stepY3 int Vertical cursor offset value when the key is repeated more than repeatY. @@ -361,8 +363,8 @@ Game specific questions I need to press a special key ----------------------------- -Bring up the virtual keyboard. On Smartphones take a look at the Keyboard action above. -On Pocket PCs it's easier to double-tap at the top of the screen. +Bring up the virtual keyboard. On Smartphones take a look at the Keyboard +action above. On Pocket PCs it's easier to double-tap at the top of the screen. The panel is obscuring the playfield area ----------------------------------------- @@ -383,17 +385,18 @@ Bind and use the quit action to quit. I cannot rotate the screen to landscape/inverse landscape --------------------------------------------------------- -Depending on the video driver, ScummVM may opt to not provide such functionality. -In general, when ScummVM starts in normal "portrait" orientation, the device driver -reports better display characteristics and you should consider launching from portrait. +Depending on the video driver, ScummVM may opt to not provide such +functionality. In general, when ScummVM starts in normal "portrait" +orientation, the device driver reports better display characteristics and you +should consider launching from portrait. I'm having problems. Is there diagnostic output available ? ----------------------------------------------------------- Insert a line in the [scummvm] section of scummvm.ini with the following: debuglevel=1 -Run ScummVM. When it closes scummvm_stdout.txt and scummvm_stderr.txt files will be -available at the program directory (see section above). +Run ScummVM. When it closes scummvm_stdout.txt and scummvm_stderr.txt files +will be available at the program directory (see section above). ScummVM crashes and returns to desktop -------------------------------------- @@ -548,18 +551,19 @@ Use the Multi Function action. -- AGI engine games -- ---------------------- -Do you expect me to play these games on keyboard less devices ? +Do you expect me to play these games on keyboard-less devices ? --------------------------------------------------------------- Sure we do :-) -If you want to get some mileage on your stylus you can use the virtual keyboard. -There is a very useful alternative though, the AGI engine's predictive input dialog. -It requires a dictionary to be present. Just tap on the command line or use the -Multi Function action to bring it up. On Smartphones, when the dialog is shown -all key mapping is disabled temporarily (including mouse emulation). Input is -performed either by pressing the phone's numeric keypad keys and dpad enter to -close the dialog, or by navigating the buttons using the dpad arrows and pressing -with dpad enter. Check the main Readme file for more information on this. +If you want to get some mileage on your stylus you can use the virtual +keyboard. There is a very useful alternative though, the AGI engine's +predictive input dialog. It requires a dictionary to be present. Just tap on +the command line or use the Multi Function action to bring it up. On +Smartphones, when the dialog is shown all key mapping is disabled temporarily +(including mouse emulation). Input is performed either by pressing the phone's +numeric keypad keys and dpad enter to close the dialog, or by navigating the +buttons using the dpad arrows and pressing with dpad enter. Check the main +Readme file for more information on this. --------------------------- -- Lure of the Temptress -- @@ -595,8 +599,9 @@ I think I found a bug, ScummVM crashes in ... See the "Reporting Bugs" section in ScummVM readme. -If you have a Pocket PC or Handheld PC, be sure to include its resolution (obtained -on the second dialog displayed on the "About" menu) in your bug report. +If you have a Pocket PC or Handheld PC, be sure to include its resolution +(obtained on the second dialog displayed on the "About" menu) in your bug +report. If you cannot reproduce this bug on another ScummVM version, you can cross post your bug report on ScummVM forums. @@ -619,6 +624,26 @@ http://www.scummvm.org/ Old news follow ... ------------------------------------------------------------------------ +0.11.0: +- Redesigned 'Free Look' action (Pocket PCs) +In order to accommodate for the requirements of the lure engine, the +usage characteristics of the 'Free Look' action have been improved. The +new behavior is available for use in all engines, but is is *strongly* +recommended for at least when playing 'Lure of the Temptress'. By using +the new scheme, when in 'Free Look' mode, it is now possible to enter +left clicks by clicking a second time near the current location of the +mouse pointer. Left and Right clicks at the current point location +are also available by using the respective actions' bound key. + +- Reduced optimization build +The ScummVM executable has grown quite large, prohibiting some devices +from running memory demanding games (or any games at all). Code +optimization level has been reduced to offset the growth of the executable. +Games run slightly slower. This will be addressed before next release. + +- Several bugfixes + + 0.10.0: Major improvements have taken place in this version, mostly for behind- the-scenes stuff. First, we have migrated to GCC for building the Windows diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index 48f157f6ff..f09a483086 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -461,7 +461,7 @@ OSystem_WINCE3::OSystem_WINCE3() : OSystem_SDL(), _orientationLandscape(0), _newOrientation(0), _panelInitialized(false), _panelVisible(true), _panelStateForced(false), _forceHideMouse(false), _unfilteredkeys(false), _freeLook(false), _forcePanelInvisible(false), _toolbarHighDrawn(false), _zoomUp(false), _zoomDown(false), - _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false), + _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false), _noDoubleTapRMB(false), _saveToolbarState(false), _saveActiveToolbar(NAME_MAIN_PANEL), _rbutton(false), _hasfocus(true), _usesEmulatedMouse(false), _mouseBackupOld(NULL), _mouseBackupToolbar(NULL), _mouseBackupDim(0) { @@ -1059,14 +1059,11 @@ void OSystem_WINCE3::update_game_settings() { panel->setVisible(false); _saveToolbarState = true; - - // Set Smush Force Redraw rate for Full Throttle - if (!ConfMan.hasKey("Smush_force_redraw")) { - ConfMan.setInt("Smush_force_redraw", 30); - ConfMan.flushToDisk(); - } } + if (ConfMan.hasKey("no_doubletap_rightclick")) + _noDoubleTapRMB = ConfMan.getBool("no_doubletap_rightclick"); + compute_sample_rate(); } @@ -2340,7 +2337,7 @@ bool OSystem_WINCE3::pollEvent(Common::Event &event) { if (_closeClick && (GetTickCount() - _tapTime < 1000)) { if (event.mouse.y <= 20 && _panelInitialized) { // top of screen (show panel) swap_panel_visibility(); - } else { // right click + } else if (!_noDoubleTapRMB) { // right click event.type = Common::EVENT_RBUTTONDOWN; _rbutton = true; } diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h index 8853c156d8..ece8c9b7b1 100644 --- a/backends/platform/wince/wince-sdl.h +++ b/backends/platform/wince/wince-sdl.h @@ -200,6 +200,7 @@ private: bool _zoomUp; // zooming up mode bool _zoomDown; // zooming down mode + bool _noDoubleTapRMB; // disable double tap -> rmb click bool _rbutton; // double tap -> right button simulation bool _closeClick; // flag when taps are spatially close together diff --git a/backends/saves/compressed/compressed-saves.cpp b/backends/saves/compressed/compressed-saves.cpp index 150cf5c47d..11cb1689cd 100644 --- a/backends/saves/compressed/compressed-saves.cpp +++ b/backends/saves/compressed/compressed-saves.cpp @@ -23,278 +23,14 @@ * */ -#include "common/savefile.h" -#include "common/util.h" +#include "common/zlib.h" #include "backends/saves/compressed/compressed-saves.h" -#if defined(USE_ZLIB) -#include <zlib.h> - -#if ZLIB_VERNUM < 0x1204 -#error Version 1.2.0.4 or newer of zlib is required for this code -#endif - -/** - * A simple wrapper class which can be used to wrap around an arbitrary - * other InSaveFile and will then provide on-the-fly decompression support. - * Assumes the compressed data to be in gzip format. - */ -class CompressedInSaveFile : public Common::InSaveFile { -protected: - enum { - BUFSIZE = 16384 // 1 << MAX_WBITS - }; - - byte _buf[BUFSIZE]; - - Common::InSaveFile *_wrapped; - z_stream _stream; - int _zlibErr; - uint32 _pos; - uint32 _origSize; - -public: - - CompressedInSaveFile(Common::InSaveFile *w) : _wrapped(w) { - assert(w != 0); - - _stream.zalloc = Z_NULL; - _stream.zfree = Z_NULL; - _stream.opaque = Z_NULL; - - // Verify file header is correct once more - w->seek(0, SEEK_SET); - uint16 header = w->readUint16BE(); - assert(header == 0x1F8B || - ((header & 0x0F00) == 0x0800 && header % 31 == 0)); - - if (header == 0x1F8B) { - // Retrieve the original file size - w->seek(-4, SEEK_END); - _origSize = w->readUint32LE(); - } else { - // Original size not available in zlib format - _origSize = 0; - } - _pos = 0; - w->seek(0, SEEK_SET); - - // Adding 32 to windowBits indicates to zlib that it is supposed to - // automatically detect whether gzip or zlib headers are used for - // the compressed file. This feature was added in zlib 1.2.0.4, - // released 10 August 2003. - // Note: This is *crucial* for savegame compatibility, do *not* remove! - _zlibErr = inflateInit2(&_stream, MAX_WBITS + 32); - if (_zlibErr != Z_OK) - return; - - // Setup input buffer - _stream.next_in = _buf; - _stream.avail_in = 0; - } - - ~CompressedInSaveFile() { - inflateEnd(&_stream); - delete _wrapped; - } - - bool ioFailed() const { return (_zlibErr != Z_OK) && (_zlibErr != Z_STREAM_END); } - void clearIOFailed() { /* errors here are not recoverable! */ } - - uint32 read(void *dataPtr, uint32 dataSize) { - _stream.next_out = (byte *)dataPtr; - _stream.avail_out = dataSize; - - // Keep going while we get no error - while (_zlibErr == Z_OK && _stream.avail_out) { - if (_stream.avail_in == 0 && !_wrapped->eos()) { - // If we are out of input data: Read more data, if available. - _stream.next_in = _buf; - _stream.avail_in = _wrapped->read(_buf, BUFSIZE); - } - _zlibErr = inflate(&_stream, Z_NO_FLUSH); - } - - // Update the position counter - _pos += dataSize - _stream.avail_out; - - return dataSize - _stream.avail_out; - } - - bool eos() const { - return (_zlibErr == Z_STREAM_END); - //return _pos == _origSize; - } - uint32 pos() const { - return _pos; - } - uint32 size() const { - return _origSize; - } - void seek(int32 offset, int whence = SEEK_SET) { - int32 newPos = 0; - switch(whence) { - case SEEK_END: - newPos = size() - offset; - break; - case SEEK_SET: - newPos = offset; - break; - case SEEK_CUR: - newPos = _pos + offset; - } - offset = newPos - _pos; - - if (offset < 0) - error("Backward seeking not supported in compressed savefiles"); - - // We could implement backward seeking, but it is tricky to do efficiently. - // A simple solution would be to restart the whole decompression from the - // start of the file. Or we could decompress the whole file in one go - // in the constructor, and wrap it into a MemoryReadStream -- but that - // would be rather wasteful. As long as we don't need it, I'd rather not - // implement this at all. -- Fingolfin - - // Skip the given amount of data (very inefficient if one tries to skip - // huge amounts of data, but usually client code will only skip a few - // bytes, so this should be fine. - byte tmpBuf[1024]; - while (!ioFailed() && offset > 0) { - offset -= read(tmpBuf, MIN((int32)sizeof(tmpBuf), offset)); - } - } -}; - -/** - * A simple wrapper class which can be used to wrap around an arbitrary - * other OutSaveFile and will then provide on-the-fly compression support. - * The compressed data is written in the gzip format. - */ -class CompressedOutSaveFile : public Common::OutSaveFile { -protected: - enum { - BUFSIZE = 16384 // 1 << MAX_WBITS - }; - - byte _buf[BUFSIZE]; - Common::OutSaveFile *_wrapped; - z_stream _stream; - int _zlibErr; - - void processData(int flushType) { - // This function is called by both write() and finalize(). - while (_zlibErr == Z_OK && (_stream.avail_in || flushType == Z_FINISH)) { - if (_stream.avail_out == 0) { - if (_wrapped->write(_buf, BUFSIZE) != BUFSIZE) { - _zlibErr = Z_ERRNO; - break; - } - _stream.next_out = _buf; - _stream.avail_out = BUFSIZE; - } - _zlibErr = deflate(&_stream, flushType); - } - } - -public: - CompressedOutSaveFile(Common::OutSaveFile *w) : _wrapped(w) { - assert(w != 0); - _stream.zalloc = Z_NULL; - _stream.zfree = Z_NULL; - _stream.opaque = Z_NULL; - - // Adding 16 to windowBits indicates to zlib that it is supposed to - // write gzip headers. This feature was added in zlib 1.2.0.4, - // released 10 August 2003. - // Note: This is *crucial* for savegame compatibility, do *not* remove! - _zlibErr = deflateInit2(&_stream, - Z_DEFAULT_COMPRESSION, - Z_DEFLATED, - MAX_WBITS + 16, - 8, - Z_DEFAULT_STRATEGY); - assert(_zlibErr == Z_OK); - - _stream.next_out = _buf; - _stream.avail_out = BUFSIZE; - _stream.avail_in = 0; - _stream.next_in = 0; - } - - ~CompressedOutSaveFile() { - finalize(); - deflateEnd(&_stream); - delete _wrapped; - } - - bool ioFailed() const { - return (_zlibErr != Z_OK && _zlibErr != Z_STREAM_END) || _wrapped->ioFailed(); - } - - void clearIOFailed() { - // Note: we don't reset the _zlibErr here, as it is not - // clear in general ho - _wrapped->clearIOFailed(); - } - - void finalize() { - if (_zlibErr != Z_OK) - return; - - // Process whatever remaining data there is. - processData(Z_FINISH); - - // Since processData only writes out blocks of size BUFSIZE, - // we may have to flush some stragglers. - uint remainder = BUFSIZE - _stream.avail_out; - if (remainder > 0) { - if (_wrapped->write(_buf, remainder) != remainder) { - _zlibErr = Z_ERRNO; - } - } - - // Finalize the wrapped savefile, too - _wrapped->finalize(); - } - - uint32 write(const void *dataPtr, uint32 dataSize) { - if (ioFailed()) - return 0; - - // Hook in the new data ... - // Note: We need to make a const_cast here, as zlib is not aware - // of the const keyword. - _stream.next_in = const_cast<byte *>((const byte *)dataPtr); - _stream.avail_in = dataSize; - - // ... and flush it to disk - processData(Z_NO_FLUSH); - - return dataSize - _stream.avail_in; - } -}; - -#endif // USE_ZLIB Common::InSaveFile *wrapInSaveFile(Common::InSaveFile *toBeWrapped) { -#if defined(USE_ZLIB) - if (toBeWrapped) { - uint16 header = toBeWrapped->readUint16BE(); - bool isCompressed = (header == 0x1F8B || - ((header & 0x0F00) == 0x0800 && - header % 31 == 0)); - toBeWrapped->seek(-2, SEEK_CUR); - if (isCompressed) - return new CompressedInSaveFile(toBeWrapped); - } -#endif - return toBeWrapped; + return Common::wrapCompressedReadStream(toBeWrapped); } Common::OutSaveFile *wrapOutSaveFile(Common::OutSaveFile *toBeWrapped) { -#if defined(USE_ZLIB) - if (toBeWrapped) - return new CompressedOutSaveFile(toBeWrapped); -#endif - return toBeWrapped; + return Common::wrapCompressedWriteStream(toBeWrapped); } diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp index dc5e8adca7..0cfd265890 100644 --- a/backends/saves/default/default-saves.cpp +++ b/backends/saves/default/default-saves.cpp @@ -28,7 +28,6 @@ #include "common/savefile.h" #include "common/util.h" #include "common/fs.h" -#include "common/file.h" #include "common/config-manager.h" #include "backends/saves/default/default-saves.h" #include "backends/saves/compressed/compressed-saves.h" @@ -37,7 +36,7 @@ #include <string.h> #include <errno.h> -#if defined(UNIX) || defined(__SYMBIAN32__) +#if defined(UNIX) #include <sys/stat.h> #endif @@ -47,8 +46,6 @@ #else #define DEFAULT_SAVE_PATH ".scummvm" #endif -#elif defined(__SYMBIAN32__) -#define DEFAULT_SAVE_PATH "Savegames" #endif DefaultSaveFileManager::DefaultSaveFileManager() { @@ -64,10 +61,6 @@ DefaultSaveFileManager::DefaultSaveFileManager() { savePath += "/" DEFAULT_SAVE_PATH; ConfMan.registerDefault("savepath", savePath); } -#elif defined(__SYMBIAN32__) - savePath = Symbian::GetExecutablePath(); - savePath += DEFAULT_SAVE_PATH "\\"; - ConfMan.registerDefault("savepath", savePath); #endif #endif // #ifdef DEFAULT_SAVE_PATH } @@ -78,13 +71,13 @@ DefaultSaveFileManager::DefaultSaveFileManager(const Common::String &defaultSave Common::StringList DefaultSaveFileManager::listSavefiles(const char *pattern) { - FilesystemNode savePath(getSavePath()); - FSList savefiles; + Common::FilesystemNode savePath(getSavePath()); + Common::FSList savefiles; Common::StringList results; Common::String search(pattern); if (savePath.lookupFile(savefiles, search, false, true, 0)) { - for (FSList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) { + for (Common::FSList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) { results.push_back(file->getName()); } } @@ -92,11 +85,11 @@ Common::StringList DefaultSaveFileManager::listSavefiles(const char *pattern) { return results; } -void DefaultSaveFileManager::checkPath(const FilesystemNode &dir) { +void DefaultSaveFileManager::checkPath(const Common::FilesystemNode &dir) { const Common::String path = dir.getPath(); clearError(); -#if defined(UNIX) || defined(__SYMBIAN32__) +#if defined(UNIX) struct stat sb; // Check whether the dir exists @@ -108,11 +101,9 @@ void DefaultSaveFileManager::checkPath(const FilesystemNode &dir) { case EACCES: setError(SFM_DIR_ACCESS, "Search or write permission denied: "+path); break; -#if !defined(__SYMBIAN32__) case ELOOP: setError(SFM_DIR_LOOP, "Too many symbolic links encountered while traversing the path: "+path); break; -#endif case ENAMETOOLONG: setError(SFM_DIR_NAMETOOLONG, "The path name is too long: "+path); break; @@ -130,11 +121,9 @@ void DefaultSaveFileManager::checkPath(const FilesystemNode &dir) { case EMLINK: setError(SFM_DIR_LINKMAX, "The link count of the parent directory would exceed {LINK_MAX}: "+path); break; -#if !defined(__SYMBIAN32__) case ELOOP: setError(SFM_DIR_LOOP, "Too many symbolic links encountered while traversing the path: "+path); break; -#endif case ENAMETOOLONG: setError(SFM_DIR_NAMETOOLONG, "The path name is too long: "+path); break; @@ -173,11 +162,11 @@ void DefaultSaveFileManager::checkPath(const FilesystemNode &dir) { Common::InSaveFile *DefaultSaveFileManager::openForLoading(const char *filename) { // Ensure that the savepath is valid. If not, generate an appropriate error. - FilesystemNode savePath(getSavePath()); + Common::FilesystemNode savePath(getSavePath()); checkPath(savePath); if (getError() == SFM_NO_ERROR) { - FilesystemNode file = savePath.getChild(filename); + Common::FilesystemNode file = savePath.getChild(filename); // Open the file for reading Common::SeekableReadStream *sf = file.openForReading(); @@ -190,11 +179,11 @@ Common::InSaveFile *DefaultSaveFileManager::openForLoading(const char *filename) Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const char *filename) { // Ensure that the savepath is valid. If not, generate an appropriate error. - FilesystemNode savePath(getSavePath()); + Common::FilesystemNode savePath(getSavePath()); checkPath(savePath); if (getError() == SFM_NO_ERROR) { - FilesystemNode file = savePath.getChild(filename); + Common::FilesystemNode file = savePath.getChild(filename); // Open the file for saving Common::WriteStream *sf = file.openForWriting(); @@ -208,8 +197,8 @@ Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const char *filename) bool DefaultSaveFileManager::removeSavefile(const char *filename) { clearError(); - FilesystemNode savePath(getSavePath()); - FilesystemNode file = savePath.getChild(filename); + Common::FilesystemNode savePath(getSavePath()); + Common::FilesystemNode file = savePath.getChild(filename); // TODO: Add new method FilesystemNode::remove() if (remove(file.getPath().c_str()) != 0) { diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h index 97845c4623..c02ce588c2 100644 --- a/backends/saves/default/default-saves.h +++ b/backends/saves/default/default-saves.h @@ -28,6 +28,7 @@ #include "common/savefile.h" #include "common/str.h" +#include "common/fs.h" /** * Provides a default savefile manager implementation for common platforms. @@ -54,7 +55,7 @@ protected: * Checks the given path for read access, existence, etc. * Sets the internal error and error message accordingly. */ - void checkPath(const FilesystemNode &dir); + void checkPath(const Common::FilesystemNode &dir); }; #endif |