1 | /********************************************************************************** |
2 | This file is part of the game 'KTron' |
3 | |
4 | Copyright (C) 1998-2000 by Matthias Kiefer <matthias.kiefer@gmx.de> |
5 | Copyright (C) 2005 Benjamin C. Meyer <ben at meyerhome dot net> |
6 | Copyright (C) 2008-2009 Stas Verberkt <legolas at legolasweb dot nl> |
7 | |
8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
21 | |
22 | *******************************************************************************/ |
23 | |
24 | #include "renderer.h" |
25 | #include "settings.h" |
26 | #include "object.h" |
27 | |
28 | #include <QPainter> |
29 | #include <QPixmap> |
30 | #include <QSize> |
31 | |
32 | #include <KPixmapCache> |
33 | #include <QSvgRenderer> |
34 | #include <KDebug> |
35 | #include <kfontutils.h> |
36 | |
37 | #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API |
38 | #include <libkdegamesprivate/kgametheme.h> |
39 | |
40 | class RendererPrivate |
41 | { |
42 | public: |
43 | RendererPrivate(); |
44 | ~RendererPrivate(); |
45 | |
46 | QSize m_sceneSize; |
47 | QSize m_partSize; |
48 | |
49 | QSvgRenderer m_renderer; |
50 | KPixmapCache m_cache; |
51 | |
52 | QPixmap *m_playField; |
53 | |
54 | QString m_currentTheme; |
55 | }; |
56 | |
57 | const QString sizeSuffix(QLatin1String( "_%1-%2" )); |
58 | const QString frameSuffix(QLatin1String( "-%1" )); |
59 | |
60 | RendererPrivate::RendererPrivate() |
61 | : m_renderer() |
62 | , m_cache(QLatin1String( "ktron-cache" )) |
63 | { |
64 | m_cache.setCacheLimit(3 * 1024); |
65 | m_cache.discard(); |
66 | m_playField = 0; |
67 | } |
68 | |
69 | RendererPrivate::~RendererPrivate() |
70 | { |
71 | delete m_playField; |
72 | } |
73 | |
74 | Renderer::Renderer() |
75 | : p(new RendererPrivate) |
76 | { |
77 | loadTheme(Settings::theme()); |
78 | } |
79 | |
80 | Renderer::Renderer(const Renderer &) |
81 | { |
82 | } |
83 | |
84 | Renderer::~Renderer() |
85 | { |
86 | delete p; |
87 | } |
88 | |
89 | Renderer *Renderer::self() |
90 | { |
91 | static Renderer r; |
92 | return &r; |
93 | } |
94 | |
95 | bool Renderer::loadTheme(const QString &name) |
96 | { |
97 | bool discardCache = !p->m_currentTheme.isEmpty(); |
98 | if (!p->m_currentTheme.isEmpty() && p->m_currentTheme == name) |
99 | return true; //requested to load the theme that is already loaded |
100 | KGameTheme theme; |
101 | //try to load theme |
102 | if (!theme.load(name)) |
103 | { |
104 | if (!theme.loadDefault()) |
105 | return false; |
106 | } |
107 | p->m_currentTheme = name; |
108 | |
109 | //load graphics |
110 | if (!p->m_renderer.load(theme.graphics())) |
111 | return false; |
112 | //flush cache |
113 | if (discardCache) |
114 | p->m_cache.discard(); |
115 | return true; |
116 | } |
117 | |
118 | QPixmap Renderer::getPart(const QString &frameSvgName) |
119 | { |
120 | return getPartOfSize(frameSvgName, p->m_partSize); |
121 | } |
122 | |
123 | QPixmap Renderer::getPartOfSize(const QString &frameSvgName, const QSize &partSize) |
124 | { |
125 | QString framePixName = frameSvgName + sizeSuffix.arg(partSize.width()).arg(partSize.height()); |
126 | QPixmap pix; |
127 | if (!p->m_cache.find(framePixName, pix)) |
128 | { |
129 | pix = QPixmap(partSize); |
130 | pix.fill(Qt::transparent); |
131 | QPainter painter(&pix); |
132 | p->m_renderer.render(&painter, frameSvgName); |
133 | painter.end(); |
134 | p->m_cache.insert(framePixName, pix); |
135 | } |
136 | |
137 | //return the static pixmap |
138 | return pixmapFromCache(p, frameSvgName, partSize); |
139 | } |
140 | |
141 | QPixmap Renderer::pixmapFromCache(RendererPrivate *p, const QString &svgName, const QSize &size) |
142 | { |
143 | if (size.isEmpty()) |
144 | return QPixmap(); |
145 | QPixmap pix; |
146 | QString pixName = svgName + sizeSuffix.arg(size.width()).arg(size.height()); |
147 | |
148 | if (!p->m_cache.find(pixName, pix)) |
149 | { |
150 | pix = QPixmap(size); |
151 | pix.fill(Qt::transparent); |
152 | QPainter painter(&pix); |
153 | p->m_renderer.render(&painter, svgName); |
154 | painter.end(); |
155 | p->m_cache.insert(pixName, pix); |
156 | } |
157 | |
158 | return pix; |
159 | } |
160 | |
161 | QPixmap Renderer::background() |
162 | { |
163 | QPixmap pix; |
164 | QString pixName = QLatin1String( "bgtile" ) + sizeSuffix.arg(p->m_sceneSize.width()).arg(p->m_sceneSize.height()); |
165 | if (!p->m_cache.find(pixName, pix)) |
166 | { |
167 | pix = QPixmap(p->m_sceneSize); |
168 | pix.fill(Qt::white); |
169 | QPainter painter(&pix); |
170 | |
171 | QPixmap bgPix = getPart(QLatin1String( "bgtile" )); |
172 | if (!bgPix.isNull()) |
173 | { |
174 | pix.fill(Qt::white); |
175 | int pw = bgPix.width(); |
176 | int ph = bgPix.height(); |
177 | for (int x = 0; x <= p->m_sceneSize.width(); x += pw) { |
178 | for (int y = 0; y <= p->m_sceneSize.height(); y += ph) { |
179 | painter.drawPixmap(x, y, bgPix); |
180 | } |
181 | } |
182 | } |
183 | else |
184 | { |
185 | pix.fill(Qt::green); |
186 | } |
187 | |
188 | painter.end(); |
189 | p->m_cache.insert(pixName, pix); |
190 | } |
191 | |
192 | // Tiled background |
193 | return pix; |
194 | } |
195 | |
196 | void Renderer::boardResized(int width, int height, int partWidth, int partHeight) |
197 | { |
198 | //new metrics |
199 | p->m_sceneSize = QSize(width, height); |
200 | p->m_partSize = QSize(partWidth, partHeight); |
201 | } |
202 | |
203 | void Renderer::resetPlayField() |
204 | { |
205 | delete p->m_playField; |
206 | p->m_playField = new QPixmap(p->m_sceneSize); |
207 | //p->m_playField->fill(Qt::green); |
208 | } |
209 | |
210 | void Renderer::updatePlayField(PlayField &playfield) |
211 | { |
212 | int i, j; |
213 | |
214 | if (!p->m_playField) |
215 | { |
216 | resetPlayField(); |
217 | } |
218 | |
219 | QPainter painter; |
220 | painter.begin(p->m_playField); |
221 | |
222 | QPixmap bgPix = background(); |
223 | painter.drawPixmap(0, 0, bgPix); |
224 | |
225 | // Draw border |
226 | for (i = 0; i < playfield.getWidth() + 2; ++i) |
227 | { |
228 | for (j = 0; j < playfield.getHeight() + 2; ++j) |
229 | { |
230 | if (i == 0 || i == playfield.getWidth() + 1 || j == 0 || j == playfield.getHeight() + 1) |
231 | { |
232 | QPixmap part = Renderer::self()->getPart(QLatin1String( "border" )); |
233 | painter.drawPixmap(calculateOffsetX(i), calculateOffsetY(j), part); |
234 | } |
235 | } |
236 | } |
237 | |
238 | // Examine all pixels and draw |
239 | for(i = 0; i < playfield.getWidth(); ++i) |
240 | { |
241 | for(j = 0; j < playfield.getHeight(); ++j) |
242 | { |
243 | if (playfield.getObjectAt(i, j)->getObjectType() != ObjectType::Object) |
244 | { |
245 | drawPart(painter, i, j, playfield.getObjectAt(i, j)->getSVGName()); |
246 | } |
247 | } |
248 | } |
249 | |
250 | painter.end(); |
251 | } |
252 | |
253 | int Renderer::calculateOffsetX(int x) |
254 | { |
255 | return (x * p->m_partSize.width()) + (p->m_sceneSize.width() - (TRON_PLAYFIELD_WIDTH + 2) * p->m_partSize.width()) / 2; |
256 | } |
257 | |
258 | int Renderer::calculateOffsetY(int y) |
259 | { |
260 | return (y * p->m_partSize.height()) + (p->m_sceneSize.height() - (TRON_PLAYFIELD_HEIGHT + 2) * p->m_partSize.height()) / 2; |
261 | } |
262 | |
263 | void Renderer::drawPart(QPainter & painter, int x, int y, QString svgName) |
264 | { |
265 | //kDebug() << "Drawing part: " << svgName; |
266 | |
267 | int xOffset = calculateOffsetX(x + 1); |
268 | int yOffset = calculateOffsetY(y + 1); |
269 | |
270 | //int type = playfield[x][y]; |
271 | |
272 | QPixmap snakePart = Renderer::self()->getPart(svgName); |
273 | |
274 | painter.drawPixmap(xOffset, yOffset, snakePart); |
275 | } |
276 | |
277 | QPixmap *Renderer::getPlayField() |
278 | { |
279 | return p->m_playField; |
280 | } |
281 | |
282 | QPixmap Renderer::messageBox(const QString &message) { |
283 | int w = p->m_sceneSize.width() / 2; |
284 | int h = p->m_sceneSize.height() / 3; |
285 | |
286 | QSize size(w, h); |
287 | QPixmap pixmap = getPartOfSize(QLatin1String( "display" ), size); |
288 | |
289 | QPainter painter(&pixmap); |
290 | |
291 | const int fontSize = KFontUtils::adaptFontSize(painter, message, w * 0.9, h, 28, 1, KFontUtils::DoNotAllowWordWrap); |
292 | |
293 | painter.setPen(QColor(255, 255, 255, 220)); |
294 | painter.setFont(QFont(QLatin1String( "Helvetica" ), fontSize, QFont::Bold)); |
295 | painter.drawText(QRectF(0, 0, w, h), Qt::AlignCenter, message); |
296 | |
297 | painter.end(); |
298 | |
299 | return pixmap; |
300 | } |
301 | |