From 103a4f66813df8f806467ad6f27cd0831ae0abf4 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 9 Aug 2008 18:34:16 +0000 Subject: Added support for image loading/blitting. Added support for loading theme files. (Make sure to grab the sample theme "scummodern.zip" from the gui/themes/ directory to try it out) Misc fixes. svn-id: r33718 --- common/xmlparser.h | 6 +++ graphics/VectorRenderer.h | 55 +++++++++++++++++++++++++++ gui/ThemeParser.cpp | 21 +++++++++++ gui/ThemeParser.h | 12 +++++- gui/ThemeRenderer.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++-- gui/ThemeRenderer.h | 49 +++++++++++++++++++++++- gui/launcher.cpp | 2 +- gui/newgui.cpp | 57 ++++------------------------ gui/theme.h | 2 +- gui/themes/default.inc | 4 ++ gui/themes/modern.stx | 5 +++ gui/themes/scummodern.zip | Bin 0 -> 29651 bytes 12 files changed, 250 insertions(+), 57 deletions(-) create mode 100644 gui/themes/scummodern.zip diff --git a/common/xmlparser.h b/common/xmlparser.h index b7a7093bc5..e3d39bfb82 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -371,6 +371,12 @@ public: _fileName = "Memory Stream"; return true; } + + bool loadStream(MemoryReadStream *stream) { + _text.loadStream(stream); + _fileName = "Compressed File Stream"; + return true; + } /** * The actual parsing function. diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index a2352762a7..7eff0a9c50 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -71,6 +71,7 @@ struct DrawStep { uint32 scale; /** scale of all the coordinates in FIXED POINT with 16 bits mantissa */ void (VectorRenderer::*drawingCall)(const Common::Rect &, const DrawStep &); /** Pointer to drawing function */ + Graphics::Surface *blitSrc; }; VectorRenderer *createRenderer(int mode); @@ -412,6 +413,12 @@ public: stepGetPositions(step, area, x, y, w, h); drawTab(x, y, stepGetRadius(step, area), w, h); } + + void drawCallback_BITMAP(const Common::Rect &area, const DrawStep &step) { + uint16 x, y, w, h; + stepGetPositions(step, area, x, y, w, h); + blitAlphaBitmap(step.blitSrc, Common::Rect(x, y, w, h)); + } void drawCallback_VOID(const Common::Rect &area, const DrawStep &step) {} @@ -464,6 +471,8 @@ public: */ virtual void blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) = 0; + virtual void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) = 0; + /** * Draws a string into the screen. Wrapper for the Graphics::Font string drawing * method. @@ -554,6 +563,11 @@ class VectorRendererSpec : public VectorRenderer { typedef VectorRenderer Base; public: + VectorRendererSpec() { + _bitmapAlphaColor = RGBToColor(255, 0, 255); + } + + /** * @see VectorRenderer::drawLine() */ @@ -672,6 +686,8 @@ public: * @see VectorRenderer::blitSurface() */ virtual void blitSurface(const Graphics::Surface *source, const Common::Rect &r) { + assert(source->w == _activeSurface->w && source->h == _activeSurface->h); + PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(r.left, r.top); PixelType *src_ptr = (PixelType *)source->getBasePtr(r.left, r.top); @@ -703,6 +719,43 @@ public: } } + virtual void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) { + assert(r.width() >= source->w && r.height() >= source->h); + + int16 x = r.left; + int16 y = r.top; + + if (r.width() > source->w) + x = x + (r.width() >> 1) - (source->w >> 1); + + if (r.height() > source->h) + y = y + (r.height() >> 1) - (source->h >> 1); + + PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(x, y); + PixelType *src_ptr = (PixelType *)source->getBasePtr(0, 0); + + int dst_pitch = surfacePitch(); + int src_pitch = source->pitch / source->bytesPerPixel; + + int w, h = source->h; + + while (h--) { + w = source->w; + + while (w--) { + if (*src_ptr != _bitmapAlphaColor) + *dst_ptr = *src_ptr; + + dst_ptr++; + src_ptr++; + } + + dst_ptr = dst_ptr - source->w + dst_pitch; + src_ptr = src_ptr - source->w + src_pitch; + } + + } + virtual void applyScreenShading(GUI::Theme::ShadingStyle shadingStyle) { int pixels = _activeSurface->w * _activeSurface->h; PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, 0); @@ -935,6 +988,8 @@ protected: PixelType _gradientEnd; /** End color for the fill gradient */ PixelType _bevelColor; + + PixelType _bitmapAlphaColor; }; /** diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp index 21554f4c7a..df36ad6c7c 100644 --- a/gui/ThemeParser.cpp +++ b/gui/ThemeParser.cpp @@ -51,6 +51,7 @@ ThemeParser::ThemeParser(ThemeRenderer *parent) : XMLParser() { _drawFunctions["fill"] = &Graphics::VectorRenderer::drawCallback_FILLSURFACE; _drawFunctions["tab"] = &Graphics::VectorRenderer::drawCallback_TAB; _drawFunctions["void"] = &Graphics::VectorRenderer::drawCallback_VOID; + _drawFunctions["bitmap"] = &Graphics::VectorRenderer::drawCallback_BITMAP; _defaultStepGlobal = defaultDrawStep(); _defaultStepLocal = 0; @@ -149,6 +150,18 @@ bool ThemeParser::parserCallback_fonts(ParserNode *node) { return true; } +bool ThemeParser::parserCallback_bitmap(ParserNode *node) { + if (resolutionCheck(node->values["resolution"])) { + node->ignore = true; + return true; + } + + if (!_theme->addBitmap(node->values["filename"])) + return parserError("Error when loading Bitmap file '%s'", node->values["filename"].c_str()); + + return true; +} + bool ThemeParser::parserCallback_text(ParserNode *node) { GUI::Theme::TextAlign alignH; GUI::Theme::TextAlignVertical alignV; @@ -319,6 +332,14 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst if (functionSpecific) { assert(stepNode->values.contains("func")); Common::String functionName = stepNode->values["func"]; + + if (functionName == "bitmap") { + if (!stepNode->values.contains("filename")) + return parserError("Need to specify a filename for Bitmap blitting."); + + if (!_theme->getBitmap(stepNode->values["filename"])) + return parserError("The given filename hasn't been loaded into the GUI."); + } if (functionName == "roundedsq" || functionName == "circle" || functionName == "tab") { if (stepNode->values.contains("radius") && stepNode->values["radius"] == "auto") { diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h index 78423652bc..b9fa69179d 100644 --- a/gui/ThemeParser.h +++ b/gui/ThemeParser.h @@ -308,7 +308,7 @@ namespace GUI { using namespace Graphics; using namespace Common; -class ThemeRenderer; +class ThemeRenderer; class ThemeParser : public XMLParser { typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const DrawStep &); @@ -354,6 +354,13 @@ protected: XML_PROP(resolution, false) KEY_END() KEY_END() + + XML_KEY(bitmaps) + XML_KEY(bitmap) + XML_PROP(filename, true) + XML_PROP(resolution, false) + KEY_END() + KEY_END() XML_KEY(defaults) XML_PROP(stroke, false) @@ -408,6 +415,7 @@ protected: XML_PROP(xpos, false) XML_PROP(ypos, false) XML_PROP(orientation, false) + XML_PROP(bitmap, false) KEY_END() XML_KEY(text) @@ -489,6 +497,8 @@ protected: bool parserCallback_color(ParserNode *node); bool parserCallback_drawstep(ParserNode *node); bool parserCallback_drawdata(ParserNode *node); + bool parserCallback_bitmaps(ParserNode *node) { return true; } + bool parserCallback_bitmap(ParserNode *node); /** Layout info callbacks */ bool parserCallback_layout_info(ParserNode *node); diff --git a/gui/ThemeRenderer.cpp b/gui/ThemeRenderer.cpp index 679db6c3e7..6cfdb777ad 100644 --- a/gui/ThemeRenderer.cpp +++ b/gui/ThemeRenderer.cpp @@ -29,6 +29,7 @@ #include "common/system.h" #include "common/events.h" #include "common/config-manager.h" +#include "graphics/imageman.h" #include "gui/launcher.h" @@ -118,6 +119,8 @@ ThemeRenderer::ThemeRenderer(Common::String themeName, GraphicsMode mode) : } else { _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); } + + ImageMan.addArchive(themeName + ".zip"); _initOk = true; _themeName = themeName; @@ -130,6 +133,13 @@ ThemeRenderer::~ThemeRenderer() { unloadTheme(); delete _parser; delete _themeEval; + + for (ImagesMap::iterator i = _bitmaps.begin(); i != _bitmaps.end(); ++i) { +// delete i->_value; + ImageMan.unregisterSurface(i->_key); + } + + ImageMan.remArchive(_stylefile + ".zip"); } bool ThemeRenderer::init() { @@ -269,6 +279,18 @@ bool ThemeRenderer::addFont(const Common::String &fontId, const Common::String & } +bool ThemeRenderer::addBitmap(const Common::String &filename) { + if (_bitmaps.contains(filename)) { + delete _bitmaps[filename]; + ImageMan.unregisterSurface(filename); + } + + ImageMan.registerSurface(filename, 0); + _bitmaps[filename] = ImageMan.getSurface(filename); + + return _bitmaps[filename] != 0; +} + bool ThemeRenderer::addDrawData(const Common::String &data, bool cached) { DrawData data_id = getDrawDataId(data); @@ -346,9 +368,41 @@ bool ThemeRenderer::loadThemeXML(Common::String themeName) { if (ConfMan.hasKey("extrapath")) Common::File::addDefaultDirectoryRecursive(ConfMan.get("extrapath")); - - if (!parser()->loadFile(themeName + ".xml")) + + if (!parser()->loadFile(themeName + ".stx")){ +#ifdef USE_ZLIB + unzFile zipFile = unzOpen((themeName + ".zip").c_str()); + + if (zipFile && unzLocateFile(zipFile, (themeName + ".stx").c_str(), 2) == UNZ_OK) { + + unz_file_info fileInfo; + unzOpenCurrentFile(zipFile); + unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + uint8 *buffer = new uint8[fileInfo.uncompressed_size+1]; + assert(buffer); + memset(buffer, 0, (fileInfo.uncompressed_size+1)*sizeof(uint8)); + unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size); + unzCloseCurrentFile(zipFile); + + Common::MemoryReadStream *stream = new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size+1, true); + + if (!parser()->loadStream(stream)) { + unzClose(zipFile); + delete stream; + return false; + } + +// delete[] buffer; + buffer = 0; + } else { + unzClose(zipFile); + return false; + } + unzClose(zipFile); +#else return false; +#endif + } return parser()->parse(); } @@ -411,6 +465,19 @@ void ThemeRenderer::queueDDText(TextData type, const Common::Rect &r, const Comm } } +void ThemeRenderer::queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &area, bool alpha) { + BitmapQueue q; + q.bitmap = bitmap; + q.area = area; + q.alpha = alpha; + + if (_buffering) { + _bitmapQueue.push_back(q); + } else { + drawBitmap(q); + } +} + void ThemeRenderer::drawDD(const DrawQueue &q, bool draw, bool restore) { Common::Rect extendedRect = q.area; extendedRect.grow(kDirtyRectangleThreshold); @@ -442,6 +509,16 @@ void ThemeRenderer::drawDDText(const DrawQueueText &q) { addDirtyRect(q.area); } +void ThemeRenderer::drawBitmap(const BitmapQueue &q) { + + if (q.alpha) + _vectorRenderer->blitAlphaBitmap(q.bitmap, q.area); + else + _vectorRenderer->blitSubSurface(q.bitmap, q.area); + + addDirtyRect(q.area); +} + void ThemeRenderer::calcBackgroundOffset(DrawData type) { uint maxShadow = 0; for (Common::List::const_iterator step = _widgets[type]->_steps.begin(); @@ -597,8 +674,10 @@ void ThemeRenderer::drawSurface(const Common::Rect &r, const Graphics::Surface & if (!ready()) return; - _vectorRenderer->blitSubSurface(&surface, r); - addDirtyRect(r); + queueBitmap(&surface, r, themeTrans); + +// _vectorRenderer->blitSubSurface(&surface, r); +// addDirtyRect(r); } void ThemeRenderer::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state) { @@ -726,6 +805,13 @@ void ThemeRenderer::updateScreen() { _screenQueue.clear(); } + if (!_bitmapQueue.empty()) { + for (Common::List::const_iterator q = _bitmapQueue.begin(); q != _bitmapQueue.end(); ++q) + drawBitmap(*q); + + _bitmapQueue.clear(); + } + if (!_textQueue.empty()) { for (Common::List::const_iterator q = _textQueue.begin(); q != _textQueue.end(); ++q) drawDDText(*q); diff --git a/gui/ThemeRenderer.h b/gui/ThemeRenderer.h index 55c75bd76e..cb68b9ca5c 100644 --- a/gui/ThemeRenderer.h +++ b/gui/ThemeRenderer.h @@ -88,6 +88,7 @@ class ThemeRenderer : public Theme { protected: typedef Common::String String; typedef GUI::Dialog Dialog; + typedef Common::HashMap ImagesMap; friend class GUI::Dialog; friend class GUI::GuiObject; @@ -197,6 +198,12 @@ protected: int deltax; }; + struct BitmapQueue { + const Graphics::Surface *bitmap; + Common::Rect area; + bool alpha; + }; + public: /** Graphics mode enumeration. * Each item represents a set of BPP and Renderer modes for a given @@ -390,8 +397,27 @@ public: * @param cached Whether this DD set will be cached beforehand. */ bool addDrawData(const Common::String &data, bool cached); + + + /** + * Interface for the ThemeParser class: Loads a font to use on the GUI from the given + * filename. + * + * @param fontName Identifier name for the font. + * @param file Name of the font file. + * @param r, g, b Color of the font. + */ bool addFont(const Common::String &fontName, const Common::String &file, int r, int g, int b); + + /** + * Interface for the ThemeParser class: Loads a bitmap file to use on the GUI. + * The filename is also used as its identifier. + * + * @param filename Name of the bitmap file. + */ + bool addBitmap(const Common::String &filename); + /** * Adds a new TextStep from the ThemeParser. This will be deprecated/removed once the * new Font API is in place. @@ -433,6 +459,19 @@ public: void *evaluator() { return _themeEval; } bool supportsImages() const { return true; } + + Graphics::Surface *getBitmap(const Common::String &name) { + return _bitmaps.contains(name) ? _bitmaps[name] : 0; + } + + const Graphics::Surface *getImageSurface(const kThemeImages n) const { + if (n == kImageLogo) + return _bitmaps.contains("logo.bmp") ? _bitmaps["logo.bmp"] : 0; + + return 0; + } + + const Common::String &getThemeName() { return _themeName; } protected: @@ -487,7 +526,9 @@ protected: * Not implemented yet. * TODO: reload themes, reload the renderer, recheck everything */ - void screenChange() {} + void screenChange() { + error("Screen Changes are not supported yet. Fix this!"); + } /** * Actual Dirty Screen handling function. @@ -570,6 +611,7 @@ protected: */ inline void drawDD(const DrawQueue &q, bool draw = true, bool restore = false); inline void drawDDText(const DrawQueueText &q); + inline void drawBitmap(const BitmapQueue &q); /** * Generates a DrawQueue item and enqueues it so it's drawn to the screen @@ -585,6 +627,7 @@ protected: inline void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0); inline void queueDDText(TextData type, const Common::Rect &r, const Common::String &text, bool restoreBg, bool elipsis, TextAlign alignH = kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0); + inline void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha); /** * DEBUG: Draws a white square around the given position and writes the given next to it. @@ -646,6 +689,8 @@ protected: /** Array of all the text fonts that can be drawn. */ TextDrawData *_texts[kTextDataMAX]; + ImagesMap _bitmaps; + /** List of all the dirty screens that must be blitted to the overlay. */ Common::List _dirtyScreen; @@ -657,6 +702,8 @@ protected: /** Queue with all the text drawing that must be done to the screen */ Common::List _textQueue; + + Common::List _bitmapQueue; bool _initOk; /** Class and renderer properly initialized */ bool _themeOk; /** Theme data successfully loaded. */ diff --git a/gui/launcher.cpp b/gui/launcher.cpp index 62f1daf244..3d35420326 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -880,7 +880,7 @@ void LauncherDialog::updateButtons() { void LauncherDialog::reflowLayout() { #ifndef DISABLE_FANCY_THEMES if (g_gui.xmlEval()->getVar("Globals.ShowLauncherLogo") == 1 && g_gui.theme()->supportsImages()) { - StaticTextWidget *ver = (StaticTextWidget*)findWidget("lLauncher.Version"); + StaticTextWidget *ver = (StaticTextWidget*)findWidget("Launcher.Version"); if (ver) { ver->setAlign((Graphics::TextAlignment)g_gui.xmlEval()->getVar("Launcher.Version.Align", Graphics::kTextAlignCenter)); ver->setLabel(gScummVMVersionDate); diff --git a/gui/newgui.cpp b/gui/newgui.cpp index c89937595b..e83c86a451 100644 --- a/gui/newgui.cpp +++ b/gui/newgui.cpp @@ -91,31 +91,16 @@ NewGui::NewGui() : _redrawStatus(kRedrawDisabled), // Clear the cursor memset(_cursor, 0xFF, sizeof(_cursor)); - bool loadClassicTheme = true; -#ifndef DISABLE_FANCY_THEMES + ConfMan.registerDefault("gui_theme", "default"); Common::String style(ConfMan.get("gui_theme")); - // The default theme for now is the 'modern' theme. if (style.compareToIgnoreCase("default") == 0) - style = "modern"; - - Common::String styleType; - Common::ConfigFile cfg; - if (loadNewTheme(style)) { - loadClassicTheme = false; - } else { - loadClassicTheme = true; - warning("falling back to classic style"); - } -#endif + style = "builtin"; + + //DEBUG: + style = "scummodern"; - if (loadClassicTheme) { - _theme = new ThemeClassic(_system); - assert(_theme); - if (!_theme->init()) { - error("Couldn't initialize classic theme"); - } - } + loadNewTheme(style); _theme->resetDrawArea(); _themeChange = false; @@ -129,7 +114,7 @@ bool NewGui::loadNewTheme(const Common::String &style) { Common::String styleType; Common::ConfigFile cfg; - Common::String oldTheme = (_theme != 0) ? _theme->getStylefileName() : ""; + Common::String oldTheme = (_theme != 0) ? _theme->getThemeName() : ""; if (_theme) _theme->disable(); @@ -142,38 +127,12 @@ bool NewGui::loadNewTheme(const Common::String &style) { delete _theme; _theme = 0; -/* if (style.compareToIgnoreCase("classic (builtin)") == 0 || - style.compareToIgnoreCase("classic") == 0) { - _theme = new ThemeClassic(_system, style); - } else { - if (Theme::themeConfigUseable(style, "", &styleType, &cfg)) { - if (0 == styleType.compareToIgnoreCase("classic")) - _theme = new ThemeClassic(_system, style, &cfg); -#ifndef DISABLE_FANCY_THEMES - else if (0 == styleType.compareToIgnoreCase("modern")) - _theme = new ThemeModern(_system, style, &cfg); -#endif - else - warning("Unsupported theme type '%s'", styleType.c_str()); - } else { - warning("Config '%s' is NOT usable for themes or not found", style.c_str()); - } - } - cfg.clear(); */ - _theme = new ThemeRenderer(style, GUI::ThemeRenderer::kGfxAntialias16bit); -// _theme = new ThemeRenderer(style, GUI::ThemeRenderer::kGfxStandard16bit); if (!_theme) return (!oldTheme.empty() ? loadNewTheme(oldTheme) : false); - if (!_theme->init()) { - warning("Could not initialize your preferred theme"); - delete _theme; - _theme = 0; - loadNewTheme(oldTheme); - return false; - } + _theme->init(); _theme->resetDrawArea(); if (!oldTheme.empty()) diff --git a/gui/theme.h b/gui/theme.h index 0d0fadb8ad..74158f473c 100644 --- a/gui/theme.h +++ b/gui/theme.h @@ -371,7 +371,7 @@ public: static bool themeConfigUseable(const Common::String &file, const Common::String &style="", Common::String *cStyle=0, Common::ConfigFile *cfg=0); const Common::String &getStylefileName() const { return _stylefile; } - const Common::String &getThemeName() const { return _stylename; } + virtual const Common::String &getThemeName() const { return _stylename; } virtual bool isDynamic() { return false; diff --git a/gui/themes/default.inc b/gui/themes/default.inc index 961917b05e..262260a7fc 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -28,6 +28,10 @@ "rgb = '63, 60, 17' " "/> " " " +" " +" " +" " +" " " " " + + + + +