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
22class QGraphicsView;
23#include <QtCore/QHash>
24#include <QtCore/QObject>
25#include <QtGui/QPixmap>
26
27#include <libkdegames_export.h>
28
29class KGameRendererPrivate;
30class KGameRendererClient;
31class KGameRendererClientPrivate;
32class KgTheme;
33class 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 */
94class 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
228Q_DECLARE_OPERATORS_FOR_FLAGS(KGameRenderer::Strategies)
229
230#endif // KGAMERENDERER_H
231