summaryrefslogtreecommitdiffstats
path: root/src/runtime/q3dsslideplayer.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2018-05-18 10:33:28 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2018-05-18 10:33:34 +0200
commit8bb3378d0d7c82eb1896ac043570ddab7c2edae9 (patch)
treef3fe8bce8b4df108c1cc9766fdbafea95c3bd490 /src/runtime/q3dsslideplayer.cpp
parent78ab305d5ca59a158232a8b47070ef35ae803033 (diff)
parent186e8bf9ec08b1aca289a23b93290bf4cd5521fe (diff)
Merge remote-tracking branch 'origin/2.0'
Diffstat (limited to 'src/runtime/q3dsslideplayer.cpp')
-rw-r--r--src/runtime/q3dsslideplayer.cpp283
1 files changed, 187 insertions, 96 deletions
diff --git a/src/runtime/q3dsslideplayer.cpp b/src/runtime/q3dsslideplayer.cpp
index fee148c..f7c2ee2 100644
--- a/src/runtime/q3dsslideplayer.cpp
+++ b/src/runtime/q3dsslideplayer.cpp
@@ -44,45 +44,63 @@
QT_BEGIN_NAMESPACE
-// NOTE: We assume that the properties for the layer has been applied before this is called
-// if it hasn't it will either return the previous value or the odl value
void Q3DSSlideUtils::getStartAndEndTime(Q3DSSlide *slide, qint32 *startTime, qint32 *endTime)
{
Q_ASSERT(startTime != nullptr || endTime != nullptr);
- qint32 eTime = -1;
+ qint32 layerEndTime = -1;
+ qint32 nodesEndtime = -1;
- // First go through the slide's parent (master slide) and look for layers which have
- // endtime explicitly set by this slide's property changes
+ // Check if there are nodes from the parent slide that has property changes on this slide.
if (Q3DSSlide *p = static_cast<Q3DSSlide *>(slide->parent())) {
for (auto *obj : p->objects()) {
- if (obj->type() != Q3DSGraphObject::Layer)
+ if (!obj->isNode())
continue;
- const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> props =
- slide->propertyChanges();
- const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *>::const_iterator it =
- props.find(obj);
- if (it == props.constEnd())
+ // Look for property updates on "this" slide.
+ const auto &props = slide->propertyChanges();
+ const auto foundIt = props.constFind(obj);
+ if (foundIt == props.constEnd())
continue;
- if ((*it)->keys().contains(QStringLiteral("endtime")) && obj->endTime() > eTime)
- eTime = obj->endTime();
+
+ // If there are property changes for the object, check if it has a new endtime.
+ std::find_if(foundIt.value()->cbegin(), foundIt.value()->cend(), [&layerEndTime, &nodesEndtime, obj](const Q3DSPropertyChange &propChange) {
+ if (propChange.name() == QLatin1String("endtime")) {
+ bool ok = false;
+ const qint32 value = propChange.value().toInt(&ok);
+ if (ok) {
+ if (obj->type() == Q3DSGraphObject::Layer && (value > layerEndTime))
+ layerEndTime = value;
+ else if (value > nodesEndtime)
+ nodesEndtime = value;
+ }
+ }
+ return false;
+ });
}
}
- // Now look for the endtime from the slides explicit layer objects
+ // Now look for the endtime on nodes on this slide.
for (const auto obj : slide->objects()) {
- if (obj->type() != Q3DSGraphObject::Layer)
+ // Skip non-node types.
+ if (!obj->isNode())
continue;
- if (obj->endTime() > eTime)
- eTime = obj->endTime();
+ // We collect both layer endtimes (if any) and object endtimes in one go.
+ if (obj->type() == Q3DSGraphObject::Layer && (obj->endTime() > layerEndTime))
+ layerEndTime = obj->endTime();
+ else if (obj->endTime() > nodesEndtime)
+ nodesEndtime = obj->endTime();
}
+ // Final fallback, if neither was found use the value set by the slide.
+ if (layerEndTime == -1 && nodesEndtime == -1)
+ nodesEndtime = slide->endTime();
+
if (startTime)
*startTime = slide->startTime();
if (endTime)
- *endTime = eTime != -1 ? eTime : slide->endTime();
+ *endTime = layerEndTime != -1 ? layerEndTime : nodesEndtime;
}
static QString getSlideName(Q3DSSlide *slide)
@@ -97,40 +115,28 @@ static Q3DSSlidePlayer::PlayerState getInitialSlideState(Q3DSSlide *slide)
}
-static void updatePosition(Q3DSSlide *slide, float pos, float duration)
+static void updatePosition(Q3DSSlide *slide, float newTimeMs, float durationMs)
{
- const auto updateAnimator = [pos](Qt3DAnimation::QClipAnimator *animator, float duration) {
+ const auto updateAnimator = [newTimeMs](Qt3DAnimation::QClipAnimator *animator, float durationMs) {
if (!animator)
return;
- const float nt = qBound(0.0f, pos / duration, 1.0f);
+ const float nt = qBound(0.0f, newTimeMs / durationMs, 1.0f);
// NOTE!!!: This is a bit funky, but it means we can avoid tracking the normalized values in the
// frontend node. This of course assumes that the limit in the fuzzy compare doesn't change!
animator->setNormalizedTime(qFuzzyCompare(nt, animator->normalizedTime()) ? qAbs(nt - (1.0f / 100000.0f)) : nt);
};
const auto updateAnimators = [&updateAnimator](const QVector<Qt3DAnimation::QClipAnimator *> &animators) {
for (auto animator : animators) {
- const float duration = animator->clip()->duration() * 1000.0f;
- updateAnimator(animator, duration);
- }
- };
-
- const auto updateAllComponentPlayers = [pos](Q3DSSlide *slide) {
- for (auto obj : slide->objects()) {
- if (obj->type() == Q3DSGraphObject::Component) {
- Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj);
- const float slidePos = pos - obj->startTime();
- Q3DSSlidePlayer *player = comp->masterSlide()->attached<Q3DSSlideAttached>()->slidePlayer;
- player->seek(slidePos);
- }
+ const float durationMs = animator->clip()->duration() * 1000.0f;
+ updateAnimator(animator, durationMs);
}
};
Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>();
Q_ASSERT(data);
- updateAllComponentPlayers(slide);
- updateAnimator(data->animator, duration);
+ updateAnimator(data->animator, durationMs);
updateAnimators(data->animators);
};
@@ -144,12 +150,11 @@ static void updateAnimators(Q3DSSlide *slide, bool running, bool restart, float
// NOTE!!!: This is a bit funky, but it means we can avoid tracking the normalized values in the
// frontend node. This of course assumes that the limit in the fuzzy compare doesn't change!
animator->setNormalizedTime(qFuzzyCompare(animator->normalizedTime(), 0.0f) ? (0.0f + (1.0f / 100000.0f)) : 0.0f);
- // NOTE: The running value might not have been updated in the frontend node yet,
- // so force update this one as well!
- if (animator->isRunning())
- animator->setRunning(false);
}
animator->clock()->setPlaybackRate(double(rate));
+ // NOTE: The running value might not have been updated in the frontend node yet,
+ // so force update if the values are the same...
+ animator->setRunning(!running);
animator->setRunning(running);
};
const auto updateAnimators = [&updateAnimator](const QVector<Qt3DAnimation::QClipAnimator *> &animators) {
@@ -157,24 +162,9 @@ static void updateAnimators(Q3DSSlide *slide, bool running, bool restart, float
updateAnimator(animator);
};
- const auto updateAllComponentPlayers = [running](Q3DSSlide *slide) {
- for (auto obj : slide->objects()) {
- if (obj->type() == Q3DSGraphObject::Component) {
- Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj);
- Q3DSSlide *compSlide = comp->currentSlide();
- Q3DSSlidePlayer *player = comp->masterSlide()->attached<Q3DSSlideAttached>()->slidePlayer;
- if (running && compSlide->initialPlayState() == Q3DSSlide::Play)
- player->play();
- else
- player->stop();
- }
- }
- };
-
Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>();
Q_ASSERT(data);
- updateAllComponentPlayers(slide);
updateAnimator(data->animator);
updateAnimators(data->animators);
}
@@ -192,20 +182,9 @@ static void updatePlaybackRate(Q3DSSlide *slide, float rate)
updateAnimator(animator);
};
- const auto updateAllComponentPlayers = [rate](Q3DSSlide *slide) {
- for (auto obj : slide->objects()) {
- if (obj->type() == Q3DSGraphObject::Component) {
- Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj);
- Q3DSSlidePlayer *player = comp->masterSlide()->attached<Q3DSSlideAttached>()->slidePlayer;
- player->setPlaybackRate(rate);
- }
- }
- };
-
Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>();
Q_ASSERT(data);
- updateAllComponentPlayers(slide);
updateAnimator(data->animator);
updateAnimators(data->animators);
}
@@ -214,7 +193,7 @@ Q3DSSlidePlayer::Q3DSSlidePlayer(Q3DSSceneManager *sceneManager,
QObject *parent)
: QObject(parent)
, m_sceneManager(sceneManager)
- , m_animationManager(new Q3DSAnimationManager(this))
+ , m_animationManager(new Q3DSAnimationManager)
{
}
@@ -236,6 +215,43 @@ void Q3DSSlidePlayer::advanceFrame()
m_animationManager->applyChanges();
}
+void Q3DSSlidePlayer::sceneReady()
+{
+ Q3DSSlideDeck *slideDeck = m_data.slideDeck;
+ if (!slideDeck)
+ return;
+
+ Q3DSSlide *currentSlide = slideDeck->currentSlide();
+ Q_ASSERT(currentSlide);
+
+ const bool viewerMode = (m_mode == PlayerMode::Viewer);
+ if (viewerMode && (currentSlide->initialPlayState() == Q3DSSlide::Play))
+ play();
+ else
+ pause();
+
+ // In viewer-mode we need to go through all components players as well
+ if (viewerMode) {
+ static const auto notifyComponentPlayers = [](Q3DSSlide *slide) {
+ if (!slide)
+ return;
+
+ const auto &objects = slide->objects();
+ std::find_if(objects.constBegin(), objects.constEnd(), [](Q3DSGraphObject *obj) {
+ if (obj->type() == Q3DSGraphObject::Component) {
+ Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj);
+ Q3DSSlide *compSlide = comp->currentSlide();
+ Q3DSSlidePlayer *player = compSlide->attached<Q3DSSlideAttached>()->slidePlayer;
+ player->sceneReady();
+ }
+ return false;
+ });
+ };
+ notifyComponentPlayers(static_cast<Q3DSSlide *>(currentSlide->parent()));
+ notifyComponentPlayers(currentSlide);
+ }
+}
+
float Q3DSSlidePlayer::duration() const
{
if (m_data.state == PlayerState::Idle)
@@ -304,9 +320,14 @@ void Q3DSSlidePlayer::stop()
void Q3DSSlidePlayer::pause()
{
- if (m_data.state != PlayerState::Playing)
+ if (m_data.state == PlayerState::Paused)
return;
+ if (m_data.state == PlayerState::Idle) {
+ qCWarning(lcSlidePlayer) << "Pause called in Idle state (no content)";
+ return;
+ }
+
setInternalState(PlayerState::Paused);
}
@@ -378,8 +399,6 @@ void Q3DSSlidePlayer::setSlideDeck(Q3DSSlideDeck *slideDeck)
// Create a slide deck for this component
compMasterData->slidePlayer->setSlideDeck(new Q3DSSlideDeck(compMasterSlide, slide));
}
-
- Q_ASSERT(compMasterData->slidePlayer->state() == PlayerState::Ready);
};
const auto forAllComponentsOnSlide = [this, prepareComponentsOnSlide](Q3DSSlide *slide) {
@@ -546,10 +565,28 @@ void Q3DSSlidePlayer::handleCurrentSlideChanged(Q3DSSlide *slide,
qCDebug(lcSlidePlayer, "Handling current slide change: from slide \"%s\", to slide \"%s\"",
qPrintable(getSlideName(previousSlide)), qPrintable(getSlideName(slide)));
+ static const auto cleanUpComponentPlayers = [](Q3DSSlide *slide) {
+ if (!slide)
+ return;
+
+ const auto &objects = slide->objects();
+ std::find_if(objects.constBegin(), objects.constEnd(), [](Q3DSGraphObject *obj) {
+ if (obj->type() == Q3DSGraphObject::Component) {
+ Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj);
+ Q3DSSlide *compSlide = comp->currentSlide();
+ Q3DSSlideAttached *data = compSlide->attached<Q3DSSlideAttached>();
+ data->slidePlayer->handleCurrentSlideChanged(nullptr, compSlide);
+ }
+ return false;
+ });
+ };
if (previousSlide && slideDidChange) {
- if (parentChanged)
+ if (parentChanged) {
+ cleanUpComponentPlayers(static_cast<Q3DSSlide *>(previousSlide->parent()));
setSlideTime(static_cast<Q3DSSlide *>(previousSlide->parent()), -1.0f);
+ }
setSlideTime(previousSlide, -1.0f);
+ cleanUpComponentPlayers(previousSlide);
Q3DSSlideAttached *data = previousSlide->attached<Q3DSSlideAttached>();
if (data && data->animator) {
// TODO: We probably want to be a bit less brute.
@@ -560,9 +597,8 @@ void Q3DSSlidePlayer::handleCurrentSlideChanged(Q3DSSlide *slide,
}
if (slide && slideDidChange && isSlideVisible(slide)) {
- m_sceneManager->handleSlideChange(previousSlide, slide);
+ processPropertyChanges(slide, previousSlide);
m_animationManager->updateAnimations(slide, (m_mode == PlayerMode::Editor));
-
if (parentChanged)
setSlideTime(static_cast<Q3DSSlide *>(slide->parent()), 0.0f);
setSlideTime(slide, 0.0f);
@@ -603,6 +639,26 @@ void Q3DSSlidePlayer::handleCurrentSlideChanged(Q3DSSlide *slide,
qint32 endTime = 0;
Q3DSSlideUtils::getStartAndEndTime(slide, &startTime, &endTime);
onDurationChanged(endTime - startTime);
+
+ static const auto updateComponentSlides = [](Q3DSSlide *slide) {
+ if (!slide)
+ return;
+ const auto &objects = slide->objects();
+ std::find_if(objects.constBegin(), objects.constEnd(), [](Q3DSGraphObject *obj) {
+ if (obj->type() == Q3DSGraphObject::Component) {
+ Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj);
+ Q3DSSlide *compSlide = comp->currentSlide();
+ Q3DSSlideAttached *data = compSlide->attached<Q3DSSlideAttached>();
+ data->slidePlayer->handleCurrentSlideChanged(compSlide, nullptr);
+ if (data->slidePlayer->m_mode == PlayerMode::Viewer)
+ data->slidePlayer->setInternalState(getInitialSlideState(compSlide));
+ }
+ return false;
+ });
+ };
+ if (parentChanged)
+ updateComponentSlides(static_cast<Q3DSSlide *>(slide->parent()));
+ updateComponentSlides(slide);
}
if (previousSlide != slide)
@@ -646,27 +702,6 @@ void Q3DSSlidePlayer::setSlideTime(Q3DSSlide *slide, float time, bool parentVisi
&& node->flags().testFlag(Q3DSNode::Active)
&& static_cast<Q3DSNodeAttached *>(node->attached())->globalVisibility;
- if (obj->type() == Q3DSGraphObject::Component) {
- Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj);
- Q3DSSlide *compMasterSlide = comp->masterSlide();
- Q_ASSERT(compMasterSlide);
- Q3DSSlidePlayer *compPlayer = compMasterSlide->attached<Q3DSSlideAttached>()->slidePlayer;
- Q_ASSERT(compPlayer);
-
- const float slideTime = time - obj->startTime();
- compPlayer->setSlideTime(compMasterSlide, slideTime, shouldBeVisible);
-
- if (!shouldBeVisible) {
- Q3DSGraphObject *n = compMasterSlide->firstChild();
- while (n) {
- compPlayer->setSlideTime(static_cast<Q3DSSlide *>(n), slideTime, shouldBeVisible);
- n = n->nextSibling();
- }
- } else {
- compPlayer->setSlideTime(comp->currentSlide(), slideTime);
- }
- }
-
if (forceUpdate || shouldBeVisible != nodeHasVisibilityTag(node))
updateNodeVisibility(node, shouldBeVisible);
}
@@ -686,7 +721,7 @@ void Q3DSSlidePlayer::sendPositionChanged(Q3DSSlide *slide, float pos)
if (!qFuzzyCompare(oldPosition, pos))
Q_EMIT positionChanged(pos);
- const bool onEOS = (m_data.state == PlayerState::Playing)
+ const bool onEOS = (m_data.state == PlayerState::Playing && m_data.pendingState == PlayerState::Playing)
&& ((m_data.position == 0.0f && m_data.playbackRate < 0.0f)
|| (m_data.position == duration() && m_data.playbackRate > 0.0f));
@@ -713,7 +748,9 @@ bool Q3DSSlidePlayer::isSlideVisible(Q3DSSlide *slide)
if (slide) {
Q3DSSlidePlayer *player = slide->attached<Q3DSSlideAttached>()->slidePlayer;
Q3DSSlideDeck *slideDeck = player->slideDeck();
- if (slideDeck->currentSlide() == slide) {
+ const bool isMasterSlide = (slideDeck->masterSlide() == slide);
+ const bool isCurrentSlide = (slideDeck->currentSlide() == slide);
+ if (isCurrentSlide || isMasterSlide) {
Q3DSSlide *parentSlide = slideDeck->parentSlide();
if (parentSlide) {
// We're a component and current, continue up the ladder...
@@ -731,6 +768,60 @@ bool Q3DSSlidePlayer::isSlideVisible(Q3DSSlide *slide)
return visible;
}
+void Q3DSSlidePlayer::processPropertyChanges(Q3DSSlide *currentSlide,
+ Q3DSSlide *previousSlide)
+{
+ Q_ASSERT(currentSlide->attached());
+
+ if (previousSlide) {
+ auto slideData = static_cast<Q3DSSlideAttached *>(previousSlide->attached());
+ for (Q3DSNode *node : qAsConst(slideData->needsMasterRollback)) {
+ const Q3DSPropertyChangeList *changeList = node->masterRollbackList();
+ if (changeList) {
+ qCDebug(lcScene, "Rolling back %d changes to master for %s", changeList->count(), node->id().constData());
+ node->applyPropertyChanges(*changeList);
+ node->notifyPropertyChanges(*changeList);
+ m_sceneManager->updateSubTreeRecursive(node);
+ }
+ }
+ slideData->needsMasterRollback.clear();
+ }
+
+ // Find properties on targets that has dynamic properties.
+ // TODO: Find a better solution (e.g., there can be duplicate updates for e.g., xyz here).
+ QHash<Q3DSGraphObject *, Q3DSPropertyChangeList> dynamicPropertyChanges;
+ const auto &tracks = currentSlide->animations();
+ std::find_if(tracks.cbegin(), tracks.cend(), [&dynamicPropertyChanges](const Q3DSAnimationTrack &track) {
+ if (track.isDynamic()) {
+ auto foundIt = dynamicPropertyChanges.constFind(track.target());
+ Q3DSPropertyChangeList changeList;
+ if (foundIt != dynamicPropertyChanges.constEnd())
+ changeList = *foundIt;
+ const QString property = track.property().split('.')[0];
+ const auto value = track.target()->propertyValue(property);
+ changeList.append(Q3DSPropertyChange::fromVariant(property, value));
+ dynamicPropertyChanges[track.target()] = changeList;
+ }
+ return false;
+ });
+
+ // Filter out properties that we needs to be marked dirty, i.e., eyeball changes.
+ const auto &propertyChanges = currentSlide->propertyChanges();
+ for (auto it = propertyChanges.cbegin(); it != propertyChanges.cend(); ++it) {
+ std::find_if((*it)->cbegin(), (*it)->cend(), [it](const Q3DSPropertyChange &propChange) {
+ if (propChange.name() == QLatin1String("eyeball"))
+ it.key()->notifyPropertyChanges(*it.value());
+
+ it.key()->applyPropertyChanges(*it.value());
+ return false;
+ });
+ }
+
+ // Now update the propeties from dynamic property values
+ for (auto it = dynamicPropertyChanges.cbegin(), ite = dynamicPropertyChanges.cend(); it != ite; ++it)
+ it.key()->applyPropertyChanges(it.value());
+}
+
void Q3DSSlidePlayer::onDurationChanged(float duration)
{
if (qFuzzyCompare(duration, m_data.duration))