[Scummvm-git-logs] scummvm master -> e4d17f881c0037009f1ce875109a0000080535b9
bgK
bastien.bouclet at gmail.com
Fri Feb 7 17:34:26 UTC 2020
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
bb27669026 COMMON: Refill the stream buffer after making a large read
b1f95cff9d MOHAWK: RIVEN: Don't accept keyboard actions while the mouse is down
36ef316518 BACKENDS: Allow to configure the stdio buffer size
99b9db456a 3DS: Disable newlib buffered io and use ScummVM's implementation
b08ab0e130 3DS: Implement dynamic graphics modes to improve performance
e4d17f881c 3DS: Convert RGB555 pixels to RGBA5551 when copying to the texture
Commit: bb276690269a14b44bad7eeaf5a23519ce9390cc
https://github.com/scummvm/scummvm/commit/bb276690269a14b44bad7eeaf5a23519ce9390cc
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-02-07T18:33:56+01:00
Commit Message:
COMMON: Refill the stream buffer after making a large read
After reading directly from the parent stream, the buffer needs to be
filled with the end of the read data so seeking back in the stream into
the buffered area and reading returns data consistent with the parent
stream.
Fixes bug #11342 (PSP port only).
Changed paths:
common/stream.cpp
test/common/bufferedseekablereadstream.h
diff --git a/common/stream.cpp b/common/stream.cpp
index d401947..8411019 100644
--- a/common/stream.cpp
+++ b/common/stream.cpp
@@ -327,6 +327,13 @@ uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) {
uint32 n = _parentStream->read(dataPtr, dataSize);
if (_parentStream->eos())
_eos = true;
+
+ // Fill the buffer from the user buffer so a seek back in
+ // the stream into the buffered area brings consistent data.
+ _bufSize = MIN(n, _realBufSize);
+ _pos = _bufSize;
+ memcpy(_buf, (byte *)dataPtr + n - _bufSize, _bufSize);
+
return alreadyRead + n;
}
diff --git a/test/common/bufferedseekablereadstream.h b/test/common/bufferedseekablereadstream.h
index bf21f22..134b2a5 100644
--- a/test/common/bufferedseekablereadstream.h
+++ b/test/common/bufferedseekablereadstream.h
@@ -79,6 +79,16 @@ class BufferedSeekableReadStreamTestSuite : public CxxTest::TestSuite {
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 7);
+ byte readBuffer[8];
+ ssrs.seek(0, SEEK_SET);
+ TS_ASSERT_EQUALS(ssrs.pos(), 0);
+ ssrs.readByte();
+ b = ssrs.read(&readBuffer, 8);
+ ssrs.seek(-1, SEEK_CUR);
+ TS_ASSERT_EQUALS(ssrs.pos(), 8);
+ b = ssrs.readByte();
+ TS_ASSERT_EQUALS(b, 8);
+
delete &ssrs;
}
};
Commit: b1f95cff9da7fbdc99cbfec86284a1a27bb302a3
https://github.com/scummvm/scummvm/commit/b1f95cff9da7fbdc99cbfec86284a1a27bb302a3
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-02-07T18:33:56+01:00
Commit Message:
MOHAWK: RIVEN: Don't accept keyboard actions while the mouse is down
Otherwise the mouse up scripts may execute after a keyboard action
changed the card's state. Affects speedrunners who mash the mouse and
keyboard at the same time.
Changed paths:
engines/mohawk/riven_card.cpp
diff --git a/engines/mohawk/riven_card.cpp b/engines/mohawk/riven_card.cpp
index 67d32c6..657936a 100644
--- a/engines/mohawk/riven_card.cpp
+++ b/engines/mohawk/riven_card.cpp
@@ -892,15 +892,23 @@ RivenScriptPtr RivenCard::onFrame() {
}
RivenScriptPtr RivenCard::onMouseUpdate() {
- RivenScriptPtr script;
+ RivenScriptPtr script(new RivenScript());
+
if (_hoveredHotspot) {
- script = _hoveredHotspot->getScript(kMouseInsideScript);
+ script += _hoveredHotspot->getScript(kMouseInsideScript);
}
- if (!script || script->empty()) {
+ if (script->empty()) {
updateMouseCursor();
}
+ // Clear the pressed hotspot, in case we missed the mouse up event
+ // because we were running a script when it fired.
+ if (_pressedHotspot && _pressedHotspot == _hoveredHotspot) {
+ script += _pressedHotspot->getScript(kMouseUpScript);
+ }
+ _pressedHotspot = nullptr;
+
return script;
}
@@ -1069,6 +1077,10 @@ void RivenCard::playMovie(uint16 index, bool queue) {
}
RivenScriptPtr RivenCard::onKeyAction(RivenAction keyAction) {
+ if (_pressedHotspot) {
+ return RivenScriptPtr(new RivenScript());
+ }
+
static const char *forwardNames[] = {
"forward", "forward1", "forward2", "forward3",
"opendoor", "openhatch", "opentrap", "opengate", "opengrate",
Commit: 36ef316518859316744805c0242900783504d07b
https://github.com/scummvm/scummvm/commit/36ef316518859316744805c0242900783504d07b
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-02-07T18:33:56+01:00
Commit Message:
BACKENDS: Allow to configure the stdio buffer size
Changed paths:
backends/fs/amigaos4/amigaos4-fs.cpp
backends/fs/stdiostream.cpp
backends/fs/stdiostream.h
backends/fs/wii/wii-fs.cpp
diff --git a/backends/fs/amigaos4/amigaos4-fs.cpp b/backends/fs/amigaos4/amigaos4-fs.cpp
index 46e289e..1fd9da6 100644
--- a/backends/fs/amigaos4/amigaos4-fs.cpp
+++ b/backends/fs/amigaos4/amigaos4-fs.cpp
@@ -456,7 +456,20 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
}
Common::SeekableReadStream *AmigaOSFilesystemNode::createReadStream() {
- return StdioStream::makeFromPath(getPath(), false);
+ StdioStream *readStream = StdioStream::makeFromPath(getPath(), false);
+
+ //
+ // 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 (readStream) {
+ readStream->setBufferSize(8192);
+ }
+
+ return readStream;
}
Common::WriteStream *AmigaOSFilesystemNode::createWriteStream() {
diff --git a/backends/fs/stdiostream.cpp b/backends/fs/stdiostream.cpp
index 8206bd1..5f3b5cd 100644
--- a/backends/fs/stdiostream.cpp
+++ b/backends/fs/stdiostream.cpp
@@ -68,6 +68,14 @@ uint32 StdioStream::read(void *ptr, uint32 len) {
return fread((byte *)ptr, 1, len, (FILE *)_handle);
}
+bool StdioStream::setBufferSize(uint32 bufferSize) {
+ if (bufferSize != 0) {
+ return setvbuf((FILE *)_handle, nullptr, _IOFBF, bufferSize) == 0;
+ } else {
+ return setvbuf((FILE *)_handle, nullptr, _IONBF, 0) == 0;
+ }
+}
+
uint32 StdioStream::write(const void *ptr, uint32 len) {
return fwrite(ptr, 1, len, (FILE *)_handle);
}
@@ -79,25 +87,6 @@ bool StdioStream::flush() {
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 defined(__WII__)
- // disable newlib's buffering, the device libraries handle caching
- if (handle)
- setvbuf(handle, NULL, _IONBF, 0);
-#endif
-
if (handle)
return new StdioStream(handle);
return 0;
diff --git a/backends/fs/stdiostream.h b/backends/fs/stdiostream.h
index c3646b4..34a5a48 100644
--- a/backends/fs/stdiostream.h
+++ b/backends/fs/stdiostream.h
@@ -41,19 +41,30 @@ public:
static StdioStream *makeFromPath(const Common::String &path, bool writeMode);
StdioStream(void *handle);
- virtual ~StdioStream();
+ ~StdioStream() override;
- virtual bool err() const override;
- virtual void clearErr() override;
- virtual bool eos() const override;
+ bool err() const override;
+ void clearErr() override;
+ bool eos() const override;
- virtual uint32 write(const void *dataPtr, uint32 dataSize) override;
- virtual bool flush() override;
+ uint32 write(const void *dataPtr, uint32 dataSize) override;
+ bool flush() override;
- virtual int32 pos() const override;
- virtual int32 size() const override;
- virtual bool seek(int32 offs, int whence = SEEK_SET) override;
- virtual uint32 read(void *dataPtr, uint32 dataSize) override;
+ int32 pos() const override;
+ int32 size() const override;
+ bool seek(int32 offs, int whence = SEEK_SET) override;
+ uint32 read(void *dataPtr, uint32 dataSize) override;
+
+ /**
+ * Configure buffered IO
+ *
+ * Must be called immediately after opening the file.
+ * A buffer size of 0 disables buffering.
+ *
+ * @param bufferSize the size of the Stdio read / write buffer
+ * @return success or failure
+ */
+ bool setBufferSize(uint32 bufferSize);
};
#endif
diff --git a/backends/fs/wii/wii-fs.cpp b/backends/fs/wii/wii-fs.cpp
index c54cdef..2d33ab3 100644
--- a/backends/fs/wii/wii-fs.cpp
+++ b/backends/fs/wii/wii-fs.cpp
@@ -206,11 +206,25 @@ AbstractFSNode *WiiFilesystemNode::getParent() const {
}
Common::SeekableReadStream *WiiFilesystemNode::createReadStream() {
- return StdioStream::makeFromPath(getPath(), false);
+ StdioStream *readStream = StdioStream::makeFromPath(getPath(), false);
+
+ // disable newlib's buffering, the device libraries handle caching
+ if (readStream) {
+ readStream->setBufferSize(0);
+ }
+
+ return readStream;
}
Common::WriteStream *WiiFilesystemNode::createWriteStream() {
- return StdioStream::makeFromPath(getPath(), true);
+ StdioStream *writeStream = StdioStream::makeFromPath(getPath(), true);
+
+ // disable newlib's buffering, the device libraries handle caching
+ if (writeStream) {
+ writeStream->setBufferSize(0);
+ }
+
+ return writeStream;
}
bool WiiFilesystemNode::createDirectory() {
Commit: 99b9db456a26ad723689acc2b6cbb9e2bdb8a56b
https://github.com/scummvm/scummvm/commit/99b9db456a26ad723689acc2b6cbb9e2bdb8a56b
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-02-07T18:33:56+01:00
Commit Message:
3DS: Disable newlib buffered io and use ScummVM's implementation
Fixes #11342.
Changed paths:
backends/fs/posix-drives/posix-drives-fs-factory.cpp
backends/fs/posix-drives/posix-drives-fs-factory.h
backends/fs/posix-drives/posix-drives-fs.cpp
backends/fs/posix-drives/posix-drives-fs.h
backends/platform/3ds/osystem.cpp
diff --git a/backends/fs/posix-drives/posix-drives-fs-factory.cpp b/backends/fs/posix-drives/posix-drives-fs-factory.cpp
index 709b57c..848d527 100644
--- a/backends/fs/posix-drives/posix-drives-fs-factory.cpp
+++ b/backends/fs/posix-drives/posix-drives-fs-factory.cpp
@@ -30,21 +30,26 @@
#include <unistd.h>
void DrivesPOSIXFilesystemFactory::addDrive(const Common::String &name) {
- _drives.push_back(Common::normalizePath(name, '/'));
+ _config.drives.push_back(Common::normalizePath(name, '/'));
+}
+
+void DrivesPOSIXFilesystemFactory::configureBuffering(DrivePOSIXFilesystemNode::BufferingMode bufferingMode, uint32 bufferSize) {
+ _config.bufferingMode = bufferingMode;
+ _config.bufferSize = bufferSize;
}
AbstractFSNode *DrivesPOSIXFilesystemFactory::makeRootFileNode() const {
- return new DrivePOSIXFilesystemNode(_drives);
+ return new DrivePOSIXFilesystemNode(_config);
}
AbstractFSNode *DrivesPOSIXFilesystemFactory::makeCurrentDirectoryFileNode() const {
char buf[MAXPATHLEN];
- return getcwd(buf, MAXPATHLEN) ? new DrivePOSIXFilesystemNode(buf, _drives) : nullptr;
+ return getcwd(buf, MAXPATHLEN) ? new DrivePOSIXFilesystemNode(buf, _config) : nullptr;
}
AbstractFSNode *DrivesPOSIXFilesystemFactory::makeFileNodePath(const Common::String &path) const {
assert(!path.empty());
- return new DrivePOSIXFilesystemNode(path, _drives);
+ return new DrivePOSIXFilesystemNode(path, _config);
}
#endif
diff --git a/backends/fs/posix-drives/posix-drives-fs-factory.h b/backends/fs/posix-drives/posix-drives-fs-factory.h
index 08b8b69..5dce588 100644
--- a/backends/fs/posix-drives/posix-drives-fs-factory.h
+++ b/backends/fs/posix-drives/posix-drives-fs-factory.h
@@ -24,6 +24,7 @@
#define POSIX_DRIVES_FILESYSTEM_FACTORY_H
#include "backends/fs/fs-factory.h"
+#include "backends/fs/posix-drives/posix-drives-fs.h"
/**
* A FilesystemFactory implementation for filesystems with a special
@@ -41,6 +42,14 @@ public:
*/
void addDrive(const Common::String &name);
+ /**
+ * Configure file stream buffering
+ *
+ * @param bufferingMode select the buffering implementation to use
+ * @param bufferSize the size of the IO buffer in bytes. A buffer size of 0 means the default size should be used
+ */
+ void configureBuffering(DrivePOSIXFilesystemNode::BufferingMode bufferingMode, uint32 bufferSize);
+
protected:
// FilesystemFactory API
AbstractFSNode *makeRootFileNode() const override;
@@ -48,7 +57,7 @@ protected:
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
private:
- Common::Array<Common::String> _drives;
+ DrivePOSIXFilesystemNode::Config _config;
};
#endif
diff --git a/backends/fs/posix-drives/posix-drives-fs.cpp b/backends/fs/posix-drives/posix-drives-fs.cpp
index c37492e..43297f1 100644
--- a/backends/fs/posix-drives/posix-drives-fs.cpp
+++ b/backends/fs/posix-drives/posix-drives-fs.cpp
@@ -25,14 +25,22 @@
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "backends/fs/posix-drives/posix-drives-fs.h"
+#include "backends/fs/posix/posix-iostream.h"
+
#include "common/algorithm.h"
+#include "common/bufferedstream.h"
#include <dirent.h>
-DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Common::String &path, const DrivesArray &drives) :
+DrivePOSIXFilesystemNode::Config::Config() {
+ bufferingMode = kBufferingModeStdio;
+ bufferSize = 0; // Use the default stdio buffer size
+}
+
+DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Common::String &path, const Config &config) :
POSIXFilesystemNode(path),
_isPseudoRoot(false),
- _drives(drives) {
+ _config(config) {
if (isDrive(path)) {
_isDirectory = true;
@@ -46,13 +54,52 @@ DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Common::String &path, c
}
}
-DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const DrivesArray &drives) :
+DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Config &config) :
_isPseudoRoot(true),
- _drives(drives) {
+ _config(config) {
_isDirectory = true;
_isValid = false;
}
+void DrivePOSIXFilesystemNode::configureStream(StdioStream *stream) {
+ if (!stream) {
+ return;
+ }
+
+ if (_config.bufferingMode != kBufferingModeStdio) {
+ // Disable stdio buffering
+ stream->setBufferSize(0);
+ } else if (_config.bufferSize) {
+ stream->setBufferSize(_config.bufferSize);
+ }
+}
+
+Common::SeekableReadStream *DrivePOSIXFilesystemNode::createReadStream() {
+ PosixIoStream *readStream = PosixIoStream::makeFromPath(getPath(), false);
+
+ configureStream(readStream);
+
+ if (_config.bufferingMode == kBufferingModeScummVM) {
+ uint32 bufferSize = _config.bufferSize != 0 ? _config.bufferSize : 1024;
+ return Common::wrapBufferedSeekableReadStream(readStream, bufferSize, DisposeAfterUse::YES);
+ }
+
+ return readStream;
+}
+
+Common::WriteStream *DrivePOSIXFilesystemNode::createWriteStream() {
+ PosixIoStream *writeStream = PosixIoStream::makeFromPath(getPath(), true);
+
+ configureStream(writeStream);
+
+ if (_config.bufferingMode == kBufferingModeScummVM) {
+ uint32 bufferSize = _config.bufferSize != 0 ? _config.bufferSize : 1024;
+ return Common::wrapBufferedWriteStream(writeStream, bufferSize);
+ }
+
+ return writeStream;
+}
+
DrivePOSIXFilesystemNode *DrivePOSIXFilesystemNode::getChildWithKnownType(const Common::String &n, bool isDirectoryFlag) const {
assert(_isDirectory);
@@ -64,7 +111,7 @@ DrivePOSIXFilesystemNode *DrivePOSIXFilesystemNode::getChildWithKnownType(const
newPath += '/';
newPath += n;
- DrivePOSIXFilesystemNode *child = new DrivePOSIXFilesystemNode(_drives);
+ DrivePOSIXFilesystemNode *child = new DrivePOSIXFilesystemNode(_config);
child->_path = newPath;
child->_isValid = true;
child->_isPseudoRoot = false;
@@ -85,8 +132,8 @@ bool DrivePOSIXFilesystemNode::getChildren(AbstractFSList &list, AbstractFSNode:
assert(_isDirectory);
if (_isPseudoRoot) {
- for (uint i = 0; i < _drives.size(); i++) {
- list.push_back(makeNode(_drives[i]));
+ for (uint i = 0; i < _config.drives.size(); i++) {
+ list.push_back(makeNode(_config.drives[i]));
}
return true;
@@ -141,7 +188,7 @@ AbstractFSNode *DrivePOSIXFilesystemNode::getParent() const {
}
if (isDrive(_path)) {
- DrivePOSIXFilesystemNode *root = new DrivePOSIXFilesystemNode(_drives);
+ DrivePOSIXFilesystemNode *root = new DrivePOSIXFilesystemNode(_config);
return root;
}
@@ -150,8 +197,9 @@ AbstractFSNode *DrivePOSIXFilesystemNode::getParent() const {
bool DrivePOSIXFilesystemNode::isDrive(const Common::String &path) const {
Common::String normalizedPath = Common::normalizePath(path, '/');
- DrivesArray::const_iterator drive = Common::find(_drives.begin(), _drives.end(), normalizedPath);
- return drive != _drives.end();
+ DrivesArray::const_iterator drive = Common::find(_config.drives.begin(), _config.drives.end(), normalizedPath);
+ return drive != _config.drives.end();
}
+
#endif //#if defined(POSIX)
diff --git a/backends/fs/posix-drives/posix-drives-fs.h b/backends/fs/posix-drives/posix-drives-fs.h
index 4c022b7..4396889 100644
--- a/backends/fs/posix-drives/posix-drives-fs.h
+++ b/backends/fs/posix-drives/posix-drives-fs.h
@@ -25,6 +25,8 @@
#include "backends/fs/posix/posix-fs.h"
+class StdioStream;
+
/**
* POSIX file system node where the top-level directory is a hardcoded
* list of drives.
@@ -32,26 +34,46 @@
class DrivePOSIXFilesystemNode : public POSIXFilesystemNode {
protected:
AbstractFSNode *makeNode(const Common::String &path) const override {
- return new DrivePOSIXFilesystemNode(path, _drives);
+ return new DrivePOSIXFilesystemNode(path, _config);
}
public:
typedef Common::Array<Common::String> DrivesArray;
- DrivePOSIXFilesystemNode(const Common::String &path, const DrivesArray &drives);
- DrivePOSIXFilesystemNode(const DrivesArray &drives);
+ enum BufferingMode {
+ /** IO buffering is fully disabled */
+ kBufferingModeDisabled,
+ /** IO buffering is enabled and uses the libc implemenation */
+ kBufferingModeStdio,
+ /** IO buffering is enabled and uses ScummVM's buffering stream wraappers */
+ kBufferingModeScummVM
+ };
+
+ struct Config {
+ DrivesArray drives;
+ BufferingMode bufferingMode;
+ uint32 bufferSize;
+
+ Config();
+ };
+
+ DrivePOSIXFilesystemNode(const Common::String &path, const Config &config);
+ DrivePOSIXFilesystemNode(const Config &config);
- // POSIXFilesystemNode API
+ // AbstractFSNode API
+ Common::SeekableReadStream *createReadStream() override;
+ Common::WriteStream *createWriteStream() override;
AbstractFSNode *getChild(const Common::String &n) const override;
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
AbstractFSNode *getParent() const override;
private:
bool _isPseudoRoot;
- const DrivesArray &_drives;
+ const Config &_config;
DrivePOSIXFilesystemNode *getChildWithKnownType(const Common::String &n, bool isDirectoryFlag) const;
bool isDrive(const Common::String &path) const;
+ void configureStream(StdioStream *stream);
};
#endif
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
index fc8cf94..475d329 100644
--- a/backends/platform/3ds/osystem.cpp
+++ b/backends/platform/3ds/osystem.cpp
@@ -87,6 +87,20 @@ OSystem_3DS::OSystem_3DS():
DrivesPOSIXFilesystemFactory *fsFactory = new DrivesPOSIXFilesystemFactory();
fsFactory->addDrive("sdmc:");
fsFactory->addDrive("romfs:");
+
+ //
+ // Disable newlib's buffered IO, and use ScummVM's own buffering stream wrappers.
+ //
+ // The newlib version in use in devkitPro has performance issues
+ // when seeking with a relative offset. See:
+ // https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=commit;h=59362c80e3a02c011fd0ef3d7f07a20098d2a9d5
+ //
+ // devKitPro has a patch to newlib that can cause data corruption when
+ // seeking back in files and then reading. See:
+ // https://github.com/devkitPro/newlib/issues/16
+ //
+ fsFactory->configureBuffering(DrivePOSIXFilesystemNode::kBufferingModeScummVM, 2048);
+
_fsFactory = fsFactory;
Posix::assureDirectoryExists("/3ds/scummvm/saves/");
Commit: b08ab0e1307460460c8923af4f5d8d134900c489
https://github.com/scummvm/scummvm/commit/b08ab0e1307460460c8923af4f5d8d134900c489
Author: Michael Ball (ballm4788 at gmail.com)
Date: 2020-02-07T18:33:56+01:00
Commit Message:
3DS: Implement dynamic graphics modes to improve performance
When launching a game, switch the graphics mode if necessary
(and by extension the pixel formats used for Graphics::Surfaces
and Sprites) to the one that most closely matches the pixel format
used in-game.
Additional Fixes:
- Fix to prevent cursor position from changing when exiting a menu.
- Fix to prevent updating of Magnification viewport position when
virtual keyboard is open.
- Cosmetic code fixes for improper whitespace and missing curly brackets.
- Remove RGB8 as a mode option because:
1) It was already commented out in the master 3DS backend.
2) There are currently no games that explicitly require it.
Notes:
- As these graphics modes are automatically implemented on a per-game basis, they
are meant for backend use only and are purposefully not accessible through the
Options menu.
- RGBA8 (aka RGBA8888) remains the default pixel format, being used for the launcher
menu, CLUT8, and for games which do not specify a particular format.
Changed paths:
backends/platform/3ds/config.cpp
backends/platform/3ds/main.cpp
backends/platform/3ds/osystem-audio.cpp
backends/platform/3ds/osystem-events.cpp
backends/platform/3ds/osystem-graphics.cpp
backends/platform/3ds/osystem.cpp
backends/platform/3ds/osystem.h
backends/platform/3ds/sprite.cpp
backends/platform/3ds/sprite.h
diff --git a/backends/platform/3ds/config.cpp b/backends/platform/3ds/config.cpp
index 663c6ae..4c567c2 100644
--- a/backends/platform/3ds/config.cpp
+++ b/backends/platform/3ds/config.cpp
@@ -22,9 +22,9 @@
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
-#include "config.h"
-#include "osystem.h"
-#include "options-dialog.h"
+#include "backends/platform/3ds/config.h"
+#include "backends/platform/3ds/osystem.h"
+#include "backends/platform/3ds/options-dialog.h"
#include "common/config-manager.h"
namespace _3DS {
@@ -33,8 +33,9 @@ Config config;
static Common::String prefix = "3ds_";
static bool confGetBool(Common::String key, bool defaultVal) {
- if (ConfMan.hasKey(prefix + key))
+ if (ConfMan.hasKey(prefix + key)) {
return ConfMan.getBool(prefix + key);
+ }
return defaultVal;
}
@@ -43,8 +44,9 @@ static void confSetBool(Common::String key, bool val) {
}
static int confGetInt(Common::String key, int defaultVal) {
- if (ConfMan.hasKey(prefix + key))
+ if (ConfMan.hasKey(prefix + key)) {
return ConfMan.getInt(prefix + key);
+ }
return defaultVal;
}
@@ -67,8 +69,9 @@ void loadConfig() {
} else if (config.screen == kScreenBottom) {
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTTOM);
GSPLCD_PowerOffBacklight(GSPLCD_SCREEN_TOP);
- } else
+ } else {
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
+ }
gspLcdExit();
}
diff --git a/backends/platform/3ds/main.cpp b/backends/platform/3ds/main.cpp
index 4179967..e003d2c 100644
--- a/backends/platform/3ds/main.cpp
+++ b/backends/platform/3ds/main.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "osystem.h"
+#include "backends/platform/3ds/osystem.h"
#include "backends/plugins/3ds/3ds-provider.h"
#include <3ds.h>
diff --git a/backends/platform/3ds/osystem-audio.cpp b/backends/platform/3ds/osystem-audio.cpp
index 3434b53..6f16a58 100644
--- a/backends/platform/3ds/osystem-audio.cpp
+++ b/backends/platform/3ds/osystem-audio.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "osystem.h"
+#include "backends/platform/3ds/osystem.h"
#include "audio/mixer.h"
namespace _3DS {
@@ -55,7 +55,9 @@ static void audioThreadFunc(void *arg) {
while (!osys->exiting) {
svcSleepThread(5000 * 1000); // Wake up the thread every 5 ms
- if (osys->sleeping) continue;
+ if (osys->sleeping) {
+ continue;
+ }
ndspWaveBuf *buf = &buffers[bufferIndex];
if (buf->status == NDSP_WBUF_FREE || buf->status == NDSP_WBUF_DONE) {
diff --git a/backends/platform/3ds/osystem-events.cpp b/backends/platform/3ds/osystem-events.cpp
index 0eb31df..a394741 100644
--- a/backends/platform/3ds/osystem-events.cpp
+++ b/backends/platform/3ds/osystem-events.cpp
@@ -108,10 +108,12 @@ static void eventThreadFunc(void *arg) {
// C-Pad used to control the cursor
hidCircleRead(&circle);
- if (circle.dx < circleDeadzone && circle.dx > -circleDeadzone)
+ if (circle.dx < circleDeadzone && circle.dx > -circleDeadzone) {
circle.dx = 0;
- if (circle.dy < circleDeadzone && circle.dy > -circleDeadzone)
+ }
+ if (circle.dy < circleDeadzone && circle.dy > -circleDeadzone) {
circle.dy = 0;
+ }
cursorDeltaX = (0.0002f + config.sensitivity / 100000.f) * circle.dx * abs(circle.dx);
cursorDeltaY = (0.0002f + config.sensitivity / 100000.f) * circle.dy * abs(circle.dy);
@@ -119,14 +121,18 @@ static void eventThreadFunc(void *arg) {
if (held & KEY_TOUCH) {
hidTouchRead(&touch);
if (config.snapToBorder) {
- if (touch.px < borderSnapZone)
+ if (touch.px < borderSnapZone) {
touch.px = 0;
- if (touch.px > 319 - borderSnapZone)
+ }
+ if (touch.px > 319 - borderSnapZone) {
touch.px = 319;
- if (touch.py < borderSnapZone)
+ }
+ if (touch.py < borderSnapZone) {
touch.py = 0;
- if (touch.py > 239 - borderSnapZone)
+ }
+ if (touch.py > 239 - borderSnapZone) {
touch.py = 239;
+ }
}
osys->transformPoint(touch);
@@ -201,8 +207,9 @@ static void aptHookFunc(APT_HookType hookType, void *param) {
switch (hookType) {
case APTHOOK_ONSUSPEND:
case APTHOOK_ONSLEEP:
- if (g_engine)
+ if (g_engine) {
g_engine->pauseEngine(true);
+ }
osys->sleeping = true;
if (R_SUCCEEDED(gspLcdInit())) {
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
@@ -211,8 +218,9 @@ static void aptHookFunc(APT_HookType hookType, void *param) {
break;
case APTHOOK_ONRESTORE:
case APTHOOK_ONWAKEUP:
- if (g_engine)
+ if (g_engine) {
g_engine->pauseEngine(false);
+ }
osys->sleeping = false;
loadConfig();
break;
@@ -348,8 +356,9 @@ bool OSystem_3DS::pollEvent(Common::Event &event) {
Common::StackLock lock(*eventMutex);
- if (_eventQueue.empty())
+ if (_eventQueue.empty()) {
return false;
+ }
event = _eventQueue.pop();
return true;
@@ -381,7 +390,7 @@ bool OSystem_3DS::notifyEvent(const Common::Event &event) {
return true;
case k3DSEventToggleMagnifyMode:
- if (g_gui.isActive()) {
+ if (_overlayVisible) {
displayMessageOnOSD(_("Magnify Mode cannot be activated in menus."));
} else if (config.screen != kScreenBoth && _magnifyMode == MODE_MAGOFF) {
// TODO: Automatically enable both screens while magnify mode is on
@@ -429,11 +438,13 @@ void OSystem_3DS::runOptionsDialog() {
optionsDialogRunning = true;
OptionsDialog dialog;
- if (g_engine)
+ if (g_engine) {
g_engine->pauseEngine(true);
+ }
int result = dialog.runModal();
- if (g_engine)
+ if (g_engine) {
g_engine->pauseEngine(false);
+ }
if (result > 0) {
int oldScreen = config.screen;
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index 95b3019..61f4fc9 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -23,24 +23,44 @@
#include "backends/platform/3ds/osystem.h"
#include "backends/platform/3ds/shader_shbin.h"
+#include "backends/platform/3ds/options-dialog.h"
+#include "backends/platform/3ds/config.h"
#include "common/rect.h"
#include "graphics/fontman.h"
#include "gui/gui-manager.h"
-#include "options-dialog.h"
-#include "config.h"
// Used to transfer the final rendered display to the framebuffer
-#define DISPLAY_TRANSFER_FLAGS \
- (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | \
- GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
- GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
- GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
+#define DISPLAY_TRANSFER_FLAGS \
+ (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | \
+ GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
+ GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
+ GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
+#define TEXTURE_TRANSFER_FLAGS(fmt) \
+ (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | \
+ GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(fmt) | \
+ GX_TRANSFER_OUT_FORMAT(fmt) | GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
+#define DEFAULT_MODE _modeRGBA8
namespace _3DS {
-
-void OSystem_3DS::initGraphics() {
+/* Group the various enums, values, etc. needed for
+ * each graphics mode into instaces of GfxMode3DS */
+static const GfxMode3DS _modeRGBA8 = { Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0),
+ GPU_RGBA8, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGBA8) };
+static const GfxMode3DS _modeRGB565 = { Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0),
+ GPU_RGB565, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGB565) };
+static const GfxMode3DS _modeRGB555 = { Graphics::PixelFormat(2, 5, 5, 5, 0, 11, 6, 1, 0),
+ GPU_RGBA5551, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGB5A1) };
+static const GfxMode3DS _modeRGB5A1 = { Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0),
+ GPU_RGBA5551, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGB5A1) };
+static const GfxMode3DS _modeCLUT8 = _modeRGBA8;
+
+static const GfxMode3DS *gfxModes[] = { &_modeRGBA8, &_modeRGB565, &_modeRGB555, &_modeRGB5A1, &_modeCLUT8 };
+
+
+void OSystem_3DS::init3DSGraphics() {
+ _gfxState.gfxMode = gfxModes[CLUT8];
_pfGame = Graphics::PixelFormat::createFormatCLUT8();
- _pfGameTexture = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+ _pfDefaultTexture = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
@@ -83,10 +103,12 @@ void OSystem_3DS::initGraphics() {
C3D_CullFace(GPU_CULL_NONE);
}
-void OSystem_3DS::destroyGraphics() {
+void OSystem_3DS::destroy3DSGraphics() {
_gameScreen.free();
_gameTopTexture.free();
_gameBottomTexture.free();
+ _cursor.free();
+ _cursorTexture.free();
_overlay.free();
_activityIcon.free();
@@ -124,8 +146,37 @@ bool OSystem_3DS::getFeatureState(OSystem::Feature f) {
}
}
+GraphicsModeID OSystem_3DS::chooseMode(Graphics::PixelFormat *format) {
+ if (format->bytesPerPixel > 2) {
+ return RGBA8;
+ } else if (format->bytesPerPixel > 1) {
+ if (format->gBits() > 5) {
+ return RGB565;
+ } else if (format->aBits() == 0) {
+ return RGB555;
+ } else {
+ return RGB5A1;
+ }
+ }
+ return CLUT8;
+}
+
+bool OSystem_3DS::setGraphicsMode(GraphicsModeID modeID) {
+ switch (modeID) {
+ case RGBA8:
+ case RGB565:
+ case RGB555:
+ case RGB5A1:
+ case CLUT8:
+ _gfxState.gfxMode = gfxModes[modeID];
+ return true;
+ default:
+ return false;
+ }
+}
+
void OSystem_3DS::initSize(uint width, uint height,
- const Graphics::PixelFormat *format) {
+ const Graphics::PixelFormat *format) {
debug("3ds initsize w:%d h:%d", width, height);
int oldScreen = config.screen;
loadConfig();
@@ -135,16 +186,28 @@ void OSystem_3DS::initSize(uint width, uint height,
_gameWidth = width;
_gameHeight = height;
- _gameTopTexture.create(width, height, _pfGameTexture);
- _overlay.create(400, 320, _pfGameTexture);
_magCenterX = _magWidth / 2;
_magCenterY = _magHeight / 2;
- if (format) {
+ _oldPfGame = _pfGame;
+ if (!format) {
+ _pfGame = Graphics::PixelFormat::createFormatCLUT8();
+ } else {
debug("pixelformat: %d %d %d %d %d", format->bytesPerPixel, format->rBits(), format->gBits(), format->bBits(), format->aBits());
_pfGame = *format;
}
+ /* If the current graphics mode does not fit with the pixel
+ * format being requested, choose one that does and switch to it */
+ assert(_pfGame.bytesPerPixel > 0);
+ if (_pfGame != _oldPfGame) {
+ assert(_transactionState == kTransactionActive);
+ _gfxState.gfxModeID = chooseMode(&_pfGame);
+ _transactionDetails.formatChanged = true;
+ }
+
+ _gameTopTexture.create(width, height, _gfxState.gfxMode);
+ _overlay.create(400, 320, &DEFAULT_MODE);
_gameScreen.create(width, height, _pfGame);
_focusDirty = true;
@@ -188,30 +251,69 @@ void OSystem_3DS::updateSize() {
_gameBottomTexture.setPosition(_gameBottomX, _gameBottomY);
_gameTopTexture.setOffset(0, 0);
_gameBottomTexture.setOffset(0, 0);
- if (_overlayVisible)
+ if (_overlayVisible) {
_cursorTexture.setScale(1.f, 1.f);
- else if (config.screen == kScreenTop)
+ } else if (config.screen == kScreenTop) {
_cursorTexture.setScale(_gameTopTexture.getScaleX(), _gameTopTexture.getScaleY());
- else
+ } else {
_cursorTexture.setScale(_gameBottomTexture.getScaleX(), _gameBottomTexture.getScaleY());
+ }
}
Common::List<Graphics::PixelFormat> OSystem_3DS::getSupportedFormats() const {
Common::List<Graphics::PixelFormat> list;
list.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); // GPU_RGBA8
list.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); // GPU_RGB565
-// list.push_back(Graphics::PixelFormat(3, 0, 0, 0, 8, 0, 8, 16, 0)); // GPU_RGB8
- list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); // RGB555 (needed for FMTOWNS?)
+ list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 11, 6, 1, 0)); // RGB555 (needed for FMTOWNS?)
list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)); // GPU_RGBA5551
list.push_back(Graphics::PixelFormat::createFormatCLUT8());
return list;
}
void OSystem_3DS::beginGFXTransaction() {
- //
+ assert(_transactionState == kTransactionNone);
+ _transactionState = kTransactionActive;
+ _transactionDetails.formatChanged = false;
+ _oldGfxState = _gfxState;
}
+
OSystem::TransactionError OSystem_3DS::endGFXTransaction() {
- return OSystem::kTransactionSuccess;
+ int errors = OSystem::kTransactionSuccess;
+
+ assert(_transactionState != kTransactionNone);
+ if (_transactionState == kTransactionRollback) {
+ if (_gfxState.gfxModeID != _oldGfxState.gfxModeID) {
+ errors |= OSystem::kTransactionModeSwitchFailed;
+ _gfxState = _oldGfxState;
+ } else if ((_gfxState.gfxMode != _oldGfxState.gfxMode) |
+ (_gfxState.gfxMode != gfxModes[_gfxState.gfxModeID])) {
+ errors |= OSystem::kTransactionFormatNotSupported;
+ _gfxState = _oldGfxState;
+ }
+
+ _oldGfxState.setup = false;
+ }
+ if (_transactionDetails.formatChanged) {
+ if (!setGraphicsMode(_gfxState.gfxModeID)) {
+ if (_oldGfxState.setup) {
+ _transactionState = kTransactionRollback;
+ errors |= endGFXTransaction();
+ }
+ } else if (_gfxState.gfxMode != gfxModes[_gfxState.gfxModeID]) {
+ if (_oldGfxState.setup) {
+ _transactionState = kTransactionRollback;
+ errors |= endGFXTransaction();
+ }
+ } else {
+ initSize(_gameWidth, _gameHeight, &_pfGame);
+ clearOverlay();
+ _gfxState.setup = true;
+ _screenChangeId++;
+ }
+ }
+
+ _transactionState = kTransactionNone;
+ return (OSystem::TransactionError)errors;
}
float OSystem_3DS::getScaleRatio() const {
@@ -239,25 +341,34 @@ void OSystem_3DS::grabPalette(byte *colors, uint start, uint num) const {
}
void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
- int y, int w, int h) {
+ int y, int w, int h) {
Common::Rect rect(x, y, x+w, y+h);
_gameScreen.copyRectToSurface(buf, pitch, x, y, w, h);
Graphics::Surface subSurface = _gameScreen.getSubArea(rect);
- Graphics::Surface *convertedSubSurface = subSurface.convertTo(_pfGameTexture, _palette);
- _gameTopTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
+ if (_pfGame == _gameTopTexture.format) {
+ _gameTopTexture.copyRectToSurface(subSurface, x, y, Common::Rect(w, h));
+ } else {
+ Graphics::Surface *convertedSubSurface = subSurface.convertTo(_gameTopTexture.format, _palette);
+ _gameTopTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
+ convertedSubSurface->free();
+ delete convertedSubSurface;
+ }
- convertedSubSurface->free();
- delete convertedSubSurface;
_gameTopTexture.markDirty();
}
void OSystem_3DS::flushGameScreen() {
- Graphics::Surface *converted = _gameScreen.convertTo(_pfGameTexture, _palette);
- _gameTopTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
+ if (_pfGame == _gameTopTexture.format) {
+ _gameTopTexture.copyRectToSurface(_gameScreen, 0, 0, Common::Rect(_gameScreen.w, _gameScreen.h));
+ } else {
+ Graphics::Surface *converted = _gameScreen.convertTo(_gameTopTexture.format, _palette);
+ _gameTopTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
+ converted->free();
+ delete converted;
+ }
+
_gameTopTexture.markDirty();
- converted->free();
- delete converted;
}
Graphics::Surface *OSystem_3DS::lockScreen() {
@@ -268,8 +379,9 @@ void OSystem_3DS::unlockScreen() {
}
void OSystem_3DS::updateScreen() {
- if (sleeping || exiting)
+ if (sleeping || exiting) {
return;
+ }
// updateFocus();
updateMagnify();
@@ -396,10 +508,12 @@ void OSystem_3DS::updateFocus() {
_focusTargetPosY = _focusTargetScaleY * _focusRect.top;
_focusTargetPosX = _focusTargetScaleX * ((float)_focusRect.left - (newWidth - _focusRect.width())/2.f);
}
- if (_focusTargetPosX < 0 && _focusTargetScaleY != 240.f / _gameHeight)
+ if (_focusTargetPosX < 0 && _focusTargetScaleY != 240.f / _gameHeight) {
_focusTargetPosX = 0;
- if (_focusTargetPosY < 0 && _focusTargetScaleX != 400.f / _gameWidth)
+ }
+ if (_focusTargetPosY < 0 && _focusTargetScaleX != 400.f / _gameWidth) {
_focusTargetPosY = 0;
+ }
_focusStepPosX = duration * (_focusTargetPosX - _focusPosX);
_focusStepPosY = duration * (_focusTargetPosY - _focusPosY);
_focusStepScaleX = duration * (_focusTargetScaleX - _focusScaleX);
@@ -407,28 +521,32 @@ void OSystem_3DS::updateFocus() {
}
if (_focusDirty || _focusPosX != _focusTargetPosX || _focusPosY != _focusTargetPosY ||
- _focusScaleX != _focusTargetScaleX || _focusScaleY != _focusTargetScaleY) {
+ _focusScaleX != _focusTargetScaleX || _focusScaleY != _focusTargetScaleY) {
_focusDirty = false;
- if ((_focusStepPosX > 0 && _focusPosX > _focusTargetPosX) || (_focusStepPosX < 0 && _focusPosX < _focusTargetPosX))
+ if ((_focusStepPosX > 0 && _focusPosX > _focusTargetPosX) || (_focusStepPosX < 0 && _focusPosX < _focusTargetPosX)) {
_focusPosX = _focusTargetPosX;
- else if (_focusPosX != _focusTargetPosX)
+ } else if (_focusPosX != _focusTargetPosX) {
_focusPosX += _focusStepPosX;
+ }
- if ((_focusStepPosY > 0 && _focusPosY > _focusTargetPosY) || (_focusStepPosY < 0 && _focusPosY < _focusTargetPosY))
+ if ((_focusStepPosY > 0 && _focusPosY > _focusTargetPosY) || (_focusStepPosY < 0 && _focusPosY < _focusTargetPosY)) {
_focusPosY = _focusTargetPosY;
- else if (_focusPosY != _focusTargetPosY)
+ } else if (_focusPosY != _focusTargetPosY) {
_focusPosY += _focusStepPosY;
+ }
- if ((_focusStepScaleX > 0 && _focusScaleX > _focusTargetScaleX) || (_focusStepScaleX < 0 && _focusScaleX < _focusTargetScaleX))
+ if ((_focusStepScaleX > 0 && _focusScaleX > _focusTargetScaleX) || (_focusStepScaleX < 0 && _focusScaleX < _focusTargetScaleX)) {
_focusScaleX = _focusTargetScaleX;
- else if (_focusScaleX != _focusTargetScaleX)
+ } else if (_focusScaleX != _focusTargetScaleX) {
_focusScaleX += _focusStepScaleX;
+ }
- if ((_focusStepScaleY > 0 && _focusScaleY > _focusTargetScaleY) || (_focusStepScaleY < 0 && _focusScaleY < _focusTargetScaleY))
+ if ((_focusStepScaleY > 0 && _focusScaleY > _focusTargetScaleY) || (_focusStepScaleY < 0 && _focusScaleY < _focusTargetScaleY)) {
_focusScaleY = _focusTargetScaleY;
- else if (_focusScaleY != _focusTargetScaleY)
+ } else if (_focusScaleY != _focusTargetScaleY) {
_focusScaleY += _focusStepScaleY;
+ }
Mtx_Identity(&_focusMatrix);
Mtx_Translate(&_focusMatrix, -_focusPosX, -_focusPosY, 0, true);
@@ -442,17 +560,14 @@ void OSystem_3DS::updateMagnify() {
_magnifyMode = MODE_MAGOFF;
}
- // TODO: When exiting GUI, prevent cursor's position within GUI from changing
- // position of magnification viewport. Possible solution: save in-game cursor
- // coordinates separately from GUI cursor coordinates?
if (_magnifyMode == MODE_MAGON) {
- if (!g_gui.isActive()) {
- _magX = (_cursorX < _magCenterX) ?
- 0 : ((_cursorX < (_gameWidth - _magCenterX)) ?
- _cursorX - _magCenterX : _gameWidth - _magWidth);
- _magY = (_cursorY < _magCenterY) ?
- 0 : ((_cursorY < _gameHeight - _magCenterY) ?
- _cursorY - _magCenterY : _gameHeight - _magHeight);
+ if (!_overlayVisible) {
+ _magX = (_cursorScreenX < _magCenterX) ?
+ 0 : ((_cursorScreenX < (_gameWidth - _magCenterX)) ?
+ _cursorScreenX - _magCenterX : _gameWidth - _magWidth);
+ _magY = (_cursorScreenY < _magCenterY) ?
+ 0 : ((_cursorScreenY < _gameHeight - _magCenterY) ?
+ _cursorScreenY - _magCenterY : _gameHeight - _magHeight);
}
_gameTopTexture.setScale(1.f,1.f);
_gameTopTexture.setPosition(0,0);
@@ -471,7 +586,7 @@ void OSystem_3DS::hideOverlay() {
}
Graphics::PixelFormat OSystem_3DS::getOverlayFormat() const {
- return _pfGameTexture;
+ return _overlay.format;
}
void OSystem_3DS::clearOverlay() {
@@ -482,13 +597,13 @@ void OSystem_3DS::grabOverlay(void *buf, int pitch) {
byte *dst = (byte *)buf;
for (int y = 0; y < getOverlayHeight(); ++y) {
- memcpy(dst, _overlay.getBasePtr(0, y), getOverlayWidth() * _pfGameTexture.bytesPerPixel);
+ memcpy(dst, _overlay.getBasePtr(0, y), getOverlayWidth() * _overlay.format.bytesPerPixel);
dst += pitch;
}
}
void OSystem_3DS::copyRectToOverlay(const void *buf, int pitch, int x,
- int y, int w, int h) {
+ int y, int w, int h) {
_overlay.copyRectToSurface(buf, pitch, x, y, w, h);
_overlay.markDirty();
}
@@ -525,19 +640,21 @@ void OSystem_3DS::displayMessageOnOSD(const char *msg) {
}
// Clip the rect
- if (width > getOverlayWidth())
+ if (width > getOverlayWidth()) {
width = getOverlayWidth();
- if (height > getOverlayHeight())
+ }
+ if (height > getOverlayHeight()) {
height = getOverlayHeight();
+ }
- _osdMessage.create(width, height, _pfGameTexture);
- _osdMessage.fillRect(Common::Rect(width, height), _pfGameTexture.ARGBToColor(200, 0, 0, 0));
+ _osdMessage.create(width, height, &DEFAULT_MODE);
+ _osdMessage.fillRect(Common::Rect(width, height), _pfDefaultTexture.ARGBToColor(200, 0, 0, 0));
// Render the message, centered, and in white
for (i = 0; i < lines.size(); i++) {
font->drawString(&_osdMessage, lines[i],
0, 0 + i * lineHeight + vOffset + lineSpacing, width,
- _pfGameTexture.RGBToColor(255, 255, 255),
+ _pfDefaultTexture.RGBToColor(255, 255, 255),
Graphics::kTextAlignCenter);
}
@@ -549,14 +666,19 @@ void OSystem_3DS::displayActivityIconOnOSD(const Graphics::Surface *icon) {
_activityIcon.free();
} else {
if (!_activityIcon.getPixels() || icon->w != _activityIcon.w || icon->h != _activityIcon.h) {
- _activityIcon.create(icon->w, icon->h, _pfGameTexture);
+ _activityIcon.create(icon->w, icon->h, &DEFAULT_MODE);
+ }
+
+ if (icon->format == _activityIcon.format) {
+ _activityIcon.copyRectToSurface(*icon, 0, 0, Common::Rect(icon->w, icon->h));
+ } else {
+ Graphics::Surface *converted = icon->convertTo(_activityIcon.format);
+ _activityIcon.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
+ converted->free();
+ delete converted;
}
- Graphics::Surface *converted = icon->convertTo(_pfGameTexture);
- _activityIcon.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
_activityIcon.markDirty();
- converted->free();
- delete converted;
}
}
@@ -575,8 +697,13 @@ bool OSystem_3DS::showMouse(bool visible) {
}
void OSystem_3DS::warpMouse(int x, int y) {
- _cursorX = x;
- _cursorY = y;
+ if (!_overlayVisible) {
+ _cursorScreenX = x;
+ _cursorScreenY = y;
+ } else {
+ _cursorOverlayX = x;
+ _cursorOverlayY = y;
+ }
// TODO: adjust for _cursorScalable ?
x -= _cursorHotspotX;
@@ -598,9 +725,9 @@ void OSystem_3DS::setCursorDelta(float deltaX, float deltaY) {
}
void OSystem_3DS::setMouseCursor(const void *buf, uint w, uint h,
- int hotspotX, int hotspotY,
- uint32 keycolor, bool dontScale,
- const Graphics::PixelFormat *format) {
+ int hotspotX, int hotspotY,
+ uint32 keycolor, bool dontScale,
+ const Graphics::PixelFormat *format) {
_cursorScalable = !dontScale;
_cursorHotspotX = hotspotX;
_cursorHotspotY = hotspotY;
@@ -609,7 +736,7 @@ void OSystem_3DS::setMouseCursor(const void *buf, uint w, uint h,
if (w != _cursor.w || h != _cursor.h || _cursor.format != _pfCursor) {
_cursor.create(w, h, _pfCursor);
- _cursorTexture.create(w, h, _pfGameTexture);
+ _cursorTexture.create(w, h, &DEFAULT_MODE);
}
if ( w != 0 && h != 0 ) {
@@ -618,7 +745,11 @@ void OSystem_3DS::setMouseCursor(const void *buf, uint w, uint h,
flushCursor();
- warpMouse(_cursorX, _cursorY);
+ if (!_overlayVisible) {
+ warpMouse(_cursorScreenX, _cursorScreenY);
+ } else {
+ warpMouse(_cursorOverlayX, _cursorOverlayY);
+ }
}
void OSystem_3DS::setCursorPalette(const byte *colors, uint start, uint num) {
@@ -653,7 +784,7 @@ void applyKeyColor(Graphics::Surface *src, Graphics::Surface *dst, const SrcColo
void OSystem_3DS::flushCursor() {
if (_cursor.getPixels()) {
- Graphics::Surface *converted = _cursor.convertTo(_pfGameTexture, _cursorPaletteEnabled ? _cursorPalette : _palette);
+ Graphics::Surface *converted = _cursor.convertTo(_cursorTexture.format, _cursorPaletteEnabled ? _cursorPalette : _palette);
_cursorTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
_cursorTexture.markDirty();
converted->free();
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
index 475d329..11022b6 100644
--- a/backends/platform/3ds/osystem.cpp
+++ b/backends/platform/3ds/osystem.cpp
@@ -27,6 +27,7 @@
#include <3ds.h>
#include "osystem.h"
+#include "backends/platform/3ds/config.h"
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
#include "backends/events/default/default-events.h"
@@ -34,7 +35,6 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/str.h"
-#include "config.h"
#include "backends/fs/posix-drives/posix-drives-fs-factory.h"
#include "backends/fs/posix-drives/posix-drives-fs.h"
@@ -62,8 +62,10 @@ OSystem_3DS::OSystem_3DS():
_cursorPaletteEnabled(false),
_cursorVisible(false),
_cursorScalable(false),
- _cursorX(0),
- _cursorY(0),
+ _cursorScreenX(0),
+ _cursorScreenY(0),
+ _cursorOverlayX(0),
+ _cursorOverlayY(0),
_cursorHotspotX(0),
_cursorHotspotY(0),
_gameTopX(0),
@@ -110,7 +112,7 @@ OSystem_3DS::~OSystem_3DS() {
exiting = true;
destroyEvents();
destroyAudio();
- destroyGraphics();
+ destroy3DSGraphics();
delete _timerManager;
_timerManager = 0;
@@ -125,15 +127,17 @@ void OSystem_3DS::initBackend() {
ConfMan.set("joystick_num", 0);
ConfMan.registerDefault("fullscreen", true);
ConfMan.registerDefault("aspect_ratio", true);
- if (!ConfMan.hasKey("vkeybd_pack_name"))
+ if (!ConfMan.hasKey("vkeybd_pack_name")) {
ConfMan.set("vkeybd_pack_name", "vkeybd_small");
- if (!ConfMan.hasKey("gui_theme"))
+ }
+ if (!ConfMan.hasKey("gui_theme")) {
ConfMan.set("gui_theme", "builtin");
+ }
_timerManager = new DefaultTimerManager();
_savefileManager = new DefaultSaveFileManager("sdmc:/3ds/scummvm/saves/");
- initGraphics();
+ init3DSGraphics();
initAudio();
EventsBaseBackend::initBackend();
initEvents();
@@ -142,7 +146,8 @@ void OSystem_3DS::initBackend() {
void OSystem_3DS::updateConfig() {
if (_gameScreen.getPixels()) {
updateSize();
- warpMouse(_cursorX, _cursorY);
+ (!_overlayVisible) ? warpMouse(_cursorScreenX, _cursorScreenY) :
+ warpMouse(_cursorOverlayX, _cursorOverlayY);
}
}
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
index 2013d10..93439d5 100644
--- a/backends/platform/3ds/osystem.h
+++ b/backends/platform/3ds/osystem.h
@@ -49,6 +49,48 @@ enum InputMode {
MODE_DRAG,
};
+enum GraphicsModeID {
+ RGBA8,
+ RGB565,
+ RGB555,
+ RGB5A1,
+ CLUT8
+};
+
+enum TransactionState {
+ kTransactionNone = 0,
+ kTransactionActive = 1,
+ kTransactionRollback = 2
+};
+
+
+struct TransactionDetails {
+ bool formatChanged, modeChanged;
+
+ TransactionDetails() {
+ formatChanged = false;
+ modeChanged = false;
+ }
+};
+
+typedef struct GfxMode3DS {
+ Graphics::PixelFormat surfaceFormat;
+ GPU_TEXCOLOR textureFormat;
+ uint32 textureTransferFlags;
+} GfxMode3DS;
+
+struct GfxState {
+ bool setup;
+ GraphicsModeID gfxModeID;
+ const GfxMode3DS *gfxMode;
+
+ GfxState() {
+ setup = false;
+ gfxModeID = CLUT8;
+ }
+};
+
+
class OSystem_3DS : public EventsBaseBackend, public PaletteManager, public Common::EventObserver {
public:
OSystem_3DS();
@@ -95,6 +137,8 @@ public:
void initSize(uint width, uint height,
const Graphics::PixelFormat *format = NULL);
virtual int getScreenChangeID() const { return _screenChangeId; };
+ GraphicsModeID chooseMode(Graphics::PixelFormat *format);
+ bool setGraphicsMode(GraphicsModeID modeID);
void beginGFXTransaction();
OSystem::TransactionError endGFXTransaction();
@@ -143,8 +187,8 @@ public:
void updateSize();
private:
- void initGraphics();
- void destroyGraphics();
+ void init3DSGraphics();
+ void destroy3DSGraphics();
void initAudio();
void destroyAudio();
void initEvents();
@@ -166,8 +210,13 @@ private:
Thread audioThread;
// Graphics
- Graphics::PixelFormat _pfGame;
- Graphics::PixelFormat _pfGameTexture;
+ GraphicsModeID _graphicsModeID;
+ TransactionState _transactionState;
+ TransactionDetails _transactionDetails;
+
+ GfxState _gfxState, _oldGfxState;
+ Graphics::PixelFormat _pfDefaultTexture;
+ Graphics::PixelFormat _pfGame, _oldPfGame;
Graphics::PixelFormat _pfCursor;
byte _palette[3 * 256];
byte _cursorPalette[3 * 256];
@@ -221,7 +270,8 @@ private:
bool _cursorPaletteEnabled;
bool _cursorVisible;
bool _cursorScalable;
- float _cursorX, _cursorY;
+ float _cursorScreenX, _cursorScreenY;
+ float _cursorOverlayX, _cursorOverlayY;
float _cursorDeltaX, _cursorDeltaY;
int _cursorHotspotX, _cursorHotspotY;
uint32 _cursorKeyColor;
diff --git a/backends/platform/3ds/sprite.cpp b/backends/platform/3ds/sprite.cpp
index 1b43837..b3bbcb3 100644
--- a/backends/platform/3ds/sprite.cpp
+++ b/backends/platform/3ds/sprite.cpp
@@ -20,12 +20,16 @@
*
*/
+#include "backends/platform/3ds/osystem.h"
#include "backends/platform/3ds/sprite.h"
#include "common/algorithm.h"
#include "common/util.h"
+namespace _3DS {
+
Sprite::Sprite()
- : dirtyPixels(true)
+ : textureTransferFlags(0)
+ , dirtyPixels(true)
, dirtyMatrix(true)
, actualWidth(0)
, actualHeight(0)
@@ -45,12 +49,13 @@ Sprite::~Sprite() {
//
}
-void Sprite::create(uint16 width, uint16 height, const Graphics::PixelFormat &f) {
+void Sprite::create(uint16 width, uint16 height, const GfxMode3DS *mode) {
free();
actualWidth = width;
actualHeight = height;
- format = f;
+ format = mode->surfaceFormat;
+ textureTransferFlags = mode->textureTransferFlags;
w = MAX<uint16>(Common::nextHigher2(width), 64u);
h = MAX<uint16>(Common::nextHigher2(height), 64u);
pitch = w * format.bytesPerPixel;
@@ -58,7 +63,7 @@ void Sprite::create(uint16 width, uint16 height, const Graphics::PixelFormat &f)
if (width && height) {
pixels = linearAlloc(h * pitch);
- C3D_TexInit(&texture, w, h, GPU_RGBA8);
+ C3D_TexInit(&texture, w, h, mode->textureFormat);
C3D_TexSetFilter(&texture, GPU_LINEAR, GPU_LINEAR);
assert(pixels && texture.data);
clear();
@@ -94,7 +99,7 @@ void Sprite::transfer() {
if (pixels && dirtyPixels) {
dirtyPixels = false;
GSPGPU_FlushDataCache(pixels, w * h * format.bytesPerPixel);
- C3D_SyncDisplayTransfer((u32*)pixels, GX_BUFFER_DIM(w, h), (u32*)texture.data, GX_BUFFER_DIM(w, h), TEXTURE_TRANSFER_FLAGS);
+ C3D_SyncDisplayTransfer((u32*)pixels, GX_BUFFER_DIM(w, h), (u32*)texture.data, GX_BUFFER_DIM(w, h), textureTransferFlags);
}
}
@@ -143,3 +148,5 @@ C3D_Mtx* Sprite::getMatrix() {
}
return &modelview;
}
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/sprite.h b/backends/platform/3ds/sprite.h
index 7bb4d36..36cc5fc 100644
--- a/backends/platform/3ds/sprite.h
+++ b/backends/platform/3ds/sprite.h
@@ -29,21 +29,20 @@
#include <3ds.h>
#include <citro3d.h>
-#define TEXTURE_TRANSFER_FLAGS \
- (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | \
- GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
- GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
+namespace _3DS {
typedef struct {
float position[3];
float texcoord[2];
} vertex;
+struct GfxMode3DS;
+
class Sprite : public Graphics::Surface {
public:
Sprite();
~Sprite();
- void create(uint16 width, uint16 height, const Graphics::PixelFormat &format);
+ void create(uint16 width, uint16 height, const GfxMode3DS *mode);
void free();
void convertToInPlace(const Graphics::PixelFormat &dstFormat, const byte *palette = 0);
void transfer();
@@ -64,6 +63,7 @@ public:
uint16 actualHeight;
private:
+ uint32 textureTransferFlags;
bool dirtyPixels;
bool dirtyMatrix;
C3D_Mtx modelview;
@@ -77,4 +77,6 @@ private:
float scaleY;
};
+} // namespace _3DS
+
#endif
Commit: e4d17f881c0037009f1ce875109a0000080535b9
https://github.com/scummvm/scummvm/commit/e4d17f881c0037009f1ce875109a0000080535b9
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-02-07T18:33:56+01:00
Commit Message:
3DS: Convert RGB555 pixels to RGBA5551 when copying to the texture
It's faster than using Graphics::Surface::convertTo
Changed paths:
backends/platform/3ds/osystem-graphics.cpp
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index 61f4fc9..a94557b 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -48,7 +48,7 @@ static const GfxMode3DS _modeRGBA8 = { Graphics::PixelFormat(4, 8, 8, 8, 8, 24,
GPU_RGBA8, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGBA8) };
static const GfxMode3DS _modeRGB565 = { Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0),
GPU_RGB565, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGB565) };
-static const GfxMode3DS _modeRGB555 = { Graphics::PixelFormat(2, 5, 5, 5, 0, 11, 6, 1, 0),
+static const GfxMode3DS _modeRGB555 = { Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0),
GPU_RGBA5551, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGB5A1) };
static const GfxMode3DS _modeRGB5A1 = { Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0),
GPU_RGBA5551, TEXTURE_TRANSFER_FLAGS(GX_TRANSFER_FMT_RGB5A1) };
@@ -264,7 +264,7 @@ Common::List<Graphics::PixelFormat> OSystem_3DS::getSupportedFormats() const {
Common::List<Graphics::PixelFormat> list;
list.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); // GPU_RGBA8
list.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); // GPU_RGB565
- list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 11, 6, 1, 0)); // RGB555 (needed for FMTOWNS?)
+ list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); // RGB555 (needed for FMTOWNS?)
list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)); // GPU_RGBA5551
list.push_back(Graphics::PixelFormat::createFormatCLUT8());
return list;
@@ -340,6 +340,18 @@ void OSystem_3DS::grabPalette(byte *colors, uint start, uint num) const {
memcpy(colors, _palette + 3 * start, 3 * num);
}
+static void copyRect555To5551(const Graphics::Surface &srcSurface, Graphics::Surface &destSurface, uint16 destX, uint16 destY, const Common::Rect &srcRect) {
+ const uint16 *src = (const uint16 *)srcSurface.getBasePtr(srcRect.left, srcRect.top);
+ uint16 *dst = (uint16 *)destSurface.getBasePtr(destX, destY);
+ for (int i = 0; i < srcRect.height(); i++) {
+ for (int j = 0; j < srcRect.width(); j++) {
+ *dst++ = (*src++ << 1) | 1;
+ }
+ src += srcSurface.pitch / 2 - srcRect.width();
+ dst += destSurface.pitch / 2 - srcRect.width();
+ }
+}
+
void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
int y, int w, int h) {
Common::Rect rect(x, y, x+w, y+h);
@@ -348,6 +360,8 @@ void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
if (_pfGame == _gameTopTexture.format) {
_gameTopTexture.copyRectToSurface(subSurface, x, y, Common::Rect(w, h));
+ } else if (_gfxState.gfxMode == &_modeRGB555) {
+ copyRect555To5551(subSurface, _gameTopTexture, x, y, Common::Rect(w, h));
} else {
Graphics::Surface *convertedSubSurface = subSurface.convertTo(_gameTopTexture.format, _palette);
_gameTopTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
@@ -361,6 +375,8 @@ void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
void OSystem_3DS::flushGameScreen() {
if (_pfGame == _gameTopTexture.format) {
_gameTopTexture.copyRectToSurface(_gameScreen, 0, 0, Common::Rect(_gameScreen.w, _gameScreen.h));
+ } else if (_gfxState.gfxMode == &_modeRGB555) {
+ copyRect555To5551(_gameScreen, _gameTopTexture, 0, 0, Common::Rect(_gameScreen.w, _gameScreen.h));
} else {
Graphics::Surface *converted = _gameScreen.convertTo(_gameTopTexture.format, _palette);
_gameTopTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
More information about the Scummvm-git-logs
mailing list