aboutsummaryrefslogtreecommitdiff
path: root/src/aocharmovie.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/aocharmovie.cpp')
-rw-r--r--src/aocharmovie.cpp431
1 files changed, 247 insertions, 184 deletions
diff --git a/src/aocharmovie.cpp b/src/aocharmovie.cpp
index 4252923a..252aab5d 100644
--- a/src/aocharmovie.cpp
+++ b/src/aocharmovie.cpp
@@ -8,248 +8,276 @@ 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);
- ticker = new QTimer(this);
preanim_timer->setSingleShot(true);
- ticker->setSingleShot(true);
+
+ ticker = new QTimer(this);
+ ticker->setTimerType(Qt::PreciseTimer);
+ ticker->setSingleShot(false);
connect(ticker, SIGNAL(timeout()), this, SLOT(movie_ticker()));
- this->setUpdatesEnabled(true);
+
+ // 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)
+void AOCharMovie::load_image(QString p_char, QString p_emote,
+ QString emote_prefix)
{
- apng = false;
-
- QString original_path =
- ao_app->get_character_path(p_char, emote_prefix + p_emote + ".gif");
- QString alt_path =
- ao_app->get_character_path(p_char, emote_prefix + p_emote + ".png");
- QString apng_path =
- ao_app->get_character_path(p_char, emote_prefix + p_emote + ".apng");
- QString alt_path_still = ao_app->get_character_path(p_char, p_emote + ".png");
-
- QString placeholder_path = ao_app->get_theme_path("placeholder.gif");
- QString placeholder_default_path =
- ao_app->get_default_theme_path("placeholder.gif");
- QString gif_path;
- current_emote = emote_prefix + p_emote;
- current_char = p_char;
- if (file_exists(apng_path)) {
- gif_path = apng_path;
- apng = true;
+#ifdef DEBUG_CHARMOVIE
+ actual_time.restart();
+#endif
+ QString emote_path;
+ QList<QString> pathlist;
+ pathlist = {
+ ao_app->get_image_suffix(ao_app->get_character_path(
+ p_char, emote_prefix + p_emote)), // Default path
+ ao_app->get_image_suffix(ao_app->get_character_path(
+ p_char, emote_prefix + "/" +
+ p_emote)), // Path check if it's categorized into a folder
+ ao_app->get_character_path(
+ p_char, p_emote + ".png"), // Non-animated path if emote_prefix fails
+ ao_app->get_image_suffix(
+ ao_app->get_theme_path("placeholder")), // Theme placeholder path
+ ao_app->get_image_suffix(ao_app->get_default_theme_path(
+ "placeholder")), // Default theme placeholder path
+ };
+
+ for (QString path : pathlist) {
+ if (file_exists(path)) {
+ emote_path = path;
+ break;
+ }
}
- else if (file_exists(original_path))
- gif_path = original_path;
- else if (file_exists(alt_path))
- gif_path = alt_path;
- else if (file_exists(alt_path_still))
- gif_path = alt_path_still;
- else if (file_exists(placeholder_path))
- gif_path = placeholder_path;
- else
- gif_path = placeholder_default_path;
- last_path = gif_path;
- delete m_movie;
- m_movie = new QMovie(this);
- m_movie->stop();
+
this->clear();
- m_movie->setFileName(gif_path);
- m_movie->jumpToFrame(0);
- this->LoadImageWithStupidMethodForFlipSupport(m_movie->currentImage());
+ ticker->stop();
+ preanim_timer->stop();
+ movie_frames.clear();
+ movie_delays.clear();
+ movie_effects.clear();
+
+ if (!file_exists(emote_path))
+ return;
+
+ m_reader->setFileName(emote_path);
+ QPixmap f_pixmap = this->get_pixmap(m_reader->read());
+ int f_delay = m_reader->nextImageDelay();
+
+ frame = 0;
+ max_frames = m_reader->imageCount();
+
+ this->set_frame(f_pixmap);
this->show();
- this->play_frame_sfx();
- // if the frame count is 0 (i.e. it's a static PNG) don't try to play the next
- // frame, ya goofus
- if (m_movie->frameCount() != 0) {
- ticker->start(m_movie->nextFrameDelay());
+ if (max_frames > 1) {
+ movie_frames.append(f_pixmap);
+ movie_delays.append(f_delay);
}
-}
-void AOCharMovie::play_frame_sfx()
-{
- int current_frame = m_movie->currentFrameNumber();
- QString sfx_to_play =
- ao_app->get_frame_sfx_name(current_char, current_emote, current_frame);
- QString screenshake_to_play =
- ao_app->get_screenshake_frame(current_char, current_emote, current_frame);
- QString realization_to_play =
- ao_app->get_realization_frame(current_char, current_emote, current_frame);
- if (sfx_to_play != "" && !use_networked_framehell) {
- frame_specific_sfx_player->play(ao_app->get_sfx_suffix(sfx_to_play));
- }
- else if (use_networked_framehell) {
- this->sfx_two_network_boogaloo();
- }
- if (screenshake_to_play != "" && !use_networked_framehell) {
- mycourtroom->doScreenShake();
- }
- else if (use_networked_framehell) {
- this->screenshake_two_network_boogaloo();
- }
- if (realization_to_play != "" && !use_networked_framehell) {
- mycourtroom->doRealization();
- }
- else if (use_networked_framehell) {
- this->realization_two_network_boogaloo();
- }
-}
+ m_char = p_char;
+ m_emote = emote_prefix + p_emote;
-void AOCharMovie::realization_two_network_boogaloo()
-{
- int current_frame = m_movie->currentFrameNumber();
- QStringList realizationList = this->frame_realization_hellstring.split("^");
- for (int i = 0; i < realizationList.length(); i++) {
- QString screenshakeList = realizationList.at(i);
- QStringList extra_garbage = screenshakeList.split("|");
- if (extra_garbage.at(0) != current_emote) {
- continue;
- }
- for (int ii = 1; ii < extra_garbage.length(); ii++) {
- QString levels_of_garbage = extra_garbage.at(ii);
- QStringList that_shouldnt_be_possible = levels_of_garbage.split("=");
- if (that_shouldnt_be_possible.at(0).toInt() == current_frame &&
- that_shouldnt_be_possible.at(1) != "") {
- mycourtroom->doRealization();
- }
- }
- }
+ if (network_strings.size() > 0) // our FX overwritten by networked ones
+ this->load_network_effects();
+ else // Use default ini FX
+ this->load_effects();
+#ifdef DEBUG_CHARMOVIE
+ qDebug() << max_frames << "Setting image to " << emote_path
+ << "Time taken to process image:" << actual_time.elapsed();
+
+ actual_time.restart();
+#endif
}
-void AOCharMovie::screenshake_two_network_boogaloo()
+void AOCharMovie::load_effects()
{
- int current_frame = m_movie->currentFrameNumber();
- QStringList realizationList = this->frame_screenshake_hellstring.split("^");
- for (int i = 0; i < realizationList.length(); i++) {
- QString screenshakeList = realizationList.at(i);
- QStringList extra_garbage = screenshakeList.split("|");
- if (extra_garbage.at(0) != current_emote) {
- continue;
- }
- for (int ii = 1; ii < extra_garbage.length(); ii++) {
- QString levels_of_garbage = extra_garbage.at(ii);
- QStringList that_shouldnt_be_possible = levels_of_garbage.split("=");
- if (that_shouldnt_be_possible.at(0).toInt() == current_frame &&
- that_shouldnt_be_possible.at(1) != "") {
- mycourtroom->doScreenShake();
- }
+ movie_effects.clear();
+ movie_effects.resize(max_frames);
+ for (int e_frame = 0; e_frame < max_frames; ++e_frame) {
+ QString effect = ao_app->get_screenshake_frame(m_char, m_emote, e_frame);
+ if (effect != "") {
+ movie_effects[e_frame].append("shake");
}
- }
-}
-void AOCharMovie::sfx_two_network_boogaloo()
-{
- int current_frame = m_movie->currentFrameNumber();
- QStringList realizationList = this->frame_sfx_hellstring.split("^");
- for (int i = 0; i < realizationList.length(); i++) {
- QString screenshakeList = realizationList.at(i);
- QStringList extra_garbage = screenshakeList.split("|");
- if (extra_garbage.at(0) != current_emote) {
- continue;
+ effect = ao_app->get_flash_frame(m_char, m_emote, e_frame);
+ if (effect != "") {
+ movie_effects[e_frame].append("flash");
}
- for (int ii = 1; ii < extra_garbage.length(); ii++) {
- QString levels_of_garbage = extra_garbage.at(ii);
- QStringList that_shouldnt_be_possible = levels_of_garbage.split("=");
- if (that_shouldnt_be_possible.at(0).toInt() == current_frame &&
- that_shouldnt_be_possible.at(1) != "") {
- frame_specific_sfx_player->play(
- ao_app->get_sfx_suffix(that_shouldnt_be_possible.at(1)));
- }
+
+ effect = ao_app->get_sfx_frame(m_char, m_emote, e_frame);
+ if (effect != "") {
+ movie_effects[e_frame].append("sfx^" + effect);
}
}
}
-void AOCharMovie::movie_ticker()
+void AOCharMovie::load_network_effects()
{
- if (m_movie->currentFrameNumber() == m_movie->frameCount() - 1) {
- delete m_movie;
- m_movie = new QMovie(this);
- m_movie->stop();
- this->clear();
- m_movie->setFileName(last_path);
- m_movie->jumpToFrame(0);
- if (play_once) {
- timer_done();
- }
- }
- else {
- m_movie->jumpToNextFrame();
- }
- this->LoadImageWithStupidMethodForFlipSupport(m_movie->currentImage());
- // imagine if QT had sane stuff like "mirror on QMovie" or "resize the image
- // on QT" or "interface with the current QMovie image" or anything else
+ movie_effects.clear();
+ movie_effects.resize(max_frames);
+ // Order is important!!!
+ QStringList effects_list = {"shake", "flash", "sfx^"};
- this->play_frame_sfx();
+ // Determines which list is smaller - effects_list or network_strings - and
+ // uses it as basis for the loop. This way, incomplete network_strings would
+ // still be parsed, and excess/unaccounted for networked information is
+ // omitted.
+ int effects_size = qMin(effects_list.size(), network_strings.size());
- if (m_movie->frameCount() == 0) {
- return;
- }
- else if (!apng) {
- ticker->start(m_movie->nextFrameDelay());
+ for (int i = 0; i < effects_size; ++i) {
+ QString netstring = network_strings.at(i);
+ QStringList emote_splits = netstring.split("^");
+ foreach (QString emote, emote_splits) {
+ QStringList parsed = emote.split("|");
+ if (parsed.size() <= 0 || parsed.at(0) != m_emote)
+ continue;
+ foreach (QString frame_data, parsed) {
+ QStringList frame_split = frame_data.split("=");
+ if (frame_split.size() <=
+ 1) // We might still be hanging at the emote itself (entry 0).
+ continue;
+ int f_frame = frame_split.at(0).toInt();
+ if (f_frame >= max_frames) {
+ qDebug() << "Warning: out of bounds" << effects_list[i] << "frame"
+ << f_frame << "out of" << max_frames << "for" << m_char
+ << m_emote;
+ continue;
+ }
+ QString f_data = frame_split.at(1);
+ if (f_data != "") {
+ QString effect = effects_list[i];
+ if (effect == "sfx^") // Currently the only frame result that feeds us
+ // data, let's yank it in.
+ effect += f_data;
+ qDebug() << effect << f_data << "frame" << f_frame << "for" << m_char
+ << m_emote;
+ movie_effects[f_frame].append(effect);
+ }
+ }
+ }
}
}
-void AOCharMovie::LoadImageWithStupidMethodForFlipSupport(QImage image)
+void AOCharMovie::play()
{
- 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())
- this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio,
- Qt::SmoothTransformation));
+ play_frame_effect(frame);
+ if (max_frames <= 1) {
+ if (play_once)
+ ticker->start(60);
+ }
else
- this->setPixmap(f_pixmap.scaled(this->width(), this->height(), aspect_ratio,
- Qt::FastTransformation));
-
- QLabel::move(x + (this->width() - this->pixmap()->width()) / 2, y);
+ ticker->start(this->get_frame_delay(movie_delays[frame]));
}
void AOCharMovie::play_pre(QString p_char, QString p_emote, int duration)
{
- QString gif_path = ao_app->get_character_path(p_char, p_emote);
-
- m_movie->stop();
- m_movie->setFileName(gif_path);
- m_movie->jumpToFrame(0);
+ load_image(p_char, p_emote, "");
+ // As much as I'd like to screw around with [Time] durations modifying the
+ // animation speed, I don't think I can reliably do that, not without looping
+ // through all frames in the image at least - which causes lag. So for now it
+ // simply ends the preanimation early instead.
play_once = true;
- play(p_char, p_emote, "");
+ if (duration >
+ 0) // It's -1 if there's no definition in [Time] for it. In which case, it
+ // will let the animation run out in full. Duration 0 does the same.
+ preanim_timer->start(duration *
+ time_mod); // This timer will not fire if the animation
+ // finishes earlier than that
+ play();
}
void AOCharMovie::play_talking(QString p_char, QString p_emote)
{
play_once = false;
- play(p_char, p_emote, "(b)");
+ load_image(p_char, p_emote, "(b)");
+ play();
}
void AOCharMovie::play_idle(QString p_char, QString p_emote)
{
play_once = false;
- play(p_char, p_emote, "(a)");
+ load_image(p_char, p_emote, "(a)");
+ play();
+}
+
+void AOCharMovie::play_frame_effect(int frame)
+{
+ if (frame < max_frames) {
+ foreach (QString effect, movie_effects[frame]) {
+ if (effect == "shake") {
+ shake();
+#ifdef DEBUG_CHARMOVIE
+ qDebug() << "Attempting to play shake on frame" << frame;
+#endif
+ }
+
+ if (effect == "flash") {
+ flash();
+#ifdef DEBUG_CHARMOVIE
+ qDebug() << "Attempting to play flash on frame" << frame;
+#endif
+ }
+
+ if (effect.startsWith("sfx^")) {
+ QString sfx = effect.section("^", 1);
+ play_sfx(sfx);
+#ifdef DEBUG_CHARMOVIE
+ qDebug() << "Attempting to play sfx" << sfx << "on frame" << frame;
+#endif
+ }
+ }
+ }
}
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();
- frame_specific_sfx_player->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;
+ auto transform_mode = Qt::FastTransformation;
+ if (f_pixmap.height() > f_h) // We are downscaling, use anti-aliasing.
+ transform_mode = Qt::SmoothTransformation;
+
+ f_pixmap = f_pixmap.scaledToHeight(f_h, transform_mode);
+ this->resize(f_pixmap.size());
+
+ return f_pixmap;
+}
+
+void AOCharMovie::set_frame(QPixmap f_pixmap)
+{
+ this->setPixmap(f_pixmap);
+ QLabel::move(
+ x + (f_w - f_pixmap.width()) / 2,
+ y + (f_h - f_pixmap.height())); // Always center horizontally, always put
+ // at the bottom vertically
+}
+
void AOCharMovie::combo_resize(int w, int h)
{
QSize f_size(w, h);
+ f_w = w;
+ f_h = h;
this->resize(f_size);
- m_movie->setScaledSize(this->size());
}
+
+int AOCharMovie::get_frame_delay(int delay)
+{
+ return static_cast<int>(double(delay) * double(speed / 100));
+}
+
void AOCharMovie::move(int ax, int ay)
{
x = ax;
@@ -257,4 +285,39 @@ void AOCharMovie::move(int ax, int ay)
QLabel::move(x, y);
}
-void AOCharMovie::timer_done() { done(); }
+void AOCharMovie::movie_ticker()
+{
+ ++frame;
+ if (frame >= max_frames) {
+ if (play_once) {
+ preanim_done();
+ return;
+ }
+ else
+ 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]);
+ play_frame_effect(frame);
+ ticker->setInterval(this->get_frame_delay(movie_delays[frame]));
+}
+
+void AOCharMovie::preanim_done()
+{
+ ticker->stop();
+ preanim_timer->stop();
+ done();
+}