void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) { Volume3DOverlay::removeFromScene(overlay, scene, transaction); _model->removeFromScene(scene, transaction); emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(getID(), NestableType::Overlay, _model); transaction.updateItem<Overlay>(getRenderItemID(), [](Overlay& data) { auto modelOverlay = static_cast<ModelOverlay*>(&data); modelOverlay->clearSubRenderItemIDs(); }); }
void Text3DOverlay::setProperties(const QVariantMap& properties) { Billboard3DOverlay::setProperties(properties); auto text = properties["text"]; if (text.isValid()) { setText(text.toString()); } auto textAlpha = properties["textAlpha"]; if (textAlpha.isValid()) { float prevTextAlpha = getTextAlpha(); setTextAlpha(textAlpha.toFloat()); // Update our payload key if necessary to handle transparency if ((prevTextAlpha < 1.0f && _textAlpha >= 1.0f) || (prevTextAlpha >= 1.0f && _textAlpha < 1.0f)) { auto itemID = getRenderItemID(); if (render::Item::isValidID(itemID)) { render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); render::Transaction transaction; transaction.updateItem(itemID); scene->enqueueTransaction(transaction); } } } bool valid; auto backgroundColor = properties["backgroundColor"]; if (backgroundColor.isValid()) { auto color = u8vec3FromVariant(backgroundColor, valid); if (valid) { _backgroundColor = color; } } if (properties["backgroundAlpha"].isValid()) { setAlpha(properties["backgroundAlpha"].toFloat()); } if (properties["lineHeight"].isValid()) { setLineHeight(properties["lineHeight"].toFloat()); } if (properties["leftMargin"].isValid()) { setLeftMargin(properties["leftMargin"].toFloat()); } if (properties["topMargin"].isValid()) { setTopMargin(properties["topMargin"].toFloat()); } if (properties["rightMargin"].isValid()) { setRightMargin(properties["rightMargin"].toFloat()); } if (properties["bottomMargin"].isValid()) { setBottomMargin(properties["bottomMargin"].toFloat()); } }
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { auto avatar = std::static_pointer_cast<OtherAvatar>(removedAvatar); AvatarHashMap::handleRemovedAvatar(avatar, removalReason); avatar->tearDownGrabs(); avatar->die(); queuePhysicsChange(avatar); // remove this avatar's entities from the tree now, if we wait (as we did previously) for this Avatar's destructor // it might not fire until after we create a new instance for the same remote avatar, which creates a race // on the creation of entities for that avatar instance and the deletion of entities for this instance avatar->removeAvatarEntitiesFromTree(); if (removalReason != KillAvatarReason::AvatarDisconnected) { if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) { emit AvatarInputs::getInstance()->avatarEnteredIgnoreRadius(avatar->getSessionUUID()); emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius(); } workload::Transaction workloadTransaction; workloadTransaction.remove(avatar->getSpaceIndex()); _space->enqueueTransaction(workloadTransaction); const render::ScenePointer& scene = qApp->getMain3DScene(); render::Transaction transaction; avatar->removeFromScene(avatar, scene, transaction); scene->enqueueTransaction(transaction); } else { // remove from node sets, if present DependencyManager::get<NodeList>()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get<UsersScriptingInterface>()->avatarDisconnected(avatar->getSessionUUID()); render::Transaction transaction; auto scene = qApp->getMain3DScene(); avatar->fadeOut(transaction, removalReason); workload::SpacePointer space = _space; transaction.transitionFinishedOperator(avatar->getRenderItemID(), [space, avatar]() { if (avatar->getLastFadeRequested() != render::Transition::Type::USER_LEAVE_DOMAIN) { // The avatar is using another transition besides the fade-out transition, which means it is still in use. // Deleting the avatar now could cause state issues, so abort deletion and show message. qCWarning(interfaceapp) << "An ending fade-out transition wants to delete an avatar, but the avatar is still in use. Avatar deletion has aborted. (avatar ID: " << avatar->getSessionUUID() << ")"; } else { const render::ScenePointer& scene = qApp->getMain3DScene(); render::Transaction transaction; avatar->removeFromScene(avatar, scene, transaction); scene->enqueueTransaction(transaction); workload::Transaction workloadTransaction; workloadTransaction.remove(avatar->getSpaceIndex()); space->enqueueTransaction(workloadTransaction); } }); scene->enqueueTransaction(transaction); } }
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { auto avatar = std::static_pointer_cast<OtherAvatar>(removedAvatar); AvatarHashMap::handleRemovedAvatar(avatar, removalReason); avatar->tearDownGrabs(); avatar->die(); queuePhysicsChange(avatar); // remove this avatar's entities from the tree now, if we wait (as we did previously) for this Avatar's destructor // it might not fire until after we create a new instance for the same remote avatar, which creates a race // on the creation of entities for that avatar instance and the deletion of entities for this instance avatar->removeAvatarEntitiesFromTree(); if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) { emit AvatarInputs::getInstance()->avatarEnteredIgnoreRadius(avatar->getSessionUUID()); emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius(); workload::Transaction workloadTransaction; workloadTransaction.remove(avatar->getSpaceIndex()); _space->enqueueTransaction(workloadTransaction); const render::ScenePointer& scene = qApp->getMain3DScene(); render::Transaction transaction; avatar->removeFromScene(avatar, scene, transaction); scene->enqueueTransaction(transaction); } else if (removalReason == KillAvatarReason::AvatarDisconnected) { // remove from node sets, if present DependencyManager::get<NodeList>()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get<UsersScriptingInterface>()->avatarDisconnected(avatar->getSessionUUID()); render::Transaction transaction; auto scene = qApp->getMain3DScene(); avatar->fadeOut(transaction, removalReason); workload::SpacePointer space = _space; transaction.transitionFinishedOperator(avatar->getRenderItemID(), [space, avatar]() { const render::ScenePointer& scene = qApp->getMain3DScene(); render::Transaction transaction; avatar->removeFromScene(avatar, scene, transaction); scene->enqueueTransaction(transaction); workload::Transaction workloadTransaction; workloadTransaction.remove(avatar->getSpaceIndex()); space->enqueueTransaction(workloadTransaction); }); scene->enqueueTransaction(transaction); } }
void ModelOverlay::update(float deltatime) { if (_updateModel) { _updateModel = false; _model->setSnapModelToCenter(true); Transform transform = evalRenderTransform(); if (_scaleToFit) { _model->setScaleToFit(true, transform.getScale() * getDimensions()); } else { _model->setScale(transform.getScale()); } _model->setRotation(transform.getRotation()); _model->setTranslation(transform.getTranslation()); _model->setURL(_url); _model->simulate(deltatime, true); } else { _model->simulate(deltatime); } _isLoaded = _model->isActive(); if (isAnimatingSomething()) { if (!jointsMapped()) { mapAnimationJoints(_model->getJointNames()); } animate(); } // check to see if when we added our model to the scene they were ready, if they were not ready, then // fix them up in the scene render::ScenePointer scene = qApp->getMain3DScene(); render::Transaction transaction; if (_model->needsFixupInScene()) { emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(getID(), NestableType::Overlay, _model); _model->removeFromScene(scene, transaction); _model->addToScene(scene, transaction); auto newRenderItemIDs{ _model->fetchRenderItemIDs() }; transaction.updateItem<Overlay>(getRenderItemID(), [newRenderItemIDs](Overlay& data) { auto modelOverlay = static_cast<ModelOverlay*>(&data); modelOverlay->setSubRenderItemIDs(newRenderItemIDs); }); processMaterials(); emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(getID(), NestableType::Overlay, _model); } if (_visibleDirty) { _visibleDirty = false; // don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0 | (_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE), false); } if (_drawInFrontDirty) { _drawInFrontDirty = false; _model->setLayeredInFront(getDrawInFront(), scene); } if (_drawInHUDDirty) { _drawInHUDDirty = false; _model->setLayeredInHUD(getDrawHUDLayer(), scene); } scene->enqueueTransaction(transaction); if (!_texturesLoaded && _model->getGeometry() && _model->getGeometry()->areTexturesLoaded()) { _texturesLoaded = true; _model->updateRenderItems(); } }
void Image3DOverlay::render(RenderArgs* args) { if (!_renderVisible || !getParentVisible() || !_texture || !_texture->isLoaded()) { return; } // Once the texture has loaded, check if we need to update the render item because of transparency if (!_textureIsLoaded && _texture && _texture->getGPUTexture()) { _textureIsLoaded = true; bool prevAlphaTexture = _alphaTexture; _alphaTexture = _texture->getGPUTexture()->getUsage().isAlpha(); if (_alphaTexture != prevAlphaTexture) { auto itemID = getRenderItemID(); if (render::Item::isValidID(itemID)) { render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); render::Transaction transaction; transaction.updateItem(itemID); scene->enqueueTransaction(transaction); } } } Q_ASSERT(args->_batch); gpu::Batch* batch = args->_batch; float imageWidth = _texture->getWidth(); float imageHeight = _texture->getHeight(); QRect fromImage; if (_fromImage.isNull()) { fromImage.setX(0); fromImage.setY(0); fromImage.setWidth(imageWidth); fromImage.setHeight(imageHeight); } else { float scaleX = imageWidth / _texture->getOriginalWidth(); float scaleY = imageHeight / _texture->getOriginalHeight(); fromImage.setX(scaleX * _fromImage.x()); fromImage.setY(scaleY * _fromImage.y()); fromImage.setWidth(scaleX * _fromImage.width()); fromImage.setHeight(scaleY * _fromImage.height()); } float maxSize = glm::max(fromImage.width(), fromImage.height()); float x = _keepAspectRatio ? fromImage.width() / (2.0f * maxSize) : 0.5f; float y = _keepAspectRatio ? -fromImage.height() / (2.0f * maxSize) : -0.5f; glm::vec2 topLeft(-x, -y); glm::vec2 bottomRight(x, y); glm::vec2 texCoordTopLeft((fromImage.x() + 0.5f) / imageWidth, (fromImage.y() + 0.5f) / imageHeight); glm::vec2 texCoordBottomRight((fromImage.x() + fromImage.width() - 0.5f) / imageWidth, (fromImage.y() + fromImage.height() - 0.5f) / imageHeight); float alpha = getAlpha(); glm::u8vec3 color = getColor(); glm::vec4 imageColor(toGlm(color), alpha); batch->setModelTransform(getRenderTransform()); batch->setResourceTexture(0, _texture->getGPUTexture()); DependencyManager::get<GeometryCache>()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, imageColor, _geometryId ); batch->setResourceTexture(0, nullptr); // restore default white color after me }
void Base3DOverlay::setProperties(const QVariantMap& properties) { Overlay::setProperties(properties); bool needRenderItemUpdate = false; auto drawInFront = properties["drawInFront"]; if (drawInFront.isValid()) { bool value = drawInFront.toBool(); setDrawInFront(value); needRenderItemUpdate = true; } auto position = properties["position"]; // if "position" property was not there, check to see if they included aliases: point, p1 if (!position.isValid()) { position = properties["p1"]; if (!position.isValid()) { position = properties["point"]; } } if (position.isValid()) { setPosition(vec3FromVariant(position)); needRenderItemUpdate = true; } if (properties["lineWidth"].isValid()) { setLineWidth(properties["lineWidth"].toFloat()); needRenderItemUpdate = true; } auto rotation = properties["rotation"]; if (rotation.isValid()) { setRotation(quatFromVariant(rotation)); needRenderItemUpdate = true; } if (properties["isSolid"].isValid()) { setIsSolid(properties["isSolid"].toBool()); } if (properties["isFilled"].isValid()) { setIsSolid(properties["isSolid"].toBool()); } if (properties["isWire"].isValid()) { setIsSolid(!properties["isWire"].toBool()); } if (properties["solid"].isValid()) { setIsSolid(properties["solid"].toBool()); } if (properties["filled"].isValid()) { setIsSolid(properties["filled"].toBool()); } if (properties["wire"].isValid()) { setIsSolid(!properties["wire"].toBool()); } if (properties["isDashedLine"].isValid()) { setIsDashedLine(properties["isDashedLine"].toBool()); } if (properties["dashed"].isValid()) { setIsDashedLine(properties["dashed"].toBool()); } if (properties["ignoreRayIntersection"].isValid()) { setIgnoreRayIntersection(properties["ignoreRayIntersection"].toBool()); } // Communicate changes to the renderItem if needed if (needRenderItemUpdate) { auto itemID = getRenderItemID(); if (render::Item::isValidID(itemID)) { render::ScenePointer scene = qApp->getMain3DScene(); render::PendingChanges pendingChanges; pendingChanges.updateItem(itemID); scene->enqueuePendingChanges(pendingChanges); } } }