diff --git a/include/aocharmovie.h b/include/aocharmovie.h index f54f510..c852bb3 100644 --- a/include/aocharmovie.h +++ b/include/aocharmovie.h @@ -1,11 +1,12 @@ #ifndef AOCHARMOVIE_H #define AOCHARMOVIE_H -#include +#include #include #include #include #include +#include class AOApplication; @@ -21,37 +22,47 @@ public: void play_talking(QString p_char, QString p_emote); void play_idle(QString p_char, QString p_emote); - void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + QPixmap get_pixmap(QImage image); + void set_frame(QPixmap f_pixmap); void stop(); + void set_flipped(bool p_flipped) {m_flipped = p_flipped;} + void move(int ax, int ay); void combo_resize(int w, int h); + private: AOApplication *ao_app; - QMovie *m_movie; - QVector movie_frames; + QVector movie_frames; + QVector movie_delays; QTimer *preanim_timer; + QTimer *ticker; + QString last_path; + QImageReader *m_reader = new QImageReader(); + QElapsedTimer actual_time; const int time_mod = 60; // These are the X and Y values before they are fixed based on the sprite's width. int x = 0; int y = 0; - bool m_flipped = false; + int frame = 0; + int max_frames = 0; + bool m_flipped = false; bool play_once = true; signals: void done(); private slots: - void frame_change(int n_frame); - void timer_done(); + void preanim_done(); + void movie_ticker(); }; #endif // AOCHARMOVIE_H diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp index ac12f63..1251a20 100644 --- a/src/aocharmovie.cpp +++ b/src/aocharmovie.cpp @@ -7,18 +7,23 @@ AOCharMovie::AOCharMovie(QWidget *p_parent, AOApplication *p_ao_app) : QLabel(p_parent) { ao_app = p_ao_app; - - m_movie = new QMovie(this); - preanim_timer = new QTimer(this); preanim_timer->setSingleShot(true); - connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); - connect(preanim_timer, SIGNAL(timeout()), this, SLOT(timer_done())); + ticker = new QTimer(this); + ticker->setTimerType(Qt::PreciseTimer); + ticker->setSingleShot(false); + connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker())); + +// connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frame_change(int))); + connect(preanim_timer, SIGNAL(timeout()), this, SLOT(preanim_done())); } void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) { +#ifdef DEBUG_CHARMOVIE + actual_time.restart(); +#endif QString emote_path; QList pathlist; pathlist = { @@ -37,111 +42,93 @@ void AOCharMovie::play(QString p_char, QString p_emote, QString emote_prefix) } } - m_movie->stop(); - m_movie->setFileName(emote_path); - - QImageReader *reader = new QImageReader(emote_path); - + this->clear(); + ticker->stop(); + preanim_timer->stop(); movie_frames.clear(); - QImage f_image = reader->read(); - while (!f_image.isNull()) - { - if (m_flipped) - movie_frames.append(f_image.mirrored(true, false)); - else - movie_frames.append(f_image); - f_image = reader->read(); - } + movie_delays.clear(); - delete reader; + m_reader->setFileName(emote_path); + QImage f_image = m_reader->read(); + int f_delay = m_reader->nextImageDelay(); + frame = 0; + max_frames = m_reader->imageCount(); + +#ifdef DEBUG_CHARMOVIE + qDebug() << max_frames << "Setting image to " << emote_path << "Time taken to process image:" << actual_time.elapsed(); + + actual_time.restart(); +#endif + + this->set_frame(movie_frames[frame]); this->show(); - m_movie->start(); + if (max_frames > 1) + { + movie_frames.append(this->get_pixmap(f_image)); + movie_delays.append(f_delay); + ticker->start(movie_delays[frame]); + } } void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration) { - QString emote_path = ao_app->get_character_path(p_char, p_emote); - - m_movie->stop(); - this->clear(); - m_movie->setFileName(emote_path); - m_movie->jumpToFrame(0); - - int full_duration = duration * time_mod; - int real_duration = 0; - - play_once = false; - - for (int n_frame = 0 ; n_frame < m_movie->frameCount() ; ++n_frame) - { - qDebug() << "frame " << n_frame << " delay of " << m_movie->nextFrameDelay(); - real_duration += m_movie->nextFrameDelay(); - m_movie->jumpToFrame(n_frame + 1); - } - -#ifdef DEBUG_GIF - qDebug() << "full_duration: " << full_duration; - qDebug() << "real_duration: " << real_duration; -#endif - - double percentage_modifier = 100.0; - - if (real_duration != 0 && duration > 0) - { - double modifier = full_duration / static_cast(real_duration); - percentage_modifier = 100 / modifier; - - if (percentage_modifier > 100.0) - percentage_modifier = 100.0; - } - -#ifdef DEBUG_GIF - qDebug() << "% mod: " << percentage_modifier; -#endif - - if (full_duration == 0 || full_duration >= real_duration) - { - play_once = true; - } - else - { - play_once = false; - preanim_timer->start(full_duration); - } - - - m_movie->setSpeed(static_cast(percentage_modifier)); +// QString emote_path = ao_app->get_character_path(p_char, p_emote); + play_once = true; play(p_char, p_emote, ""); } void AOCharMovie::play_talking(QString p_char, QString p_emote) { play_once = false; - m_movie->setSpeed(100); play(p_char, p_emote, "(b)"); } void AOCharMovie::play_idle(QString p_char, QString p_emote) { play_once = false; - m_movie->setSpeed(100); play(p_char, p_emote, "(a)"); } void AOCharMovie::stop() { //for all intents and purposes, stopping is the same as hiding. at no point do we want a frozen gif to display - m_movie->stop(); + ticker->stop(); preanim_timer->stop(); this->hide(); } +QPixmap AOCharMovie::get_pixmap(QImage image) +{ + QPixmap f_pixmap; + if(m_flipped) + f_pixmap = QPixmap::fromImage(image.mirrored(true, false)); + else + f_pixmap = QPixmap::fromImage(image); + auto aspect_ratio = Qt::KeepAspectRatio; + + if (f_pixmap.size().width() > f_pixmap.size().height()) + aspect_ratio = Qt::KeepAspectRatioByExpanding; + + if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) + f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation); + else + f_pixmap = f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation); + + return f_pixmap; +} + +void AOCharMovie::set_frame(QPixmap f_pixmap) +{ + this->setPixmap(f_pixmap); + QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); +} + void AOCharMovie::combo_resize(int w, int h) { QSize f_size(w, h); this->resize(f_size); - m_movie->setScaledSize(f_size); +// m_reader->setScaledSize(f_size); } void AOCharMovie::move(int ax, int ay) @@ -151,34 +138,38 @@ void AOCharMovie::move(int ax, int ay) QLabel::move(x, y); } -void AOCharMovie::frame_change(int n_frame) +void AOCharMovie::movie_ticker() { - - if (movie_frames.size() > n_frame) + ++frame; + if(frame == max_frames) { - QPixmap f_pixmap = QPixmap::fromImage(movie_frames.at(n_frame)); - auto aspect_ratio = Qt::KeepAspectRatio; - - if (f_pixmap.size().width() > f_pixmap.size().height()) - aspect_ratio = Qt::KeepAspectRatioByExpanding; - - if (f_pixmap.size().width() > this->size().width() || f_pixmap.size().height() > this->size().height()) - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::SmoothTransformation)); + if(play_once) + { + preanim_done(); + return; + } else - this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio, Qt::FastTransformation)); - - QLabel::move(x + (this->width() - this->pixmap()->width())/2, y); - } - - if (m_movie->frameCount() - 1 == n_frame && play_once) - { - preanim_timer->start(m_movie->nextFrameDelay()); - m_movie->stop(); + frame = 0; } +// qint64 difference = elapsed - movie_delays[frame]; + if(frame >= movie_frames.size()) + { + m_reader->jumpToImage(frame); + movie_frames.resize(frame + 1); + movie_frames[frame] = this->get_pixmap(m_reader->read()); + movie_delays.resize(frame + 1); + movie_delays[frame] = m_reader->nextImageDelay(); + } + +#ifdef DEBUG_CHARMOVIE + qDebug() << frame << movie_delays[frame] << "actual time taken from last frame:" << actual_time.restart(); +#endif + + this->set_frame(movie_frames[frame]); + ticker->setInterval(movie_delays[frame]); } -void AOCharMovie::timer_done() +void AOCharMovie::preanim_done() { - done(); }