diff options
| author | Bastien Bouclet | 2016-09-13 20:35:05 +0200 | 
|---|---|---|
| committer | Bastien Bouclet | 2016-09-13 20:41:26 +0200 | 
| commit | 9cbaad61405f0a4c8b88eb4e6637b84a12633c1a (patch) | |
| tree | e4c26a252fb7876c7ed59b6407fa2cbb6011b659 | |
| parent | 05bc82b6225f79ad42e6259be8e227aed6e7c0dc (diff) | |
| download | scummvm-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.cpp | 209 | ||||
| -rw-r--r-- | backends/graphics/opengl/opengl-graphics.h | 77 | 
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  };  | 
