kgrrenderer.cpp 11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/****************************************************************************
 *    Copyright 2012  Ian Wadham <iandw.au@gmail.com>                       *
 *                                                                          *
 *    This program is free software; you can redistribute it and/or         *
 *    modify it under the terms of the GNU General Public License as        *
 *    published by the Free Software Foundation; either version 2 of        *
 *    the License, or (at your option) any later version.                   *
 *                                                                          *
 *    This program is distributed in the hope that it will be useful,       *
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *    GNU General Public License for more details.                          *
 *                                                                          *
 *    You should have received a copy of the GNU General Public License     *
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ****************************************************************************/

18 19 20
    // TODO - Border tiles, display tiles.
    // TODO - Add attributes to theme: HasBorderTiles, HasDisplayTiles.

21
#include <KGameRenderer>
22
#include <KGameRenderedItem>
23 24 25 26 27 28 29
#include <KgThemeProvider>
#include <KgThemeSelector>
#include <KLocalizedString>

#include <QDebug>
#include <QString>

30
#include "kgrglobals.h"
31 32
#include "kgrthemetypes.h"
#include "kgrrenderer.h"
33
#include "kgrscene.h"
34

35 36
#include <cmath>

37
KGrRenderer::KGrRenderer (KGrScene * scene)
38
    :
39 40
    QObject (scene),
    m_scene (scene)
41
{
42 43 44 45 46
    // Set up two theme providers: for the Set and the Actors.
    m_setProvider     = new KgThemeProvider("Theme", this);	// Save config.
    m_actorsProvider  = new KgThemeProvider("",      this);	// Do not save.

    // Find SVG files for the Set, i.e. tiles and backgrounds.
47 48 49 50
    const QMetaObject * setThemeClass = & KGrSetTheme::staticMetaObject;
    m_setProvider->discoverThemes ("appdata", QLatin1String ("themes"),
                                   QLatin1String ("egypt"), setThemeClass);

51 52 53 54 55 56 57 58 59
    // Find SVG files for the Actors, i.e. hero and enemies.
    const QMetaObject * actorsThemeClass = & KGrActorsTheme::staticMetaObject;
    m_actorsProvider->discoverThemes ("appdata", QLatin1String ("themes"),
                                   QLatin1String ("egypt"), actorsThemeClass);

    // Set up a dialog for selecting themes.
    m_themeSelector  = new KgThemeSelector (m_setProvider,
                                            KgThemeSelector::DefaultBehavior,
                                            0);	// No parent: modeless dialog.
60

61 62
    // Set up the renderer for the Set, i.e. tiles and backgrounds.
    m_setRenderer    = new KGameRenderer (m_setProvider);
63
    m_setRenderer->setParent (this);
64 65
    m_setRenderer->setFrameSuffix ("_%1");
    m_setRenderer->setFrameBaseIndex (1);
66

67 68 69 70 71 72 73 74 75 76 77
    // Set up the renderer for the Actors, i.e. hero and enemies.
    m_actorsRenderer = new KGameRenderer (m_actorsProvider);
    m_actorsRenderer->setParent (this);
    m_actorsRenderer->setFrameSuffix ("_%1");
    m_actorsRenderer->setFrameBaseIndex (1);

    // Match the Actors SVG theme to the Set theme, whenever the theme changes.
    connect (m_setProvider, SIGNAL(currentThemeChanged(const KgTheme*)),
             this,            SLOT(currentThemeChanged(const KgTheme*)));

    // Match the starting SVG theme for the Actors to the one for the Set.
78
    matchThemes (m_setProvider->currentTheme());
79 80 81 82 83 84 85
}

KGrRenderer::~KGrRenderer()
{
    delete m_themeSelector;
}

86
void KGrRenderer::matchThemes (const KgTheme * currentSetTheme)
87 88 89 90 91 92 93 94
{
    // Start of game or change of theme: initialise the counts of pixmap keys.
    initPixmapKeys();

    foreach (const KgTheme * actorsTheme, m_actorsProvider->themes()) {
	if (actorsTheme->customData("Set") ==
            currentSetTheme->customData("Set")) {
	    m_actorsProvider->setCurrentTheme (actorsTheme);
95
	    break;
96 97
	}
    }
98
}
99

100 101 102 103 104 105
void KGrRenderer::currentThemeChanged (const KgTheme* currentSetTheme)
{
    qDebug() << "KGrRenderer::currentThemeChanged()" << currentSetTheme->name();

    matchThemes (currentSetTheme);
    m_scene->changeTheme();
106 107
}

108 109
void KGrRenderer::selectTheme()
{
110
    // Show the theme-selection dialog.
111 112 113 114 115 116 117 118 119 120 121 122 123
    m_themeSelector->showAsDialog (i18n("Theme Selector"));
}

KGrRenderer::PixmapSpec KGrRenderer::keyTable [] = {
    {ENEMY,    Actors, "enemy_1",       "",   -1, -2},	// For editor only.
    {HERO,     Actors, "hero_1",        "",   -1, -2},	// For editor only.
    {CONCRETE, Set,    "concrete",      "-%1", 0, -2},
    {BRICK,    Set,    "brick",         "-%1", 0, -2},
    {FBRICK,   Set,    "false_brick",   "",   -1, -2},	// For editor only.
    {HLADDER,  Set,    "hidden_ladder", "",   -1, -2},	// For editor only.
    {LADDER,   Set,    "ladder",        "-%1", 0, -2},
    {NUGGET,   Set,    "gold",          "-%1", 0, -2},
    {BAR,      Set,    "bar",           "-%1", 0, -2},
124
    {BACKDROP, Set,    "background",    "%1",  0, -2},
125
    {FREE,     Set,    "empty",         "",   -1, -2}	// Must be last entry.
126 127 128 129
};

void KGrRenderer::initPixmapKeys()
{
130
    // Set all pixmaps in keyTable[] as "not counted yet" (frameCount -2).
131
    int index = 0;
132
    do {
133 134
	keyTable[index].frameCount = -2;
	index++;
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    } while (keyTable[index].picType != FREE);
}

KGameRenderedItem * KGrRenderer::getTileItem
                    (const char picType, KGameRenderedItem * currentTile)
{
    if (currentTile) {
	// Remove the tile that was here before.
        m_scene->removeItem (currentTile);
        delete currentTile;
    }

    int index;
    if ((picType == FREE) || ((index = findKeyTableIndex (picType)) < 0)) {
        return 0;	// Empty place or missing type, so no KGameRenderedItem.
150
    }
151 152 153 154 155 156

    // Get the pixmap key and use one of the two renderers to create the tile.
    QString key = getPixmapKey (picType, index);
    KGameRenderedItem * tile =
                new KGameRenderedItem ((keyTable[index].picSource == Set) ?
                                       m_setRenderer : m_actorsRenderer, key);
157
    tile->setAcceptedMouseButtons (0);
158 159
    m_scene->addItem (tile);
    return tile;
160 161
}

162 163 164 165 166 167 168 169 170 171 172
KGrSprite * KGrRenderer::getSpriteItem (const char picType, const int tickTime)
{
    int index = findKeyTableIndex (picType);
    if (index < 0) {
        return 0;	// Missing type, so no KGrSprite item.
    }
    QString key = (picType == HERO) ? "hero" :
                  ((picType == ENEMY) ? "enemy" : "brick");
    KGrSprite * sprite = new KGrSprite ((keyTable[index].picSource == Set) ?
                                        m_setRenderer : m_actorsRenderer,
                                        key, picType, tickTime);
173
    sprite->setAcceptedMouseButtons (0);
174
    // We cannot add the sprite to the scene yet: it needs a frame and size.
175 176 177
    return sprite;
}

178 179 180 181 182 183 184 185 186 187
KGameRenderedItem * KGrRenderer::getBackground
                    (const int level, KGameRenderedItem * currentBackground)
{
    if (currentBackground) {
        m_scene->removeItem (currentBackground);
        delete currentBackground;
    }

    QString key = getBackgroundKey (level);
    KGameRenderedItem * background = new KGameRenderedItem (m_setRenderer, key);
188
    background->setAcceptedMouseButtons (0);
189
    m_scene->addItem (background);
190 191 192 193

    return background;
}

194 195
KGameRenderedItem * KGrRenderer::getBorderItem
                    (QString spriteKey, KGameRenderedItem * currentItem)
196
{
197 198 199 200
    if (currentItem) {
        m_scene->removeItem (currentItem);
        delete currentItem;
    }
201

202 203 204
    if (!hasBorder()) {
        return 0;
    }
205

206
    KGameRenderedItem * item = new KGameRenderedItem (m_setRenderer, spriteKey);
207
    item->setAcceptedMouseButtons (0);
208 209 210
    m_scene->addItem (item);
    return item;
}
211

212 213 214
bool KGrRenderer::hasBorder() const
{
    QString s = m_setRenderer->theme()->customData("DrawCanvasBorder", "0");
215

216
    if (s == QString ("1"))
217 218 219 220
        return true;
    else
        return false;
}
221

222 223 224 225 226
QColor KGrRenderer::borderColor() const
{
    QString s = m_setRenderer->theme()->customData("BorderColor", "#000000");
    return QColor (s);
}
227

228 229 230 231
QColor KGrRenderer::textColor() const
{
    QString s = m_setRenderer->theme()->customData("TextColor", "#FFFFFF");
    return QColor (s);
232 233
}

234 235 236 237 238 239 240 241 242 243 244 245
QPixmap KGrRenderer::getPixmap (const char picType)
{
    // Get the pixmap key and use one of the two renderers to create the tile.
    int index   = findKeyTableIndex (picType);
    QString key = getPixmapKey      (picType, index);

    if (keyTable[index].picSource == Set)
        return m_setRenderer->spritePixmap (key, m_scene->tileSize ());
    else
        return m_actorsRenderer->spritePixmap (key, m_scene->tileSize ());
}

246
QString KGrRenderer::getPixmapKey (const char picType, const int index)
247
{
248
    QString pixmapKey = "";
249
    // int index = findKeyTableIndex (picType);
250 251 252 253 254 255 256 257 258 259 260 261 262
    int frameCount = (index < 0) ? -1 : keyTable[index].frameCount;
    if (frameCount > -1) {
	pixmapKey = keyTable[index].picKey;	// No suffix.
	if (frameCount > 0) {
	    // Pick a random frame number and add it as a suffix.
	    // Note: We are not worried about having a good seed for this.
	    pixmapKey = pixmapKey + QString(keyTable[index].frameSuffix);
	    pixmapKey = pixmapKey.arg (keyTable[index].frameBaseIndex +
				       (rand() % frameCount));
	}
    }
    return pixmapKey;
}
263

264 265
QString KGrRenderer::getBackgroundKey (const int level)
{
266
    QString pixmapKey = "";
267 268 269 270 271 272 273 274 275 276
    int index = findKeyTableIndex (BACKDROP);
    int frameCount = (index < 0) ? -1 : keyTable[index].frameCount;
    if (frameCount > -1) {
	pixmapKey = keyTable[index].picKey;
	if (frameCount > 0) {
	    // Cycle through available backgrounds as the game-level increases.
	    pixmapKey = pixmapKey + QString(keyTable[index].frameSuffix);
	    pixmapKey = pixmapKey.arg (level % frameCount);
	}
    }
277 278

    qDebug() << "BACKGROUND pixmap key" << pixmapKey;
279 280 281 282 283
    return pixmapKey;
}

int KGrRenderer::findKeyTableIndex (const char picType)
{
284
    int index = 0;
285 286
    while (true) {		// Find ANY picType, including FREE.
	if (keyTable[index].picType == picType) {
287
	    if (keyTable[index].frameCount == -2) {
288
		keyTable[index].frameCount = countFrames (index);
289 290 291
	    }
	    break;
	}
292 293 294 295
	else if (keyTable[index].picType == FREE) {
	    index = -1;		// Not found.
	    break;
	}
296 297
	index++;
    }
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    return index;
}

int KGrRenderer::countFrames (const int index)
{
    int count = -1;
    int frame = keyTable[index].frameBaseIndex;
    KGameRenderer * r = (keyTable[index].picSource == Set) ? m_setRenderer :
                                                             m_actorsRenderer;
    if (r->spriteExists (keyTable[index].picKey)) {
        count++;
    }

    if ((count == 0) && (QString(keyTable[index].picKey) != QString("brick"))) {
	return count;
    }

    if (frame < 0) {
	return count;		// This element cannot have more than one frame.
    }

    count = 0;
    QString pixmapKey = QString(keyTable[index].picKey) +
                        QString(keyTable[index].frameSuffix);
    while (r->spriteExists (pixmapKey.arg (frame))) {
	count++;
	frame++;
    }

    return count;
328 329 330
}

#include "kgrrenderer.moc"