diff --git a/.gitignore b/.gitignore index 665238e7da..76ae194c82 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,7 @@ android/.gradle android/app/src/main/jniLibs # VSCode -# List taken from Github Global Ignores master@435c4d92 +# List taken from Github Global Ignores master@435c4d92 # https://github.com/github/gitignore/commits/master/Global/VisualStudioCode.gitignore .vscode/* !.vscode/settings.json @@ -66,7 +66,7 @@ gvr-interface/libs/* # ignore files for various dev environments TAGS *.sw[po] -*.qmlc +*.jsc # ignore QML compilation output *.qmlc diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 47a81ba1fe..fb4b65726a 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -214,7 +214,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) uint64_t getTimestamp() const override { return _lastEncodeTime; } - const AvatarSharedPointer& getAvatar() const { return _avatar; } + AvatarSharedPointer getAvatar() const { return _avatar; } private: AvatarSharedPointer _avatar; @@ -326,7 +326,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) int remainingAvatars = (int)sortedAvatars.size(); while (!sortedAvatars.empty()) { - const auto& avatarData = sortedAvatars.top().getAvatar(); + const auto avatarData = sortedAvatars.top().getAvatar(); sortedAvatars.pop(); remainingAvatars--; diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index a380632425..4de09c1bf3 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -33,6 +33,7 @@ Rectangle { property string itemName; property string itemId; property string itemHref; + property string itemAuthor; property double balanceAfterPurchase; property bool alreadyOwned: false; property int itemPrice: -1; @@ -81,12 +82,12 @@ Rectangle { if (result.status !== 'success') { failureErrorText.text = result.message; root.activeView = "checkoutFailure"; - UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemPrice, !root.alreadyOwned, result.message); + UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); } else { root.itemHref = result.data.download_url; root.isWearable = result.data.categories.indexOf("Wearables") > -1; root.activeView = "checkoutSuccess"; - UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemPrice, !root.alreadyOwned); + UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned); } } @@ -880,6 +881,7 @@ Rectangle { root.itemPrice = message.params.itemPrice; itemHref = message.params.itemHref; referrer = message.params.referrer; + itemAuthor = message.params.itemAuthor; setBuyText(); break; default: diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index b261743434..2ad2b75553 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -66,7 +66,7 @@ Item { source: "image://security/securityImage"; cache: false; onVisibleChanged: { - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } } Item { @@ -194,7 +194,7 @@ Item { securityImageSubmitButton.text = "Submitting..."; securityImageSubmitButton.enabled = false; var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) - commerce.chooseSecurityImage(securityImagePath); + Commerce.chooseSecurityImage(securityImagePath); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 5a5eeeb91f..42ee44d584 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -197,14 +197,36 @@ Item { anchors.topMargin: 26; anchors.left: parent.left; anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 30; + width: paintedWidth; height: 30; // Text size size: 22; // Style color: hifi.colors.baseGrayHighlight; } + + RalewaySemiBold { + id: myPurchasesLink; + text: 'My Purchases'; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 26; + anchors.right: parent.right; + anchors.rightMargin: 20; + width: paintedWidth; + height: 30; + y: 4; + // Text size + size: 18; + // Style + color: hifi.colors.baseGrayHighlight; + horizontalAlignment: Text.AlignRight; + + onLinkActivated: { + sendSignalToWallet({method: 'goToPurchases_fromWalletHome'}); + } + } + ListModel { id: tempTransactionHistoryModel; } diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc deleted file mode 100644 index ab20e996b9..0000000000 Binary files a/interface/resources/qml/js/Utils.jsc and /dev/null differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6bb8f886bc..1539b54a1e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -191,6 +191,7 @@ #include #include #include +#include #include #include @@ -698,6 +699,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(nullptr, qApp->getOcteeSceneStats()); DependencyManager::set(); DependencyManager::set(); @@ -4285,7 +4287,7 @@ void Application::init() { getEntities()->init(); getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) { - auto dims = item.getDimensions(); + auto dims = item.getScaledDimensions(); auto maxSize = glm::compMax(dims); if (maxSize <= 0.0f) { @@ -4639,7 +4641,7 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { _lastAcceptedKeyPress = usecTimestampNow(); setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(), - entity->getDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); + entity->getScaledDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); } } } @@ -5947,6 +5949,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get())); diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index aad7768b99..e5e94da68a 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -407,7 +407,7 @@ void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &s ShapeInfo::PointList points; pointCollection.push_back(points); - GeometryCache::computeSimpleHullPointListForShape((int)shapeEntity->getShape(), shapeEntity->getDimensions(), pointCollection.back()); + GeometryCache::computeSimpleHullPointListForShape((int)shapeEntity->getShape(), shapeEntity->getScaledDimensions(), pointCollection.back()); shapeInfo.setPointCollection(pointCollection); } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 8a294182bd..93caef555f 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -150,7 +150,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); } float getRadius() const override { return std::static_pointer_cast(_avatar)->getBoundingRadius(); } uint64_t getTimestamp() const override { return std::static_pointer_cast(_avatar)->getLastRenderUpdateTime(); } - const AvatarSharedPointer& getAvatar() const { return _avatar; } + AvatarSharedPointer getAvatar() const { return _avatar; } private: AvatarSharedPointer _avatar; }; @@ -185,7 +185,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { render::Transaction transaction; while (!sortedAvatars.empty()) { const SortableAvatar& sortData = sortedAvatars.top(); - const auto& avatar = std::static_pointer_cast(sortData.getAvatar()); + const auto avatar = std::static_pointer_cast(sortData.getAvatar()); bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID()); if (ignoring) { @@ -239,7 +239,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { sortedAvatars.pop(); while (inView && !sortedAvatars.empty()) { const SortableAvatar& newSortData = sortedAvatars.top(); - const auto& newAvatar = std::static_pointer_cast(newSortData.getAvatar()); + const auto newAvatar = std::static_pointer_cast(newSortData.getAvatar()); inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD; if (inView && newAvatar->hasNewJointData()) { numAVatarsNotUpdated++; diff --git a/interface/src/scripting/GooglePolyScriptingInterface.cpp b/interface/src/scripting/GooglePolyScriptingInterface.cpp new file mode 100644 index 0000000000..8ed5d59d07 --- /dev/null +++ b/interface/src/scripting/GooglePolyScriptingInterface.cpp @@ -0,0 +1,181 @@ +// +// GooglePolyScriptingInterface.cpp +// interface/src/scripting +// +// Created by Elisa Lupin-Jimenez on 12/3/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GooglePolyScriptingInterface.h" +#include "ScriptEngineLogging.h" + +const QString LIST_POLY_URL = "https://poly.googleapis.com/v1/assets?"; +const QString GET_POLY_URL = "https://poly.googleapis.com/v1/assets/model?"; + +const QStringList VALID_FORMATS = QStringList() << "BLOCKS" << "FBX" << "GLTF" << "GLTF2" << "OBJ" << "TILT" << ""; +const QStringList VALID_CATEGORIES = QStringList() << "animals" << "architecture" << "art" << "food" << + "nature" << "objects" << "people" << "scenes" << "technology" << "transport" << ""; + +GooglePolyScriptingInterface::GooglePolyScriptingInterface() { + // nothing to be implemented +} + +void GooglePolyScriptingInterface::setAPIKey(const QString& key) { + _authCode = key; +} + +QString GooglePolyScriptingInterface::getAssetList(const QString& keyword, const QString& category, const QString& format) { + QUrl url = formatURLQuery(keyword, category, format); + if (!url.isEmpty()) { + QByteArray json = parseJSON(url, 0).toJsonDocument().toJson(); + return (QString) json; + } else { + qCDebug(scriptengine) << "Invalid filters were specified."; + return ""; + } +} + +QString GooglePolyScriptingInterface::getFBX(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "FBX"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getOBJ(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "OBJ"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getBlocks(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "BLOCKS"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getGLTF(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "GLTF"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getGLTF2(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "GLTF2"); + return getModelURL(url); +} + +// This method will not be useful until we support Tilt models +QString GooglePolyScriptingInterface::getTilt(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "TILT"); + return getModelURL(url); +} + +// Can provide asset name or full URL to model +QString GooglePolyScriptingInterface::getModelInfo(const QString& input) { + QString name(input); + if (input.contains("poly.googleapis") || input.contains("poly.google.com")) { + QStringList list = input.split("/"); + if (input.contains("poly.googleapis")) { + name = list[4]; + } else { + name = list.last(); + } + } + QString urlString(GET_POLY_URL); + urlString = urlString.replace("model", name) + "key=" + _authCode; + qCDebug(scriptengine) << "Google URL request: " << urlString; + QUrl url(urlString); + QString json = parseJSON(url, 2).toString(); + return json; +} + +int GooglePolyScriptingInterface::getRandIntInRange(int length) { + QTime time = QTime::currentTime(); + qsrand((uint)time.msec()); + return qrand() % length; +} + +QUrl GooglePolyScriptingInterface::formatURLQuery(const QString& keyword, const QString& category, const QString& format) { + QString queries; + if (!VALID_FORMATS.contains(format, Qt::CaseInsensitive) || !VALID_CATEGORIES.contains(category, Qt::CaseInsensitive)) { + return QUrl(""); + } else { + if (!keyword.isEmpty()) { + QString keywords(keyword); + keywords.replace(" ", "+"); + queries.append("&keywords=" + keywords); + } + if (!category.isEmpty()) { + queries.append("&category=" + category); + } + if (!format.isEmpty()) { + queries.append("&format=" + format); + } + QString urlString(LIST_POLY_URL + "key=" + _authCode + queries); + return QUrl(urlString); + } +} + +QString GooglePolyScriptingInterface::getModelURL(const QUrl& url) { + qCDebug(scriptengine) << "Google URL request: " << url; + if (!url.isEmpty()) { + return parseJSON(url, 1).toString(); + } else { + qCDebug(scriptengine) << "Invalid filters were specified."; + return ""; + } +} + +// FIXME: synchronous +QByteArray GooglePolyScriptingInterface::getHTTPRequest(const QUrl& url) { + QNetworkAccessManager manager; + QNetworkReply *response = manager.get(QNetworkRequest(url)); + QEventLoop event; + connect(response, SIGNAL(finished()), &event, SLOT(quit())); + event.exec(); + + return response->readAll(); +} + +// 0 = asset list, 1 = model from asset list, 2 = specific model +QVariant GooglePolyScriptingInterface::parseJSON(const QUrl& url, int fileType) { + QByteArray jsonString = getHTTPRequest(url); + QJsonDocument doc = QJsonDocument::fromJson(jsonString); + QJsonObject obj = doc.object(); + if (obj.isEmpty()) { + qCDebug(scriptengine) << "Assets with specified filters not found"; + return ""; + } + if (obj.keys().first() == "error") { + QString error = obj.value("error").toObject().value("message").toString(); + qCDebug(scriptengine) << error; + return ""; + } + if (fileType == 0 || fileType == 1) { + QJsonArray arr = obj.value("assets").toArray(); + // return model url + if (fileType == 1) { + int random = getRandIntInRange(arr.size()); + QJsonObject json = arr.at(random).toObject(); + // nested JSONs + return json.value("formats").toArray().at(0).toObject().value("root").toObject().value("url"); + } + // return whole asset list + return QJsonDocument(arr); + // return specific object + } else { + return jsonString; + } +} diff --git a/interface/src/scripting/GooglePolyScriptingInterface.h b/interface/src/scripting/GooglePolyScriptingInterface.h new file mode 100644 index 0000000000..fdd3597bec --- /dev/null +++ b/interface/src/scripting/GooglePolyScriptingInterface.h @@ -0,0 +1,47 @@ +// +// GooglePolyScriptingInterface.h +// interface/src/scripting +// +// Created by Elisa Lupin-Jimenez on 12/3/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GooglePolyScriptingInterface_h +#define hifi_GooglePolyScriptingInterface_h + +#include +#include + +class GooglePolyScriptingInterface : public QObject, public Dependency { + Q_OBJECT + +public: + GooglePolyScriptingInterface(); + +public slots: + void setAPIKey(const QString& key); + + QString getAssetList(const QString& keyword, const QString& category, const QString& format); + QString getFBX(const QString& keyword, const QString& category); + QString getOBJ(const QString& keyword, const QString& category); + QString getBlocks(const QString& keyword, const QString& categoryy); + QString getGLTF(const QString& keyword, const QString& category); + QString getGLTF2(const QString& keyword, const QString& category); + QString getTilt(const QString& keyword, const QString& category); + QString getModelInfo(const QString& input); + +private: + QString _authCode; + + QUrl formatURLQuery(const QString& keyword, const QString& category, const QString& format); + QString getModelURL(const QUrl& url); + QByteArray getHTTPRequest(const QUrl& url); + QVariant parseJSON(const QUrl& url, int fileType); + int getRandIntInRange(int length); + +}; + +#endif // hifi_GooglePolyScriptingInterface_h diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 5b29279dba..6922ca87b7 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -42,7 +42,7 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) : setTransform(base3DOverlay->getTransform()); } -QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties) { +QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& properties, bool scalesWithParent) { // the position and rotation in _transform are relative to the parent (aka local). The versions coming from // scripts are in world-frame, unless localPosition or localRotation are used. Patch up the properties // so that "position" and "rotation" are relative-to-parent values. @@ -56,7 +56,7 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert result["position"] = result["localPosition"]; } else if (result["position"].isValid()) { glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]), - parentID, parentJointIndex, success); + parentID, parentJointIndex, scalesWithParent, success); if (success) { result["position"] = vec3toVariant(localPosition); } @@ -66,7 +66,7 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert result["orientation"] = result["localOrientation"]; } else if (result["orientation"].isValid()) { glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]), - parentID, parentJointIndex, success); + parentID, parentJointIndex, scalesWithParent, success); if (success) { result["orientation"] = quatToVariant(localOrientation); } @@ -118,7 +118,7 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { } } - properties = convertOverlayLocationFromScriptSemantics(properties); + properties = convertOverlayLocationFromScriptSemantics(properties, getScalesWithParent()); Overlay::setProperties(properties); bool needRenderItemUpdate = false; @@ -335,4 +335,4 @@ SpatialParentTree* Base3DOverlay::getParentTree() const { void Base3DOverlay::setVisible(bool visible) { Parent::setVisible(visible); notifyRenderVariableChange(); -} \ No newline at end of file +} diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 2cbf4308ae..62675bacea 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -56,12 +56,12 @@ glm::vec3 Line3DOverlay::getEnd() const { if (_endParentID != QUuid()) { glm::vec3 localOffset = _direction * _length; bool success; - worldEnd = localToWorld(localOffset, _endParentID, _endParentJointIndex, success); + worldEnd = localToWorld(localOffset, _endParentID, _endParentJointIndex, getScalesWithParent(), success); return worldEnd; } localEnd = getLocalEnd(); - worldEnd = localToWorld(localEnd, getParentID(), getParentJointIndex(), success); + worldEnd = localToWorld(localEnd, getParentID(), getParentJointIndex(), getScalesWithParent(), success); if (!success) { qDebug() << "Line3DOverlay::getEnd failed"; } @@ -79,10 +79,10 @@ void Line3DOverlay::setEnd(const glm::vec3& end) { glm::vec3 offset; if (_endParentID != QUuid()) { - offset = worldToLocal(end, _endParentID, _endParentJointIndex, success); + offset = worldToLocal(end, _endParentID, _endParentJointIndex, getScalesWithParent(), success); } else { localStart = getLocalStart(); - localEnd = worldToLocal(end, getParentID(), getParentJointIndex(), success); + localEnd = worldToLocal(end, getParentID(), getParentJointIndex(), getScalesWithParent(), success); offset = localEnd - localStart; } if (!success) { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index ba8bf8cbef..67fa94f7e5 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -24,7 +24,6 @@ ModelOverlay::ModelOverlay() : _model(std::make_shared(nullptr, this)), _modelTextures(QVariantMap()) { - _model->init(); _model->setLoadingPriority(_loadPriority); _isLoaded = false; } @@ -38,7 +37,6 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) : _scaleToFit(modelOverlay->_scaleToFit), _loadPriority(modelOverlay->_loadPriority) { - _model->init(); _model->setLoadingPriority(_loadPriority); if (_url.isValid()) { _updateModel = true; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index bb7f141cd9..c532e7659f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -138,7 +138,6 @@ Avatar::~Avatar() { void Avatar::init() { getHead()->init(); - _skeletonModel->init(); _initialized = true; } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c75b54fdc4..39081ba44b 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -268,6 +268,7 @@ public: virtual float getModelScale() const { return _modelScale; } virtual void setModelScale(float scale) { _modelScale = scale; } + virtual glm::vec3 scaleForChildren() const override { return glm::vec3(getModelScale()); } virtual void setAvatarEntityDataChanged(bool value) override; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 8c3b56d89e..3a737e581b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -349,7 +349,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene float getRadius() const override { return 0.5f * _renderer->getEntity()->getQueryAACube().getScale(); } uint64_t getTimestamp() const override { return _renderer->getUpdateTime(); } - const EntityRendererPointer& getRenderer() const { return _renderer; } + EntityRendererPointer getRenderer() const { return _renderer; } private: EntityRendererPointer _renderer; }; @@ -382,7 +382,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene std::unordered_map::iterator itr; size_t numSorted = sortedRenderables.size(); while (!sortedRenderables.empty() && usecTimestampNow() < expiry) { - const EntityRendererPointer& renderable = sortedRenderables.top().getRenderer(); + const auto renderable = sortedRenderables.top().getRenderer(); renderable->updateInScene(scene, transaction); _renderablesToUpdate.erase(renderable->getEntity()->getID()); sortedRenderables.pop(); @@ -612,7 +612,7 @@ static glm::vec2 projectOntoEntityXYPlane(EntityItemPointer entity, const PickRa glm::vec3 entityPosition = entity->getWorldPosition(); glm::quat entityRotation = entity->getWorldOrientation(); - glm::vec3 entityDimensions = entity->getDimensions(); + glm::vec3 entityDimensions = entity->getScaledDimensions(); glm::vec3 entityRegistrationPoint = entity->getRegistrationPoint(); // project the intersection point onto the local xy plane of the object. diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 696d7ab8db..fc33ebc498 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -37,7 +37,7 @@ void LightEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint lightPayload.editBound() = render::Item::Bound(); } - glm::vec3 dimensions = entity->getDimensions(); + glm::vec3 dimensions = entity->getScaledDimensions(); float largestDiameter = glm::compMax(dimensions); light->setMaximumRadius(largestDiameter / 2.0f); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index bc99522d0f..79fe36d88f 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -78,11 +78,11 @@ RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityI RenderableModelEntityItem::~RenderableModelEntityItem() { } -void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { +void RenderableModelEntityItem::setUnscaledDimensions(const glm::vec3& value) { glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions - if (getDimensions() != newDimensions) { + if (getUnscaledDimensions() != newDimensions) { _dimensionsInitialized = true; - ModelEntityItem::setDimensions(value); + ModelEntityItem::setUnscaledDimensions(value); } } @@ -124,11 +124,11 @@ void RenderableModelEntityItem::doInitialModelSimulation() { // translation/rotation/scale/registration. The first two are straightforward, but the latter two have guards to // make sure they don't happen after they've already been set. Here we reset those guards. This doesn't cause the // entity values to change -- it just allows the model to match once it comes in. - model->setScaleToFit(false, getDimensions()); + model->setScaleToFit(false, getScaledDimensions()); model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); // now recalculate the bounds and registration - model->setScaleToFit(true, getDimensions()); + model->setScaleToFit(true, getScaledDimensions()); model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); model->setRotation(getWorldOrientation()); model->setTranslation(getWorldPosition()); @@ -169,7 +169,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const { return true; } - if (model->getScaleToFitDimensions() != getDimensions()) { + if (model->getScaleToFitDimensions() != getScaledDimensions()) { return true; } @@ -209,17 +209,17 @@ void RenderableModelEntityItem::updateModelBounds() { updateRenderItems = true; } - if (model->getScaleToFitDimensions() != getDimensions() || + if (model->getScaleToFitDimensions() != getScaledDimensions() || model->getRegistrationPoint() != getRegistrationPoint()) { // The machinery for updateModelBounds will give existing models the opportunity to fix their // translation/rotation/scale/registration. The first two are straightforward, but the latter two // have guards to make sure they don't happen after they've already been set. Here we reset those guards. // This doesn't cause the entity values to change -- it just allows the model to match once it comes in. - model->setScaleToFit(false, getDimensions()); + model->setScaleToFit(false, getScaledDimensions()); model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); // now recalculate the bounds and registration - model->setScaleToFit(true, getDimensions()); + model->setScaleToFit(true, getScaledDimensions()); model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); updateRenderItems = true; model->scaleToFit(); @@ -372,7 +372,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { const uint32_t QUAD_STRIDE = 4; ShapeType type = getShapeType(); - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); auto model = getModel(); if (type == SHAPE_TYPE_COMPOUND) { updateModelBounds(); @@ -1153,7 +1153,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return true; } - if (model->getScaleToFitDimensions() != entity->getDimensions() || + if (model->getScaleToFitDimensions() != entity->getScaledDimensions() || model->getRegistrationPoint() != entity->getRegistrationPoint()) { return true; } @@ -1209,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate); connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate); model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity)); - model->init(); entity->setModel(model); withWriteLock([&] { _model = model; }); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index b4f2665692..7af10b09fd 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -60,7 +60,7 @@ public: RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized); virtual ~RenderableModelEntityItem(); - virtual void setDimensions(const glm::vec3& value) override; + virtual void setUnscaledDimensions(const glm::vec3& value) override; virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; void doInitialModelSimulation(); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index fbf85fa8c2..21764dff7f 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -303,6 +303,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { batch.setInputBuffer(0, _verticesBuffer, 0, sizeof(Vertex)); #ifndef POLYLINE_ENTITY_USE_FADE_EFFECT + // glColor4f must be called after setInputFormat if it must be taken into account if (_isFading) { batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime)); } else { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 356bf3a69c..496f8b7323 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -213,7 +213,7 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const { glm::vec3 result; withReadLock([&] { - glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units + glm::vec3 scale = getScaledDimensions() / _voxelVolumeSize; // meters / voxel-units if (isEdged(_voxelSurfaceStyle)) { result = scale / -2.0f; } @@ -228,7 +228,7 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { voxelVolumeSize = _voxelVolumeSize; }); - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units bool success; // TODO -- Does this actually have to happen in world space? glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes @@ -393,7 +393,7 @@ bool RenderablePolyVoxEntityItem::setSphere(const vec3& centerWorldCoords, float glm::mat4 vtwMatrix = voxelToWorldMatrix(); glm::mat4 wtvMatrix = glm::inverse(vtwMatrix); - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec3 voxelSize = dimensions / _voxelVolumeSize; float smallestDimensionSize = voxelSize.x; smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y); @@ -454,7 +454,7 @@ bool RenderablePolyVoxEntityItem::setCapsule(const vec3& startWorldCoords, const glm::mat4 vtwMatrix = voxelToWorldMatrix(); glm::mat4 wtvMatrix = glm::inverse(vtwMatrix); - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec3 voxelSize = dimensions / _voxelVolumeSize; float smallestDimensionSize = voxelSize.x; smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y); @@ -580,7 +580,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // the PolyVox ray intersection code requires a near and far point. // set ray cast length to long enough to cover all of the voxel space float distanceToEntity = glm::distance(origin, getWorldPosition()); - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); float largestDimension = glm::compMax(dimensions) * 2.0f; glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension); @@ -668,7 +668,7 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() const { void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType shapeType = getShapeType(); if (shapeType == SHAPE_TYPE_NONE) { - info.setParams(getShapeType(), 0.5f * getDimensions()); + info.setParams(getShapeType(), 0.5f * getScaledDimensions()); return; } diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 3524709395..cdee2c5ec9 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -63,7 +63,7 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return true; } - if (_dimensions != entity->getDimensions()) { + if (_dimensions != entity->getScaledDimensions()) { return true; } @@ -82,7 +82,7 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _shape = entity->getShape(); _position = entity->getWorldPosition(); - _dimensions = entity->getDimensions(); + _dimensions = entity->getScaledDimensions(); _orientation = entity->getWorldOrientation(); _renderTransform = getModelTransform(); @@ -137,11 +137,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { }); if (proceduralRender) { - batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { - geometryCache->renderWireShape(batch, geometryShape); + geometryCache->renderWireShape(batch, geometryShape, outColor); } else { - geometryCache->renderShape(batch, geometryShape); + geometryCache->renderShape(batch, geometryShape, outColor); } } else { // FIXME, support instanced multi-shape rendering using multidraw indirect diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 6c0f4447ae..968c181940 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -54,7 +54,7 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint return true; } - if (_dimensions != entity->getDimensions()) { + if (_dimensions != entity->getScaledDimensions()) { return true; } @@ -67,7 +67,7 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { _textColor = toGlm(entity->getTextColorX()); _backgroundColor = toGlm(entity->getBackgroundColorX()); - _dimensions = entity->getDimensions(); + _dimensions = entity->getScaledDimensions(); _faceCamera = entity->getFaceCamera(); _lineHeight = entity->getLineHeight(); _text = entity->getText(); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 16e2c4c789..3789cca69a 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -126,7 +126,10 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene withWriteLock([&] { // This work must be done on the main thread if (!hasWebSurface()) { - buildWebSurface(entity); + // If we couldn't create a new web surface, exit + if (!buildWebSurface(entity)) { + return; + } } if (_contextPosition != entity->getWorldPosition()) { @@ -146,7 +149,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene glm::vec2 windowSize = getWindowSize(entity); _webSurface->resize(QSize(windowSize.x, windowSize.y)); _renderTransform = getModelTransform(); - _renderTransform.postScale(entity->getDimensions()); + _renderTransform.postScale(entity->getScaledDimensions()); }); } @@ -190,7 +193,6 @@ void WebEntityRenderer::doRender(RenderArgs* args) { }); batch.setResourceTexture(0, _texture); float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; - batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio); DependencyManager::get()->bindWebBrowserProgram(batch, fadeRatio < OPAQUE_ALPHA_THRESHOLD); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId); @@ -277,7 +279,7 @@ void WebEntityRenderer::destroyWebSurface() { } glm::vec2 WebEntityRenderer::getWindowSize(const TypedEntityPointer& entity) const { - glm::vec2 dims = glm::vec2(entity->getDimensions()); + glm::vec2 dims = glm::vec2(entity->getScaledDimensions()); dims *= METERS_TO_INCHES * _lastDPI; // ensure no side is never larger then MAX_WINDOW_SIZE diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 04da70d733..591bccaabe 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -208,7 +208,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen entity->resetRenderingPropertiesChanged(); _lastPosition = entity->getWorldPosition(); _lastRotation = entity->getWorldOrientation(); - _lastDimensions = entity->getDimensions(); + _lastDimensions = entity->getScaledDimensions(); _keyLightProperties = entity->getKeyLightProperties(); _skyboxProperties = entity->getSkyboxProperties(); @@ -280,7 +280,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint if (entity->getWorldPosition() != _lastPosition) { return true; } - if (entity->getDimensions() != _lastDimensions) { + if (entity->getScaledDimensions() != _lastDimensions) { return true; } if (entity->getWorldOrientation() != _lastRotation) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 271fef33c8..d1842b6fbe 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -50,6 +50,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : { setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY); setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY); + setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS); // explicitly set transform parts to set dirty flags used by batch rendering locationChanged(); dimensionsChanged(); @@ -243,7 +244,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getLocalAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration()); - APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); + APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getUnscaledDimensions()); APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity()); APPEND_ENTITY_PROPERTY(PROP_DAMPING, getDamping()); @@ -779,7 +780,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, customSetAcceleration); } - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setDimensions); + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setUnscaledDimensions); READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity); READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, setGravity); @@ -898,7 +899,7 @@ void EntityItem::debugDump() const { qCDebug(entities) << "EntityItem id:" << getEntityItemID(); qCDebug(entities, " edited ago:%f", (double)getEditedAgo()); qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z); - qCDebug(entities) << " dimensions:" << getDimensions(); + qCDebug(entities) << " dimensions:" << getScaledDimensions(); } // adjust any internal timestamps to fix clock skew for this server @@ -923,7 +924,7 @@ void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSk } float EntityItem::computeMass() const { - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); return getDensity() * _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z; } @@ -942,7 +943,7 @@ void EntityItem::setMass(float mass) { // we must protect the density range to help maintain stability of physics simulation // therefore this method might not accept the mass that is supplied. - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); float volume = _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z; // compute new density @@ -1178,7 +1179,7 @@ bool EntityItem::wantTerseEditLogging() const { glm::mat4 EntityItem::getEntityToWorldMatrix() const { glm::mat4 translation = glm::translate(getWorldPosition()); glm::mat4 rotation = glm::mat4_cast(getWorldOrientation()); - glm::mat4 scale = glm::scale(getDimensions()); + glm::mat4 scale = glm::scale(getScaledDimensions()); glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); return translation * rotation * scale * registration; } @@ -1218,7 +1219,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete + COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getUnscaledDimensions); COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getLocalVelocity); @@ -1326,7 +1327,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration); // these (along with "position" above) affect tree structure - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setUnscaledDimensions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); // these (along with all properties above) affect the simulation @@ -1429,7 +1430,7 @@ void EntityItem::recordCreationTime() { const Transform EntityItem::getTransformToCenter(bool& success) const { Transform result = getTransform(success); if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center - result.postTranslate((ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()) * getDimensions()); // Position to center + result.postTranslate((ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()) * getScaledDimensions()); // Position to center } return result; } @@ -1445,7 +1446,7 @@ AACube EntityItem::getMaximumAACube(bool& success) const { // we want to compute the furthestExtent that an entity can extend out from its "position" // to do this we compute the max of these two vec3s: registration and 1-registration // and then scale by dimensions - glm::vec3 maxExtents = getDimensions() * glm::max(_registrationPoint, glm::vec3(1.0f) - _registrationPoint); + glm::vec3 maxExtents = getScaledDimensions() * glm::max(_registrationPoint, glm::vec3(1.0f) - _registrationPoint); // there exists a sphere that contains maxExtents for all rotations float radius = glm::length(maxExtents); @@ -1470,7 +1471,7 @@ AACube EntityItem::getMinimumAACube(bool& success) const { glm::vec3 position = getWorldPosition(success); if (success) { _recalcMinAACube = false; - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint); Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; @@ -1500,7 +1501,7 @@ AABox EntityItem::getAABox(bool& success) const { glm::vec3 position = getWorldPosition(success); if (success) { _recalcAABox = false; - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint); Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; @@ -1540,12 +1541,12 @@ bool EntityItem::shouldPuffQueryAACube() const { // ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) // ... radius = sqrt(3 x maxDimension ^ 2) / 2.0f; float EntityItem::getRadius() const { - return 0.5f * glm::length(getDimensions()); + return 0.5f * glm::length(getScaledDimensions()); } void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const { if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) { - glm::mat4 scale = glm::scale(getDimensions()); + glm::mat4 scale = glm::scale(getScaledDimensions()); glm::mat4 registration = scale * glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); glm::vec3 regTransVec = glm::vec3(registration[3]); // extract position component from matrix info.setOffset(regTransVec); @@ -1566,12 +1567,12 @@ bool EntityItem::contains(const glm::vec3& point) const { } void EntityItem::computeShapeInfo(ShapeInfo& info) { - info.setParams(getShapeType(), 0.5f * getDimensions()); + info.setParams(getShapeType(), 0.5f * getScaledDimensions()); adjustShapeInfoByRegistration(info); } float EntityItem::getVolumeEstimate() const { - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); return dimensions.x * dimensions.y * dimensions.z; } @@ -1671,11 +1672,21 @@ void EntityItem::setParentID(const QUuid& value) { } } -void EntityItem::setDimensions(const glm::vec3& value) { +glm::vec3 EntityItem::getScaledDimensions() const { + glm::vec3 scale = getSNScale(); + return _unscaledDimensions * scale; +} + +void EntityItem::setScaledDimensions(const glm::vec3& value) { + glm::vec3 parentScale = getSNScale(); + setUnscaledDimensions(value * parentScale); +} + +void EntityItem::setUnscaledDimensions(const glm::vec3& value) { glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions - if (getDimensions() != newDimensions) { + if (getUnscaledDimensions() != newDimensions) { withWriteLock([&] { - _dimensions = newDimensions; + _unscaledDimensions = newDimensions; }); locationChanged(); dimensionsChanged(); @@ -2071,17 +2082,6 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi } EntityDynamicPointer action = _objectActions[actionID]; - - action->setOwnerEntity(nullptr); - action->setIsMine(false); - - if (simulation) { - action->removeFromSimulation(simulation); - } - - bool success = true; - serializeActions(success, _allActionsDataCache); - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; auto removedActionType = action->getType(); if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) { _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING; @@ -2098,7 +2098,17 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi // because they should have been set correctly when the action was added // and/or when children were linked } + action->setOwnerEntity(nullptr); + action->setIsMine(false); _objectActions.remove(actionID); + + if (simulation) { + action->removeFromSimulation(simulation); + } + + bool success = true; + serializeActions(success, _allActionsDataCache); + _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; setDynamicDataNeedsTransmit(true); return success; } @@ -2366,6 +2376,16 @@ void EntityItem::dimensionsChanged() { somethingChangedNotification(); } +bool EntityItem::getScalesWithParent() const { + // keep this logic the same as in EntityItemProperties::getScalesWithParent + if (getClientOnly()) { + QUuid ancestorID = findAncestorOfType(NestableType::Avatar); + return !ancestorID.isNull(); + } else { + return false; + } +} + void EntityItem::globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate, const glm::vec3& offset) const { // TODO -- combine this with convertLocationToScriptSemantics bool success; @@ -2373,7 +2393,7 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt if (success) { properties.setPosition(globalPosition + offset); properties.setRotation(getWorldOrientation()); - properties.setDimensions(getDimensions()); + properties.setDimensions(getScaledDimensions()); // Should we do velocities and accelerations, too? This could end up being quite involved, which is why the method exists. } else { properties.setPosition(getQueryAACube().calcCenter() + offset); // best we can do diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 088d21e84d..0136590ffa 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -180,8 +180,11 @@ public: void setDescription(const QString& value); /// Dimensions in meters (0.0 - TREE_SCALE) - inline const glm::vec3 getDimensions() const { return _dimensions; } - virtual void setDimensions(const glm::vec3& value); + glm::vec3 getScaledDimensions() const; + virtual void setScaledDimensions(const glm::vec3& value); + + inline const glm::vec3 getUnscaledDimensions() const { return _unscaledDimensions; } + virtual void setUnscaledDimensions(const glm::vec3& value); float getLocalRenderAlpha() const; void setLocalRenderAlpha(float localRenderAlpha); @@ -456,6 +459,8 @@ public: virtual void locationChanged(bool tellPhysics = true) override; + virtual bool getScalesWithParent() const override; + using ChangeHandlerCallback = std::function; using ChangeHandlerId = QUuid; ChangeHandlerId registerChangeHandler(const ChangeHandlerCallback& handler); @@ -477,7 +482,7 @@ protected: virtual void dimensionsChanged() override; - glm::vec3 _dimensions { ENTITY_ITEM_DEFAULT_DIMENSIONS }; + glm::vec3 _unscaledDimensions { ENTITY_ITEM_DEFAULT_DIMENSIONS }; EntityTypes::EntityType _type { EntityTypes::Unknown }; quint64 _lastSimulated { 0 }; // last time this entity called simulate(), this includes velocity, angular velocity, // and physics changes diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 13ebd9ef9f..111b851962 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -365,6 +365,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LOCAL_ROTATION, localRotation); CHECK_PROPERTY_CHANGE(PROP_LOCAL_VELOCITY, localVelocity); CHECK_PROPERTY_CHANGE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity); + CHECK_PROPERTY_CHANGE(PROP_LOCAL_DIMENSIONS, localDimensions); CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed); CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed); @@ -628,6 +629,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_VELOCITY, localVelocity); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_DIMENSIONS, localDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); @@ -805,6 +807,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation); COPY_PROPERTY_FROM_QSCRIPTVALUE(localVelocity, glmVec3, setLocalVelocity); COPY_PROPERTY_FROM_QSCRIPTVALUE(localAngularVelocity, glmVec3, setLocalAngularVelocity); + COPY_PROPERTY_FROM_QSCRIPTVALUE(localDimensions, glmVec3, setLocalDimensions); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations); @@ -953,6 +956,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(localRotation); COPY_PROPERTY_IF_CHANGED(localVelocity); COPY_PROPERTY_IF_CHANGED(localAngularVelocity); + COPY_PROPERTY_IF_CHANGED(localDimensions); COPY_PROPERTY_IF_CHANGED(jointRotationsSet); COPY_PROPERTY_IF_CHANGED(jointRotations); @@ -1132,6 +1136,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glm::quat); ADD_PROPERTY_TO_MAP(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glm::vec3); + ADD_PROPERTY_TO_MAP(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector); ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector); @@ -2470,9 +2475,25 @@ bool EntityItemProperties::transformChanged() const { localPositionChanged() || localRotationChanged(); } +bool EntityItemProperties::getScalesWithParent() const { + // keep this logic the same as in EntityItem::getScalesWithParent + bool scalesWithParent { false }; + if (parentIDChanged()) { + bool success; + SpatiallyNestablePointer parent = SpatiallyNestable::findByID(getParentID(), success); + if (success && parent) { + bool avatarAncestor = (parent->getNestableType() == NestableType::Avatar || + parent->hasAncestorOfType(NestableType::Avatar)); + scalesWithParent = getClientOnly() && avatarAncestor; + } + } + return scalesWithParent; +} + bool EntityItemProperties::parentRelatedPropertyChanged() const { return positionChanged() || rotationChanged() || localPositionChanged() || localRotationChanged() || + localDimensionsChanged() || parentIDChanged() || parentJointIndexChanged(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 4f7ba1317b..4887b42138 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -88,6 +88,7 @@ public: EntityPropertyFlags getChangedProperties() const; bool transformChanged() const; + bool getScalesWithParent() const; bool parentRelatedPropertyChanged() const; bool queryAACubeRelatedPropertyChanged() const; @@ -227,6 +228,7 @@ public: DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION); DEFINE_PROPERTY_REF(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3); + DEFINE_PROPERTY_REF(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, glmVec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector, QVector()); DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector, QVector()); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 41c1e77bb8..d515d60535 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -220,6 +220,8 @@ enum EntityPropertyList { PROP_HAZE_KEYLIGHT_RANGE, PROP_HAZE_KEYLIGHT_ALTITUDE, + PROP_LOCAL_DIMENSIONS, // only used to convert values to and from scripts + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index d278283ffa..206065beeb 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -117,7 +117,8 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { } } -EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties& entitySideProperties) { +EntityItemProperties convertPropertiesToScriptSemantics(const EntityItemProperties& entitySideProperties, + bool scalesWithParent) { // In EntityTree code, properties.position and properties.rotation are relative to the parent. In javascript, // they are in world-space. The local versions are put into localPosition and localRotation and position and // rotation are converted from local to world space. @@ -126,35 +127,48 @@ EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties scriptSideProperties.setLocalRotation(entitySideProperties.getRotation()); scriptSideProperties.setLocalVelocity(entitySideProperties.getLocalVelocity()); scriptSideProperties.setLocalAngularVelocity(entitySideProperties.getLocalAngularVelocity()); + scriptSideProperties.setLocalDimensions(entitySideProperties.getDimensions()); bool success; glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), + scalesWithParent, success); glm::quat worldRotation = SpatiallyNestable::localToWorld(entitySideProperties.getRotation(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), + scalesWithParent, success); glm::vec3 worldVelocity = SpatiallyNestable::localToWorldVelocity(entitySideProperties.getVelocity(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), + scalesWithParent, success); glm::vec3 worldAngularVelocity = SpatiallyNestable::localToWorldAngularVelocity(entitySideProperties.getAngularVelocity(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), + scalesWithParent, success); + glm::vec3 worldDimensions = SpatiallyNestable::localToWorldDimensions(entitySideProperties.getDimensions(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex(), + scalesWithParent, + success); + scriptSideProperties.setPosition(worldPosition); scriptSideProperties.setRotation(worldRotation); scriptSideProperties.setVelocity(worldVelocity); scriptSideProperties.setAngularVelocity(worldAngularVelocity); + scriptSideProperties.setDimensions(worldDimensions); return scriptSideProperties; } -EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperties& scriptSideProperties) { +EntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProperties& scriptSideProperties, + bool scalesWithParent) { // convert position and rotation properties from world-space to local, unless localPosition and localRotation // are set. If they are set, they overwrite position and rotation. EntityItemProperties entitySideProperties = scriptSideProperties; @@ -168,7 +182,7 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti glm::vec3 localPosition = SpatiallyNestable::worldToLocal(entitySideProperties.getPosition(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), - success); + scalesWithParent, success); entitySideProperties.setPosition(localPosition); } @@ -178,7 +192,7 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti glm::quat localRotation = SpatiallyNestable::worldToLocal(entitySideProperties.getRotation(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), - success); + scalesWithParent, success); entitySideProperties.setRotation(localRotation); } @@ -188,7 +202,7 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti glm::vec3 localVelocity = SpatiallyNestable::worldToLocalVelocity(entitySideProperties.getVelocity(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), - success); + scalesWithParent, success); entitySideProperties.setVelocity(localVelocity); } @@ -199,10 +213,20 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti SpatiallyNestable::worldToLocalAngularVelocity(entitySideProperties.getAngularVelocity(), entitySideProperties.getParentID(), entitySideProperties.getParentJointIndex(), - success); + scalesWithParent, success); entitySideProperties.setAngularVelocity(localAngularVelocity); } + if (scriptSideProperties.localDimensionsChanged()) { + entitySideProperties.setDimensions(scriptSideProperties.getLocalDimensions()); + } else if (scriptSideProperties.dimensionsChanged()) { + glm::vec3 localDimensions = SpatiallyNestable::worldToLocalDimensions(entitySideProperties.getDimensions(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex(), + scalesWithParent, success); + entitySideProperties.setDimensions(localDimensions); + } + return entitySideProperties; } @@ -212,9 +236,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties _activityTracking.addedEntityCount++; - EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties); - propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); - + EntityItemProperties propertiesWithSimID = properties; if (clientOnly) { auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); @@ -222,6 +244,11 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties propertiesWithSimID.setOwningAvatarID(myNodeID); } + bool scalesWithParent = propertiesWithSimID.getScalesWithParent(); + + propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent); + propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); + auto dimensions = propertiesWithSimID.getDimensions(); float volume = dimensions.x * dimensions.y * dimensions.z; auto density = propertiesWithSimID.getDensity(); @@ -295,15 +322,20 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) { PROFILE_RANGE(script_entities, __FUNCTION__); + bool scalesWithParent { false }; EntityItemProperties results; if (_entityTree) { _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity)); if (entity) { + scalesWithParent = entity->getScalesWithParent(); if (desiredProperties.getHasProperty(PROP_POSITION) || desiredProperties.getHasProperty(PROP_ROTATION) || desiredProperties.getHasProperty(PROP_LOCAL_POSITION) || - desiredProperties.getHasProperty(PROP_LOCAL_ROTATION)) { + desiredProperties.getHasProperty(PROP_LOCAL_ROTATION) || + desiredProperties.getHasProperty(PROP_LOCAL_VELOCITY) || + desiredProperties.getHasProperty(PROP_LOCAL_ANGULAR_VELOCITY) || + desiredProperties.getHasProperty(PROP_LOCAL_DIMENSIONS)) { // if we are explicitly getting position or rotation, we need parent information to make sense of them. desiredProperties.setHasProperty(PROP_PARENT_ID); desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX); @@ -316,6 +348,9 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit desiredProperties = entity->getEntityProperties(params); desiredProperties.setHasProperty(PROP_LOCAL_POSITION); desiredProperties.setHasProperty(PROP_LOCAL_ROTATION); + desiredProperties.setHasProperty(PROP_LOCAL_VELOCITY); + desiredProperties.setHasProperty(PROP_LOCAL_ANGULAR_VELOCITY); + desiredProperties.setHasProperty(PROP_LOCAL_DIMENSIONS); } results = entity->getProperties(desiredProperties); @@ -323,7 +358,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit }); } - return convertLocationToScriptSemantics(results); + return convertPropertiesToScriptSemantics(results, scalesWithParent); } QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) { @@ -390,10 +425,13 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) { properties.setRotation(entity->getWorldOrientation()); } + if (!scriptSideProperties.localDimensionsChanged() && !scriptSideProperties.dimensionsChanged()) { + properties.setDimensions(entity->getScaledDimensions()); + } } - properties = convertLocationFromScriptSemantics(properties); properties.setClientOnly(entity->getClientOnly()); properties.setOwningAvatarID(entity->getOwningAvatarID()); + properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent()); float cost = calculateCost(density * volume, oldVelocity, newVelocity); cost *= costMultiplier; @@ -529,7 +567,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { return; } - auto dimensions = entity->getDimensions(); + auto dimensions = entity->getScaledDimensions(); float volume = dimensions.x * dimensions.y * dimensions.z; auto density = entity->getDensity(); auto velocity = entity->getWorldVelocity().length(); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 7e2958583d..926975f735 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -667,7 +667,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con glm::mat4 entityToWorldMatrix = translation * rotation; glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); - glm::vec3 dimensions = entity->getDimensions(); + glm::vec3 dimensions = entity->getScaledDimensions(); glm::vec3 registrationPoint = entity->getRegistrationPoint(); glm::vec3 corner = -(dimensions * registrationPoint); @@ -763,7 +763,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc glm::vec3 penetration; if (!success || entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) { - glm::vec3 dimensions = entity->getDimensions(); + glm::vec3 dimensions = entity->getScaledDimensions(); // FIXME - consider allowing the entity to determine penetration so that // entities could presumably dull actuall hull testing if they wanted to diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index f4944603f1..45f36a1744 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -41,16 +41,16 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem( _color[RED_INDEX] = _color[GREEN_INDEX] = _color[BLUE_INDEX] = 0; } -void LightEntityItem::setDimensions(const glm::vec3& value) { +void LightEntityItem::setUnscaledDimensions(const glm::vec3& value) { if (_isSpotlight) { // If we are a spotlight, treat the z value as our radius or length, and // recalculate the x/y dimensions to properly encapsulate the spotlight. const float length = value.z; const float width = length * glm::sin(glm::radians(_cutoff)); - EntityItem::setDimensions(glm::vec3(width, width, length)); + EntityItem::setUnscaledDimensions(glm::vec3(width, width, length)); } else { float maxDimension = glm::compMax(value); - EntityItem::setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); + EntityItem::setUnscaledDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); } } @@ -98,7 +98,7 @@ void LightEntityItem::setIsSpotlight(bool value) { return; } - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec3 newDimensions; if (value) { const float length = dimensions.z; @@ -112,7 +112,7 @@ void LightEntityItem::setIsSpotlight(bool value) { _isSpotlight = value; _lightPropertiesChanged = true; }); - setDimensions(newDimensions); + setScaledDimensions(newDimensions); } void LightEntityItem::setCutoff(float value) { @@ -128,9 +128,9 @@ void LightEntityItem::setCutoff(float value) { if (getIsSpotlight()) { // If we are a spotlight, adjusting the cutoff will affect the area we encapsulate, // so update the dimensions to reflect this. - const float length = getDimensions().z; + const float length = getScaledDimensions().z; const float width = length * glm::sin(glm::radians(_cutoff)); - setDimensions(glm::vec3(width, width, length)); + setScaledDimensions(glm::vec3(width, width, length)); } withWriteLock([&] { diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index edc7376079..870b283c26 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -29,7 +29,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value) override; + virtual void setUnscaledDimensions(const glm::vec3& value) override; virtual bool setProperties(const EntityItemProperties& properties) override; virtual bool setSubClassProperties(const EntityItemProperties& properties) override; diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 02d16f2537..00196d7b23 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -80,7 +80,7 @@ bool LineEntityItem::appendPoint(const glm::vec3& point) { qCDebug(entities) << "MAX POINTS REACHED!"; return false; } - glm::vec3 halfBox = getDimensions() * 0.5f; + glm::vec3 halfBox = getScaledDimensions() * 0.5f; if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { qCDebug(entities) << "Point is outside entity's bounding box"; return false; @@ -96,7 +96,7 @@ bool LineEntityItem::setLinePoints(const QVector& points) { if (points.size() > MAX_POINTS_PER_LINE) { return false; } - glm::vec3 halfBox = getDimensions() * 0.5f; + glm::vec3 halfBox = getScaledDimensions() * 0.5f; for (int i = 0; i < points.size(); i++) { glm::vec3 point = points.at(i); if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { @@ -157,7 +157,7 @@ void LineEntityItem::debugDump() const { qCDebug(entities) << " LINE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 3a79df34c6..3e6d19f430 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -289,7 +289,7 @@ void ModelEntityItem::debugDump() const { qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID(); qCDebug(entities) << " edited ago:" << getEditedAgo(); qCDebug(entities) << " position:" << getWorldPosition(); - qCDebug(entities) << " dimensions:" << getDimensions(); + qCDebug(entities) << " dimensions:" << getScaledDimensions(); qCDebug(entities) << " model URL:" << getModelURL(); qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL(); } diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index bc0c093518..c20572a491 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -353,7 +353,7 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() { float maxDistanceValue = glm::compMax(maxDistance); //times 2 because dimensions are diameters not radii glm::vec3 dims(2.0f * maxDistanceValue); - EntityItem::setDimensions(dims); + EntityItem::setScaledDimensions(dims); } @@ -593,7 +593,7 @@ void ParticleEffectEntityItem::debugDump() const { _particleProperties.color.gradient.target.green << "," << _particleProperties.color.gradient.target.blue; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index e69fb2e100..498d13058e 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -191,7 +191,7 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() { } // if Polyline has only one or fewer points, use default dimension settings - setDimensions(newScale); + setScaledDimensions(newScale); EntityItem::setRegistrationPoint(newRegistrationPoint); } @@ -257,7 +257,7 @@ void PolyLineEntityItem::debugDump() const { qCDebug(entities) << " QUAD EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index b08d94ca7e..84ce83d3a1 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -229,7 +229,7 @@ void PolyVoxEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " POLYVOX EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } @@ -377,7 +377,7 @@ EntityItemID PolyVoxEntityItem::getZPNeighborID() const { glm::vec3 PolyVoxEntityItem::getSurfacePositionAdjustment() const { glm::vec3 result; withReadLock([&] { - glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units + glm::vec3 scale = getScaledDimensions() / _voxelVolumeSize; // meters / voxel-units if (isEdged()) { result = scale / -2.0f; } @@ -392,7 +392,7 @@ glm::mat4 PolyVoxEntityItem::voxelToLocalMatrix() const { voxelVolumeSize = _voxelVolumeSize; }); - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units bool success; // TODO -- Does this actually have to happen in world space? glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 15704ebc17..3750bc3b57 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -106,11 +106,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { break; case entity::Shape::Circle: // Circle is implicitly flat so we enforce flat dimensions - setDimensions(getDimensions()); + setUnscaledDimensions(getUnscaledDimensions()); break; case entity::Shape::Quad: // Quad is implicitly flat so we enforce flat dimensions - setDimensions(getDimensions()); + setUnscaledDimensions(getUnscaledDimensions()); break; default: _type = EntityTypes::Shape; @@ -204,15 +204,15 @@ void ShapeEntityItem::setColor(const QColor& value) { setAlpha(value.alpha()); } -void ShapeEntityItem::setDimensions(const glm::vec3& value) { +void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { const float MAX_FLAT_DIMENSION = 0.0001f; - if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { + if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { // enforce flatness in Y glm::vec3 newDimensions = value; newDimensions.y = MAX_FLAT_DIMENSION; - EntityItem::setDimensions(newDimensions); - } else { - EntityItem::setDimensions(value); + EntityItem::setUnscaledDimensions(newDimensions); + } else { + EntityItem::setUnscaledDimensions(value); } } @@ -256,7 +256,7 @@ void ShapeEntityItem::debugDump() const { qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType()); qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; } @@ -266,7 +266,7 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { // This will be called whenever DIRTY_SHAPE flag (set by dimension change, etc) // is set. - const glm::vec3 entityDimensions = getDimensions(); + const glm::vec3 entityDimensions = getScaledDimensions(); switch (_shape){ case entity::Shape::Quad: diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 20e36c88e6..c5df17db54 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -80,7 +80,7 @@ public: const rgbColor& getColor() const { return _color; } void setColor(const rgbColor& value); - void setDimensions(const glm::vec3& value) override; + void setUnscaledDimensions(const glm::vec3& value) override; xColor getXColor() const; void setColor(const xColor& value); diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 67e83ab3fd..639da69a17 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -41,9 +41,9 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void TextEntityItem::setDimensions(const glm::vec3& value) { +void TextEntityItem::setUnscaledDimensions(const glm::vec3& value) { // NOTE: Text Entities always have a "depth" of 1cm. - EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } EntityItemProperties TextEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { @@ -132,7 +132,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getWorldOrientation(); glm::vec3 position = getWorldPosition() + rotation * diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 8db929fa47..520a935e55 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value) override; + virtual void setUnscaledDimensions(const glm::vec3& value) override; virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 5ee630d8ed..54db6e7c3b 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -36,9 +36,9 @@ WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(enti const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void WebEntityItem::setDimensions(const glm::vec3& value) { +void WebEntityItem::setUnscaledDimensions(const glm::vec3& value) { // NOTE: Web Entities always have a "depth" of 1cm. - EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); } EntityItemProperties WebEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { @@ -109,7 +109,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { - glm::vec3 dimensions = getDimensions(); + glm::vec3 dimensions = getScaledDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getWorldOrientation(); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 9e84a3a776..f5066beebc 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -22,7 +22,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value) override; + virtual void setUnscaledDimensions(const glm::vec3& value) override; virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 0ed523202b..fbfbc71a85 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -242,7 +242,7 @@ void ZoneEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); qCDebug(entities) << " _backgroundMode:" << EntityItemProperties::getBackgroundModeString(_backgroundMode); qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getHazeModeString(_hazeMode); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index f93d430152..2192f5f45b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -605,6 +605,10 @@ void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) { if (_input._colorAttribute != newColor) { _input._colorAttribute = newColor; glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r); + // Color has been changed and is not white. To prevent colors from bleeding + // between different objects, we need to set the _hadColorAttribute flag + // as if a previous render call had potential colors + _input._hadColorAttribute = (newColor != glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } (void)CHECK_GL_ERROR(); } diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 1908db614d..5558d3ada1 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -253,6 +253,7 @@ protected: struct InputStageState { bool _invalidFormat { true }; + bool _hadColorAttribute{ true }; Stream::FormatPointer _format; std::string _formatKey; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp index e8ebcbe05c..42bd56e6e4 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp @@ -62,6 +62,8 @@ void GL41Backend::updateInput() { // now we need to bind the buffers and assign the attrib pointers if (_input._format) { + bool hasColorAttribute{ false }; + const Buffers& buffers = _input._buffers; const Offsets& offsets = _input._bufferOffsets; const Offsets& strides = _input._bufferStrides; @@ -98,6 +100,8 @@ void GL41Backend::updateInput() { uintptr_t pointer = (uintptr_t)(attrib._offset + offsets[bufferNum]); GLboolean isNormalized = attrib._element.isNormalized(); + hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR); + for (size_t locNum = 0; locNum < locationCount; ++locNum) { if (attrib._element.isInteger()) { glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride, @@ -117,6 +121,15 @@ void GL41Backend::updateInput() { } } } + + if (_input._hadColorAttribute && !hasColorAttribute) { + // The previous input stage had a color attribute but this one doesn't so reset + // color to pure white. + const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); + glVertexAttrib4fv(Stream::COLOR, &white.r); + _input._colorAttribute = white; + } + _input._hadColorAttribute = hasColorAttribute; } // everything format related should be in sync now _input._invalidFormat = false; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp index ece62e15f1..4a43fc988c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -32,6 +32,8 @@ void GL45Backend::updateInput() { // Assign the vertex format required if (_input._format) { + bool hasColorAttribute{ false }; + _input._attribBindingBuffers.reset(); const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); @@ -54,6 +56,9 @@ void GL45Backend::updateInput() { GLboolean isNormalized = attrib._element.isNormalized(); GLenum perLocationSize = attrib._element.getLocationSize(); + + hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR); + for (GLuint locNum = 0; locNum < locationCount; ++locNum) { GLuint attriNum = (GLuint)(slot + locNum); newActivation.set(attriNum); @@ -84,6 +89,15 @@ void GL45Backend::updateInput() { glVertexBindingDivisor(bufferChannelNum, frequency); #endif } + + if (_input._hadColorAttribute && !hasColorAttribute) { + // The previous input stage had a color attribute but this one doesn't so reset + // color to pure white. + const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); + glVertexAttrib4fv(Stream::COLOR, &white.r); + _input._colorAttribute = white; + } + _input._hadColorAttribute = hasColorAttribute; } // Manage Activation what was and what is expected now diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp index aec6df4f14..c63170de75 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp @@ -89,17 +89,19 @@ void UserActivityLoggerScriptingInterface::doLogAction(QString action, QJsonObje Q_ARG(QJsonObject, details)); } -void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem) { +void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem) { QJsonObject payload; payload["marketplaceID"] = marketplaceID; + payload["contentCreator"] = contentCreator; payload["cost"] = cost; payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem; doLogAction("commercePurchaseSuccess", payload); } -void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails) { +void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails) { QJsonObject payload; payload["marketplaceID"] = marketplaceID; + payload["contentCreator"] = contentCreator; payload["cost"] = cost; payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem; payload["errorDetails"] = errorDetails; diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.h b/libraries/networking/src/UserActivityLoggerScriptingInterface.h index 0e08b050d7..71d411056d 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.h +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.h @@ -33,8 +33,8 @@ public: Q_INVOKABLE void bubbleToggled(bool newValue); Q_INVOKABLE void bubbleActivated(); Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{}); - Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem); - Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails); + Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem); + Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails); Q_INVOKABLE void commerceEntityRezzed(QString marketplaceID, QString source, QString type); Q_INVOKABLE void commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain); Q_INVOKABLE void commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName); diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 2f57523f79..77ed589e0b 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -191,6 +191,8 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { pendingMessage.enqueuePacket(std::move(packet)); + bool processedLastOrOnly = false; + while (pendingMessage.hasAvailablePackets()) { auto packet = pendingMessage.removeNextPacket(); @@ -201,9 +203,13 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { // if this was the last or only packet, then we can remove the pending message from our hash if (packetPosition == Packet::PacketPosition::LAST || packetPosition == Packet::PacketPosition::ONLY) { - _pendingReceivedMessages.erase(messageNumber); + processedLastOrOnly = true; } } + + if (processedLastOrOnly) { + _pendingReceivedMessages.erase(messageNumber); + } } void Connection::sync() { diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 05d40f9621..85f321a198 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -197,7 +197,7 @@ uint qHash(const PacketType& key, uint seed); QDebug operator<<(QDebug debug, const PacketType& type); enum class EntityVersion : PacketVersion { - StrokeColorProperty = 77, + StrokeColorProperty = 0, HasDynamicOwnershipTests, HazeEffect, StaticCertJsonVersionOne, diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index 3bb2aa2ef9..396cd13508 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -40,17 +40,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { // Still relying on the raw data from the model - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE); - if (useCauterizedMesh) { - ModelPointer model = _model.lock(); - if (model) { - CauterizedModel* skeleton = static_cast(model.get()); - useCauterizedMesh = useCauterizedMesh && skeleton->getEnableCauterization(); - } else { - useCauterizedMesh = false; - } - } - + bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _cauterizedClusterBuffer); diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 1c98f5abf3..44eddc6e31 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -21,9 +21,12 @@ public: void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; + void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } + private: gpu::BufferPointer _cauterizedClusterBuffer; Transform _cauterizedTransform; + bool _enableCauterization { false }; }; #endif // hifi_CauterizedMeshPartPayload_h diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index c437a8c556..dbb82ab638 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -178,6 +178,12 @@ void CauterizedModel::updateRenderItems() { modelTransform.setTranslation(self->getTranslation()); modelTransform.setRotation(self->getRotation()); + bool isWireframe = self->isWireframe(); + bool isVisible = self->isVisible(); + bool isLayeredInFront = self->isLayeredInFront(); + bool isLayeredInHUD = self->isLayeredInHUD(); + bool enableCauterization = self->getEnableCauterization(); + render::Transaction transaction; for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) { @@ -186,7 +192,10 @@ void CauterizedModel::updateRenderItems() { auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices); - transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized](CauterizedMeshPartPayload& data) { + bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); + + transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey, + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) { data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized); Transform renderTransform = modelTransform; @@ -200,6 +209,11 @@ void CauterizedModel::updateRenderItems() { renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0])); } data.updateTransformForCauterizedMesh(renderTransform); + + data.setEnableCauterization(enableCauterization); + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + data.setShapeKey(invalidatePayloadShapeKey, isWireframe); }); } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 76c354bdf8..2616d08600 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -760,6 +760,20 @@ void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape) { _shapes[shape].drawWire(batch); } +void GeometryCache::renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) { + batch.setInputFormat(getSolidStreamFormat()); + // Color must be set after input format + batch._glColor4f(color.r, color.g, color.b, color.a); + _shapes[shape].draw(batch); +} + +void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) { + batch.setInputFormat(getSolidStreamFormat()); + // Color must be set after input format + batch._glColor4f(color.r, color.g, color.b, color.a); + _shapes[shape].drawWire(batch); +} + void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) { gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT); batch.setInputBuffer(gpu::Stream::COLOR, colorView); @@ -811,6 +825,14 @@ void GeometryCache::renderWireCube(gpu::Batch& batch) { renderWireShape(batch, Cube); } +void GeometryCache::renderCube(gpu::Batch& batch, const glm::vec4& color) { + renderShape(batch, Cube, color); +} + +void GeometryCache::renderWireCube(gpu::Batch& batch, const glm::vec4& color) { + renderWireShape(batch, Cube, color); +} + void GeometryCache::renderSphere(gpu::Batch& batch) { renderShape(batch, Sphere); } @@ -819,6 +841,14 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) { renderWireShape(batch, Sphere); } +void GeometryCache::renderSphere(gpu::Batch& batch, const glm::vec4& color) { + renderShape(batch, Sphere, color); +} + +void GeometryCache::renderWireSphere(gpu::Batch& batch, const glm::vec4& color) { + renderWireShape(batch, Sphere, color); +} + void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge, diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index cd8c43f1df..0585cc9e55 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -251,14 +251,20 @@ public: // Dynamic geometry void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); + void renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color); + void renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color); size_t getShapeTriangleCount(Shape shape); void renderCube(gpu::Batch& batch); void renderWireCube(gpu::Batch& batch); + void renderCube(gpu::Batch& batch, const glm::vec4& color); + void renderWireCube(gpu::Batch& batch, const glm::vec4& color); size_t getCubeTriangleCount(); void renderSphere(gpu::Batch& batch); void renderWireSphere(gpu::Batch& batch); + void renderSphere(gpu::Batch& batch, const glm::vec4& color); + void renderWireSphere(gpu::Batch& batch, const glm::vec4& color); size_t getSphereTriangleCount(); void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 1ea3e1a705..2a59c7d3c5 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -122,11 +122,6 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputFormat((_drawMesh->getVertexFormat())); batch.setInputStream(0, _drawMesh->getVertexStream()); - - // TODO: Get rid of that extra call - if (!_hasColorAttrib) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } } void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool enableTextures) const { @@ -325,7 +320,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in _shapeID(shapeIndex) { assert(model && model->isLoaded()); - _model = model; + _blendedVertexBuffer = model->_blendedVertexBuffers[_meshIndex]; auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); const Model::MeshState& state = model->getMeshState(_meshIndex); @@ -339,13 +334,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in } updateTransformForSkinnedMesh(renderTransform, transform); - initCache(); + initCache(model); } -void ModelMeshPartPayload::initCache() { - ModelPointer model = _model.lock(); - assert(model && model->isLoaded()); - +void ModelMeshPartPayload::initCache(const ModelPointer& model) { if (_drawMesh) { auto vertexFormat = _drawMesh->getVertexFormat(); _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); @@ -355,6 +347,7 @@ void ModelMeshPartPayload::initCache() { const FBXMesh& mesh = geometry.meshes.at(_meshIndex); _isBlendShaped = !mesh.blendshapes.isEmpty(); + _hasTangents = !mesh.tangents.isEmpty(); } auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); @@ -388,94 +381,70 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render _worldBound.transform(boundTransform); } -ItemKey ModelMeshPartPayload::getKey() const { +void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) { ItemKey::Builder builder; builder.withTypeShape(); - ModelPointer model = _model.lock(); - if (model) { - if (!model->isVisible()) { - builder.withInvisible(); - } + if (!isVisible) { + builder.withInvisible(); + } - if (model->isLayeredInFront() || model->isLayeredInHUD()) { - builder.withLayered(); - } + if (isLayered) { + builder.withLayered(); + } - if (_isBlendShaped || _isSkinned) { - builder.withDeformed(); - } + if (_isBlendShaped || _isSkinned) { + builder.withDeformed(); + } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); - if (matKey.isTranslucent()) { - builder.withTransparent(); - } + if (_drawMaterial) { + auto matKey = _drawMaterial->getKey(); + if (matKey.isTranslucent()) { + builder.withTransparent(); } } - return builder.build(); + + _itemKey = builder.build(); +} + +ItemKey ModelMeshPartPayload::getKey() const { + return _itemKey; +} + +void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) { + if (isLayeredInFront) { + _layer = Item::LAYER_3D_FRONT; + } else if (isLayeredInHUD) { + _layer = Item::LAYER_3D_HUD; + } else { + _layer = Item::LAYER_3D; + } } int ModelMeshPartPayload::getLayer() const { - ModelPointer model = _model.lock(); - if (model) { - if (model->isLayeredInFront()) { - return Item::LAYER_3D_FRONT; - } else if (model->isLayeredInHUD()) { - return Item::LAYER_3D_HUD; - } - } - return Item::LAYER_3D; + return _layer; } -ShapeKey ModelMeshPartPayload::getShapeKey() const { - // guard against partially loaded meshes - ModelPointer model = _model.lock(); - if (!model || !model->isLoaded() || !model->getGeometry()) { - return ShapeKey::Builder::invalid(); +void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe) { + if (invalidateShapeKey) { + _shapeKey = ShapeKey::Builder::invalid(); + return; } - const FBXGeometry& geometry = model->getFBXGeometry(); - const auto& networkMeshes = model->getGeometry()->getMeshes(); - - // guard against partially loaded meshes - if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)model->_meshStates.size()) { - return ShapeKey::Builder::invalid(); - } - - const FBXMesh& mesh = geometry.meshes.at(_meshIndex); - - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown - // to false to rebuild out mesh groups. - if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) { - model->_needsFixupInScene = true; // trigger remove/add cycle - model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - return ShapeKey::Builder::invalid(); - } - - - int vertexCount = mesh.vertices.size(); - if (vertexCount == 0) { - // sanity check - return ShapeKey::Builder::invalid(); // FIXME - } - - model::MaterialKey drawMaterialKey; if (_drawMaterial) { drawMaterialKey = _drawMaterial->getKey(); } bool isTranslucent = drawMaterialKey.isTranslucent(); - bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); + bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents; bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); bool isUnlit = drawMaterialKey.isUnlit(); bool isSkinned = _isSkinned; - bool wireframe = model->isWireframe(); - if (wireframe) { + if (isWireframe) { isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false; } @@ -500,10 +469,14 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { if (isSkinned) { builder.withSkinned(); } - if (wireframe) { + if (isWireframe) { builder.withWireframe(); } - return builder.build(); + _shapeKey = builder.build(); +} + +ShapeKey ModelMeshPartPayload::getShapeKey() const { + return _shapeKey; } void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { @@ -515,10 +488,9 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); batch.setInputFormat((_drawMesh->getVertexFormat())); - ModelPointer model = _model.lock(); - if (model) { - batch.setInputBuffer(0, model->_blendedVertexBuffers[_meshIndex], 0, sizeof(glm::vec3)); - batch.setInputBuffer(1, model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); + if (_blendedVertexBuffer) { + batch.setInputBuffer(0, _blendedVertexBuffer, 0, sizeof(glm::vec3)); + batch.setInputBuffer(1, _blendedVertexBuffer, _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); } else { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); @@ -526,11 +498,6 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } } - - // TODO: Get rid of that extra call - if (!_hasColorAttrib) { - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } } void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { @@ -544,31 +511,9 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline: void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - ModelPointer model = _model.lock(); - if (!model || !model->isAddedToScene() || !model->isVisible()) { - return; // bail asap - } - - if (_state == WAITING_TO_START) { - if (model->isLoaded()) { - _state = STARTED; - model->setRenderItemsNeedUpdate(); - } else { - return; - } - } - - if (_materialNeedsUpdate && model->getGeometry()->areTexturesLoaded()) { - model->setRenderItemsNeedUpdate(); - _materialNeedsUpdate = false; - } - if (!args) { return; } - if (!getShapeKey().isValid()) { - return; - } gpu::Batch& batch = *(args->_batch); auto locations = args->_shapePipeline->locations; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 971c6fe90b..fb55883101 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -96,32 +96,32 @@ public: render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) override; + void setKey(bool isVisible, bool isLayered); + void setLayer(bool isLayeredInFront, bool isLayeredInHUD); + void setShapeKey(bool invalidateShapeKey, bool isWireframe); + // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; - void initCache(); - void computeAdjustedLocalBound(const std::vector& clusterMatrices); gpu::BufferPointer _clusterBuffer; - ModelWeakPointer _model; int _meshIndex; int _shapeID; bool _isSkinned{ false }; bool _isBlendShaped { false }; - bool _materialNeedsUpdate { true }; + bool _hasTangents { false }; private: + void initCache(const ModelPointer& model); - enum State : uint8_t { - WAITING_TO_START = 0, - STARTED = 1, - }; - - mutable State _state { WAITING_TO_START } ; + gpu::BufferPointer _blendedVertexBuffer; + render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() }; + render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; + int _layer { render::Item::LAYER_3D }; }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c4bc435691..b91f4dd405 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -210,6 +210,24 @@ int Model::getRenderInfoTextureCount() { return _renderInfoTextureCount; } +bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) { + if (!getGeometry()) { + return true; + } + + const FBXGeometry& geometry = getFBXGeometry(); + const auto& networkMeshes = getGeometry()->getMeshes(); + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown + // to false to rebuild out mesh groups. + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size()) { + _needsFixupInScene = true; // trigger remove/add cycle + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + return true; + } + + return false; +} + void Model::updateRenderItems() { if (!_addedToScene) { return; @@ -237,6 +255,11 @@ void Model::updateRenderItems() { Transform modelTransform = self->getTransform(); modelTransform.setScale(glm::vec3(1.0f)); + bool isWireframe = self->isWireframe(); + bool isVisible = self->isVisible(); + bool isLayeredInFront = self->isLayeredInFront(); + bool isLayeredInHUD = self->isLayeredInHUD(); + render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -244,13 +267,20 @@ void Model::updateRenderItems() { auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices); - transaction.updateItem(itemID, [modelTransform, clusterMatrices](ModelMeshPartPayload& data) { + bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); + + transaction.updateItem(itemID, [modelTransform, clusterMatrices, invalidatePayloadShapeKey, + isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { data.updateClusterBuffer(clusterMatrices); Transform renderTransform = modelTransform; if (clusterMatrices.size() == 1) { renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0])); } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); + + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + data.setShapeKey(invalidatePayloadShapeKey, isWireframe); }); } @@ -272,16 +302,6 @@ void Model::setRenderItemsNeedUpdate() { emit requestRenderUpdate(); } -void Model::initJointTransforms() { - if (isLoaded()) { - glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); - _rig.setModelOffset(modelOffset); - } -} - -void Model::init() { -} - void Model::reset() { if (isLoaded()) { const FBXGeometry& geometry = getFBXGeometry(); @@ -574,47 +594,72 @@ void Model::calculateTriangleSets() { } } -void Model::setVisibleInScene(bool newValue, const render::ScenePointer& scene) { - if (_isVisible != newValue) { - _isVisible = newValue; +void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene) { + if (_isVisible != isVisible) { + _isVisible = isVisible; + + bool isLayeredInFront = _isLayeredInFront; + bool isLayeredInHUD = _isLayeredInHUD; render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.resetItem(item, _collisionRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + }); } scene->enqueueTransaction(transaction); } } -void Model::setLayeredInFront(bool layered, const render::ScenePointer& scene) { - if (_isLayeredInFront != layered) { - _isLayeredInFront = layered; +void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) { + if (_isLayeredInFront != isLayeredInFront) { + _isLayeredInFront = isLayeredInFront; + + bool isVisible = _isVisible; + bool isLayeredInHUD = _isLayeredInHUD; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.resetItem(item, _collisionRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } scene->enqueueTransaction(transaction); } } -void Model::setLayeredInHUD(bool layered, const render::ScenePointer& scene) { - if (_isLayeredInHUD != layered) { - _isLayeredInHUD = layered; +void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene) { + if (_isLayeredInHUD != isLayeredInHUD) { + _isLayeredInHUD = isLayeredInHUD; + + bool isVisible = _isVisible; + bool isLayeredInFront = _isLayeredInFront; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.resetItem(item, _collisionRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } scene->enqueueTransaction(transaction); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 7568a17342..4df7faac84 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -82,9 +82,9 @@ public: const QUrl& getURL() const { return _url; } // new Scene/Engine rendering support - void setVisibleInScene(bool newValue, const render::ScenePointer& scene); - void setLayeredInFront(bool layered, const render::ScenePointer& scene); - void setLayeredInHUD(bool layered, const render::ScenePointer& scene); + void setVisibleInScene(bool isVisible, const render::ScenePointer& scene); + void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); + void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); bool needsFixupInScene() const; bool needsReload() const { return _needsReload; } @@ -122,7 +122,6 @@ public: void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } bool isWireframe() const { return _isWireframe; } - void init(); void reset(); void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); @@ -346,11 +345,7 @@ protected: // hook for derived classes to be notified when setUrl invalidates the current model. virtual void onInvalidate() {}; - -protected: - virtual void deleteGeometry(); - void initJointTransforms(); QVector _blendshapeCoefficients; @@ -419,6 +414,8 @@ protected: bool _isLayeredInFront { false }; bool _isLayeredInHUD { false }; + bool shouldInvalidatePayloadShapeKey(int meshIndex); + private: float _loadingPriority { 0.0f }; diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index dc6a877bb9..279fa42ea4 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -28,7 +28,7 @@ glm::vec3 getPosition() const override { return _thing->getPosition(); } float getRadius() const override { return 0.5f * _thing->getBoundingRadius(); } uint64_t getTimestamp() const override { return _thing->getLastTime(); } - const Thing& getThing() const { return _thing; } + Thing getThing() const { return _thing; } private: Thing _thing; }; @@ -43,6 +43,13 @@ (3) Loop over your priority queue and do timeboxed work: + NOTE: Be careful using references to members of instances of T from std::priority_queue. + Under the hood std::priority_queue may re-use instances of T. + For example, after a pop() or a push() the top T may have the same memory address + as the top T before the pop() or push() (but point to a swapped instance of T). + This causes a reference to member variable of T to point to a different value + when operations taken on std::priority_queue shuffle around the instances of T. + uint64_t cutoffTime = usecTimestampNow() + TIME_BUDGET; while (!sortedThings.empty()) { const Thing& thing = sortedThings.top(); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 2114cbf944..20a5a76b73 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -19,7 +19,7 @@ #include "SharedLogging.h" const float defaultAACubeSize = 1.0f; -const int maxParentingChain = 30; +const int MAX_PARENTING_CHAIN_SIZE = 30; SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : _nestableType(nestableType), @@ -28,6 +28,7 @@ SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : // set flags in _transform _transform.setTranslation(glm::vec3(0.0f)); _transform.setRotation(glm::quat()); + _transform.setScale(1.0f); _scaleChanged = usecTimestampNow(); _translationChanged = usecTimestampNow(); _rotationChanged = usecTimestampNow(); @@ -85,6 +86,9 @@ Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const } if (parent) { result = parent->getTransform(_parentJointIndex, success, depth + 1); + if (getScalesWithParent()) { + result.setScale(parent->scaleForChildren()); + } } return result; } @@ -165,7 +169,7 @@ void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) { glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, - bool& success) { + bool scalesWithParent, bool& success) { QSharedPointer parentFinder = DependencyManager::get(); if (!parentFinder) { success = false; @@ -189,6 +193,9 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, if (!success) { return glm::vec3(0.0f); } + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } } success = true; @@ -199,7 +206,7 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, - bool& success) { + bool scalesWithParent, bool& success) { QSharedPointer parentFinder = DependencyManager::get(); if (!parentFinder) { success = false; @@ -223,6 +230,9 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, if (!success) { return glm::quat(); } + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } } success = true; @@ -231,7 +241,7 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, } glm::vec3 SpatiallyNestable::worldToLocalVelocity(const glm::vec3& velocity, const QUuid& parentID, - int parentJointIndex, bool& success) { + int parentJointIndex, bool scalesWithParent, bool& success) { SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success); if (!success || !parent) { return velocity; @@ -240,6 +250,9 @@ glm::vec3 SpatiallyNestable::worldToLocalVelocity(const glm::vec3& velocity, con if (!success) { return velocity; } + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } glm::vec3 parentVelocity = parent->getWorldVelocity(success); if (!success) { return velocity; @@ -249,7 +262,7 @@ glm::vec3 SpatiallyNestable::worldToLocalVelocity(const glm::vec3& velocity, con } glm::vec3 SpatiallyNestable::worldToLocalAngularVelocity(const glm::vec3& angularVelocity, const QUuid& parentID, - int parentJointIndex, bool& success) { + int parentJointIndex, bool scalesWithParent, bool& success) { SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success); if (!success || !parent) { return angularVelocity; @@ -258,12 +271,50 @@ glm::vec3 SpatiallyNestable::worldToLocalAngularVelocity(const glm::vec3& angula if (!success) { return angularVelocity; } + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } return glm::inverse(parentTransform.getRotation()) * angularVelocity; } + +glm::vec3 SpatiallyNestable::worldToLocalDimensions(const glm::vec3& dimensions, + const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success) { + if (!scalesWithParent) { + success = true; + return dimensions; + } + + QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + success = false; + return dimensions; + } + + Transform parentTransform; + auto parentWP = parentFinder->find(parentID, success); + if (!success) { + return dimensions; + } + + auto parent = parentWP.lock(); + if (!parentID.isNull() && !parent) { + success = false; + return dimensions; + } + + success = true; + if (parent) { + return dimensions / parent->scaleForChildren(); + } + return dimensions; +} + glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success) { Transform result; QSharedPointer parentFinder = DependencyManager::get(); @@ -289,6 +340,9 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, if (!success) { return glm::vec3(0.0f); } + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } } success = true; @@ -300,6 +354,7 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success) { Transform result; QSharedPointer parentFinder = DependencyManager::get(); @@ -325,7 +380,9 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, if (!success) { return glm::quat(); } - parentTransform.setScale(1.0f); + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } } success = true; @@ -336,7 +393,7 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, } glm::vec3 SpatiallyNestable::localToWorldVelocity(const glm::vec3& velocity, const QUuid& parentID, - int parentJointIndex, bool& success) { + int parentJointIndex, bool scalesWithParent, bool& success) { SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success); if (!success || !parent) { return velocity; @@ -345,6 +402,9 @@ glm::vec3 SpatiallyNestable::localToWorldVelocity(const glm::vec3& velocity, con if (!success) { return velocity; } + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } glm::vec3 parentVelocity = parent->getWorldVelocity(success); if (!success) { return velocity; @@ -354,7 +414,7 @@ glm::vec3 SpatiallyNestable::localToWorldVelocity(const glm::vec3& velocity, con } glm::vec3 SpatiallyNestable::localToWorldAngularVelocity(const glm::vec3& angularVelocity, const QUuid& parentID, - int parentJointIndex, bool& success) { + int parentJointIndex, bool scalesWithParent, bool& success) { SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success); if (!success || !parent) { return angularVelocity; @@ -363,10 +423,47 @@ glm::vec3 SpatiallyNestable::localToWorldAngularVelocity(const glm::vec3& angula if (!success) { return angularVelocity; } - + if (scalesWithParent) { + parentTransform.setScale(parent->scaleForChildren()); + } return parentTransform.getRotation() * angularVelocity; } + +glm::vec3 SpatiallyNestable::localToWorldDimensions(const glm::vec3& dimensions, + const QUuid& parentID, int parentJointIndex, bool scalesWithParent, + bool& success) { + if (!scalesWithParent) { + success = true; + return dimensions; + } + + Transform result; + QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + success = false; + return dimensions; + } + + Transform parentTransform; + auto parentWP = parentFinder->find(parentID, success); + if (!success) { + return dimensions; + } + + auto parent = parentWP.lock(); + if (!parentID.isNull() && !parent) { + success = false; + return dimensions; + } + + success = true; + if (parent) { + return dimensions * parent->scaleForChildren(); + } + return dimensions; +} + glm::vec3 SpatiallyNestable::getWorldPosition(bool& success) const { return getTransform(success).getTranslation(); } @@ -615,10 +712,10 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, i // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform jointInWorldFrame; - if (depth > maxParentingChain) { + if (depth > MAX_PARENTING_CHAIN_SIZE) { success = false; // someone created a loop. break it... - qCDebug(shared) << "Parenting loop detected."; + qCDebug(shared) << "Parenting loop detected: " << getID(); SpatiallyNestablePointer _this = getThisPointer(); _this->setParentID(QUuid()); bool setPositionSuccess; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 9cd38f9ce9..2a315e9230 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -50,19 +50,28 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex); - static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success); - static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); + static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success); + static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success); static glm::vec3 worldToLocalVelocity(const glm::vec3& velocity, const QUuid& parentID, - int parentJointIndex, bool& success); + int parentJointIndex, bool scalesWithParent, bool& success); static glm::vec3 worldToLocalAngularVelocity(const glm::vec3& angularVelocity, const QUuid& parentID, - int parentJointIndex, bool& success); + int parentJointIndex, bool scalesWithParent, bool& success); + static glm::vec3 worldToLocalDimensions(const glm::vec3& dimensions, const QUuid& parentID, + int parentJointIndex, bool scalesWithParent, bool& success); - static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success); - static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); + static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success); + static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success); static glm::vec3 localToWorldVelocity(const glm::vec3& velocity, - const QUuid& parentID, int parentJointIndex, bool& success); + const QUuid& parentID, int parentJointIndex, bool scalesWithParent, bool& success); static glm::vec3 localToWorldAngularVelocity(const glm::vec3& angularVelocity, - const QUuid& parentID, int parentJointIndex, bool& success); + const QUuid& parentID, int parentJointIndex, + bool scalesWithParent, bool& success); + static glm::vec3 localToWorldDimensions(const glm::vec3& dimensions, const QUuid& parentID, + int parentJointIndex, bool scalesWithParent, bool& success); static QString nestableTypeToString(NestableType nestableType); @@ -140,6 +149,9 @@ public: virtual glm::vec3 getLocalSNScale() const; virtual void setLocalSNScale(const glm::vec3& scale); + virtual bool getScalesWithParent() const { return false; } + virtual glm::vec3 scaleForChildren() const { return glm::vec3(1.0f); } + QList getChildren() const; bool hasChildren() const; diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index cde44e78c9..b3e3134380 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -103,6 +103,7 @@ case 'transactionHistory_linkClicked': tablet.gotoWebScreen(message.marketplaceLink, MARKETPLACES_INJECT_SCRIPT_URL); break; + case 'goToPurchases_fromWalletHome': case 'goToPurchases': tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); break; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 698dd93f29..fb49de1050 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -29,7 +29,7 @@ var commerceMode = false; var userIsLoggedIn = false; var walletNeedsSetup = false; - var metaverseServerURL = "https://metaverse.highfidelity.com"; + var marketplaceBaseURL = "https://highfidelity.com"; function injectCommonCode(isDirectoryPage) { @@ -58,7 +58,7 @@ ); // Footer. - var isInitialHiFiPage = location.href === metaverseServerURL + "/marketplace?"; + var isInitialHiFiPage = location.href === marketplaceBaseURL + "/marketplace?"; $("body").append( '
' + (!isInitialHiFiPage ? '' : '') + @@ -70,7 +70,7 @@ // Footer actions. $("#back-button").on("click", function () { - (document.referrer !== "") ? window.history.back() : window.location = (metaverseServerURL + "/marketplace?"); + (document.referrer !== "") ? window.history.back() : window.location = (marketplaceBaseURL + "/marketplace?"); }); $("#all-markets").on("click", function () { EventBridge.emitWebEvent(GOTO_DIRECTORY); @@ -89,7 +89,7 @@ window.location = "https://clara.io/library?gameCheck=true&public=true"; }); $('#exploreHifiMarketplace').on('click', function () { - window.location = "http://www.highfidelity.com/marketplace"; + window.location = marketplaceBaseURL + "/marketplace"; }); } @@ -250,7 +250,8 @@ itemName: name, itemPrice: price ? parseInt(price, 10) : 0, itemHref: href, - referrer: referrer + referrer: referrer, + itemAuthor: author })); } @@ -657,9 +658,9 @@ var HIFI_ITEM_PAGE = 3; var pageType = DIRECTORY; - if (location.href.indexOf("highfidelity.com/") !== -1) { pageType = HIFI; } + if (location.href.indexOf(marketplaceBaseURL + "/") !== -1) { pageType = HIFI; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } - if (location.href.indexOf("highfidelity.com/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } + if (location.href.indexOf(marketplaceBaseURL + "/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } injectCommonCode(pageType === DIRECTORY); switch (pageType) { @@ -693,7 +694,10 @@ commerceMode = !!parsedJsonMessage.data.commerceMode; userIsLoggedIn = !!parsedJsonMessage.data.userIsLoggedIn; walletNeedsSetup = !!parsedJsonMessage.data.walletNeedsSetup; - metaverseServerURL = parsedJsonMessage.data.metaverseServerURL; + marketplaceBaseURL = parsedJsonMessage.data.metaverseServerURL; + if (marketplaceBaseURL.indexOf('metaverse.') !== -1) { + marketplaceBaseURL = marketplaceBaseURL.replace('metaverse.', ''); + } injectCode(); } } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 15e72c8e8a..a5360974f6 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -8,7 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global Tablet, Script, HMD, UserActivityLogger, Entities */ +/* global Tablet, Script, HMD, UserActivityLogger, Entities, Account, Wallet, ContextOverlay, Settings, Camera, Vec3, + Quat, MyAvatar, Clipboard, Menu, Grid, Uuid, GlobalServices, openLoginWindow */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ var selectionDisplay = null; // for gridTool.js to ignore @@ -219,6 +220,41 @@ var selectionDisplay = null; // for gridTool.js to ignore function rezEntity(itemHref, isWearable) { var success = Clipboard.importEntities(itemHref); + var wearableLocalPosition = null; + var wearableLocalRotation = null; + var wearableLocalDimensions = null; + var wearableDimensions = null; + + if (isWearable) { + var wearableTransforms = Settings.getValue("io.highfidelity.avatarStore.checkOut.transforms"); + if (!wearableTransforms) { + // TODO delete this clause + wearableTransforms = Settings.getValue("io.highfidelity.avatarStore.checkOut.tranforms"); + } + var certPos = itemHref.search("certificate_id="); // TODO how do I parse a URL from here? + if (certPos >= 0) { + certPos += 15; // length of "certificate_id=" + var certURLEncoded = itemHref.substring(certPos); + var certB64Encoded = decodeURIComponent(certURLEncoded); + for (var key in wearableTransforms) { + if (wearableTransforms.hasOwnProperty(key)) { + var certificateTransforms = wearableTransforms[key].certificateTransforms; + if (certificateTransforms) { + for (var certID in certificateTransforms) { + if (certificateTransforms.hasOwnProperty(certID) && + certID == certB64Encoded) { + var certificateTransform = certificateTransforms[certID]; + wearableLocalPosition = certificateTransform.localPosition; + wearableLocalRotation = certificateTransform.localRotation; + wearableLocalDimensions = certificateTransform.localDimensions; + wearableDimensions = certificateTransform.dimensions; + } + } + } + } + } + } + } if (success) { var VERY_LARGE = 10000; @@ -287,6 +323,24 @@ var selectionDisplay = null; // for gridTool.js to ignore } } } + + if (isWearable) { + // apply the relative offsets saved during checkout + var offsets = {}; + if (wearableLocalPosition) { + offsets.localPosition = wearableLocalPosition; + } + if (wearableLocalRotation) { + offsets.localRotation = wearableLocalRotation; + } + if (wearableLocalDimensions) { + offsets.localDimensions = wearableLocalDimensions; + } else if (wearableDimensions) { + offsets.dimensions = wearableDimensions; + } + // we currently assume a wearable is a single entity + Entities.editEntity(pastedEntityIDs[0], offsets); + } } else { Window.notifyEditError("Can't import entities: entities would be out of bounds."); } diff --git a/tests/gpu-test/src/TestShapes.cpp b/tests/gpu-test/src/TestShapes.cpp index 253d89cf61..67a348c002 100644 --- a/tests/gpu-test/src/TestShapes.cpp +++ b/tests/gpu-test/src/TestShapes.cpp @@ -29,19 +29,18 @@ void TestShapes::renderTest(size_t testId, RenderArgs* args) { float seconds = secTimestampNow() - startSecs; seconds /= 4.0f; batch.setModelTransform(Transform()); - batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f); + const auto color = glm::vec4(0.8f, 0.25f, 0.25f, 1.0f); bool wire = (seconds - floorf(seconds) > 0.5f); int shapeIndex = ((int)seconds) % TYPE_COUNT; if (wire) { - geometryCache->renderWireShape(batch, SHAPE[shapeIndex]); + geometryCache->renderWireShape(batch, SHAPE[shapeIndex], color); } else { - geometryCache->renderShape(batch, SHAPE[shapeIndex]); + geometryCache->renderShape(batch, SHAPE[shapeIndex], color); } batch.setModelTransform(Transform().setScale(1.01f)); - batch._glColor4f(1, 1, 1, 1); - geometryCache->renderWireCube(batch); + geometryCache->renderWireCube(batch, glm::vec4(1,1,1,1)); }