aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Bouclet2016-09-13 20:35:05 +0200
committerBastien Bouclet2016-09-13 20:41:26 +0200
commit9cbaad61405f0a4c8b88eb4e6637b84a12633c1a (patch)
treee4c26a252fb7876c7ed59b6407fa2cbb6011b659
parent05bc82b6225f79ad42e6259be8e227aed6e7c0dc (diff)
downloadscummvm-rg350-9cbaad61405f0a4c8b88eb4e6637b84a12633c1a.tar.gz
scummvm-rg350-9cbaad61405f0a4c8b88eb4e6637b84a12633c1a.tar.bz2
scummvm-rg350-9cbaad61405f0a4c8b88eb4e6637b84a12633c1a.zip
SDL: Switch the OpenGL renderer to use small textures to draw the OSD
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp209
-rw-r--r--backends/graphics/opengl/opengl-graphics.h77
2 files changed, 201 insertions, 85 deletions
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 8861d364e6..3e2be6e8cd 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -57,7 +57,8 @@ OpenGLGraphicsManager::OpenGLGraphicsManager()
_cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false),
_forceRedraw(false), _scissorOverride(3)
#ifdef USE_OSD
- , _osdAlpha(0), _osdFadeStartTime(0), _osd(nullptr)
+ , _osdMessageChangeRequest(false), _osdMessageAlpha(0), _osdMessageFadeStartTime(0), _osdMessageSurface(nullptr),
+ _osdIconChangeRequest(false), _osdIconSurface(nullptr)
#endif
{
memset(_gamePalette, 0, sizeof(_gamePalette));
@@ -69,7 +70,9 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() {
delete _overlay;
delete _cursor;
#ifdef USE_OSD
- delete _osd;
+ delete _osdMessageSurface;
+ delete _osdIconSurface;
+ _osdIconNextData.free();
#endif
#if !USE_FORCED_GLES
ShaderManager::destroy();
@@ -362,13 +365,27 @@ void OpenGLGraphicsManager::updateScreen() {
return;
}
+#ifdef USE_OSD
+ {
+ Common::StackLock lock(_osdMutex);
+
+ if (_osdMessageChangeRequest) {
+ osdMessageUpdateSurface();
+ }
+
+ if (_osdIconChangeRequest) {
+ osdIconUpdateSurface();
+ }
+ }
+#endif
+
// We only update the screen when there actually have been any changes.
if ( !_forceRedraw
&& !_gameScreen->isDirty()
&& !(_overlayVisible && _overlay->isDirty())
&& !(_cursorVisible && _cursor && _cursor->isDirty())
#ifdef USE_OSD
- && _osdAlpha == 0
+ && !_osdMessageSurface && !_osdIconSurface
#endif
) {
return;
@@ -381,9 +398,6 @@ void OpenGLGraphicsManager::updateScreen() {
_cursor->updateGLTexture();
}
_overlay->updateGLTexture();
-#ifdef USE_OSD
- _osd->updateGLTexture();
-#endif
// Clear the screen buffer.
if (_scissorOverride && !_overlayVisible) {
@@ -424,29 +438,45 @@ void OpenGLGraphicsManager::updateScreen() {
#ifdef USE_OSD
// Fourth step: Draw the OSD.
- if (_osdAlpha > 0) {
- Common::StackLock lock(_osdMutex);
-
+ if (_osdMessageSurface) {
// Update alpha value.
- const int diff = g_system->getMillis(false) - _osdFadeStartTime;
+ const int diff = g_system->getMillis(false) - _osdMessageFadeStartTime;
if (diff > 0) {
- if (diff >= kOSDFadeOutDuration) {
+ if (diff >= kOSDMessageFadeOutDuration) {
// Back to full transparency.
- _osdAlpha = 0;
+ _osdMessageAlpha = 0;
} else {
// Do a fade out.
- _osdAlpha = kOSDInitialAlpha - diff * kOSDInitialAlpha / kOSDFadeOutDuration;
+ _osdMessageAlpha = kOSDMessageInitialAlpha - diff * kOSDMessageInitialAlpha / kOSDMessageFadeOutDuration;
}
}
// Set the OSD transparency.
- g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, _osdAlpha / 100.0f);
+ g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, _osdMessageAlpha / 100.0f);
+
+ int dstX = (_outputScreenWidth - _osdMessageSurface->getWidth()) / 2;
+ int dstY = (_outputScreenHeight - _osdMessageSurface->getHeight()) / 2;
// Draw the OSD texture.
- g_context.getActivePipeline()->drawTexture(_osd->getGLTexture(), 0, 0, _outputScreenWidth, _outputScreenHeight);
+ g_context.getActivePipeline()->drawTexture(_osdMessageSurface->getGLTexture(),
+ dstX, dstY, _osdMessageSurface->getWidth(), _osdMessageSurface->getHeight());
// Reset color.
g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+
+ if (_osdMessageAlpha <= 0) {
+ delete _osdMessageSurface;
+ _osdMessageSurface = nullptr;
+ }
+ }
+
+ if (_osdIconSurface) {
+ int dstX = _outputScreenWidth - _osdIconSurface->getWidth() - kOSDIconRightMargin;
+ int dstY = kOSDIconTopMargin;
+
+ // Draw the OSD icon texture.
+ g_context.getActivePipeline()->drawTexture(_osdIconSurface->getGLTexture(),
+ dstX, dstY, _osdIconSurface->getWidth(), _osdIconSurface->getHeight());
}
#endif
@@ -703,85 +733,130 @@ void OpenGLGraphicsManager::setCursorPalette(const byte *colors, uint start, uin
void OpenGLGraphicsManager::displayMessageOnOSD(const char *msg) {
#ifdef USE_OSD
// HACK: Actually no client code should use graphics functions from
- // another thread. But the MT-32 emulator still does, thus we need to
- // make sure this doesn't happen while a updateScreen call is done.
+ // another thread. But the MT-32 emulator and network synchronization still do,
+ // thus we need to make sure this doesn't happen while a updateScreen call is done.
Common::StackLock lock(_osdMutex);
- // Slip up the lines.
+ _osdMessageChangeRequest = true;
+
+ _osdMessageNextData = msg;
+#endif
+}
+
+#ifdef USE_OSD
+void OpenGLGraphicsManager::osdMessageUpdateSurface() {
+ // Split up the lines.
Common::Array<Common::String> osdLines;
- Common::StringTokenizer tokenizer(msg, "\n");
+ Common::StringTokenizer tokenizer(_osdMessageNextData, "\n");
while (!tokenizer.empty()) {
osdLines.push_back(tokenizer.nextToken());
}
// Do the actual drawing like the SDL backend.
const Graphics::Font *font = getFontOSD();
- Graphics::Surface *dst = _osd->getSurface();
- _osd->fill(0);
- _osd->flagDirty();
// Determine a rect which would contain the message string (clipped to the
// screen dimensions).
const int vOffset = 6;
const int lineSpacing = 1;
const int lineHeight = font->getFontHeight() + 2 * lineSpacing;
- int width = 0;
- int height = lineHeight * osdLines.size() + 2 * vOffset;
+ uint width = 0;
+ uint height = lineHeight * osdLines.size() + 2 * vOffset;
for (uint i = 0; i < osdLines.size(); i++) {
- width = MAX(width, font->getStringWidth(osdLines[i]) + 14);
+ width = MAX<uint>(width, font->getStringWidth(osdLines[i]) + 14);
}
// Clip the rect
- width = MIN<int>(width, dst->w);
- height = MIN<int>(height, dst->h);
+ width = MIN<uint>(width, _displayWidth);
+ height = MIN<uint>(height, _displayHeight);
+
+ delete _osdMessageSurface;
+ _osdMessageSurface = nullptr;
+
+ _osdMessageSurface = createSurface(_defaultFormatAlpha);
+ assert(_osdMessageSurface);
+ // We always filter the osd with GL_LINEAR. This assures it's
+ // readable in case it needs to be scaled and does not affect it
+ // otherwise.
+ _osdMessageSurface->enableLinearFiltering(true);
+
+ _osdMessageSurface->allocate(width, height);
- int dstX = (dst->w - width) / 2;
- int dstY = (dst->h - height) / 2;
+ Graphics::Surface *dst = _osdMessageSurface->getSurface();
// Draw a dark gray rect.
const uint32 color = dst->format.RGBToColor(40, 40, 40);
- dst->fillRect(Common::Rect(dstX, dstY, dstX + width, dstY + height), color);
+ dst->fillRect(Common::Rect(0, 0, width, height), color);
- // Render the message, centered, and in white
+ // Render the message in white
const uint32 white = dst->format.RGBToColor(255, 255, 255);
for (uint i = 0; i < osdLines.size(); ++i) {
font->drawString(dst, osdLines[i],
- dstX, dstY + i * lineHeight + vOffset + lineSpacing, width,
+ 0, i * lineHeight + vOffset + lineSpacing, width,
white, Graphics::kTextAlignCenter);
}
+ _osdMessageSurface->updateGLTexture();
+
// Init the OSD display parameters.
- _osdAlpha = kOSDInitialAlpha;
- _osdFadeStartTime = g_system->getMillis() + kOSDFadeOutDelay;
-#endif
-}
+ _osdMessageAlpha = kOSDMessageInitialAlpha;
+ _osdMessageFadeStartTime = g_system->getMillis() + kOSDMessageFadeOutDelay;
-void OpenGLGraphicsManager::copyRectToOSD(const void *buf, int pitch, int x, int y, int w, int h) {
-#ifdef USE_OSD
- _osd->copyRectToTexture(x, y, w, h, buf, pitch);
-#endif
+ // Clear the text update request
+ _osdMessageNextData.clear();
+ _osdMessageChangeRequest = false;
}
+#endif
-void OpenGLGraphicsManager::clearOSD() {
+void OpenGLGraphicsManager::displayActivityIconOnOSD(const Graphics::Surface *icon) {
#ifdef USE_OSD
// HACK: Actually no client code should use graphics functions from
- // another thread. But the MT-32 emulator still does, thus we need to
- // make sure this doesn't happen while a updateScreen call is done.
+ // another thread. But the MT-32 emulator and network synchronization still do,
+ // thus we need to make sure this doesn't happen while a updateScreen call is done.
+ // HACK: We can't make OpenGL calls outside of the main thread. This method
+ // stores a copy of the icon. The main thread will pick up the changed icon,
+ // and copy it to an OpenGL texture.
Common::StackLock lock(_osdMutex);
- Graphics::Surface *dst = _osd->getSurface();
- _osd->fill(0);
- _osd->flagDirty();
+ _osdIconChangeRequest = true;
- // Init the OSD display parameters.
- _osdAlpha = kOSDInitialAlpha;
- _osdFadeStartTime = g_system->getMillis() + kOSDFadeOutDelay;
+ _osdIconNextData.free();
+ _osdIconNextData.copyFrom(*icon);
#endif
}
-Graphics::PixelFormat OpenGLGraphicsManager::getOSDFormat() {
- return _defaultFormatAlpha;
+#ifdef USE_OSD
+void OpenGLGraphicsManager::osdIconUpdateSurface() {
+ delete _osdIconSurface;
+ _osdIconSurface = nullptr;
+
+ if (_osdIconNextData.getPixels()) {
+ Graphics::Surface *converted = _osdIconNextData.convertTo(_defaultFormatAlpha);
+ _osdIconNextData.free();
+
+ _osdIconSurface = createSurface(_defaultFormatAlpha);
+ assert(_osdIconSurface);
+ // We always filter the osd with GL_LINEAR. This assures it's
+ // readable in case it needs to be scaled and does not affect it
+ // otherwise.
+ _osdIconSurface->enableLinearFiltering(true);
+
+ _osdIconSurface->allocate(converted->w, converted->h);
+
+ Graphics::Surface *dst = _osdIconSurface->getSurface();
+
+ // Copy the icon to the texture
+ dst->copyRectToSurface(*converted, 0, 0, Common::Rect(0, 0, converted->w, converted->h));
+
+ converted->free();
+ delete converted;
+
+ _osdIconSurface->updateGLTexture();
+ }
+
+ _osdIconChangeRequest = false;
}
+#endif
void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
assert(_gameScreen->hasPalette());
@@ -849,22 +924,6 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
_overlay->allocate(overlayWidth, overlayHeight);
_overlay->fill(0);
-#ifdef USE_OSD
- if (!_osd || _osd->getFormat() != _defaultFormatAlpha) {
- delete _osd;
- _osd = nullptr;
-
- _osd = createSurface(_defaultFormatAlpha);
- assert(_osd);
- // We always filter the osd with GL_LINEAR. This assures it's
- // readable in case it needs to be scaled and does not affect it
- // otherwise.
- _osd->enableLinearFiltering(true);
- }
- _osd->allocate(_overlay->getWidth(), _overlay->getHeight());
- _osd->fill(0);
-#endif
-
// Re-setup the scaling for the screen and cursor
recalculateDisplayArea();
recalculateCursorScaling();
@@ -949,8 +1008,12 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def
}
#ifdef USE_OSD
- if (_osd) {
- _osd->recreate();
+ if (_osdMessageSurface) {
+ _osdMessageSurface->recreate();
+ }
+
+ if (_osdIconSurface) {
+ _osdIconSurface->recreate();
}
#endif
}
@@ -969,8 +1032,12 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
}
#ifdef USE_OSD
- if (_osd) {
- _osd->destroy();
+ if (_osdMessageSurface) {
+ _osdMessageSurface->destroy();
+ }
+
+ if (_osdIconSurface) {
+ _osdIconSurface->destroy();
}
#endif
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 55d2c5c826..366ad48fad 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -30,6 +30,8 @@
#include "common/frac.h"
#include "common/mutex.h"
+#include "graphics/surface.h"
+
namespace Graphics {
class Font;
} // End of namespace Graphics
@@ -115,9 +117,7 @@ public:
virtual void setCursorPalette(const byte *colors, uint start, uint num);
virtual void displayMessageOnOSD(const char *msg);
- virtual void copyRectToOSD(const void *buf, int pitch, int x, int y, int w, int h);
- virtual void clearOSD();
- virtual Graphics::PixelFormat getOSDFormat();
+ virtual void displayActivityIconOnOSD(const Graphics::Surface *icon);
// PaletteManager interface
virtual void setPalette(const byte *colors, uint start, uint num);
@@ -548,30 +548,79 @@ protected:
private:
/**
- * The OSD's contents.
+ * Request for the OSD icon surface to be updated.
*/
- Surface *_osd;
+ bool _osdMessageChangeRequest;
/**
- * Current opacity level of the OSD.
+ * The next OSD message.
+ *
+ * If this value is not empty, the OSD message will be set
+ * to it on the next frame.
*/
- uint8 _osdAlpha;
+ Common::String _osdMessageNextData;
/**
- * When fading the OSD has started.
+ * Set the OSD message surface with the value of the next OSD message.
*/
- uint32 _osdFadeStartTime;
+ void osdMessageUpdateSurface();
/**
- * Mutex to allow displayMessageOnOSD to be used from the audio thread.
+ * The OSD message's contents.
*/
- Common::Mutex _osdMutex;
+ Surface *_osdMessageSurface;
+
+ /**
+ * Current opacity level of the OSD message.
+ */
+ uint8 _osdMessageAlpha;
+
+ /**
+ * When fading the OSD message has started.
+ */
+ uint32 _osdMessageFadeStartTime;
+
+ enum {
+ kOSDMessageFadeOutDelay = 2 * 1000,
+ kOSDMessageFadeOutDuration = 500,
+ kOSDMessageInitialAlpha = 80
+ };
+
+ /**
+ * Request for the OSD icon surface to be updated.
+ */
+ bool _osdIconChangeRequest;
+
+ /**
+ * The next OSD background activity icon.
+ *
+ * The OSD icon will be updated with this data on the next frame.
+ * Can be an unallocated surface if the OSD icon should not be displayed.
+ */
+ Graphics::Surface _osdIconNextData;
+
+ /**
+ * Set the OSD icon surface with the value of the next OSD icon.
+ */
+ void osdIconUpdateSurface();
+
+ /**
+ * The OSD background activity icon's contents.
+ */
+ Surface *_osdIconSurface;
enum {
- kOSDFadeOutDelay = 2 * 1000,
- kOSDFadeOutDuration = 500,
- kOSDInitialAlpha = 80
+ kOSDIconTopMargin = 10,
+ kOSDIconRightMargin = 10
};
+
+ /**
+ * Mutex for the OSD draw calls.
+ *
+ * Mutex to allow displayMessageOnOSD and displayActivityIconOnOSD
+ * to be used from the audio and network threads.
+ */
+ Common::Mutex _osdMutex;
#endif
};