1 | /*************************************************************************** |
2 | * Copyright 2010-2012 Stefan Majewsky <majewsky@gmx.net> * |
3 | * * |
4 | * This program is free software; you can redistribute it and/or modify * |
5 | * it under the terms of the GNU Library General Public License * |
6 | * version 2 as published by the Free Software Foundation * |
7 | * * |
8 | * This program is distributed in the hope that it will be useful, * |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
11 | * GNU Library General Public License for more details. * |
12 | * * |
13 | * You should have received a copy of the GNU Library General Public * |
14 | * License along with this program; if not, write to the * |
15 | * Free Software Foundation, Inc., * |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
17 | ***************************************************************************/ |
18 | |
19 | #ifndef KGAMERENDERER_H |
20 | #define KGAMERENDERER_H |
21 | |
22 | class QGraphicsView; |
23 | #include <QtCore/QHash> |
24 | #include <QtCore/QObject> |
25 | #include <QtGui/QPixmap> |
26 | |
27 | #include <libkdegames_export.h> |
28 | |
29 | class KGameRendererPrivate; |
30 | class KGameRendererClient; |
31 | class KGameRendererClientPrivate; |
32 | class KgTheme; |
33 | class KgThemeProvider; |
34 | |
35 | #ifndef KDEGAMES_QCOLOR_QHASH |
36 | # define KDEGAMES_QCOLOR_QHASH |
37 | inline uint qHash(const QColor& color) |
38 | { |
39 | return color.rgba(); |
40 | } |
41 | #endif // KDEGAMES_QCOLOR_QHASH |
42 | |
43 | /** |
44 | * @class KGameRenderer kgamerenderer.h <KGameRenderer> |
45 | * @since 4.6 |
46 | * @short Cache-enabled rendering of SVG themes. |
47 | * |
48 | * KGameRenderer is a light-weight rendering framework for the rendering of |
49 | * SVG themes (as represented by KgTheme) into pixmap caches. |
50 | * |
51 | * @section terminology Terminology |
52 | * |
53 | * @li Themes in the context of KGameRenderer are KgTheme instances. The theme |
54 | * selection by a KgRenderer can be managed by a KgThemeProvider. |
55 | * @li A sprite is either a single pixmap ("non-animated sprites") or a sequence |
56 | * of pixmaps which are shown consecutively to produce an animation |
57 | * ("animated sprites"). Non-animated sprites correspond to a single element |
58 | * with the same key in the SVG theme file. The element keys for the pixmaps |
59 | * of an animated sprite are produced by appending the frameSuffix() to the |
60 | * sprite key. |
61 | * |
62 | * @section clients Access to the pixmaps |
63 | * |
64 | * Sprite pixmaps can be retrieved from KGameRenderer in the main thread using |
65 | * the synchronous KGameRenderer::spritePixmap() method. However, it is highly |
66 | * recommended to use the asynchronous interface provided by the interface class |
67 | * KGameRendererClient. A client corresponds to one pixmap and registers itself |
68 | * with the corresponding KGameRenderer instance to get notified when a new |
69 | * pixmap is available. |
70 | * |
71 | * For QGraphicsView-based applications, the KGameRenderedItem class provides a |
72 | * QGraphicsPixmapItem which is a KGameRendererClient and displays the pixmap |
73 | * for a given sprite. |
74 | * |
75 | * @section strategies Rendering strategy |
76 | * |
77 | * For each theme, KGameRenderer keeps two caches around: an in-process cache of |
78 | * QPixmaps, and a disk cache containing QImages (powered by KImageCache). You |
79 | * therefore will not need to implement any caching for the pixmaps provided by |
80 | * KGameRenderer. |
81 | * |
82 | * When requests from a KGameRendererClient cannot be served immediately because |
83 | * the requested sprite is not in the caches, a rendering request is sent to a |
84 | * worker thread. |
85 | * |
86 | * @section legacy Support for legacy themes |
87 | * |
88 | * When porting applications to KGameRenderer, you probably have to support |
89 | * the format of existing themes. KGameRenderer provides the frameBaseIndex() |
90 | * and frameSuffix() properties for this purpose. It is recommended not to |
91 | * change these properties in new applications. |
92 | * |
93 | */ |
94 | class KDEGAMES_EXPORT KGameRenderer : public QObject |
95 | { |
96 | Q_OBJECT |
97 | Q_PROPERTY(const KgTheme* theme READ theme NOTIFY themeChanged) |
98 | Q_PROPERTY(KgThemeProvider* themeProvider READ themeProvider NOTIFY readOnlyProperty) |
99 | public: |
100 | ///Describes the various strategies which KGameRenderer can use to speed |
101 | ///up rendering. |
102 | ///\see setStrategyEnabled |
103 | enum Strategy |
104 | { |
105 | ///If set, pixmaps will be cached in a shared disk cache (using |
106 | ///KSharedDataCache). This is especially useful for complex SVG |
107 | ///themes because KGameRenderer will not load the SVG if all needed |
108 | ///pixmaps are available from the disk cache. |
109 | UseDiskCache = 1 << 0, |
110 | ///If set, pixmap requests from KGameRendererClients will be |
111 | ///handled asynchronously if possible. This is especially useful |
112 | ///when many clients are requesting complex pixmaps at one time. |
113 | UseRenderingThreads = 1 << 1 |
114 | }; |
115 | Q_DECLARE_FLAGS(Strategies, Strategy) |
116 | |
117 | ///Constructs a new KGameRenderer that renders @a prov->currentTheme(). |
118 | ///@param cacheSize the cache size in megabytes (if not given, a sane |
119 | ///default is used) |
120 | ///@warning This constructor may only be called from the main thread. |
121 | explicit KGameRenderer(KgThemeProvider* prov, unsigned cacheSize = 0); |
122 | ///@overload that allows to use KGameRenderer without a theme provider |
123 | /// (useful when there is only one theme) |
124 | ///@note Takes ownership of @a theme. |
125 | explicit KGameRenderer(KgTheme* theme, unsigned cacheSize = 0); |
126 | ///Deletes this KGameRenderer instance, as well as all clients using it. |
127 | virtual ~KGameRenderer(); |
128 | |
129 | ///@return the primary view which is used by newly created |
130 | ///KGameRenderedItem instances associated with this renderer |
131 | ///@see KGameRenderedItem::setPrimaryView |
132 | QGraphicsView* defaultPrimaryView() const; |
133 | ///Set the primary view which will be used by newly created |
134 | ///KGameRenderedItem instances associated with this renderer. |
135 | ///Calls to this method will have no effect on existing instances. |
136 | ///@see KGameRenderedItem::setPrimaryView |
137 | void setDefaultPrimaryView(QGraphicsView* view); |
138 | ///@return the frame base index. @see setFrameBaseIndex() |
139 | int frameBaseIndex() const; |
140 | ///Sets the frame base index, i.e. the lowest frame index. Usually, |
141 | ///frame numbering starts at zero, so the frame base index is zero. |
142 | /// |
143 | ///For example, if you set the frame base index to 42, and use the |
144 | ///default frame suffix, the 3 frames of an animated sprite "foo" are |
145 | ///provided by the SVG elements "foo_42", "foo_43" and "foo_44". |
146 | /// |
147 | ///It is recommended not to alter the frame base index unless you need |
148 | ///to support legacy themes. |
149 | void setFrameBaseIndex(int frameBaseIndex); |
150 | ///@return the frame suffix. @see setFrameSuffix() |
151 | QString frameSuffix() const; |
152 | ///Sets the frame suffix. This suffix will be added to a sprite key |
153 | ///to create the corresponding SVG element key, after any occurrence of |
154 | ///"%1" in the suffix has been replaced by the frame number. |
155 | ///@note Giving a suffix which does not include "%1" will reset to the |
156 | ///default suffix "_%1". |
157 | /// |
158 | ///For example, if the frame suffix is set to "_%1" (the default), the |
159 | ///SVG element key for the frame no. 23 of the sprite "foo" is "foo_23". |
160 | ///@note Frame numbering starts at zero unless you setFrameBaseIndex(). |
161 | void setFrameSuffix(const QString& suffix); |
162 | ///@return the optimization strategies used by this renderer |
163 | ///@see setStrategyEnabled() |
164 | Strategies strategies() const; |
165 | ///Enables/disables an optimization strategy for this renderer. By |
166 | ///default, both the UseDiskCache and the UseRenderingThreads strategies |
167 | ///are enabled. This is a sane default for 99% of all games. You might |
168 | ///only want to disable optimizations if the graphics are so simple that |
169 | ///the optimisations create an overhead in your special case. |
170 | /// |
171 | ///If you disable UseDiskCache, you should do so before setTheme(), |
172 | ///because changes to UseDiskCache cause a full theme reload. |
173 | void setStrategyEnabled(Strategy strategy, bool enabled = true); |
174 | |
175 | ///@return the KgTheme instance used by this renderer |
176 | const KgTheme* theme() const; |
177 | ///@return the KgThemeProvider instance used by this renderer, or 0 if |
178 | /// the renderer was created with a single static theme |
179 | KgThemeProvider* themeProvider() const; |
180 | |
181 | ///@return the bounding rectangle of the sprite with this @a key |
182 | ///This is equal to QSvgRenderer::boundsOnElement() of the corresponding |
183 | ///SVG element. |
184 | QRectF boundsOnSprite(const QString& key, int frame = -1) const; |
185 | ///@return the count of frames available for the sprite with this @a key |
186 | ///If this sprite is not animated (i.e. there are no SVG elements for |
187 | ///any frames), this method returns 0. If the sprite does not exist at |
188 | ///all, -1 is returned. |
189 | /// |
190 | ///If the sprite is animated, the method counts frames starting at zero |
191 | ///(unless you change the frameBaseIndex()), and returns the number of |
192 | ///frames for which corresponding elements exist in the SVG file. |
193 | /// |
194 | ///For example, if the SVG contains the elements "foo_0", "foo_1" and |
195 | ///"foo_3", frameCount("foo") returns 2 for the default frame suffix. |
196 | ///(The element "foo_3" is ignored because "foo_2" is missing.) |
197 | int frameCount(const QString& key) const; |
198 | ///@return if the sprite with the given @a key exists |
199 | ///This is the same as \code renderer.frameCount(key) >= 0 \endcode |
200 | bool spriteExists(const QString& key) const; |
201 | ///@return a rendered pixmap |
202 | ///@param key the key of the sprite |
203 | ///@param size the size of the resulting pixmap |
204 | ///@param frame the number of the frame which you want |
205 | ///@param customColors the custom color replacements for this client. |
206 | /// That is, for each entry in this has, the key color will be |
207 | /// replaced by its value if it is encountered in the sprite. |
208 | ///@note For non-animated frames, set @a frame to -1 or omit it. |
209 | ///@note Custom colors increase the rendering time considerably, so use |
210 | /// this feature only if you really need its flexibility. |
211 | |
212 | // The parentheses around QHash<QColor, QColor>() avoid compile |
213 | // errors on platforms with older gcc versions, e.g. OS X 10.6. |
214 | QPixmap spritePixmap(const QString& key, const QSize& size, int frame = -1, const QHash<QColor, QColor>& customColors = (QHash<QColor, QColor>())) const; |
215 | Q_SIGNALS: |
216 | void themeChanged(const KgTheme* theme); |
217 | ///This signal is never emitted. It is provided because QML likes to |
218 | ///complain about properties without NOTIFY signals, even readonly ones. |
219 | void readOnlyProperty(); |
220 | private: |
221 | friend class KGameRendererPrivate; |
222 | friend class KGameRendererClient; |
223 | friend class KGameRendererClientPrivate; |
224 | KGameRendererPrivate* const d; |
225 | Q_PRIVATE_SLOT(d, void _k_setTheme(const KgTheme*)); |
226 | }; |
227 | |
228 | Q_DECLARE_OPERATORS_FOR_FLAGS(KGameRenderer::Strategies) |
229 | |
230 | #endif // KGAMERENDERER_H |
231 | |