kgrrenderer.cpp 9.04 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 22 23 24 25 26 27
#include <KGameRenderer>
#include <KgThemeProvider>
#include <KgThemeSelector>
#include <KLocalizedString>

#include <QDebug>
#include <QString>
28
#include <QGraphicsScene>
29

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

34 35
#include <cmath>

36
KGrRenderer::KGrRenderer (QGraphicsScene * scene)
37
    :
38 39
    QObject (scene),
    m_scene (scene)
40 41 42
{
    qDebug() << "KGrRenderer called";

43 44 45 46 47
    // 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.
48 49 50 51
    const QMetaObject * setThemeClass = & KGrSetTheme::staticMetaObject;
    m_setProvider->discoverThemes ("appdata", QLatin1String ("themes"),
                                   QLatin1String ("egypt"), setThemeClass);

52 53 54 55 56 57 58 59 60
    // 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.
61

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

68 69 70 71 72 73 74 75 76 77 78 79
    // 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.
    currentThemeChanged (m_setProvider->currentTheme());
80 81 82 83 84 85 86
}

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

87 88 89 90 91 92 93 94 95 96 97 98 99 100
void KGrRenderer::currentThemeChanged (const KgTheme* currentSetTheme)
{
    // Start of game or change of theme: initialise the counts of pixmap keys.
    initPixmapKeys();

    // Make the Actors theme (hero, etc.) match the Set theme (bricks, etc.).
    qDebug() << "KGrRenderer::currentThemeChanged()" << currentSetTheme->name();
    foreach (const KgTheme * actorsTheme, m_actorsProvider->themes()) {
	qDebug() << "KGrRenderer::currentThemeChanged() Actors" << actorsTheme->customData("Set") << currentSetTheme->customData("Set");
	if (actorsTheme->customData("Set") ==
            currentSetTheme->customData("Set")) {
	    m_actorsProvider->setCurrentTheme (actorsTheme);
	    qDebug() << "actorsTheme" << actorsTheme->customData("Set")
                     << actorsTheme->customData("Actors");
101
	    break;
102 103
	}
    }
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

    // Save the KGoldrunner attributes of the current theme.
    QString s     = currentSetTheme->customData("DrawCanvasBorder", "0");
    m_hasBorder   = (s == QString ("1"));
    qDebug() << "THEME HAS BORDER?" << s << m_hasBorder;
    s             = currentSetTheme->customData("BorderColor", "#000000");
    m_borderColor = QColor (s);
    qDebug() << "SET BORDER COLOR" << s << m_borderColor;
    s             = currentSetTheme->customData("TextColor", "#FFFFFF");
    m_textColor   = QColor (s);
    qDebug() << "SET TEXT COLOR" << s << m_textColor;

    // Fill the scene (and view) with the new background color.  Do this even if
    // the background has no border, to avoid ugly white rectangles appearing
    // if rendering and painting is momentarily a bit slow.
    m_scene->setBackgroundBrush (m_borderColor);
120 121
}

122 123
void KGrRenderer::selectTheme()
{
124
    // Show the theme-selection dialog.
125 126 127 128 129 130 131 132 133 134 135 136 137
    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},
138
    {BACKDROP, Set,    "background",    "%1",  0, -2},
139 140 141 142 143
    {FREE,     Set,    "",              "",   -1, -2}	// Must be last entry.
};

void KGrRenderer::initPixmapKeys()
{
144
    // Set all pixmaps in keyTable[] as "not counted yet" (frameCount -2).
145
    int index = 0;
146
    while (keyTable[index].picType != FREE) {
147 148 149 150 151 152 153
	keyTable[index].frameCount = -2;
	index++;
    }
}

QString KGrRenderer::getPixmapKey (const char picType)
{
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    QString pixmapKey = "";
    int index = findKeyTableIndex (picType);
    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));
	}
    }
    qDebug() << "picType" << picType << "pixmapKey" << pixmapKey;
    return pixmapKey;
}
170

171 172
QString KGrRenderer::getBackgroundKey (const int level)
{
173
    QString pixmapKey = "";
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    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);
	}
    }
    qDebug() << "picType" << BACKDROP << "pixmapKey" << pixmapKey;
    return pixmapKey;
}

int KGrRenderer::findKeyTableIndex (const char picType)
{
190 191 192
    int index = 0;
    while (true) {
	if (keyTable[index].picType == FREE) {
193 194
	    index = -1;		// Pixmap key not found.
	    break;
195 196 197
	}
	else if (keyTable[index].picType == picType) {
	    if (keyTable[index].frameCount == -2) {
198
		keyTable[index].frameCount = countFrames (index);
199 200 201 202 203
	    }
	    break;
	}
	index++;
    }
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
    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++;
    }

    qDebug() << "KGrRenderer::countFrames 1" << 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))) {
	qDebug() << "KGrRenderer::countFrames found" << pixmapKey.arg (frame);
	count++;
	frame++;
    }

    qDebug() << "KGrRenderer::countFrames 2" << keyTable[index].picKey << count;
    return count;
237 238 239
}

#include "kgrrenderer.moc"