asynchronously load animations for bigly performant gainz
This commit is contained in:
parent
2a18c1cdec
commit
3bcf01bb21
@ -8,6 +8,8 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QBitmap>
|
#include <QBitmap>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
|
||||||
class AOApplication;
|
class AOApplication;
|
||||||
class VPath;
|
class VPath;
|
||||||
@ -140,11 +142,17 @@ protected:
|
|||||||
// Center the QLabel in the viewport based on the dimensions of f_pixmap
|
// Center the QLabel in the viewport based on the dimensions of f_pixmap
|
||||||
void center_pixmap(QPixmap f_pixmap);
|
void center_pixmap(QPixmap f_pixmap);
|
||||||
|
|
||||||
// Populates the frame and delay vectors with the next frame's data.
|
private:
|
||||||
void load_next_frame();
|
// Populates the frame and delay vectors.
|
||||||
|
void populate_vectors();
|
||||||
|
|
||||||
|
// used in populate_vectors
|
||||||
|
void load_next_frame();
|
||||||
|
bool exit_loop; //awful solution but i'm not fucking using QThread
|
||||||
|
QFuture<void> frame_loader;
|
||||||
|
QMutex mutex;
|
||||||
|
QWaitCondition frameAdded;
|
||||||
|
|
||||||
// used in load_next_frame
|
|
||||||
QFuture<void> future;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void done();
|
void done();
|
||||||
@ -243,4 +251,5 @@ public:
|
|||||||
StickerLayer(QWidget *p_parent, AOApplication *p_ao_app);
|
StickerLayer(QWidget *p_parent, AOApplication *p_ao_app);
|
||||||
void load_image(QString p_charname);
|
void load_image(QString p_charname);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AOLAYER_H
|
#endif // AOLAYER_H
|
||||||
|
@ -269,6 +269,9 @@ void CharLayer::start_playback(QString p_image)
|
|||||||
|
|
||||||
void AOLayer::start_playback(QString p_image)
|
void AOLayer::start_playback(QString p_image)
|
||||||
{
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
if (frame_loader.isRunning())
|
||||||
|
exit_loop = true; // tell the loader to stop, we have a new image to load
|
||||||
this->show();
|
this->show();
|
||||||
|
|
||||||
if (!ao_app->is_continuous_enabled()) {
|
if (!ao_app->is_continuous_enabled()) {
|
||||||
@ -276,7 +279,7 @@ void AOLayer::start_playback(QString p_image)
|
|||||||
force_continuous = true;
|
force_continuous = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((last_path == p_image) && (!force_continuous))
|
if (((last_path == p_image) && (!force_continuous)) || p_image == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
@ -296,7 +299,7 @@ void AOLayer::start_playback(QString p_image)
|
|||||||
stretch = stretch_override.startsWith("true");
|
stretch = stretch_override.startsWith("true");
|
||||||
|
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << "stretch:" << stretch << "filename:" << p_image;
|
qDebug() << "[AOLayer::start_playback] Stretch:" << stretch << "Filename:" << p_image;
|
||||||
#endif
|
#endif
|
||||||
m_reader.setFileName(p_image);
|
m_reader.setFileName(p_image);
|
||||||
if (m_reader.loopCount() == 0)
|
if (m_reader.loopCount() == 0)
|
||||||
@ -309,39 +312,22 @@ void AOLayer::start_playback(QString p_image)
|
|||||||
frame = 0;
|
frame = 0;
|
||||||
continuous = false;
|
continuous = false;
|
||||||
}
|
}
|
||||||
// CANTFIX: this causes a hitch
|
frame_loader = QtConcurrent::run(this, &AOLayer::populate_vectors);
|
||||||
// The correct way of doing this would be to use QImageReader::jumpToImage()
|
|
||||||
// and populate missing data in the movie ticker when it's needed. This is
|
|
||||||
// unfortunately completely impossible, because QImageReader::jumpToImage() is
|
|
||||||
// not implemented in any image format AO2 is equipped to use. Instead, the
|
|
||||||
// default behavior is used - that is, absolutely nothing.
|
|
||||||
// This is why continuous playback can be toggled off.
|
|
||||||
if (continuous) {
|
|
||||||
for (int i = frame; i--;) {
|
|
||||||
if (i <= -1)
|
|
||||||
break;
|
|
||||||
load_next_frame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_path = p_image;
|
last_path = p_image;
|
||||||
QPixmap f_pixmap = this->get_pixmap(m_reader.read());
|
while (movie_frames.size() <= frame)
|
||||||
int f_delay = m_reader.nextImageDelay();
|
frameAdded.wait(&mutex);
|
||||||
|
this->set_frame(movie_frames[frame]);
|
||||||
|
|
||||||
this->set_frame(f_pixmap);
|
if (max_frames <= 1) {
|
||||||
if (max_frames > 1) {
|
|
||||||
movie_frames.append(f_pixmap);
|
|
||||||
movie_delays.append(f_delay);
|
|
||||||
}
|
|
||||||
else if (max_frames <= 1) {
|
|
||||||
duration = static_duration;
|
duration = static_duration;
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << "max_frames is <= 1, using static duration";
|
qDebug() << "[AOLayer::start_playback] max_frames is <= 1, using static duration";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (duration > 0 && cull_image == true)
|
if (duration > 0 && cull_image == true)
|
||||||
shfx_timer->start(duration);
|
shfx_timer->start(duration);
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << max_frames << "Setting image to " << p_image
|
qDebug() << "[AOLayer::start_playback] Max frames:" << max_frames << "Setting image to " << p_image
|
||||||
<< "Time taken to process image:" << actual_time.elapsed();
|
<< "Time taken to process image:" << actual_time.elapsed();
|
||||||
|
|
||||||
actual_time.restart();
|
actual_time.restart();
|
||||||
@ -372,8 +358,12 @@ void AOLayer::play()
|
|||||||
else
|
else
|
||||||
this->freeze();
|
this->freeze();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
|
while (movie_delays.size() <= frame) {
|
||||||
|
frameAdded.wait(&mutex);
|
||||||
|
}
|
||||||
ticker->start(this->get_frame_delay(movie_delays[frame]));
|
ticker->start(this->get_frame_delay(movie_delays[frame]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOLayer::set_play_once(bool p_play_once) { play_once = p_play_once; }
|
void AOLayer::set_play_once(bool p_play_once) { play_once = p_play_once; }
|
||||||
@ -451,7 +441,7 @@ void CharLayer::load_network_effects()
|
|||||||
// data, let's yank it in.
|
// data, let's yank it in.
|
||||||
effect += f_data;
|
effect += f_data;
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << effect << f_data << "frame" << f_frame << "for"
|
qDebug() << "[CharLayer::load_network_effects]" << effect << f_data << "frame" << f_frame << "for"
|
||||||
<< m_emote;
|
<< m_emote;
|
||||||
#endif
|
#endif
|
||||||
movie_effects[f_frame].append(effect);
|
movie_effects[f_frame].append(effect);
|
||||||
@ -472,14 +462,14 @@ void CharLayer::play_frame_effect(int p_frame)
|
|||||||
if (effect == "shake") {
|
if (effect == "shake") {
|
||||||
shake();
|
shake();
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << "Attempting to play shake on frame" << frame;
|
qDebug() << "[CharLayer::play_frame_effect] Attempting to play shake on frame" << frame;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effect == "flash") {
|
if (effect == "flash") {
|
||||||
flash();
|
flash();
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << "Attempting to play flash on frame" << frame;
|
qDebug() << "[CharLayer::play_frame_effect] Attempting to play flash on frame" << frame;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,7 +477,7 @@ void CharLayer::play_frame_effect(int p_frame)
|
|||||||
QString sfx = effect.section("^", 1);
|
QString sfx = effect.section("^", 1);
|
||||||
play_sfx(sfx);
|
play_sfx(sfx);
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame;
|
qDebug() << "[CharLayer::play_frame_effect] Attempting to play sfx" << sfx << "on frame" << frame;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,11 +519,12 @@ void CharLayer::movie_ticker()
|
|||||||
void AOLayer::movie_ticker()
|
void AOLayer::movie_ticker()
|
||||||
{
|
{
|
||||||
++frame;
|
++frame;
|
||||||
if (frame >= movie_frames.size() && frame < max_frames) { // need to load the image
|
mutex.lock();
|
||||||
future.waitForFinished(); // Do Not want this to be running twice
|
while (frame >= movie_frames.size() && frame < max_frames) { // oops! our frame isn't ready yet
|
||||||
future = QtConcurrent::run(this, &AOLayer::load_next_frame);
|
frameAdded.wait(&mutex);
|
||||||
}
|
}
|
||||||
else if (frame >= max_frames) {
|
mutex.unlock();
|
||||||
|
if (frame >= max_frames) {
|
||||||
if (play_once) {
|
if (play_once) {
|
||||||
if (cull_image)
|
if (cull_image)
|
||||||
this->stop();
|
this->stop();
|
||||||
@ -545,21 +536,31 @@ void AOLayer::movie_ticker()
|
|||||||
else
|
else
|
||||||
frame = 0;
|
frame = 0;
|
||||||
}
|
}
|
||||||
future.waitForFinished(); // don't set the frame before we definitely have it in memory
|
|
||||||
#ifdef DEBUG_MOVIE
|
#ifdef DEBUG_MOVIE
|
||||||
qDebug() << frame << movie_delays[frame]
|
qDebug() << "[AOLayer::movie_ticker] Frame:" << frame << "Delay:" << movie_delays[frame]
|
||||||
<< "actual time taken from last frame:" << actual_time.restart();
|
<< "Actual time taken from last frame:" << actual_time.restart();
|
||||||
#endif
|
#endif
|
||||||
this->set_frame(movie_frames[frame]);
|
this->set_frame(movie_frames[frame]);
|
||||||
ticker->setInterval(this->get_frame_delay(movie_delays[frame]));
|
ticker->setInterval(this->get_frame_delay(movie_delays[frame]));
|
||||||
if (frame + 1 >= movie_frames.size() && frame + 1 < max_frames) { // load the next frame before we tick again
|
}
|
||||||
future = QtConcurrent::run(this, &AOLayer::load_next_frame);
|
|
||||||
|
void AOLayer::populate_vectors() {
|
||||||
|
while (movie_frames.size() < max_frames && !exit_loop) {
|
||||||
|
load_next_frame();
|
||||||
|
#ifdef DEBUG_MOVIE
|
||||||
|
qDebug() << "[AOLayer::populate_vectors] Loaded frame" << movie_frames.size();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
exit_loop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOLayer::load_next_frame() {
|
void AOLayer::load_next_frame() {
|
||||||
|
//QMutexLocker locker(&mutex);
|
||||||
|
mutex.lock();
|
||||||
movie_frames.append(this->get_pixmap(m_reader.read()));
|
movie_frames.append(this->get_pixmap(m_reader.read()));
|
||||||
movie_delays.append(m_reader.nextImageDelay());
|
movie_delays.append(m_reader.nextImageDelay());
|
||||||
|
mutex.unlock();
|
||||||
|
frameAdded.wakeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharLayer::preanim_done()
|
void CharLayer::preanim_done()
|
||||||
|
Loading…
Reference in New Issue
Block a user