Added async transition query on scene

This commit is contained in:
Olivier Prat 2017-07-13 11:05:04 +02:00
parent 0f60cca617
commit 2d2722bfc5
9 changed files with 122 additions and 114 deletions

View file

@ -282,10 +282,11 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
const render::ScenePointer& scene = qApp->getMain3DScene();
while (avatarItr != _avatarsToFade.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*avatarItr);
// TEMP OP avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE);
// TEMP OP avatar->animateScaleChanges(deltaTime);
// TEMP OP if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
if (!avatar->isFading(scene)) {
// avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE);
// avatar->animateScaleChanges(deltaTime);
// if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
avatar->updateFadingStatus(scene);
if (!avatar->isFading()) {
// fading to zero is such a rare event we push a unique transaction for each
if (avatar->isInScene()) {
render::Transaction transaction;

View file

@ -96,7 +96,7 @@ void Overlays::cleanupOverlaysToDelete() {
} while (!_overlaysToDelete.isEmpty());
}
if (transaction._removedItems.size() > 0) {
if (transaction.hasRemovedItems()) {
scene->enqueueTransaction(transaction);
}
}

View file

@ -498,15 +498,6 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
_mustFadeIn = true;
}
bool Avatar::isFading(render::ScenePointer scene) const {
if (isInScene()) {
const auto& item = scene->getItem(_renderItemID);
auto transitionId = item.getTransitionId();
return _isWaitingForFade || transitionId!= render::TransitionStage::INVALID_INDEX;
}
return _isWaitingForFade;
}
void Avatar::fadeIn(render::ScenePointer scene) {
render::Transaction transaction;
fade(transaction, render::Transition::USER_ENTER_DOMAIN);
@ -534,7 +525,17 @@ void Avatar::fade(render::Transaction& transaction, render::Transition::Type typ
transaction.addTransitionToItem(itemId, type, _renderItemID);
}
}
_isWaitingForFade = true;
_isFading = true;
}
void Avatar::updateFadingStatus(render::ScenePointer scene) {
render::Transaction transaction;
transaction.queryTransitionOnItem(_renderItemID, [this](render::ItemID id, const render::Transition* transition) {
if (transition == nullptr || transition->isFinished) {
_isFading = false;
}
});
scene->enqueueTransaction(transaction);
}
void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
@ -712,14 +713,6 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
_mustFadeIn = false;
}
if (isInScene()) {
const auto& item = scene->getItem(_renderItemID);
auto transitionId = item.getTransitionId();
if (_isWaitingForFade && transitionId != render::TransitionStage::INVALID_INDEX) {
_isWaitingForFade = false;
}
}
for (auto attachmentModelToRemove : _attachmentsToRemove) {
attachmentModelToRemove->removeFromScene(scene, transaction);
}

View file

@ -252,7 +252,8 @@ public:
void fadeIn(render::ScenePointer scene);
void fadeOut(render::ScenePointer scene, KillAvatarReason reason);
bool isFading(render::ScenePointer scene) const;
bool isFading() const { return _isFading; }
void updateFadingStatus(render::ScenePointer scene);
public slots:
@ -356,7 +357,7 @@ private:
bool _isLookAtTarget { false };
bool _isAnimatingScale { false };
bool _mustFadeIn{ false };
bool _isWaitingForFade{ false };
bool _isFading{ false };
static int _jointConesID;

View file

@ -548,8 +548,6 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou
auto transitionStage = scene->getStage<render::TransitionStage>(render::TransitionStage::getName());
uint64_t now = usecTimestampNow();
const double deltaTime = (int64_t(now) - int64_t(_previousTime)) / double(USECS_PER_SECOND);
render::Transaction transaction;
bool hasTransactions = false;
bool isFirstItem = true;
output = (FadeConfig::Category) jobConfig->editedCategory;
@ -557,21 +555,12 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou
// And now update fade effect
for (auto transitionId : *transitionStage) {
auto& state = transitionStage->editTransition(transitionId);
if (!update(*jobConfig, scene, state, deltaTime)) {
// Remove transition for this item
transaction.addTransitionToItem(state.itemId, render::Transition::NONE);
hasTransactions = true;
}
update(*jobConfig, scene, state, deltaTime);
if (isFirstItem) {
jobConfig->setProperty("threshold", state.threshold);
isFirstItem = false;
}
}
if (hasTransactions) {
scene->enqueueTransaction(transaction);
}
_previousTime = now;
}
@ -585,13 +574,12 @@ const FadeConfig::Category FadeJob::transitionToCategory[render::Transition::TYP
FadeConfig::AVATAR_CHANGE
};
bool FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const {
void FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const {
const auto fadeCategory = transitionToCategory[transition.eventType];
auto& eventConfig = config.events[fadeCategory];
auto& item = scene->getItem(transition.itemId);
const double eventDuration = (double)eventConfig.duration;
const FadeConfig::Timing timing = (FadeConfig::Timing) eventConfig.timing;
bool continueTransition = true;
if (item.exist()) {
auto aabb = item.getBound();
@ -619,7 +607,7 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re
transition.baseInvSize.x = 1.f / dimensions.x;
transition.baseInvSize.y = 1.f / dimensions.y;
transition.baseInvSize.z = 1.f / dimensions.z;
continueTransition = transition.threshold < 1.f;
transition.isFinished = transition.threshold >= 1.f;
if (transition.eventType == render::Transition::ELEMENT_ENTER_DOMAIN) {
transition.threshold = 1.f - transition.threshold;
}
@ -655,7 +643,7 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re
transition.threshold = computeElementEnterRatio(transition.time, eventConfig.duration, timing);
transition.baseOffset = transition.noiseOffset - dimensions.y / 2.f;
transition.baseInvSize.y = 1.f / dimensions.y;
continueTransition = transition.threshold < 1.f;
transition.isFinished = transition.threshold >= 1.f;
if (transition.eventType == render::Transition::USER_LEAVE_DOMAIN) {
transition.threshold = 1.f - transition.threshold;
}
@ -671,10 +659,9 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re
}
transition.noiseOffset += eventConfig.noiseSpeed * (float)transition.time;
transition.threshold = std::max(0.f, std::min(1.f, transition.threshold));
transition.threshold = (transition.threshold - 0.5f)*_thresholdScale[fadeCategory] + 0.5f;
transition.time += deltaTime;
return continueTransition;
}
float FadeJob::computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing) {

View file

@ -236,7 +236,7 @@ private:
float _thresholdScale[FadeConfig::CATEGORY_COUNT];
uint64_t _previousTime{ 0 };
bool update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const;
void update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const;
static float computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing);
const render::Item* findNearestItem(const render::RenderContextPointer& renderContext, const render::Varying& input, float& minIsectDistance) const;

View file

@ -19,8 +19,7 @@ using namespace render;
void Transaction::resetItem(ItemID id, const PayloadPointer& payload) {
if (payload) {
_resetItems.emplace_back(id);
_resetPayloads.emplace_back(payload);
_resetItems.emplace_back(Reset{ id, payload });
} else {
qCDebug(renderlogging) << "WARNING: Transaction::resetItem with a null payload!";
removeItem(id);
@ -32,20 +31,19 @@ void Transaction::removeItem(ItemID id) {
}
void Transaction::addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId) {
_transitioningItems.emplace_back(id);
_transitioningItemBounds.emplace_back(boundId);
_transitionTypes.emplace_back(transition);
_addedTransitions.emplace_back(TransitionAdd{ id, transition, boundId });
}
void Transaction::removeTransitionFromItem(ItemID id) {
_transitioningItems.emplace_back(id);
_transitioningItemBounds.emplace_back(render::Item::INVALID_ITEM_ID);
_transitionTypes.emplace_back(render::Transition::NONE);
_addedTransitions.emplace_back(TransitionAdd{ id, Transition::NONE, render::Item::INVALID_ITEM_ID });
}
void Transaction::queryTransitionOnItem(ItemID id, TransitionQueryFunc func) {
_queriedTransitions.emplace_back(TransitionQuery{ id, func });
}
void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) {
_updatedItems.emplace_back(id);
_updateFunctors.emplace_back(functor);
_updatedItems.emplace_back(Update{ id, functor });
}
void Transaction::resetSelection(const Selection& selection) {
@ -54,14 +52,11 @@ void Transaction::resetSelection(const Selection& selection) {
void Transaction::merge(const Transaction& transaction) {
_resetItems.insert(_resetItems.end(), transaction._resetItems.begin(), transaction._resetItems.end());
_resetPayloads.insert(_resetPayloads.end(), transaction._resetPayloads.begin(), transaction._resetPayloads.end());
_removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end());
_updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end());
_updateFunctors.insert(_updateFunctors.end(), transaction._updateFunctors.begin(), transaction._updateFunctors.end());
_resetSelections.insert(_resetSelections.end(), transaction._resetSelections.begin(), transaction._resetSelections.end());
_transitioningItems.insert(_transitioningItems.end(), transaction._transitioningItems.begin(), transaction._transitioningItems.end());
_transitioningItemBounds.insert(_transitioningItemBounds.end(), transaction._transitioningItemBounds.begin(), transaction._transitioningItemBounds.end());
_transitionTypes.insert(_transitionTypes.end(), transaction._transitionTypes.begin(), transaction._transitionTypes.end());
_addedTransitions.insert(_addedTransitions.end(), transaction._addedTransitions.begin(), transaction._addedTransitions.end());
_queriedTransitions.insert(_queriedTransitions.end(), transaction._queriedTransitions.begin(), transaction._queriedTransitions.end());
}
@ -120,19 +115,21 @@ void Scene::processTransactionQueue() {
// capture anything coming from the transaction
// resets and potential NEW items
resetItems(consolidatedTransaction._resetItems, consolidatedTransaction._resetPayloads);
resetItems(consolidatedTransaction._resetItems);
// Update the numItemsAtomic counter AFTER the reset changes went through
_numAllocatedItems.exchange(maxID);
// updates
updateItems(consolidatedTransaction._updatedItems, consolidatedTransaction._updateFunctors);
updateItems(consolidatedTransaction._updatedItems);
// removes
removeItems(consolidatedTransaction._removedItems);
// Transitions
transitionItems(consolidatedTransaction._transitioningItems, consolidatedTransaction._transitionTypes, consolidatedTransaction._transitioningItemBounds);
// add transitions
transitionItems(consolidatedTransaction._addedTransitions);
queryTransitionItems(consolidatedTransaction._queriedTransitions);
// Update the numItemsAtomic counter AFTER the pending changes went through
_numAllocatedItems.exchange(maxID);
@ -146,34 +143,31 @@ void Scene::processTransactionQueue() {
}
}
void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
auto resetPayload = payloads.begin();
for (auto resetID : ids) {
void Scene::resetItems(const Transaction::Resets& transactions) {
for (auto& reset : transactions) {
// Access the true item
auto& item = _items[resetID];
auto itemId = std::get<0>(reset);
auto& item = _items[itemId];
auto oldKey = item.getKey();
auto oldCell = item.getCell();
// Reset the item with a new payload
item.resetPayload(*resetPayload);
item.resetPayload(std::get<1>(reset));
auto newKey = item.getKey();
// Update the item's container
assert((oldKey.isSpatial() == newKey.isSpatial()) || oldKey._flags.none());
if (newKey.isSpatial()) {
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), resetID, newKey);
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), itemId, newKey);
item.resetCell(newCell, newKey.isSmall());
} else {
_masterNonspatialSet.insert(resetID);
_masterNonspatialSet.insert(itemId);
}
// next loop
resetPayload++;
}
}
void Scene::removeItems(const ItemIDs& ids) {
for (auto removedID :ids) {
void Scene::removeItems(const Transaction::Removes& transactions) {
for (auto removedID : transactions) {
// Access the true item
auto& item = _items[removedID];
auto oldCell = item.getCell();
@ -197,12 +191,10 @@ void Scene::removeItems(const ItemIDs& ids) {
}
}
void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
auto updateFunctor = functors.begin();
for (auto updateID : ids) {
void Scene::updateItems(const Transaction::Updates& transactions) {
for (auto& update : transactions) {
auto updateID = std::get<0>(update);
if (updateID == Item::INVALID_ITEM_ID) {
updateFunctor++;
continue;
}
@ -212,7 +204,7 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
auto oldKey = item.getKey();
// Update the item
item.update((*updateFunctor));
item.update(std::get<1>(update));
auto newKey = item.getKey();
// Update the item's container
@ -234,39 +226,54 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
_masterNonspatialSet.insert(updateID);
}
}
// next loop
updateFunctor++;
}
}
void Scene::transitionItems(const ItemIDs& ids, const TransitionTypes& types, const ItemIDs& boundIds) {
auto transitionType = types.begin();
auto boundId = boundIds.begin();
void Scene::transitionItems(const Transaction::TransitionAdds& transactions) {
auto transitionStage = getStage<TransitionStage>(TransitionStage::getName());
for (auto itemId : ids) {
for (auto& add : transactions) {
auto itemId = std::get<0>(add);
// Access the true item
const auto& item = _items[itemId];
if (item.exist()) {
auto transitionId = INVALID_INDEX;
auto transitionType = std::get<1>(add);
auto boundId = std::get<2>(add);
// Remove pre-existing transition, if need be
if (item.getTransitionId() != render::TransitionStage::INVALID_INDEX) {
if (TransitionStage::isIndexInvalid(item.getTransitionId())) {
transitionStage->removeTransition(item.getTransitionId());
}
// Add a new one.
if (*transitionType != Transition::NONE) {
transitionId = transitionStage->addTransition(itemId, *transitionType, *boundId);
if (transitionType != Transition::NONE) {
transitionId = transitionStage->addTransition(itemId, transitionType, boundId);
}
setItemTransition(itemId, transitionId);
}
}
}
// next loop
transitionType++;
boundId++;
void Scene::queryTransitionItems(const Transaction::TransitionQueries& transactions) {
auto transitionStage = getStage<TransitionStage>(TransitionStage::getName());
for (auto& query : transactions) {
auto itemId = std::get<0>(query);
// Access the true item
const auto& item = _items[itemId];
auto func = std::get<1>(query);
if (item.exist() && func != nullptr) {
auto transitionId = item.getTransitionId();
if (TransitionStage::isIndexInvalid(transitionId)) {
auto& transition = transitionStage->getTransition(transitionId);
func(itemId, &transition);
}
else {
func(itemId, nullptr);
}
}
}
}
@ -325,8 +332,8 @@ Selection Scene::getSelection(const Selection::Name& name) const {
}
}
void Scene::resetSelections(const Selections& selections) {
for (auto selection : selections) {
void Scene::resetSelections(const Transaction::SelectionResets& transactions) {
for (auto selection : transactions) {
auto found = _selections.find(selection.getName());
if (found == _selections.end()) {
_selections.insert(SelectionMap::value_type(selection.getName(), selection));

View file

@ -21,6 +21,7 @@
namespace render {
class Engine;
class Scene;
// Transaction is the mechanism to make any change to the scene.
// Whenever a new item need to be reset,
@ -32,16 +33,22 @@ class Engine;
// of updating the scene before it s rendered.
//
class Transaction {
friend class Scene;
public:
typedef std::function<void(ItemID, const Transition*)> TransitionQueryFunc;
Transaction() {}
~Transaction() {}
// Item transactions
void resetItem(ItemID id, const PayloadPointer& payload);
void removeItem(ItemID id);
bool hasRemovedItems() const { return !_removedItems.empty(); }
void addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId = render::Item::INVALID_ITEM_ID);
void removeTransitionFromItem(ItemID id);
void queryTransitionOnItem(ItemID id, TransitionQueryFunc func);
template <class T> void updateItem(ItemID id, std::function<void(T&)> func) {
updateItem(id, std::make_shared<UpdateFunctor<T>>(func));
@ -58,18 +65,28 @@ public:
// Checkers if there is work to do when processing the transaction
bool touchTransactions() const { return !_resetSelections.empty(); }
ItemIDs _resetItems;
Payloads _resetPayloads;
ItemIDs _removedItems;
ItemIDs _updatedItems;
ItemIDs _transitioningItems;
ItemIDs _transitioningItemBounds;
TransitionTypes _transitionTypes;
UpdateFunctors _updateFunctors;
Selections _resetSelections;
protected:
using Reset = std::tuple<ItemID, PayloadPointer>;
using Remove = ItemID;
using Update = std::tuple<ItemID, UpdateFunctorPointer>;
using TransitionAdd = std::tuple<ItemID, Transition::Type, ItemID>;
using TransitionQuery = std::tuple<ItemID, TransitionQueryFunc>;
using SelectionReset = Selection;
using Resets = std::vector<Reset>;
using Removes = std::vector<Remove>;
using Updates = std::vector<Update>;
using TransitionAdds = std::vector<TransitionAdd>;
using TransitionQueries = std::vector<TransitionQuery>;
using SelectionResets = std::vector<SelectionReset>;
Resets _resetItems;
Removes _removedItems;
Updates _updatedItems;
TransitionAdds _addedTransitions;
TransitionQueries _queriedTransitions;
SelectionResets _resetSelections;
};
typedef std::queue<Transaction> TransactionQueue;
@ -134,6 +151,7 @@ public:
void resetItemTransition(ItemID id);
protected:
// Thread safe elements that can be accessed from anywhere
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
std::atomic<unsigned int> _numAllocatedItems{ 1 }; // num of allocated items, matching the _items.size()
@ -147,10 +165,11 @@ protected:
ItemSpatialTree _masterSpatialTree;
ItemIDSet _masterNonspatialSet;
void resetItems(const ItemIDs& ids, Payloads& payloads);
void removeItems(const ItemIDs& ids);
void updateItems(const ItemIDs& ids, UpdateFunctors& functors);
void transitionItems(const ItemIDs& ids, const TransitionTypes& types, const ItemIDs& boundIds);
void resetItems(const Transaction::Resets& transactions);
void removeItems(const Transaction::Removes& transactions);
void updateItems(const Transaction::Updates& transactions);
void transitionItems(const Transaction::TransitionAdds& transactions);
void queryTransitionItems(const Transaction::TransitionQueries& transactions);
void collectSubItems(ItemID parentId, ItemIDs& subItems) const;
@ -158,7 +177,7 @@ protected:
mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method
SelectionMap _selections;
void resetSelections(const Selections& selections);
void resetSelections(const Transaction::SelectionResets& transactions);
// More actions coming to selections soon:
// void removeFromSelection(const Selection& selection);
// void appendToSelection(const Selection& selection);

View file

@ -41,7 +41,7 @@ namespace render {
glm::vec3 baseOffset{ 0.f, 0.f, 0.f };
glm::vec3 baseInvSize{ 1.f, 1.f, 1.f };
float threshold{ 0.f };
bool isFinished{ false };
};
typedef std::shared_ptr<Transition> TransitionPointer;