From 4645e706a8c62fb291efb987dca9fa82394139ee Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 17 Jul 2008 21:58:43 +0000 Subject: Rendering pipeline (almost) fixed. This time for real. svn-id: r33092 --- graphics/VectorRenderer.cpp | 9 +++-- gui/ThemeRenderer.cpp | 81 ++++++++++++++++++++++++++++++++++----------- gui/ThemeRenderer.h | 29 ++++++++++++---- gui/dialog.cpp | 6 +++- gui/newgui.cpp | 69 ++++++++++++++++++++++---------------- gui/newgui.h | 11 +++++- gui/theme.h | 14 ++++++++ 7 files changed, 159 insertions(+), 60 deletions(-) diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp index a8915eb0a6..f2ce0e26b8 100644 --- a/graphics/VectorRenderer.cpp +++ b/graphics/VectorRenderer.cpp @@ -487,11 +487,7 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer: int real_radius = r; int short_h = h - r + 2; int long_h = h; - PixelType color1, color2; - - if (fill_m == kFillForeground || fill_m == kFillBackground) - color1 = color2 = color; - + if (fill_m == kFillDisabled) { while (sw++ < Base::_strokeWidth) { colorFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color); @@ -543,6 +539,9 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer: } } else { __BE_RESET(); + + PixelType color1, color2; + color1 = color2 = color; while (x++ < y) { __BE_ALGORITHM(); diff --git a/gui/ThemeRenderer.cpp b/gui/ThemeRenderer.cpp index 7b64baba11..9b3d115576 100644 --- a/gui/ThemeRenderer.cpp +++ b/gui/ThemeRenderer.cpp @@ -76,7 +76,8 @@ const char *ThemeRenderer::kDrawDataStrings[] = { ThemeRenderer::ThemeRenderer(Common::String themeName, GraphicsMode mode) : _vectorRenderer(0), _system(0), _graphicsMode(kGfxDisabled), - _screen(0), _backBuffer(0), _bytesPerPixel(0), _initOk(false), _themeOk(false), _enabled(false) { + _screen(0), _backBuffer(0), _bytesPerPixel(0), _initOk(false), + _themeOk(false), _enabled(false), _dialogCount(0), _cachedDialog(0) { _system = g_system; _parser = new ThemeParser(this); @@ -238,8 +239,11 @@ bool ThemeRenderer::loadTheme(Common::String themeName) { warning("Error when parsing custom theme '%s': Missing data assets.", themeName.c_str()); return false; #endif - } else if (_widgets[i]->_cached) { - // draw the cached widget to the cache surface + } else { + calcBackgroundOffset((DrawData)i); + + // TODO: draw the cached widget to the cache surface + if (_widgets[i]->_cached) {} } } @@ -293,6 +297,14 @@ void ThemeRenderer::drawCached(DrawData type, const Common::Rect &r) { void ThemeRenderer::drawDD(DrawData type, const Common::Rect &r, uint32 dynamicData) { if (_widgets[type] == 0) return; + + Common::Rect extendedRect = r; + extendedRect.grow(kDirtyRectangleThreshold); + extendedRect.right += _widgets[type]->_backgroundOffset; + extendedRect.bottom += _widgets[type]->_backgroundOffset; + + restoreBackground(extendedRect); + addDirtyRect(extendedRect); if (isWidgetCached(type, r)) { drawCached(type, r); @@ -312,6 +324,33 @@ void ThemeRenderer::drawDDText(DrawData type, const Common::Rect &r, const Commo } } +void ThemeRenderer::calcBackgroundOffset(DrawData type) { + uint maxShadow = 0; + for (Common::List::const_iterator step = _widgets[type]->_steps.begin(); + step != _widgets[type]->_steps.end(); ++step) { + if (((*step).autoWidth || (*step).autoHeight) && (*step).shadow > maxShadow) + maxShadow = (*step).shadow; + } + + _widgets[type]->_backgroundOffset = maxShadow; +} + +void ThemeRenderer::restoreBackground(Common::Rect r, bool special) { +/* const OverlayColor *src = (const OverlayColor*)_backBuffer->getBasePtr(r.left, r.top); + OverlayColor *dst = (OverlayColor*)_screen->getBasePtr(r.left, r.top); + + int h = r.height(); + int w = r.width(); + while (h--) { + memcpy(dst, src, w * sizeof(OverlayColor)); + src += _backBuffer->w; + dst += _screen->w; + }*/ + + debugWidgetPosition("", r); + printf(" BG_RESTORE "); +} + void ThemeRenderer::drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints) { if (!ready()) return; @@ -327,8 +366,6 @@ void ThemeRenderer::drawButton(const Common::Rect &r, const Common::String &str, drawDD(dd, r); drawDDText(dd, r, str); - - addDirtyRect(r); } void ThemeRenderer::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) { @@ -336,7 +373,6 @@ void ThemeRenderer::drawLineSeparator(const Common::Rect &r, WidgetStateInfo sta return; drawDD(kDDSeparator, r); - addDirtyRect(r); } void ThemeRenderer::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) { @@ -355,8 +391,6 @@ void ThemeRenderer::drawCheckbox(const Common::Rect &r, const Common::String &st r2.right = r.right; drawDDText(checked ? kDDCheckboxEnabled : kDDCheckboxDisabled, r2, str); - - addDirtyRect(r); } void ThemeRenderer::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) { @@ -369,8 +403,6 @@ void ThemeRenderer::drawSlider(const Common::Rect &r, int width, WidgetStateInfo r2.setWidth(MIN((int16)width, r.width())); drawDD(kDDSliderFull, r2); - - addDirtyRect(r); } void ThemeRenderer::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState sb_state, WidgetStateInfo state) { @@ -379,8 +411,6 @@ void ThemeRenderer::drawScrollbar(const Common::Rect &r, int sliderY, int slider drawDD(kDDScrollbarBase, r); // TODO: Need to find a scrollbar in the GUI for testing... :p - - addDirtyRect(r); } void ThemeRenderer::drawDialogBackground(const Common::Rect &r, uint16 hints, WidgetStateInfo state) { @@ -396,8 +426,6 @@ void ThemeRenderer::drawDialogBackground(const Common::Rect &r, uint16 hints, Wi } else { drawDD(kDDDefaultBackground, r); } - - addDirtyRect(r); } void ThemeRenderer::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state) { @@ -405,7 +433,6 @@ void ThemeRenderer::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo return; debugWidgetPosition("Caret", r); - addDirtyRect(r); } void ThemeRenderer::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, TextAlign align) { @@ -420,8 +447,6 @@ void ThemeRenderer::drawPopUpWidget(const Common::Rect &r, const Common::String Common::Rect text(r.left, r.top, r.right - 16, r.bottom); drawDDText(dd, text, sel); } - - addDirtyRect(r); } void ThemeRenderer::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) { @@ -452,8 +477,6 @@ void ThemeRenderer::drawWidgetBackground(const Common::Rect &r, uint16 hints, Wi drawDD(kDDWidgetBackgroundDefault, r); break; } - - addDirtyRect(r); } void ThemeRenderer::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) { @@ -514,4 +537,24 @@ void ThemeRenderer::renderDirtyScreen() { _dirtyScreen.clear(); } +void ThemeRenderer::openDialog(bool top) { + if (_dialogCount++ == 0) + return; + + _cachedDialog = _dialogCount - 1; + memcpy(_backBuffer->pixels, _screen->pixels, _screen->w * _screen->h * _screen->bytesPerPixel); +} + +bool ThemeRenderer::closeDialog() { + assert(_dialogCount); + + _dialogCount--; + + if (_dialogCount != _cachedDialog) + return false; + + memcpy(_screen->pixels, _backBuffer->pixels, _screen->w * _screen->h * _screen->bytesPerPixel); + return true; +} + } // end of namespace GUI. diff --git a/gui/ThemeRenderer.h b/gui/ThemeRenderer.h index a5fccd8163..11728f8e6e 100644 --- a/gui/ThemeRenderer.h +++ b/gui/ThemeRenderer.h @@ -42,13 +42,23 @@ namespace GUI { struct WidgetDrawData; struct WidgetDrawData { + /** List of all the steps needed to draw this widget */ Common::List _steps; + + /** Single step that defines the text shown inside the widget */ Graphics::TextStep _textStep; bool _hasText; + /** Extra space that the widget occupies when it's drawn. + E.g. when taking into account rounded corners, drop shadows, etc + Used when restoring the widget background */ + uint16 _backgroundOffset; + + /** Sets whether the widget is cached beforehand. */ bool _cached; + + /** Texture where the cached widget is stored. */ Graphics::Surface *_surfaceCache; - uint32 _cachedW, _cachedH; ~WidgetDrawData() { _steps.clear(); @@ -145,14 +155,18 @@ public: void refresh() {} void enable(); void disable(); - void openDialog() {} - void closeAllDialogs() {} + + void closeAllDialogs() { + _dialogCount = 0; + _cachedDialog = 0; + } void updateScreen(); //{} void resetDrawArea() {} - void openDialog(bool top) {} + void openDialog(bool top);// {} + bool closeDialog();// {} /** Font management */ const Graphics::Font *getFont(FontStyle font) const { return _font; } @@ -177,7 +191,7 @@ public: void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state) {} bool addDirtyRect(Common::Rect r, bool backup = false, bool special = false) { - r.grow(kDirtyRectangleThreshold); +// r.grow(kDirtyRectangleThreshold); _dirtyScreen.push_back(r); return true; } @@ -260,13 +274,14 @@ protected: bool isWidgetCached(DrawData type, const Common::Rect &r); void drawCached(DrawData type, const Common::Rect &r); + void calcBackgroundOffset(DrawData type); inline void drawDD(DrawData type, const Common::Rect &r, uint32 dynamicData = 0); inline void drawDDText(DrawData type, const Common::Rect &r, const Common::String &text); inline void debugWidgetPosition(const char *name, const Common::Rect &r); // TODO - void restoreBackground(Common::Rect r, bool special = false) {} + void restoreBackground(Common::Rect r, bool special = false); int getTabSpacing() const { return 0; @@ -295,6 +310,8 @@ protected: Graphics::Surface *_screen; Graphics::Surface *_backBuffer; + uint32 _dialogCount; + uint32 _cachedDialog; int _bytesPerPixel; GraphicsMode _graphicsMode; diff --git a/gui/dialog.cpp b/gui/dialog.cpp index ef396301be..0594941d65 100644 --- a/gui/dialog.cpp +++ b/gui/dialog.cpp @@ -132,7 +132,11 @@ void Dialog::releaseFocus() { } void Dialog::draw() { - g_gui._needRedraw = true; + //TANOKU - FIXME when is this enabled? what does this do? + // Update: called on tab drawing, mainly... + // we can pass this as open a new dialog or something +// g_gui._needRedraw = true; + g_gui._redrawStatus = GUI::NewGui::kRedrawTopDialog; } void Dialog::drawDialog() { diff --git a/gui/newgui.cpp b/gui/newgui.cpp index 4d0b3905b9..f3734c6ee0 100644 --- a/gui/newgui.cpp +++ b/gui/newgui.cpp @@ -81,7 +81,7 @@ void GuiObject::reflowLayout() { } // Constructor -NewGui::NewGui() : _needRedraw(false), +NewGui::NewGui() : _redrawStatus(kRedrawDisabled), _stateIsSaved(false), _cursorAnimateCounter(0), _cursorAnimateTimer(0) { _theme = 0; _useStdCursor = false; @@ -187,29 +187,48 @@ bool NewGui::loadNewTheme(const Common::String &style) { void NewGui::redraw() { int i; - // Restore the overlay to its initial state, then draw all dialogs. - // This is necessary to get the blending right. - _theme->clearAll(); + if (_redrawStatus == kRedrawDisabled) + return; - _theme->closeAllDialogs(); - //for (i = 0; i < _dialogStack.size(); ++i) - // _theme->closeDialog(); + switch (_redrawStatus) { + case kRedrawCloseDialog: + printf("Dialog closed!\n"); + if (_theme->closeDialog()) + break; - for (i = 0; i < _dialogStack.size(); i++) { - // Special treatment when topmost dialog has dimsInactive() set to false - // This is the case for PopUpWidget which should not dim a dialog - // which it belongs to - if ((i == _dialogStack.size() - 2) && !_dialogStack[i + 1]->dimsInactive()) - _theme->openDialog(true); - else if ((i != (_dialogStack.size() - 1)) || !_dialogStack[i]->dimsInactive()) - _theme->openDialog(false); - else + case kRedrawFull: + _theme->clearAll(); + _theme->closeAllDialogs(); + + for (i = 0; i < _dialogStack.size(); i++) { + if ((i == _dialogStack.size() - 2) && !_dialogStack[i + 1]->dimsInactive()) + _theme->openDialog(true); + else if ((i != (_dialogStack.size() - 1)) || !_dialogStack[i]->dimsInactive()) + _theme->openDialog(false); + else + _theme->openDialog(true); + + _dialogStack[i]->drawDialog(); + } + break; + + case kRedrawTopDialog: + _dialogStack.top()->drawDialog(); + printf("Top dialog redraw!\n"); + break; + + case kRedrawOpenDialog: _theme->openDialog(true); + _dialogStack.top()->drawDialog(); + printf("Dialog opened!\n"); + break; - _dialogStack[i]->drawDialog(); + default: + return; } _theme->updateScreen(); + _redrawStatus = kRedrawDisabled; } Dialog *NewGui::getTopDialog() const { @@ -240,10 +259,7 @@ void NewGui::runLoop() { Common::EventManager *eventMan = _system->getEventManager(); while (!_dialogStack.empty() && activeDialog == getTopDialog()) { - if (_needRedraw) { - redraw(); - _needRedraw = false; - } + redraw(); // Don't "tickle" the dialog until the theme has had a chance // to re-allocate buffers in case of a scaler change. @@ -274,6 +290,7 @@ void NewGui::runLoop() { _theme->refresh(); _themeChange = false; + _redrawStatus = kRedrawFull; redraw(); } @@ -330,11 +347,6 @@ void NewGui::runLoop() { _system->delayMillis(10); } - // HACK: since we reopen all dialogs anyway on redraw - // we for now use Theme::closeAllDialogs here, until - // we properly add (and implement) Theme::closeDialog - _theme->closeAllDialogs(); - if (didSaveState) { _theme->disable(); restoreState(); @@ -366,7 +378,7 @@ void NewGui::restoreState() { void NewGui::openDialog(Dialog *dialog) { _dialogStack.push(dialog); - _needRedraw = true; + _redrawStatus = kRedrawOpenDialog; // We reflow the dialog just before opening it. If the screen changed // since the last time we looked, also refresh the loaded theme, @@ -393,7 +405,7 @@ void NewGui::closeTopDialog() { // Remove the dialog from the stack _dialogStack.pop(); - _needRedraw = true; + _redrawStatus = kRedrawCloseDialog; } void NewGui::setupCursor() { @@ -451,6 +463,7 @@ void NewGui::screenChange() { // We need to redraw immediately. Otherwise // some other event may cause a widget to be // redrawn before redraw() has been called. + _redrawStatus = kRedrawFull; redraw(); } diff --git a/gui/newgui.h b/gui/newgui.h index 4cf082c877..ae58b2efe8 100644 --- a/gui/newgui.h +++ b/gui/newgui.h @@ -90,12 +90,21 @@ public: void screenChange(); + enum RedrawStatus { + kRedrawDisabled = 0, + kRedrawOpenDialog, + kRedrawCloseDialog, + kRedrawTopDialog, + kRedrawFull + }; + protected: OSystem *_system; Theme *_theme; - bool _needRedraw; +// bool _needRedraw; + RedrawStatus _redrawStatus; int _lastScreenChangeID; DialogStack _dialogStack; diff --git a/gui/theme.h b/gui/theme.h index e9ce8bb01d..91f59d961c 100644 --- a/gui/theme.h +++ b/gui/theme.h @@ -238,6 +238,20 @@ public: */ virtual void closeAllDialogs() = 0; + /** + * Closes the topmost dialog, and redraws the screen + * accordingly. + * + * TODO: Make this purely virtual by making ThemeClassic + * and ThemeModern implement it too. + * + * @returns True if the dialog was sucessfully closed. + * If we weren't able to restore the screen after closing + * the dialog, we return false, which means we need to redraw + * the dialog stack from scratch. + */ + virtual bool closeDialog() { return false; } + /** * Clear the complete GUI screen. */ -- cgit v1.2.3