1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Declarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "spriteengine.h"
43 #include "spritestate.h"
51 SpriteEngine::SpriteEngine(QObject *parent) :
52 QObject(parent), m_timeOffset(0)
56 m_advanceTime.start();
59 SpriteEngine::SpriteEngine(QList<SpriteState*> states, QObject *parent) :
60 QObject(parent), m_states(states), m_timeOffset(0)
64 m_advanceTime.start();
67 SpriteEngine::~SpriteEngine()
71 int SpriteEngine::maxFrames()
74 foreach(SpriteState* s, m_states)
80 void SpriteEngine::setGoal(int state, int sprite, bool jump)
82 if(sprite >= m_sprites.count() || state >= m_states.count())
85 m_goals[sprite] = state;
89 if(m_sprites[sprite] == state)
90 return;//Already there
91 m_sprites[sprite] = state;
93 restartSprite(sprite);
97 QImage SpriteEngine::assembledImage()
104 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
106 foreach(SpriteState* state, m_states){
107 if(state->frames() > m_maxFrames)
108 m_maxFrames = state->frames();
110 QImage img(state->source().toLocalFile());
112 qWarning() << "SpriteEngine: loading image failed..." << state->source().toLocalFile();
117 if(img.width() / state->frames() != frameWidth){
118 qWarning() << "SpriteEngine: Irregular frame width..." << state->source().toLocalFile();
122 frameWidth = img.width() / state->frames();
124 if(img.width() > maxSize){
125 qWarning() << "SpriteEngine: Animation too wide..." << state->source().toLocalFile();
130 if(img.height()!=frameHeight){
131 qWarning() << "SpriteEngine: Irregular frame height..." << state->source().toLocalFile();
135 frameHeight = img.height();
138 if(img.height() > maxSize){
139 qWarning() << "SpriteEngine: Animation too tall..." << state->source().toLocalFile();
144 QImage image(frameWidth * m_maxFrames, frameHeight * m_states.count(), QImage::Format_ARGB32);
148 foreach(SpriteState* state, m_states){
149 QImage img(state->source().toLocalFile());
150 p.drawImage(0,y,img);
154 if(image.height() > maxSize){
155 qWarning() << "SpriteEngine: Too many animations to fit in one texture...";
161 void SpriteEngine::setCount(int c)
165 m_startTimes.resize(c);
168 void SpriteEngine::startSprite(int index)
170 if(index >= m_sprites.count())
172 m_sprites[index] = 0;
174 restartSprite(index);
177 void SpriteEngine::restartSprite(int index)
179 m_startTimes[index] = m_timeOffset + m_advanceTime.elapsed();
180 int time = m_states[m_sprites[index]]->duration() * m_states[m_sprites[index]]->frames() + m_startTimes[index];
181 for(int i=0; i<m_stateUpdates.count(); i++)
182 m_stateUpdates[i].second.removeAll(index);
183 addToUpdateList(time, index);
186 uint SpriteEngine::updateSprites(uint time)
188 //Sprite State Update;
189 while(!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){
190 foreach(int idx, m_stateUpdates.first().second){
191 if(idx >= m_sprites.count())
192 continue;//TODO: Proper fix(because this does happen and I'm just ignoring it)
193 int stateIdx = m_sprites[idx];
195 int goalPath = goalSeek(stateIdx, idx);
196 if(goalPath == -1){//Random
197 qreal r =(qreal) qrand() / (qreal) RAND_MAX;
199 for(QVariantMap::const_iterator iter=m_states[stateIdx]->m_to.constBegin();
200 iter!=m_states[stateIdx]->m_to.constEnd(); iter++)
201 total += (*iter).toReal();
203 for(QVariantMap::const_iterator iter= m_states[stateIdx]->m_to.constBegin();
204 iter!=m_states[stateIdx]->m_to.constEnd(); iter++){
205 if(r < (*iter).toReal()){
206 bool superBreak = false;
207 for(int i=0; i<m_states.count(); i++){
208 if(m_states[i]->name() == iter.key()){
217 r -= (*iter).toReal();
219 }else{//Random out of shortest paths to goal
222 if(nextIdx == -1)//No to states means stay here
225 m_sprites[idx] = nextIdx;
226 m_startTimes[idx] = time;
227 //TODO: emit something?
228 addToUpdateList((m_states[nextIdx]->duration() * m_states[nextIdx]->frames()) + time, idx);
230 m_stateUpdates.pop_front();
234 m_advanceTime.start();
235 if(m_stateUpdates.isEmpty())
237 return m_stateUpdates.first().first;
240 int SpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist)
243 if(m_goals[spriteIdx] != -1)
244 goalName = m_states[m_goals[spriteIdx]]->name();
246 goalName = m_globalGoal;
247 if(goalName.isEmpty())
249 //TODO: caching instead of excessively redoing iterative deepening (which was chosen arbitarily anyways)
250 // Paraphrased - implement in an *efficient* manner
251 for(int i=0; i<m_states.count(); i++)
252 if(m_states[curIdx]->name() == goalName)
255 dist = m_states.count();
256 SpriteState* curState = m_states[curIdx];
257 for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
258 iter!=curState->m_to.constEnd(); iter++){
259 if(iter.key() == goalName)
260 for(int i=0; i<m_states.count(); i++)
261 if(m_states[i]->name() == goalName)
265 for(int i=1; i<dist; i++){
266 for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
267 iter!=curState->m_to.constEnd(); iter++){
269 for(int j=0; j<m_states.count(); j++)//One place that could be a lot more efficient...
270 if(m_states[j]->name() == iter.key())
271 if(goalSeek(j, spriteIdx, i) != -1)
276 if(!options.isEmpty()){
277 if(options.count()==1)
278 return *(options.begin());
280 qreal r =(qreal) qrand() / (qreal) RAND_MAX;
282 for(QSet<int>::const_iterator iter=options.constBegin();
283 iter!=options.constEnd(); iter++)
284 total += curState->m_to.value(m_states[(*iter)]->name()).toReal();
286 for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
287 iter!=curState->m_to.constEnd(); iter++){
288 bool superContinue = true;
289 for(int j=0; j<m_states.count(); j++)
290 if(m_states[j]->name() == iter.key())
291 if(options.contains(j))
292 superContinue = false;
295 if(r < (*iter).toReal()){
296 bool superBreak = false;
297 for(int j=0; j<m_states.count(); j++){
298 if(m_states[j]->name() == iter.key()){
315 void SpriteEngine::addToUpdateList(uint t, int idx)
317 for(int i=0; i<m_stateUpdates.count(); i++){
318 if(m_stateUpdates[i].first==t){
319 m_stateUpdates[i].second << idx;
321 }else if(m_stateUpdates[i].first > t){
324 m_stateUpdates.insert(i, qMakePair(t, tmpList));
330 m_stateUpdates << qMakePair(t, tmpList);