File indexing completed on 2024-04-28 04:05:04
0001 /* 0002 SPDX-FileCopyrightText: 2010-2012 Stefan Majewsky <majewsky@gmx.net> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #ifndef KGAMERENDERER_H 0008 #define KGAMERENDERER_H 0009 0010 // own 0011 #include "kdegames_export.h" 0012 // Qt 0013 #include <QHash> 0014 #include <QObject> 0015 #include <QPixmap> 0016 // Std 0017 #include <memory> 0018 0019 class KGameRendererPrivate; 0020 class KGameRendererClient; 0021 class KGameRendererClientPrivate; 0022 class KGameTheme; 0023 class KGameThemeProvider; 0024 0025 #ifndef KDEGAMES_QCOLOR_QHASH 0026 #define KDEGAMES_QCOLOR_QHASH 0027 inline uint qHash(const QColor &color) 0028 { 0029 return color.rgba(); 0030 } 0031 #endif // KDEGAMES_QCOLOR_QHASH 0032 0033 /** 0034 * @class KGameRenderer kgamerenderer.h <KGameRenderer> 0035 * @short Cache-enabled rendering of SVG themes. 0036 * 0037 * KGameRenderer is a light-weight rendering framework for the rendering of 0038 * SVG themes (as represented by KGameTheme) into pixmap caches. 0039 * 0040 * @section terminology Terminology 0041 * 0042 * @li Themes in the context of KGameRenderer are KGameTheme instances. The theme 0043 * selection by a KGameRenderer can be managed by a KGameThemeProvider. 0044 * @li A sprite is either a single pixmap ("non-animated sprites") or a sequence 0045 * of pixmaps which are shown consecutively to produce an animation 0046 * ("animated sprites"). Non-animated sprites correspond to a single element 0047 * with the same key in the SVG theme file. The element keys for the pixmaps 0048 * of an animated sprite are produced by appending the frameSuffix() to the 0049 * sprite key. 0050 * 0051 * @section clients Access to the pixmaps 0052 * 0053 * Sprite pixmaps can be retrieved from KGameRenderer in the main thread using 0054 * the synchronous KGameRenderer::spritePixmap() method. However, it is highly 0055 * recommended to use the asynchronous interface provided by the interface class 0056 * KGameRendererClient. A client corresponds to one pixmap and registers itself 0057 * with the corresponding KGameRenderer instance to get notified when a new 0058 * pixmap is available. 0059 * 0060 * For QGraphicsView-based applications, the KGameRenderedItem class provides a 0061 * QGraphicsPixmapItem which is a KGameRendererClient and displays the pixmap 0062 * for a given sprite. 0063 * 0064 * @section strategies Rendering strategy 0065 * 0066 * For each theme, KGameRenderer keeps two caches around: an in-process cache of 0067 * QPixmaps, and a disk cache containing QImages (powered by KImageCache). You 0068 * therefore will not need to implement any caching for the pixmaps provided by 0069 * KGameRenderer. 0070 * 0071 * When requests from a KGameRendererClient cannot be served immediately because 0072 * the requested sprite is not in the caches, a rendering request is sent to a 0073 * worker thread. 0074 * 0075 * @section legacy Support for legacy themes 0076 * 0077 * When porting applications to KGameRenderer, you probably have to support 0078 * the format of existing themes. KGameRenderer provides the frameBaseIndex() 0079 * and frameSuffix() properties for this purpose. It is recommended not to 0080 * change these properties in new applications. 0081 * @since 4.6 0082 */ 0083 class KDEGAMES_EXPORT KGameRenderer : public QObject 0084 { 0085 Q_OBJECT 0086 Q_PROPERTY(const KGameTheme *theme READ theme NOTIFY themeChanged) 0087 Q_PROPERTY(KGameThemeProvider *themeProvider READ themeProvider NOTIFY readOnlyProperty) 0088 0089 public: 0090 /// Describes the various strategies which KGameRenderer can use to speed 0091 /// up rendering. 0092 /// \see setStrategyEnabled 0093 enum Strategy { 0094 /// If set, pixmaps will be cached in a shared disk cache (using 0095 /// KSharedDataCache). This is especially useful for complex SVG 0096 /// themes because KGameRenderer will not load the SVG if all needed 0097 /// pixmaps are available from the disk cache. 0098 UseDiskCache = 1 << 0, 0099 /// If set, pixmap requests from KGameRendererClients will be 0100 /// handled asynchronously if possible. This is especially useful 0101 /// when many clients are requesting complex pixmaps at one time. 0102 UseRenderingThreads = 1 << 1 0103 }; 0104 /** 0105 * Stores a combination of #Strategy values. 0106 */ 0107 Q_DECLARE_FLAGS(Strategies, Strategy) 0108 0109 /// Constructs a new KGameRenderer that renders @a prov->currentTheme(). 0110 /// @param prov the theme provider 0111 /// @param cacheSize the cache size in megabytes (if not given, a sane 0112 /// default is used) 0113 /// @warning This constructor may only be called from the main thread. 0114 explicit KGameRenderer(KGameThemeProvider *prov, unsigned cacheSize = 0); 0115 /// overload that allows to use KGameRenderer without a theme provider 0116 /// (useful when there is only one theme) 0117 /// @note Takes ownership of @a theme. 0118 explicit KGameRenderer(KGameTheme *theme, unsigned cacheSize = 0); 0119 /// Deletes this KGameRenderer instance, as well as all clients using it. 0120 ~KGameRenderer() override; 0121 0122 /// @return the frame base index. @see setFrameBaseIndex() 0123 int frameBaseIndex() const; 0124 /// Sets the frame base index, i.e. the lowest frame index. Usually, 0125 /// frame numbering starts at zero, so the frame base index is zero. 0126 /// 0127 /// For example, if you set the frame base index to 42, and use the 0128 /// default frame suffix, the 3 frames of an animated sprite "foo" are 0129 /// provided by the SVG elements "foo_42", "foo_43" and "foo_44". 0130 /// 0131 /// It is recommended not to alter the frame base index unless you need 0132 /// to support legacy themes. 0133 void setFrameBaseIndex(int frameBaseIndex); 0134 /// @return the frame suffix. @see setFrameSuffix() 0135 QString frameSuffix() const; 0136 /// Sets the frame suffix. This suffix will be added to a sprite key 0137 /// to create the corresponding SVG element key, after any occurrence of 0138 /// "%1" in the suffix has been replaced by the frame number. 0139 /// @note Giving a suffix which does not include "%1" will reset to the 0140 /// default suffix "_%1". 0141 /// 0142 /// For example, if the frame suffix is set to "_%1" (the default), the 0143 /// SVG element key for the frame no. 23 of the sprite "foo" is "foo_23". 0144 /// @note Frame numbering starts at zero unless you setFrameBaseIndex(). 0145 void setFrameSuffix(const QString &suffix); 0146 /// @return the optimization strategies used by this renderer 0147 /// @see setStrategyEnabled() 0148 Strategies strategies() const; 0149 /// Enables/disables an optimization strategy for this renderer. By 0150 /// default, both the UseDiskCache and the UseRenderingThreads strategies 0151 /// are enabled. This is a sane default for 99% of all games. You might 0152 /// only want to disable optimizations if the graphics are so simple that 0153 /// the optimizations create an overhead in your special case. 0154 /// 0155 /// If you disable UseDiskCache, you should do so before setTheme(), 0156 /// because changes to UseDiskCache cause a full theme reload. 0157 void setStrategyEnabled(Strategy strategy, bool enabled = true); 0158 0159 /// @return the KGameTheme instance used by this renderer 0160 const KGameTheme *theme() const; 0161 /// @return the KGameThemeProvider instance used by this renderer, or 0 if 0162 /// the renderer was created with a single static theme 0163 KGameThemeProvider *themeProvider() const; 0164 0165 /// @return the bounding rectangle of the sprite with this @a key 0166 /// This is equal to QSvgRenderer::boundsOnElement() of the corresponding 0167 /// SVG element. 0168 QRectF boundsOnSprite(const QString &key, int frame = -1) const; 0169 /// @return the count of frames available for the sprite with this @a key 0170 /// If this sprite is not animated (i.e. there are no SVG elements for 0171 /// any frames), this method returns 0. If the sprite does not exist at 0172 /// all, -1 is returned. 0173 /// 0174 /// If the sprite is animated, the method counts frames starting at zero 0175 /// (unless you change the frameBaseIndex()), and returns the number of 0176 /// frames for which corresponding elements exist in the SVG file. 0177 /// 0178 /// For example, if the SVG contains the elements "foo_0", "foo_1" and 0179 /// "foo_3", frameCount("foo") returns 2 for the default frame suffix. 0180 /// (The element "foo_3" is ignored because "foo_2" is missing.) 0181 int frameCount(const QString &key) const; 0182 /// @return if the sprite with the given @a key exists 0183 /// This is the same as \code renderer.frameCount(key) >= 0 \endcode 0184 bool spriteExists(const QString &key) const; 0185 /// @return a rendered pixmap 0186 /// @param key the key of the sprite 0187 /// @param size the size of the resulting pixmap 0188 /// @param frame the number of the frame which you want 0189 /// @param customColors the custom color replacements for this client. 0190 /// That is, for each entry in this has, the key color will be 0191 /// replaced by its value if it is encountered in the sprite. 0192 /// @note For non-animated frames, set @a frame to -1 or omit it. 0193 /// @note Custom colors increase the rendering time considerably, so use 0194 /// this feature only if you really need its flexibility. 0195 0196 // The parentheses around QHash<QColor, QColor>() avoid compile 0197 // errors on platforms with older gcc versions, e.g. OS X 10.6. 0198 QPixmap spritePixmap(const QString &key, QSize size, int frame = -1, const QHash<QColor, QColor> &customColors = (QHash<QColor, QColor>())) const; 0199 0200 Q_SIGNALS: 0201 void themeChanged(const KGameTheme *theme); 0202 /// This signal is never emitted. It is provided because QML likes to 0203 /// complain about properties without NOTIFY signals, even readonly ones. 0204 void readOnlyProperty(); 0205 0206 private: 0207 friend class KGameRendererPrivate; 0208 friend class KGameRendererClient; 0209 friend class KGameRendererClientPrivate; 0210 std::unique_ptr<KGameRendererPrivate> const d_ptr; 0211 Q_DECLARE_PRIVATE(KGameRenderer) 0212 }; 0213 0214 Q_DECLARE_OPERATORS_FOR_FLAGS(KGameRenderer::Strategies) 0215 0216 #endif // KGAMERENDERER_H