GRAPHICS: MACGUI: Add WM direct copy mode

This does not keep the current screen state cached in a surface, but re-creates
the screen from its various components each time something changes. This avoids
an intermediate blitting.

The mode is enabled just by not providing a surface to the WM, and instead
providing a width and height.
This commit is contained in:
Nathanael Gentry 2020-08-11 12:54:14 -04:00
parent 59dd1716b1
commit a639ae4002
5 changed files with 103 additions and 24 deletions

View File

@ -52,6 +52,10 @@ public:
MacMenu(int id, const Common::Rect &bounds, MacWindowManager *wm);
~MacMenu();
virtual ManagedSurface *getBorderSurface() override { return nullptr; }
virtual const Common::Rect &getInnerDimensions() override { return _dims; }
virtual bool isDirty() override { return _contentIsDirty || _dimensionsDirty; }
static Common::StringArray *readMenuFromResource(Common::SeekableReadStream *res);
static MacMenu *createMenuFromPEexe(Common::PEResources *exe, MacWindowManager *wm);

View File

@ -191,7 +191,7 @@ void MacWindow::center(bool toCenter) {
if (!_wm)
return;
Common::Rect screen = _wm->_screen->getBounds();
Common::Rect screen = _wm->getScreenBounds();
if (toCenter) {
move((screen.width() - _dims.width()) / 2, (screen.height() - _dims.height()) / 2);

View File

@ -115,6 +115,28 @@ public:
*/
ManagedSurface *getWindowSurface() { return _composeSurface; }
/**
* Method to access the border surface of the window.
* @return A pointer to the border surface of the window.
*/
virtual ManagedSurface *getBorderSurface() = 0;
/**
* Accessor to retrieve the dimensions of the inner surface of the window
* (i.e. without taking borders into account).
* Note that the returned dimensions' position is relative to the WM's
* screen, just like in getDimensions().
* @return The inner dimensions of the window.
*/
virtual const Common::Rect &getInnerDimensions() = 0;
/**
* Method called to internally draw the window. This relies on the window
* being marked as dirty unless otherwise specified.
* @param forceRedraw Its behavior depends on the subclass.
*/
virtual bool draw(bool forceRedraw = false) = 0;
/**
* Method called to draw the window into the target surface.
* This method is most often called by the WM, and relies on
@ -133,6 +155,11 @@ public:
*/
virtual bool processEvent(Common::Event &event) = 0;
/**
* Method that checks if the window is needs redrawing.
*/
virtual bool isDirty() = 0;
/**
* Set the callback that will be used when an event needs to be processed.
* @param callback A function pointer to a function that accepts:
@ -196,15 +223,6 @@ public:
*/
virtual void setDimensions(const Common::Rect &r) override;
/**
* Accessor to retrieve the dimensions of the inner surface of the window
* (i.e. without taking borders into account).
* Note that the returned dimensions' position is relative to the WM's
* screen, just like in getDimensions().
* @return The inner dimensions of the window.
*/
const Common::Rect &getInnerDimensions() { return _innerDims; }
/**
* Set a background pattern for the window.
* @param pattern
@ -221,6 +239,9 @@ public:
virtual bool draw(bool forceRedraw = false) override;
virtual void blit(ManagedSurface *g, Common::Rect &dest) override;
virtual const Common::Rect &getInnerDimensions() override { return _innerDims; }
virtual ManagedSurface *getBorderSurface() override { return &_borderSurface; }
/**
* Centers the window using the dimensions of the parent window manager, or undoes this; does
* nothing if WM is null.
@ -307,6 +328,8 @@ public:
void markAllDirty();
void mergeDirtyRects();
virtual bool isDirty() override { return _borderIsDirty || _contentIsDirty; }
private:
void prepareBorderSurface(ManagedSurface *g);
void drawSimpleBorder(ManagedSurface *g);

View File

@ -156,7 +156,7 @@ static const byte macCursorCrossBar[] = {
static void menuTimerHandler(void *refCon);
MacWindowManager::MacWindowManager(uint32 mode, MacPatterns *patterns) {
_screen = 0;
_screen = nullptr;
_screenCopy = nullptr;
_desktopBmp = nullptr;
_desktop = nullptr;
@ -243,6 +243,17 @@ void MacWindowManager::setScreen(ManagedSurface *screen) {
drawDesktop();
}
void MacWindowManager::setScreen(int w, int h) {
if (_desktop)
_desktop->free();
else
_desktop = new ManagedSurface();
_screenDims = Common::Rect(w, h);
_desktop->create(w, h, PixelFormat::createFormatCLUT8());
drawDesktop();
}
void MacWindowManager::setMode(uint32 mode) {
_mode = mode;
@ -300,7 +311,7 @@ MacMenu *MacWindowManager::addMenu() {
delete _menu;
}
_menu = new MacMenu(getNextId(), _screen->getBounds(), this);
_menu = new MacMenu(getNextId(), getScreenBounds(), this);
_windows[_menu->getId()] = _menu;
@ -327,6 +338,9 @@ void MacWindowManager::activateMenu() {
}
void MacWindowManager::activateScreenCopy() {
if (!_screen)
return;
if (!_screenCopy)
_screenCopy = new ManagedSurface(*_screen); // Create a copy
else
@ -463,19 +477,22 @@ void MacWindowManager::drawDesktop() {
}
void MacWindowManager::draw() {
assert(_screen);
removeMarked();
if (_fullRefresh) {
if (!(_mode & kWMModeNoDesktop)) {
if (_desktop->w != _screen->w || _desktop->h != _screen->h) {
_desktop->free();
_desktop->create(_screen->w, _screen->h, PixelFormat::createFormatCLUT8());
drawDesktop();
}
Common::Rect screen = getScreenBounds();
if (_desktop->w != screen.width() || _desktop->h != screen.height()) {
_desktop->free();
_desktop->create(screen.width(), screen.height(), PixelFormat::createFormatCLUT8());
drawDesktop();
}
if (_screen) {
_screen->blitFrom(*_desktop, Common::Point(0, 0));
g_system->copyRectToScreen(_screen->getPixels(), _screen->pitch, 0, 0, _screen->w, _screen->h);
} else {
_screenCopyPauseToken = new PauseToken(pauseEngine());
g_system->copyRectToScreen(_desktop->getPixels(), _desktop->pitch, 0, 0, _desktop->w, _desktop->h);
}
if (_redrawEngineCallback != nullptr)
@ -489,7 +506,7 @@ void MacWindowManager::draw() {
continue;
Common::Rect clip = w->getDimensions();
clip.clip(_screen->getBounds());
clip.clip(getScreenBounds());
clip.clip(Common::Rect(0, 0, g_system->getWidth() - 1, g_system->getHeight() - 1));
if (clip.isEmpty())
@ -505,7 +522,26 @@ void MacWindowManager::draw() {
}
}
if (w->draw(_screen, forceRedraw)) {
if (!_screen) {
if (w->isDirty() || forceRedraw) {
w->draw(forceRedraw);
Common::Rect dims = w->getDimensions();
Common::Rect innerDims = w->getInnerDimensions();
g_system->copyRectToScreen(w->getBorderSurface()->getBasePtr(0, 0), w->getBorderSurface()->pitch, clip.left, clip.top, dims.width(), dims.height());
g_system->copyRectToScreen(w->getWindowSurface()->getBasePtr(MAX(clip.left - innerDims.left, 0), MAX(clip.top - innerDims.top, 0)), w->getWindowSurface()->pitch, clip.left + (-dims.left + innerDims.left), clip.top + (-dims.top + innerDims.top), innerDims.width(), innerDims.height());
dirtyRects.push_back(clip);
}
if (_screenCopyPauseToken) {
_screenCopyPauseToken->clear();
delete _screenCopyPauseToken;
_screenCopyPauseToken = nullptr;
}
} else if (w->draw(_screen, forceRedraw)) {
w->setDirty(false);
g_system->copyRectToScreen(_screen->getBasePtr(clip.left, clip.top), _screen->pitch, clip.left, clip.top, clip.width(), clip.height());
dirtyRects.push_back(clip);
@ -513,8 +549,13 @@ void MacWindowManager::draw() {
}
// Menu is drawn on top of everything and always
if (_menu && !(_mode & kWMModeFullscreen))
_menu->draw(_screen, _fullRefresh);
if (_menu && !(_mode & kWMModeFullscreen)) {
if (_screen) {
_menu->draw(_screen, _fullRefresh);
} else {
g_system->copyRectToScreen(_menu->getWindowSurface()->getBasePtr(_menu->_dims.left, _menu->_dims.top), _menu->getWindowSurface()->pitch, _menu->_dims.left, _menu->_dims.top, _menu->_dims.width(), _menu->_dims.height());
}
}
_fullRefresh = false;
}

View File

@ -147,6 +147,14 @@ public:
* @param screen Surface on which the desktop will be drawn.
*/
void setScreen(ManagedSurface *screen);
/**
* Mutator to indicate the dimensions of the desktop, when a backing surface is not used.
* Note that this method should be called as soon as the WM is created.
* @param screen Surface on which the desktop will be drawn.
*/
void setScreen(int w, int h);
/**
* Create a window with the given parameters.
* Note that this method allocates the necessary memory for the window.
@ -258,6 +266,8 @@ public:
MacWidget *getActiveWidget() { return _activeWidget; }
Common::Rect getScreenBounds() { return _screen ? _screen->getBounds() : _screenDims; }
void clearWidgetRefs(MacWidget *widget);
void pushCursor(MacCursorType type, Cursor *cursor = nullptr);
@ -325,6 +335,7 @@ public:
ManagedSurface *_screen;
ManagedSurface *_screenCopy;
Common::Rect _screenDims;
private:
Common::List<BaseMacWindow *> _windowStack;