diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index ad337a6361..247a42428a 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -189,15 +189,17 @@ Windows.ScrollingWindow { var grabbable = MenuInterface.isOptionChecked("Create Entities As Grabbable (except Zones, Particles, and Lights)"); if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { - var name = assetProxyModel.data(treeView.selection.currentIndex); - var modelURL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; - var textures = JSON.stringify({ "tex.picture": defaultURL}); - var shapeType = "box"; - var dynamic = false; - var collisionless = true; - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); - var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, grabbable, position, gravity); + Entities.addEntity({ + type: "Image", + name: assetProxyModel.data(treeView.selection.currentIndex), + imageURL: defaultURL, + keepAspectRatio: false, + dynamic: false, + collisionless: true, + grabbable: grabbable, + position: Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))), + gravity: Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0) + }); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; diff --git a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml index 256d951a45..493bfa2a30 100644 --- a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml +++ b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml @@ -75,6 +75,10 @@ Rectangle { if(materialUrlOrJson) { wearable.text = 'Material: ' + materialUrlOrJson; } + } else if (wearable.sourceUrl) { + wearable.text = extractTitleFromUrl(wearable.sourceUrl); + } else if (wearable.name) { + wearable.text = wearable.name; } wearablesCombobox.model.append(wearable); } diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index c8ec7238d6..f7dc26df5f 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -176,6 +176,7 @@ Item { Item { property alias buttonGlyphText: buttonGlyph.text; property alias buttonText: buttonText.text; + property alias glyphSize: buttonGlyph.size; property string buttonColor: hifi.colors.black; property string buttonColor_hover: hifi.colors.blueHighlight; property alias enabled: buttonMouseArea.enabled; @@ -186,7 +187,8 @@ Item { anchors.top: parent.top; anchors.topMargin: 4; anchors.horizontalCenter: parent.horizontalCenter; - anchors.bottom: parent.verticalCenter; + anchors.bottom: buttonText.visible ? parent.verticalCenter : parent.bottom; + anchors.bottomMargin: buttonText.visible ? 0 : 4; width: parent.width; size: 40; horizontalAlignment: Text.AlignHCenter; @@ -196,6 +198,7 @@ Item { RalewayRegular { id: buttonText; + visible: text !== ""; anchors.top: parent.verticalCenter; anchors.topMargin: 4; anchors.bottom: parent.bottom; @@ -300,7 +303,7 @@ Item { anchors.right: certificateButton.left; anchors.top: parent.top; anchors.bottom: parent.bottom; - width: 78; + width: 72; onLoaded: { item.buttonGlyphText = hifi.glyphs.uninstall; @@ -310,6 +313,10 @@ Item { Commerce.uninstallApp(root.itemHref); } } + + onVisibleChanged: { + trashButton.updateProperties(); + } } Loader { @@ -319,7 +326,7 @@ Item { anchors.right: uninstallButton.visible ? uninstallButton.left : certificateButton.left; anchors.top: parent.top; anchors.bottom: parent.bottom; - width: 84; + width: 78; onLoaded: { item.buttonGlyphText = hifi.glyphs.update; @@ -339,6 +346,45 @@ Item { }); } } + + onVisibleChanged: { + trashButton.updateProperties(); + } + } + + Loader { + id: trashButton; + visible: root.itemEdition > 0; + sourceComponent: contextCardButton; + anchors.right: updateButton.visible ? updateButton.left : (uninstallButton.visible ? uninstallButton.left : certificateButton.left); + anchors.top: parent.top; + anchors.bottom: parent.bottom; + width: (updateButton.visible && uninstallButton.visible) ? 15 : 78; + + onLoaded: { + item.buttonGlyphText = hifi.glyphs.trash; + updateProperties(); + item.buttonClicked = function() { + sendToPurchases({method: 'showTrashLightbox', + isInstalled: root.isInstalled, + itemHref: root.itemHref, + itemName: root.itemName, + certID: root.certificateId, + itemType: root.itemType, + wornEntityID: root.wornEntityID + }); + } + } + + function updateProperties() { + if (updateButton.visible && uninstallButton.visible) { + item.buttonText = ""; + item.glyphSize = 20; + } else { + item.buttonText = "Send to Trash"; + item.glyphSize = 30; + } + } } } diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 18d6bc9f78..9433618b6b 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -651,6 +651,42 @@ Rectangle { lightboxPopup.visible = false; }; lightboxPopup.visible = true; + } else if (msg.method === "showTrashLightbox") { + lightboxPopup.titleText = "Send \"" + msg.itemName + "\" to Trash"; + lightboxPopup.bodyText = "Sending this item to the Trash means you will no longer own this item " + + "and it will be inaccessible to you from Purchases.\n\nThis action cannot be undone."; + lightboxPopup.button1text = "CANCEL"; + lightboxPopup.button1method = function() { + lightboxPopup.visible = false; + } + lightboxPopup.button2text = "CONFIRM"; + lightboxPopup.button2method = function() { + if (msg.isInstalled) { + Commerce.uninstallApp(msg.itemHref); + } + + if (MyAvatar.skeletonModelURL === msg.itemHref) { + MyAvatar.useFullAvatarURL(''); + } + + if (msg.itemType === "wearable" && msg.wornEntityID !== '') { + Entities.deleteEntity(msg.wornEntityID); + purchasesModel.setProperty(index, 'wornEntityID', ''); + } + + Commerce.transferAssetToUsername("trashbot", msg.certID, 1, "Sent " + msg.itemName + " to trash."); + + lightboxPopup.titleText = '"' + msg.itemName + '" Sent to Trash'; + lightboxPopup.button1text = "OK"; + lightboxPopup.button1method = function() { + root.purchasesReceived = false; + lightboxPopup.visible = false; + getPurchases(); + } + lightboxPopup.button2text = ""; + lightboxPopup.bodyText = ""; + }; + lightboxPopup.visible = true; } else if (msg.method === "showChangeAvatarLightbox") { lightboxPopup.titleText = "Change Avatar"; lightboxPopup.bodyText = "This will change your current avatar to " + msg.itemName + " while retaining your wearables."; diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index f665032b01..b5374b2fe0 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -189,15 +189,17 @@ Rectangle { var grabbable = MenuInterface.isOptionChecked("Create Entities As Grabbable (except Zones, Particles, and Lights)"); if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { - var name = assetProxyModel.data(treeView.selection.currentIndex); - var modelURL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; - var textures = JSON.stringify({ "tex.picture": defaultURL}); - var shapeType = "box"; - var dynamic = false; - var collisionless = true; - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); - var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); - Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, collisionless, grabbable, position, gravity); + Entities.addEntity({ + type: "Image", + name: assetProxyModel.data(treeView.selection.currentIndex), + imageURL: defaultURL, + keepAspectRatio: false, + dynamic: false, + collisionless: true, + grabbable: grabbable, + position: Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))), + gravity: Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0) + }); } else { var SHAPE_TYPE_NONE = 0; var SHAPE_TYPE_SIMPLE_HULL = 1; diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index fa268ad6ee..a01d978b2f 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -15,6 +15,7 @@ Item { property var openBrowser: null; property string subMenu: "" signal showDesktop(); + signal screenChanged(var type, var url); property bool shown: true property int currentApp: -1; property alias tabletApps: tabletApps @@ -113,6 +114,8 @@ Item { if (loader.item.hasOwnProperty("gotoPreviousApp")) { loader.item.gotoPreviousApp = true; } + + screenChanged("Web", url) }); } } @@ -266,6 +269,24 @@ Item { if (callback) { callback(); } + + var type = "Unknown"; + if (newSource === "") { + type = "Closed"; + } else if (newSource === "hifi/tablet/TabletMenu.qml") { + type = "Menu"; + } else if (newSource === "hifi/tablet/TabletHome.qml") { + type = "Home"; + } else if (newSource === "hifi/tablet/TabletWebView.qml") { + // Handled in `callback()` + return; + } else if (newSource.toLowerCase().indexOf(".qml") > -1) { + type = "QML"; + } else { + console.log("newSource is of unknown type!"); + } + + screenChanged(type, newSource); }); } } diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index d55ec363f0..ef2df5e218 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -20,6 +20,7 @@ Windows.ScrollingWindow { id: tabletRoot objectName: "tabletRoot" property string username: "Unknown user" + signal screenChanged(var type, var url); property var rootMenu; property string subMenu: "" @@ -69,6 +70,8 @@ Windows.ScrollingWindow { if (loader.item.hasOwnProperty("closeButtonVisible")) { loader.item.closeButtonVisible = false; } + + screenChanged("Web", url); }); } @@ -179,7 +182,25 @@ Windows.ScrollingWindow { if (callback) { callback(); + } + + var type = "Unknown"; + if (newSource === "") { + type = "Closed"; + } else if (newSource === "hifi/tablet/TabletMenu.qml") { + type = "Menu"; + } else if (newSource === "hifi/tablet/TabletHome.qml") { + type = "Home"; + } else if (newSource === "hifi/tablet/TabletWebView.qml") { + // Handled in `callback()` + return; + } else if (newSource.toLowerCase().indexOf(".qml") > -1) { + type = "QML"; + } else { + console.log("newSource is of unknown type!"); } + + screenChanged(type, newSource); }); } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 36fb666f69..5e41530d93 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2315,6 +2315,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); + EntityTreeRenderer::setGetAvatarUpOperator([] { + return DependencyManager::get()->getMyAvatar()->getWorldOrientation() * Vectors::UP; + }); + // Preload Tablet sounds DependencyManager::get()->preloadSounds(); DependencyManager::get()->createKeyboard(); @@ -2460,6 +2464,10 @@ void Application::updateHeartbeat() const { void Application::onAboutToQuit() { emit beforeAboutToQuit(); + if (getLoginDialogPoppedUp() && _firstRun.get()) { + _firstRun.set(false); + } + foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { if (inputPlugin->isActive()) { inputPlugin->deactivate(); @@ -5252,7 +5260,8 @@ void Application::resumeAfterLoginDialogActionTaken() { // this will force the model the look at the correct directory (weird order of operations issue) scriptEngines->reloadLocalFiles(); - if (!_defaultScriptsLocation.exists()) { + // if the --scripts command-line argument was used. + if (!_defaultScriptsLocation.exists() && (arguments().indexOf(QString("--").append(SCRIPTS_SWITCH))) != -1) { scriptEngines->loadDefaultScripts(); scriptEngines->defaultScriptsLocationOverridden(true); } else { @@ -5260,39 +5269,25 @@ void Application::resumeAfterLoginDialogActionTaken() { } } - if (_firstRun.get()) { - // not first run anymore since action was taken. - _firstRun.set(false); - } - auto accountManager = DependencyManager::get(); auto addressManager = DependencyManager::get(); // restart domain handler. nodeList->getDomainHandler().resetting(); - if (!accountManager->isLoggedIn()) { + QVariant testProperty = property(hifi::properties::TEST); + if (testProperty.isValid()) { + const auto testScript = property(hifi::properties::TEST).toUrl(); + // Set last parameter to exit interface when the test script finishes, if so requested + DependencyManager::get()->loadScript(testScript, false, false, false, false, quitWhenFinished); + // This is done so we don't get a "connection time-out" message when we haven't passed in a URL. if (arguments().contains("--url")) { auto reply = SandboxUtils::getStatus(); connect(reply, &QNetworkReply::finished, this, [this, reply] { handleSandboxStatus(reply); }); - } else { - addressManager->goToEntry(); } } else { - QVariant testProperty = property(hifi::properties::TEST); - if (testProperty.isValid()) { - const auto testScript = property(hifi::properties::TEST).toUrl(); - // Set last parameter to exit interface when the test script finishes, if so requested - DependencyManager::get()->loadScript(testScript, false, false, false, false, quitWhenFinished); - // This is done so we don't get a "connection time-out" message when we haven't passed in a URL. - if (arguments().contains("--url")) { - auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [this, reply] { handleSandboxStatus(reply); }); - } - } else { - auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [this, reply] { handleSandboxStatus(reply); }); - } + auto reply = SandboxUtils::getStatus(); + connect(reply, &QNetworkReply::finished, this, [this, reply] { handleSandboxStatus(reply); }); } auto menu = Menu::getInstance(); @@ -7698,16 +7693,13 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { EntityItemProperties properties; - properties.setType(EntityTypes::Model); properties.setName(mapping.right(mapping.length() - 1)); if (filePath.toLower().endsWith(PNG_EXTENSION) || filePath.toLower().endsWith(JPG_EXTENSION)) { - QJsonObject textures { - {"tex.picture", QString("atp:" + mapping) } - }; - properties.setModelURL("https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"); - properties.setTextures(QJsonDocument(textures).toJson(QJsonDocument::Compact)); - properties.setShapeType(SHAPE_TYPE_BOX); + properties.setType(EntityTypes::Image); + properties.setImageURL(QString("atp:" + mapping)); + properties.setKeepAspectRatio(false); } else { + properties.setType(EntityTypes::Model); properties.setModelURL("atp:" + mapping); properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0224e5687a..397817cf60 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2418,10 +2418,10 @@ void MyAvatar::attachmentDataToEntityProperties(const AttachmentData& data, Enti void MyAvatar::initHeadBones() { int neckJointIndex = -1; if (_skeletonModel->isLoaded()) { - neckJointIndex = _skeletonModel->getHFMModel().neckJointIndex; + neckJointIndex = getJointIndex("Neck"); } if (neckJointIndex == -1) { - neckJointIndex = (_skeletonModel->getHFMModel().headJointIndex - 1); + neckJointIndex = (getJointIndex("Head") - 1); if (neckJointIndex < 0) { // return if the head is not even there. can't cauterize!! return; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index a8a7dd16c2..356b365f93 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -301,8 +301,8 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { eyeParams.eyeSaccade = head->getSaccade(); eyeParams.modelRotation = getRotation(); eyeParams.modelTranslation = getTranslation(); - eyeParams.leftEyeJointIndex = hfmModel.leftEyeJointIndex; - eyeParams.rightEyeJointIndex = hfmModel.rightEyeJointIndex; + eyeParams.leftEyeJointIndex = _rig.indexOfJoint("LeftEye"); + eyeParams.rightEyeJointIndex = _rig.indexOfJoint("RightEye"); _rig.updateFromEyeParameters(eyeParams); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index b343d2a1ad..6e9c91785f 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -95,7 +95,12 @@ void LoginDialog::toggleAction() { } else { // change the menu item to login loginAction->setText("Log In / Sign Up"); - connection = connect(loginAction, &QAction::triggered, [] { LoginDialog::showWithSelection(); }); + connection = connect(loginAction, &QAction::triggered, [] { + // if not in login state, show. + if (!qApp->getLoginDialogPoppedUp()) { + LoginDialog::showWithSelection(); + } + }); } } diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index e24e3b3ed8..d3d0c873a4 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -82,18 +82,21 @@ void Image3DOverlay::render(RenderArgs* args) { float imageHeight = _texture->getHeight(); QRect fromImage; - if (_fromImage.isNull()) { + if (_fromImage.width() <= 0) { fromImage.setX(0); - fromImage.setY(0); fromImage.setWidth(imageWidth); - fromImage.setHeight(imageHeight); } else { float scaleX = imageWidth / _texture->getOriginalWidth(); - float scaleY = imageHeight / _texture->getOriginalHeight(); - fromImage.setX(scaleX * _fromImage.x()); - fromImage.setY(scaleY * _fromImage.y()); fromImage.setWidth(scaleX * _fromImage.width()); + } + + if (_fromImage.height() <= 0) { + fromImage.setY(0); + fromImage.setHeight(imageHeight); + } else { + float scaleY = imageHeight / _texture->getOriginalHeight(); + fromImage.setY(scaleY * _fromImage.y()); fromImage.setHeight(scaleY * _fromImage.height()); } @@ -247,9 +250,6 @@ QVariant Image3DOverlay::getProperty(const QString& property) { if (property == "subImage") { return _fromImage; } - if (property == "offsetPosition") { - return vec3toVariant(getOffsetPosition()); - } if (property == "emissive") { return _emissive; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 128ac05b81..44fdd8797f 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -343,18 +343,18 @@ void Rig::initJointStates(const HFMModel& hfmModel, const glm::mat4& modelOffset buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); - _rootJointIndex = hfmModel.rootJointIndex; - _leftEyeJointIndex = hfmModel.leftEyeJointIndex; - _rightEyeJointIndex = hfmModel.rightEyeJointIndex; - _leftHandJointIndex = hfmModel.leftHandJointIndex; + _rootJointIndex = indexOfJoint("Hips"); + _leftEyeJointIndex = indexOfJoint("LeftEye"); + _rightEyeJointIndex = indexOfJoint("RightEye"); + _leftHandJointIndex = indexOfJoint("LeftHand"); _leftElbowJointIndex = _leftHandJointIndex >= 0 ? hfmModel.joints.at(_leftHandJointIndex).parentIndex : -1; _leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? hfmModel.joints.at(_leftElbowJointIndex).parentIndex : -1; - _rightHandJointIndex = hfmModel.rightHandJointIndex; + _rightHandJointIndex = indexOfJoint("RightHand"); _rightElbowJointIndex = _rightHandJointIndex >= 0 ? hfmModel.joints.at(_rightHandJointIndex).parentIndex : -1; _rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? hfmModel.joints.at(_rightElbowJointIndex).parentIndex : -1; - _leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.leftEyeJointIndex); - _rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.rightEyeJointIndex); + _leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(indexOfJoint("LeftEye")); + _rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(indexOfJoint("RightEye")); } void Rig::reset(const HFMModel& hfmModel) { @@ -390,18 +390,18 @@ void Rig::reset(const HFMModel& hfmModel) { buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); - _rootJointIndex = hfmModel.rootJointIndex; - _leftEyeJointIndex = hfmModel.leftEyeJointIndex; - _rightEyeJointIndex = hfmModel.rightEyeJointIndex; - _leftHandJointIndex = hfmModel.leftHandJointIndex; + _rootJointIndex = indexOfJoint("Hips");; + _leftEyeJointIndex = indexOfJoint("LeftEye"); + _rightEyeJointIndex = indexOfJoint("RightEye"); + _leftHandJointIndex = indexOfJoint("LeftHand"); _leftElbowJointIndex = _leftHandJointIndex >= 0 ? hfmModel.joints.at(_leftHandJointIndex).parentIndex : -1; _leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? hfmModel.joints.at(_leftElbowJointIndex).parentIndex : -1; - _rightHandJointIndex = hfmModel.rightHandJointIndex; + _rightHandJointIndex = indexOfJoint("RightHand"); _rightElbowJointIndex = _rightHandJointIndex >= 0 ? hfmModel.joints.at(_rightHandJointIndex).parentIndex : -1; _rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? hfmModel.joints.at(_rightElbowJointIndex).parentIndex : -1; - _leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.leftEyeJointIndex); - _rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.rightEyeJointIndex); + _leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(indexOfJoint("LeftEye")); + _rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(indexOfJoint("RightEye")); if (!_animGraphURL.isEmpty()) { _animNode.reset(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index b4ea9c20f9..0761cdf597 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1314,7 +1314,7 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const { case CAMERA_MATRIX_INDEX: { glm::quat rotation; if (_skeletonModel && _skeletonModel->isActive()) { - int headJointIndex = _skeletonModel->getHFMModel().headJointIndex; + int headJointIndex = getJointIndex("Head"); if (headJointIndex >= 0) { _skeletonModel->getAbsoluteJointRotationInRigFrame(headJointIndex, rotation); } @@ -1363,7 +1363,7 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const { case CAMERA_MATRIX_INDEX: { glm::vec3 translation; if (_skeletonModel && _skeletonModel->isActive()) { - int headJointIndex = _skeletonModel->getHFMModel().headJointIndex; + int headJointIndex = getJointIndex("Head"); if (headJointIndex >= 0) { _skeletonModel->getAbsoluteJointTranslationInRigFrame(headJointIndex, translation); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index 36e37dd3d4..7f2dbda3de 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -66,7 +66,7 @@ void SkeletonModel::initJointStates() { } // Determine the default eye position for avatar scale = 1.0 - int headJointIndex = hfmModel.headJointIndex; + int headJointIndex = _rig.indexOfJoint("Head"); if (0 > headJointIndex || headJointIndex >= _rig.getJointStateCount()) { qCWarning(avatars_renderer) << "Bad head joint! Got:" << headJointIndex << "jointCount:" << _rig.getJointStateCount(); } @@ -74,7 +74,7 @@ void SkeletonModel::initJointStates() { getEyeModelPositions(leftEyePosition, rightEyePosition); glm::vec3 midEyePosition = (leftEyePosition + rightEyePosition) / 2.0f; - int rootJointIndex = hfmModel.rootJointIndex; + int rootJointIndex = _rig.indexOfJoint("Hips"); glm::vec3 rootModelPosition; getJointPosition(rootJointIndex, rootModelPosition); @@ -96,7 +96,6 @@ void SkeletonModel::initJointStates() { // Called within Model::simulate call, below. void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { assert(!_owningAvatar->isMyAvatar()); - const HFMModel& hfmModel = getHFMModel(); Head* head = _owningAvatar->getHead(); @@ -124,7 +123,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { // If the head is not positioned, updateEyeJoints won't get the math right glm::quat headOrientation; - _rig.getJointRotation(hfmModel.headJointIndex, headOrientation); + _rig.getJointRotation(_rig.indexOfJoint("Head"), headOrientation); glm::vec3 eulers = safeEulerAngles(headOrientation); head->setBasePitch(glm::degrees(-eulers.x)); head->setBaseYaw(glm::degrees(eulers.y)); @@ -135,8 +134,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { eyeParams.eyeSaccade = glm::vec3(0.0f); eyeParams.modelRotation = getRotation(); eyeParams.modelTranslation = getTranslation(); - eyeParams.leftEyeJointIndex = hfmModel.leftEyeJointIndex; - eyeParams.rightEyeJointIndex = hfmModel.rightEyeJointIndex; + eyeParams.leftEyeJointIndex = _rig.indexOfJoint("LeftEye"); + eyeParams.rightEyeJointIndex = _rig.indexOfJoint("RightEye"); _rig.updateFromEyeParameters(eyeParams); } @@ -259,45 +258,44 @@ bool SkeletonModel::getRightShoulderPosition(glm::vec3& position) const { } bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { - return isActive() && getJointPositionInWorldFrame(getHFMModel().headJointIndex, headPosition); + return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition); } bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { - return isActive() && getJointPositionInWorldFrame(getHFMModel().neckJointIndex, neckPosition); + return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Neck"), neckPosition); } bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const { - return isActive() && getJointPosition(getHFMModel().neckJointIndex, neckPosition); + return isActive() && getJointPosition(_rig.indexOfJoint("Neck"), neckPosition); } bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { if (!isActive()) { return false; } - const HFMModel& hfmModel = getHFMModel(); - if (getJointPosition(hfmModel.leftEyeJointIndex, firstEyePosition) && - getJointPosition(hfmModel.rightEyeJointIndex, secondEyePosition)) { + if (getJointPosition(_rig.indexOfJoint("LeftEye"), firstEyePosition) && + getJointPosition(_rig.indexOfJoint("RightEye"), secondEyePosition)) { return true; } // no eye joints; try to estimate based on head/neck joints glm::vec3 neckPosition, headPosition; - if (getJointPosition(hfmModel.neckJointIndex, neckPosition) && - getJointPosition(hfmModel.headJointIndex, headPosition)) { + if (getJointPosition(_rig.indexOfJoint("Neck"), neckPosition) && + getJointPosition(_rig.indexOfJoint("Head"), headPosition)) { const float EYE_PROPORTION = 0.6f; glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION); glm::quat headRotation; - getJointRotation(hfmModel.headJointIndex, headRotation); + getJointRotation(_rig.indexOfJoint("Head"), headRotation); const float EYES_FORWARD = 0.25f; const float EYE_SEPARATION = 0.1f; float headHeight = glm::distance(neckPosition, headPosition); firstEyePosition = baseEyePosition + headRotation * glm::vec3(EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight; secondEyePosition = baseEyePosition + headRotation * glm::vec3(-EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight; return true; - } else if (getJointPosition(hfmModel.headJointIndex, headPosition)) { + } else if (getJointPosition(_rig.indexOfJoint("Head"), headPosition)) { glm::vec3 baseEyePosition = headPosition; glm::quat headRotation; - getJointRotation(hfmModel.headJointIndex, headRotation); + getJointRotation(_rig.indexOfJoint("Head"), headRotation); const float EYES_FORWARD_HEAD_ONLY = 0.30f; const float EYE_SEPARATION = 0.1f; firstEyePosition = baseEyePosition + headRotation * glm::vec3(EYE_SEPARATION, 0.0f, EYES_FORWARD_HEAD_ONLY); @@ -331,7 +329,7 @@ void SkeletonModel::computeBoundingShape() { } const HFMModel& hfmModel = getHFMModel(); - if (hfmModel.joints.isEmpty() || hfmModel.rootJointIndex == -1) { + if (hfmModel.joints.isEmpty() || _rig.indexOfJoint("Hips") == -1) { // rootJointIndex == -1 if the avatar model has no skeleton return; } @@ -369,7 +367,7 @@ void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch& } bool SkeletonModel::hasSkeleton() { - return isActive() ? getHFMModel().rootJointIndex != -1 : false; + return isActive() ? _rig.indexOfJoint("Hips") != -1 : false; } void SkeletonModel::onInvalidate() { diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h index c53cf8d333..ef0e1e0fae 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h @@ -41,10 +41,10 @@ public: void updateAttitude(const glm::quat& orientation); /// Returns the index of the left hand joint, or -1 if not found. - int getLeftHandJointIndex() const { return isActive() ? getHFMModel().leftHandJointIndex : -1; } + int getLeftHandJointIndex() const { return isActive() ? _rig.indexOfJoint("LeftHand") : -1; } /// Returns the index of the right hand joint, or -1 if not found. - int getRightHandJointIndex() const { return isActive() ? getHFMModel().rightHandJointIndex : -1; } + int getRightHandJointIndex() const { return isActive() ? _rig.indexOfJoint("RightHand") : -1; } bool getLeftGrabPosition(glm::vec3& position) const; bool getRightGrabPosition(glm::vec3& position) const; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 980ff8834c..4fe77c90ad 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -41,6 +41,7 @@ #include std::function EntityTreeRenderer::_entitiesShouldFadeFunction = []() { return true; }; +std::function EntityTreeRenderer::_getAvatarUpOperator = []() { return Vectors::UP; }; QString resolveScriptURL(const QString& scriptUrl) { auto normalizedScriptUrl = DependencyManager::get()->normalizeURL(scriptUrl); @@ -61,8 +62,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf _lastPointerEventValid(false), _viewState(viewState), _scriptingServices(scriptingServices), - _displayModelBounds(false), - _layeredZones(this) + _displayModelBounds(false) { setMouseRayPickResultOperator([](unsigned int rayPickID) { RayToEntityIntersectionResult entityResult; @@ -516,41 +516,36 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVectorgetScript().isEmpty(); // only consider entities that are zones or have scripts, all other entities can - // be ignored because they can have events fired on them. + // be ignored because they can't have events fired on them. // FIXME - this could be optimized further by determining if the script is loaded // and if it has either an enterEntity or leaveEntity method // // also, don't flag a scripted entity as containing the avatar until the script is loaded, // so that the script is awake in time to receive the "entityEntity" call (even if the entity is a zone). - if ((!hasScript && isZone) || - (hasScript && entity->isScriptPreloadFinished())) { - // now check to see if the point contains our entity, this can be expensive if - // the entity has a collision hull - if (entity->contains(_avatarPosition)) { + bool contains = false; + bool scriptHasLoaded = hasScript && entity->isScriptPreloadFinished(); + if (isZone || scriptHasLoaded) { + contains = entity->contains(_avatarPosition); + } + + if (contains) { + // if this entity is a zone and visible, add it to our layered zones + if (isZone && entity->getVisible() && renderableForEntity(entity)) { + _layeredZones.insert(std::dynamic_pointer_cast(entity)); + } + + if ((!hasScript && isZone) || scriptHasLoaded) { if (entitiesContainingAvatar) { *entitiesContainingAvatar << entity->getEntityItemID(); } - - // if this entity is a zone and visible, determine if it is the bestZone - if (isZone && entity->getVisible() && renderableForEntity(entity)) { - auto zone = std::dynamic_pointer_cast(entity); - _layeredZones.insert(zone); - } - } } } + } // check if our layered zones have changed - if (_layeredZones.empty()) { - if (oldLayeredZones.empty()) { - return; - } - } else if (!oldLayeredZones.empty()) { - if (_layeredZones.contains(oldLayeredZones)) { - return; - } + if ((_layeredZones.empty() && oldLayeredZones.empty()) || (!oldLayeredZones.empty() && _layeredZones.contains(oldLayeredZones))) { + return; } - _layeredZones.apply(); applyLayeredZones(); @@ -653,8 +648,8 @@ bool EntityTreeRenderer::applyLayeredZones() { } else { qCWarning(entitiesrenderer) << "EntityTreeRenderer::applyLayeredZones(), Unexpected null scene, possibly during application shutdown"; } - - return true; + + return true; } void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { @@ -1151,18 +1146,12 @@ std::pair EntityTreeRenderer:: return { it, success }; } -void EntityTreeRenderer::LayeredZones::apply() { - assert(_entityTreeRenderer); -} - void EntityTreeRenderer::LayeredZones::update(std::shared_ptr zone) { - assert(_entityTreeRenderer); bool isVisible = zone->isVisible(); if (empty() && isVisible) { // there are no zones: set this one insert(zone); - apply(); return; } else { LayeredZone zoneLayer(zone); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 4ba1a0060b..d0bd8a97e3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -117,6 +117,9 @@ public: // Access the workload Space workload::SpacePointer getWorkloadSpace() const { return _space; } + static void setGetAvatarUpOperator(std::function getAvatarUpOperator) { _getAvatarUpOperator = getAvatarUpOperator; } + static glm::vec3 getAvatarUp() { return _getAvatarUpOperator(); } + signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); @@ -205,42 +208,28 @@ private: class LayeredZones : public std::set { public: - LayeredZones(EntityTreeRenderer* parent) : _entityTreeRenderer(parent) {} + LayeredZones() {}; LayeredZones(LayeredZones&& other); // avoid accidental misconstruction - LayeredZones() = delete; LayeredZones(const LayeredZones&) = delete; LayeredZones& operator=(const LayeredZones&) = delete; LayeredZones& operator=(LayeredZones&&) = delete; void clear(); std::pair insert(const LayeredZone& layer); - - void apply(); void update(std::shared_ptr zone); - bool contains(const LayeredZones& other); std::shared_ptr getZone() { return empty() ? nullptr : begin()->zone; } private: - void applyPartial(iterator layer); - std::map _map; - iterator _skyboxLayer{ end() }; - EntityTreeRenderer* _entityTreeRenderer; + iterator _skyboxLayer { end() }; }; LayeredZones _layeredZones; - QString _zoneUserData; - NetworkTexturePointer _ambientTexture; - NetworkTexturePointer _skyboxTexture; - QString _ambientTextureURL; - QString _skyboxTextureURL; float _avgRenderableUpdateCost { 0.0f }; - bool _pendingAmbientTexture { false }; - bool _pendingSkyboxTexture { false }; uint64_t _lastZoneCheck { 0 }; const uint64_t ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz @@ -262,6 +251,8 @@ private: mutable std::mutex _spaceLock; workload::SpacePointer _space{ new workload::Space() }; workload::Transaction::Updates _spaceUpdates; + + static std::function _getAvatarUpOperator; }; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 75d06191ea..a149b0255c 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -25,6 +25,7 @@ #include "RenderableWebEntityItem.h" #include "RenderableZoneEntityItem.h" #include "RenderableMaterialEntityItem.h" +#include "RenderableImageEntityItem.h" using namespace render; @@ -217,22 +218,39 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, using Type = EntityTypes::EntityType_t; auto type = entity->getType(); switch (type) { - case Type::Light: - result = make_renderer(entity); - break; - case Type::Line: - result = make_renderer(entity); + case Type::Shape: + case Type::Box: + case Type::Sphere: + result = make_renderer(entity); break; case Type::Model: result = make_renderer(entity); break; + case Type::Text: + result = make_renderer(entity); + break; + + case Type::Image: + result = make_renderer(entity); + break; + + case Type::Web: + if (!nsightActive()) { + result = make_renderer(entity); + } + break; + case Type::ParticleEffect: result = make_renderer(entity); break; + case Type::Line: + result = make_renderer(entity); + break; + case Type::PolyLine: result = make_renderer(entity); break; @@ -241,20 +259,8 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, result = make_renderer(entity); break; - case Type::Shape: - case Type::Box: - case Type::Sphere: - result = make_renderer(entity); - break; - - case Type::Text: - result = make_renderer(entity); - break; - - case Type::Web: - if (!nsightActive()) { - result = make_renderer(entity); - } + case Type::Light: + result = make_renderer(entity); break; case Type::Zone: diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp new file mode 100644 index 0000000000..7c5b7fc0da --- /dev/null +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -0,0 +1,218 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 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 "RenderableImageEntityItem.h" + +#include +#include + +using namespace render; +using namespace render::entities; + +ImageEntityRenderer::ImageEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { + _geometryId = DependencyManager::get()->allocateID(); +} + +ImageEntityRenderer::~ImageEntityRenderer() { + auto geometryCache = DependencyManager::get(); + if (geometryCache) { + geometryCache->releaseID(_geometryId); + } +} + +bool ImageEntityRenderer::isTransparent() const { + return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f; +} + +bool ImageEntityRenderer::needsRenderUpdate() const { + bool textureLoadedChanged = resultWithReadLock([&] { + return (!_textureIsLoaded && _texture && _texture->isLoaded()); + }); + + if (textureLoadedChanged) { + return true; + } + + return Parent::needsRenderUpdate(); +} + +bool ImageEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { + bool needsUpdate = resultWithReadLock([&] { + if (_imageURL != entity->getImageURL()) { + return true; + } + + if (_emissive != entity->getEmissive()) { + return true; + } + + if (_keepAspectRatio != entity->getKeepAspectRatio()) { + return true; + } + + if (_billboardMode != entity->getBillboardMode()) { + return true; + } + + if (_subImage != entity->getSubImage()) { + return true; + } + + if (_color != entity->getColor()) { + return true; + } + + if (_alpha != entity->getAlpha()) { + return true; + } + + return false; + }); + + return needsUpdate; +} + +void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + withWriteLock([&] { + auto imageURL = entity->getImageURL(); + if (_imageURL != imageURL) { + _imageURL = imageURL; + if (imageURL.isEmpty()) { + _texture.reset(); + } else { + _texture = DependencyManager::get()->getTexture(_imageURL); + } + _textureIsLoaded = false; + } + + _emissive = entity->getEmissive(); + _keepAspectRatio = entity->getKeepAspectRatio(); + _billboardMode = entity->getBillboardMode(); + _subImage = entity->getSubImage(); + + _color = entity->getColor(); + _alpha = entity->getAlpha(); + + if (!_textureIsLoaded && _texture && _texture->isLoaded()) { + _textureIsLoaded = true; + } + }); + + void* key = (void*)this; + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity]() { + withWriteLock([&] { + _dimensions = entity->getScaledDimensions(); + updateModelTransformAndBound(); + _renderTransform = getModelTransform(); + }); + }); +} + +ShapeKey ImageEntityRenderer::getShapeKey() { + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); + if (isTransparent()) { + builder.withTranslucent(); + } + + withReadLock([&] { + if (_emissive) { + builder.withUnlit(); + } + }); + + return builder.build(); +} + +void ImageEntityRenderer::doRender(RenderArgs* args) { + NetworkTexturePointer texture; + QRect subImage; + glm::u8vec3 color; + glm::vec3 dimensions; + Transform transform; + withReadLock([&] { + texture = _texture; + subImage = _subImage; + color = _color; + dimensions = _dimensions; + transform = _renderTransform; + }); + + if (!_visible || !texture || !texture->isLoaded()) { + return; + } + + Q_ASSERT(args->_batch); + gpu::Batch* batch = args->_batch; + + if (_billboardMode == BillboardMode::YAW) { + //rotate about vertical to face the camera + glm::vec3 dPosition = args->getViewFrustum().getPosition() - transform.getTranslation(); + // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees + float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); + glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); + transform.setRotation(orientation); + } else if (_billboardMode == BillboardMode::FULL) { + glm::vec3 billboardPos = transform.getTranslation(); + glm::vec3 cameraPos = args->getViewFrustum().getPosition(); + // use the referencial from the avatar, y isn't always up + glm::vec3 avatarUP = EntityTreeRenderer::getAvatarUp(); + // check to see if glm::lookAt will work / using glm::lookAt variable name + glm::highp_vec3 s(glm::cross(billboardPos - cameraPos, avatarUP)); + + // make sure s is not NaN for any component + if (glm::length2(s) > 0.0f) { + glm::quat rotation(conjugate(toQuat(glm::lookAt(cameraPos, billboardPos, avatarUP)))); + transform.setRotation(rotation); + } + } + transform.postScale(dimensions); + + batch->setModelTransform(transform); + batch->setResourceTexture(0, texture->getGPUTexture()); + + float imageWidth = texture->getWidth(); + float imageHeight = texture->getHeight(); + + QRect fromImage; + if (subImage.width() <= 0) { + fromImage.setX(0); + fromImage.setWidth(imageWidth); + } else { + float scaleX = imageWidth / texture->getOriginalWidth(); + fromImage.setX(scaleX * subImage.x()); + fromImage.setWidth(scaleX * subImage.width()); + } + + if (subImage.height() <= 0) { + fromImage.setY(0); + fromImage.setHeight(imageHeight); + } else { + float scaleY = imageHeight / texture->getOriginalHeight(); + fromImage.setY(scaleY * subImage.y()); + fromImage.setHeight(scaleY * subImage.height()); + } + + float maxSize = glm::max(fromImage.width(), fromImage.height()); + float x = _keepAspectRatio ? fromImage.width() / (2.0f * maxSize) : 0.5f; + float y = _keepAspectRatio ? -fromImage.height() / (2.0f * maxSize) : -0.5f; + + glm::vec2 topLeft(-x, -y); + glm::vec2 bottomRight(x, y); + glm::vec2 texCoordTopLeft((fromImage.x() + 0.5f) / imageWidth, (fromImage.y() + 0.5f) / imageHeight); + glm::vec2 texCoordBottomRight((fromImage.x() + fromImage.width() - 0.5f) / imageWidth, + (fromImage.y() + fromImage.height() - 0.5f) / imageHeight); + + glm::vec4 imageColor(toGlm(color), _alpha); + + DependencyManager::get()->renderQuad( + *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, + imageColor, _geometryId + ); + + batch->setResourceTexture(0, nullptr); +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.h b/libraries/entities-renderer/src/RenderableImageEntityItem.h new file mode 100644 index 0000000000..669db13a22 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.h @@ -0,0 +1,56 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 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_RenderableImageEntityItem_h +#define hifi_RenderableImageEntityItem_h + +#include "RenderableEntityItem.h" + +#include + +namespace render { + namespace entities { + + class ImageEntityRenderer : public TypedEntityRenderer { + using Parent = TypedEntityRenderer; + using Pointer = std::shared_ptr; + public: + ImageEntityRenderer(const EntityItemPointer& entity); + ~ImageEntityRenderer(); + + protected: + ShapeKey getShapeKey() override; + + bool isTransparent() const override; + + private: + virtual bool needsRenderUpdate() const override; + virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; + virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRender(RenderArgs* args) override; + + QString _imageURL; + NetworkTexturePointer _texture; + bool _textureIsLoaded { false }; + + bool _emissive; + bool _keepAspectRatio; + BillboardMode _billboardMode; + QRect _subImage; + + glm::u8vec3 _color; + float _alpha; + + glm::vec3 _dimensions; + + int _geometryId { 0 }; + }; + + } +} +#endif // hifi_RenderableImageEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0497bc5a2b..dcad562ba7 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -83,34 +83,6 @@ void RenderableModelEntityItem::setUnscaledDimensions(const glm::vec3& value) { } } -QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures) { - // If textures are unset, revert to original textures - if (textures.isEmpty()) { - return defaultTextures; - } - - // Legacy: a ,\n-delimited list of filename:"texturepath" - if (*textures.cbegin() != '{') { - textures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}"; - } - - QJsonParseError error; - QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error); - // If textures are invalid, revert to original textures - if (error.error != QJsonParseError::NoError) { - qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << textures; - return defaultTextures; - } - - QVariantMap texturesMap = texturesJson.toVariant().toMap(); - // If textures are unset, revert to original textures - if (texturesMap.isEmpty()) { - return defaultTextures; - } - - return texturesJson.toVariant().toMap(); -} - void RenderableModelEntityItem::doInitialModelSimulation() { DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__); ModelPointer model = getModel(); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index ce9e7ab764..6e281081d2 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "GLMHelpers.h" @@ -59,7 +58,7 @@ bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint return true; } - if (_faceCamera != entity->getFaceCamera()) { + if (_billboardMode != entity->getBillboardMode()) { return true; } return false; @@ -79,7 +78,7 @@ void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { _textColor = toGlm(entity->getTextColor()); _backgroundColor = toGlm(entity->getBackgroundColor()); - _faceCamera = entity->getFaceCamera(); + _billboardMode = entity->getBillboardMode(); _lineHeight = entity->getLineHeight(); _text = entity->getText(); } @@ -110,13 +109,26 @@ void TextEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; auto transformToTopLeft = modelTransform; - if (_faceCamera) { + if (_billboardMode == BillboardMode::YAW) { //rotate about vertical to face the camera glm::vec3 dPosition = args->getViewFrustum().getPosition() - modelTransform.getTranslation(); // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); transformToTopLeft.setRotation(orientation); + } else if (_billboardMode == BillboardMode::FULL) { + glm::vec3 billboardPos = transformToTopLeft.getTranslation(); + glm::vec3 cameraPos = args->getViewFrustum().getPosition(); + // use the referencial from the avatar, y isn't always up + glm::vec3 avatarUP = EntityTreeRenderer::getAvatarUp(); + // check to see if glm::lookAt will work / using glm::lookAt variable name + glm::highp_vec3 s(glm::cross(billboardPos - cameraPos, avatarUP)); + + // make sure s is not NaN for any component + if (glm::length2(s) > 0.0f) { + glm::quat rotation(conjugate(toQuat(glm::lookAt(cameraPos, billboardPos, avatarUP)))); + transformToTopLeft.setRotation(rotation); + } } transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index ac7f2b620f..a368f280c5 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -32,7 +32,7 @@ private: virtual void doRender(RenderArgs* args) override; int _geometryID{ 0 }; std::shared_ptr _textRenderer; - bool _faceCamera; + BillboardMode _billboardMode; glm::vec3 _dimensions; glm::vec3 _textColor; glm::vec3 _backgroundColor; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index b6307a83da..a48f2f7762 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -219,15 +219,6 @@ QString EntityItemProperties::getBloomModeAsString() const { return getComponentModeAsString(_bloomMode); } -QString EntityItemProperties::getComponentModeString(uint32_t mode) { - // return "inherit" if mode is not valid - if (mode < COMPONENT_MODE_ITEM_COUNT) { - return COMPONENT_MODES[mode].second; - } else { - return COMPONENT_MODES[COMPONENT_MODE_INHERIT].second; - } -} - std::array::const_iterator EntityItemProperties::findComponent(const QString& mode) { return std::find_if(COMPONENT_MODES.begin(), COMPONENT_MODES.end(), [&](const ComponentPair& pair) { return (pair.second == mode); @@ -329,6 +320,33 @@ void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHost } } +QHash stringToBillboardModeLookup; + +void addBillboardMode(BillboardMode mode) { + stringToBillboardModeLookup[BillboardModeHelpers::getNameForBillboardMode(mode)] = mode; +} + +void buildStringToBillboardModeLookup() { + addBillboardMode(BillboardMode::NONE); + addBillboardMode(BillboardMode::YAW); + addBillboardMode(BillboardMode::FULL); +} + +QString EntityItemProperties::getBillboardModeAsString() const { + return BillboardModeHelpers::getNameForBillboardMode(_billboardMode); +} + +void EntityItemProperties::setBillboardModeFromString(const QString& materialMappingMode) { + if (stringToBillboardModeLookup.empty()) { + buildStringToBillboardModeLookup(); + } + auto billboardModeItr = stringToBillboardModeLookup.find(materialMappingMode.toLower()); + if (billboardModeItr != stringToBillboardModeLookup.end()) { + _billboardMode = billboardModeItr.value(); + _billboardModeChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -416,6 +434,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SPIN_FINISH, spinFinish); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_ROTATE_WITH_ENTITY, rotateWithEntity); + CHECK_PROPERTY_CHANGE(PROP_IMAGE_URL, imageURL); + CHECK_PROPERTY_CHANGE(PROP_EMISSIVE, emissive); + CHECK_PROPERTY_CHANGE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio); + CHECK_PROPERTY_CHANGE(PROP_SUB_IMAGE, subImage); + // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); CHECK_PROPERTY_CHANGE(PROP_ITEM_DESCRIPTION, itemDescription); @@ -445,7 +468,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints); CHECK_PROPERTY_CHANGE(PROP_HREF, href); CHECK_PROPERTY_CHANGE(PROP_DESCRIPTION, description); - CHECK_PROPERTY_CHANGE(PROP_FACE_CAMERA, faceCamera); + CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode); CHECK_PROPERTY_CHANGE(PROP_ACTION_DATA, actionData); CHECK_PROPERTY_CHANGE(PROP_NORMALS, normals); CHECK_PROPERTY_CHANGE(PROP_STROKE_COLORS, strokeColors); @@ -681,18 +704,19 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * * @see The different entity types have additional properties as follows: * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} - * @see {@link Entities.EntityProperties-Light|EntityProperties-Light} - * @see {@link Entities.EntityProperties-Line|EntityProperties-Line} - * @see {@link Entities.EntityProperties-Material|EntityProperties-Material} + * @see {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} + * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} * @see {@link Entities.EntityProperties-Model|EntityProperties-Model} + * @see {@link Entities.EntityProperties-Text|EntityProperties-Text} + * @see {@link Entities.EntityProperties-Image|EntityProperties-Image} + * @see {@link Entities.EntityProperties-Web|EntityProperties-Web} * @see {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} + * @see {@link Entities.EntityProperties-Line|EntityProperties-Line} * @see {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} * @see {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} - * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} - * @see {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} - * @see {@link Entities.EntityProperties-Text|EntityProperties-Text} - * @see {@link Entities.EntityProperties-Web|EntityProperties-Web} + * @see {@link Entities.EntityProperties-Light|EntityProperties-Light} * @see {@link Entities.EntityProperties-Zone|EntityProperties-Zone} + * @see {@link Entities.EntityProperties-Material|EntityProperties-Material} */ /**jsdoc @@ -812,7 +836,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * materialData: JSON.stringify({ * materialVersion: 1, * materials: { - * // Can only set albedo on a Shape entity. * // Value overrides entity's "color" property. * albedo: [1.0, 1.0, 0] // Yellow * } @@ -829,8 +852,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * {@link Entities.EntityProperties|naturalDimensions}. * @property {Color} color=255,255,255 - Currently not used. * @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".
- * Note: If the name ends with "default-image-model.fbx" then the entity is considered to be an "Image" - * entity, in which case the textures property should be set per the example. * @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the * model's original textures. Use a texture name from the originalTextures property to override that texture. * Only the texture names and URLs to be overridden need be specified; original textures are used where there are no @@ -876,24 +897,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * dimensions: { x: 0.0945, y: 0.0921, z: 0.0423 }, * lifetime: 300 // Delete after 5 minutes. * }); - * @example Create an "Image" entity like you can in the Create app. - * var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; - * var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg"; - * var entity = Entities.addEntity({ - * type: "Model", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -3 })), - * rotation: MyAvatar.orientation, - * dimensions: { - * x: 0.5385, - * y: 0.2819, - * z: 0.0092 - * }, - * shapeType: "box", - * collisionless: true, - * modelURL: IMAGE_MODEL, - * textures: JSON.stringify({ "tex.picture": DEFAULT_IMAGE }), - * lifetime: 300 // Delete after 5 minutes - * }); */ /**jsdoc @@ -1134,8 +1137,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {number} lineHeight=0.1 - The height of each line of text (thus determining the font size). * @property {Color} textColor=255,255,255 - The color of the text. * @property {Color} backgroundColor=0,0,0 - The color of the background rectangle. - * @property {boolean} faceCamera=false - If true, the entity is oriented to face each user's camera (i.e., it - * differs for each user present). + * @property {BillboardMode} billboardMode="none" - If "none", the entity is not billboarded. If "yaw", the entity will be + * oriented to follow your camera around the y-axis. If "full" the entity will be oriented to face your camera. The following deprecated + * behavior is also supported: you can also set "faceCamera" to true to set billboardMode to "yaw", and you can set + * "isFacingAvatar" to true to set billboardMode to "full". Setting either to false sets the mode to "none" * @example Create a text entity. * var text = Entities.addEntity({ * type: "Text", @@ -1143,7 +1148,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, * lineHeight: 0.12, * text: "Hello\nthere!", - * faceCamera: true, + * billboardMode: "yaw", * lifetime: 300 // Delete after 5 minutes. * }); */ @@ -1254,6 +1259,32 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * }); */ +/**jsdoc + * The "Image" {@link Entities.EntityType|EntityType} displays an image on a 2D rectangle in the domain. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * @typedef {object} Entities.EntityProperties-Image + * @property {string} imageURL="" - The URL of the image to use. + * @property {boolean} emissive=false - Whether or not the image should be emissive (unlit). + * @property {boolean} keepAspectRatio=true - Whether or not the image should maintain its aspect ratio. + * @property {BillboardMode} billboardMode="none" - If "none", the entity is not billboarded. If "yaw", the entity will be + * oriented to follow your camera around the y-axis. If "full" the entity will be oriented to face your camera. The following deprecated + * behavior is also supported: you can also set "faceCamera" to true to set billboardMode to "yaw", and you can set + * "isFacingAvatar" to true to set billboardMode to "full". Setting either to false sets the mode to "none" + * @property {Rect} subImage={ x: 0, y: 0, width: -1, height: -1 } - The portion of the image to display. If width or height are -1, defaults to + * the full image in that dimension. + * @property {Color} color=255,255,255 - The color of image. + * @property {number} alpha=1 - The alpha of the image. + * @example Create a image entity. + * var image = Entities.addEntity({ + * type: "Image", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, + * imageURL: "https://images.pexels.com/photos/1020315/pexels-photo-1020315.jpeg", + * billboardMode: "yaw", + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, bool strictSemantics, EntityPsuedoPropertyFlags psueudoPropertyFlags) const { @@ -1329,11 +1360,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_DYNAMIC, dynamic, collisionsWillMove, getDynamic()); // legacy support COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FACE_CAMERA, faceCamera); // Text only. COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); // Certifiable Properties @@ -1354,33 +1383,44 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool // Particles only if (_type == EntityTypes::ParticleEffect) { - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTING_PARTICLES, isEmitting); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_PARTICLES, maxParticles); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFESPAN, lifespan); + + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTING_PARTICLES, isEmitting); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RATE, emitRate); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_SPEED, emitSpeed); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPEED_SPREAD, speedSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ORIENTATION, emitOrientation); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_DIMENSIONS, emitDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RADIUS_START, emitRadiusStart); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POLAR_START, polarStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POLAR_FINISH, polarFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_AZIMUTH_START, azimuthStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_AZIMUTH_FINISH, azimuthFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ACCELERATION, emitAcceleration); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION_SPREAD, accelerationSpread); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_RADIUS, particleRadius); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_SPREAD, radiusSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_START, radiusStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_FINISH, radiusFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR_SPREAD, colorSpread, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR_START, colorStart, vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR_FINISH, colorFinish, vec3Color); + + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); + + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_SPIN, particleSpin); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_SPREAD, spinSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_START, spinStart); @@ -1390,22 +1430,21 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool // Models only if (_type == EntityTypes::Model) { + COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL); - if (!psuedoPropertyFlagsButDesiredEmpty) { - _animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - } + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS, jointTranslations); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); + if (!psuedoPropertyFlagsButDesiredEmpty) { + _animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + } } - if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); - } - // FIXME: Shouldn't provide a shapeType property for Box and Sphere entities. if (_type == EntityTypes::Box) { COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Box")); @@ -1417,26 +1456,17 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool if (_type == EntityTypes::Box || _type == EntityTypes::Sphere || _type == EntityTypes::Shape) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHAPE, shape); COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - } - - // FIXME - it seems like ParticleEffect should also support this - if (_type == EntityTypes::Model || _type == EntityTypes::Zone) { - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); - } - - // Models & Particles - if (_type == EntityTypes::Model || _type == EntityTypes::ParticleEffect) { - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); } // Lights only if (_type == EntityTypes::Light) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_SPOTLIGHT, isSpotlight); + COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_INTENSITY, intensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FALLOFF_RADIUS, falloffRadius); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EXPONENT, exponent); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CUTOFF, cutoff); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FALLOFF_RADIUS, falloffRadius); } // Text only @@ -1445,6 +1475,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(PROP_TEXT_COLOR, textColor, getTextColor(), u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(PROP_BACKGROUND_COLOR, backgroundColor, getBackgroundColor(), u8vec3Color); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); } // Zones only @@ -1452,24 +1483,22 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool if (!psuedoPropertyFlagsButDesiredEmpty) { _keyLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); _ambientLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - _skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); } + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GHOSTING_ALLOWED, ghostingAllowed); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FILTER_URL, filterURL); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); - if (!psuedoPropertyFlagsButDesiredEmpty) { - _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - } - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString()); - if (!psuedoPropertyFlagsButDesiredEmpty) { - _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); - } COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString()); } // Web only @@ -1497,15 +1526,22 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool } // Lines & PolyLines - if (_type == EntityTypes::Line || _type == EntityTypes::PolyLine) { + if (_type == EntityTypes::Line) { COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals); // Polyline only. - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_STROKE_COLORS, strokeColors, qVectorVec3Color); // Polyline only. - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); // Polyline only. - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); // Polyline only. - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); // Polyline only. + } + + if (_type == EntityTypes::PolyLine) { + COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_WIDTH, lineWidth); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); + + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NORMALS, normals); + COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_STROKE_COLORS, strokeColors, qVectorVec3Color); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); } // Materials @@ -1521,6 +1557,26 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_REPEAT, materialRepeat); } + // Image only + if (_type == EntityTypes::Image) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SUB_IMAGE, subImage); + + COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); + + // Handle conversions to old 'textures' property from "imageURL" + if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) && + (!skipDefaults || defaultEntityProperties._imageURL != _imageURL)) { + QScriptValue textures = engine->newObject(); + textures.setProperty("tex.picture", _imageURL); + properties.setProperty("textures", textures); + } + } + /**jsdoc * The axis-aligned bounding box of an entity. * @typedef {object} Entities.BoundingBox @@ -1611,6 +1667,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool properties.setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL)); } + if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::FaceCamera)) { + properties.setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); + } + if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::IsFacingAvatar)) { + properties.setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); + } + // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); @@ -1651,7 +1714,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail , bool, setEmitterShouldTrail); + COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail, bool, setEmitterShouldTrail); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha); @@ -1740,20 +1803,24 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(href, QString, setHref); COPY_PROPERTY_FROM_QSCRIPTVALUE(description, QString, setDescription); - COPY_PROPERTY_FROM_QSCRIPTVALUE(faceCamera, bool, setFaceCamera); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(actionData, QByteArray, setActionData); COPY_PROPERTY_FROM_QSCRIPTVALUE(normals, qVectorVec3, setNormals); COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeColors, qVectorVec3, setStrokeColors); - COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths,qVectorFloat, setStrokeWidths); + COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths, qVectorFloat, setStrokeWidths); COPY_PROPERTY_FROM_QSCRIPTVALUE(isUVModeStretch, bool, setIsUVModeStretch); + COPY_PROPERTY_FROM_QSCRIPTVALUE(imageURL, QString, setImageURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE(emissive, bool, setEmissive); + COPY_PROPERTY_FROM_QSCRIPTVALUE(keepAspectRatio, bool, setKeepAspectRatio); + COPY_PROPERTY_FROM_QSCRIPTVALUE(subImage, QRect, setSubImage); if (!honorReadOnly) { // this is used by the json reader to set things that we don't want javascript to able to affect. COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() { - auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec - return result; - }); + auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec + return result; + }); // TODO: expose this to QScriptValue for JSON saves? //COPY_PROPERTY_FROM_QSCRIPTVALUE(simulationOwner, ???, setSimulatorPriority); } @@ -1810,6 +1877,47 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneAvatarEntity, bool, setCloneAvatarEntity); COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneOriginID, QUuid, setCloneOriginID); + // Handle conversions from old 'textures' property to "imageURL" + { + QScriptValue V = object.property("textures"); + if (_type == EntityTypes::Image && V.isValid() && !object.property("imageURL").isValid()) { + bool isValid = false; + QString textures = QString_convertFromScriptValue(V, isValid); + if (isValid) { + QVariantMap texturesMap = parseTexturesToMap(textures, QVariantMap()); + auto texPicture = texturesMap.find("tex.picture"); + if (texPicture != texturesMap.end()) { + auto imageURL = texPicture.value().toString(); + if (_defaultSettings || imageURL != _imageURL) { + setImageURL(imageURL); + } + } + } + } + } + + // Handle old "faceCamera" and "isFacingAvatar" props + { + QScriptValue P = object.property("faceCamera"); + if (P.isValid() && !object.property("billboardMode").isValid()) { + bool newValue = P.toVariant().toBool(); + bool oldValue = getBillboardMode() == BillboardMode::YAW; + if (_defaultSettings || newValue != oldValue) { + setBillboardMode(newValue ? BillboardMode::YAW : BillboardMode::NONE); + } + } + } + { + QScriptValue P = object.property("isFacingAvatar"); + if (P.isValid() && !object.property("billboardMode").isValid() && !object.property("faceCamera").isValid()) { + bool newValue = P.toVariant().toBool(); + bool oldValue = getBillboardMode() == BillboardMode::FULL; + if (_defaultSettings || newValue != oldValue) { + setBillboardMode(newValue ? BillboardMode::FULL : BillboardMode::NONE); + } + } + } + _lastEdited = usecTimestampNow(); } @@ -1886,6 +1994,11 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(spinFinish); COPY_PROPERTY_IF_CHANGED(rotateWithEntity); + COPY_PROPERTY_IF_CHANGED(imageURL); + COPY_PROPERTY_IF_CHANGED(emissive); + COPY_PROPERTY_IF_CHANGED(keepAspectRatio); + COPY_PROPERTY_IF_CHANGED(subImage); + // Certifiable Properties COPY_PROPERTY_IF_CHANGED(itemName); COPY_PROPERTY_IF_CHANGED(itemDescription); @@ -1916,7 +2029,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(linePoints); COPY_PROPERTY_IF_CHANGED(href); COPY_PROPERTY_IF_CHANGED(description); - COPY_PROPERTY_IF_CHANGED(faceCamera); + COPY_PROPERTY_IF_CHANGED(billboardMode); COPY_PROPERTY_IF_CHANGED(actionData); COPY_PROPERTY_IF_CHANGED(normals); COPY_PROPERTY_IF_CHANGED(strokeColors); @@ -2018,7 +2131,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue static std::once_flag initMap; - std::call_once(initMap, [](){ + std::call_once(initMap, []() { ADD_PROPERTY_TO_MAP(PROP_VISIBLE, Visible, visible, bool); ADD_PROPERTY_TO_MAP(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool); ADD_PROPERTY_TO_MAP(PROP_POSITION, Position, position, vec3); @@ -2135,7 +2248,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector); ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); ADD_PROPERTY_TO_MAP(PROP_DESCRIPTION, Description, description, QString); - ADD_PROPERTY_TO_MAP(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool); + ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode); ADD_PROPERTY_TO_MAP(PROP_ACTION_DATA, ActionData, actionData, QByteArray); ADD_PROPERTY_TO_MAP(PROP_NORMALS, Normals, normals, QVector); ADD_PROPERTY_TO_MAP(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector); @@ -2241,6 +2354,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, EquippableIndicatorOffset, equippableIndicatorOffset); + ADD_PROPERTY_TO_MAP(PROP_IMAGE_URL, ImageURL, imageURL, QString); + ADD_PROPERTY_TO_MAP(PROP_EMISSIVE, Emissive, emissive, bool); + ADD_PROPERTY_TO_MAP(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool); + ADD_PROPERTY_TO_MAP(PROP_SUB_IMAGE, SubImage, subImage, QRect); + // FIXME - these are not yet handled //ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); @@ -2350,8 +2468,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy bool successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags); int propertyCount = 0; - bool headerFits = successIDFits && successTypeFits && successLastEditedFits - && successLastUpdatedFits && successPropertyFlagsFits; + bool headerFits = successIDFits && successTypeFits && successLastEditedFits && + successLastUpdatedFits && successPropertyFlagsFits; int startOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -2404,39 +2522,40 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, properties.getTextColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor()); - APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, properties.getFaceCamera()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode()); } if (properties.getType() == EntityTypes::Model) { + APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, properties.getModelURL()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures()); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType())); - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - - _staticAnimation.setProperties(properties); - _staticAnimation.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, properties.getJointRotationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, properties.getJointRotations()); APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, properties.getJointTranslationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, properties.getJointTranslations()); APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, properties.getRelayParentJoints()); + + _staticAnimation.setProperties(properties); + _staticAnimation.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); } if (properties.getType() == EntityTypes::Light) { APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight()); APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); APPEND_ENTITY_PROPERTY(PROP_INTENSITY, properties.getIntensity()); - APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, properties.getFalloffRadius()); APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent()); APPEND_ENTITY_PROPERTY(PROP_CUTOFF, properties.getCutoff()); + APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, properties.getFalloffRadius()); } if (properties.getType() == EntityTypes::ParticleEffect) { - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures()); + APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType())); APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, properties.getMaxParticles()); APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, properties.getLifespan()); + APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, properties.getIsEmitting()); APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, properties.getEmitRate()); APPEND_ENTITY_PROPERTY(PROP_EMIT_SPEED, properties.getEmitSpeed()); @@ -2444,24 +2563,33 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, properties.getEmitOrientation()); APPEND_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, properties.getEmitDimensions()); APPEND_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, properties.getEmitRadiusStart()); + APPEND_ENTITY_PROPERTY(PROP_POLAR_START, properties.getPolarStart()); APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, properties.getPolarFinish()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, properties.getAzimuthStart()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, properties.getAzimuthFinish()); + APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread()); + APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); + APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread()); APPEND_ENTITY_PROPERTY(PROP_COLOR_START, properties.getColorStart()); APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, properties.getColorFinish()); + + APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); + + APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures()); APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, properties.getEmitterShouldTrail()); + APPEND_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, properties.getParticleSpin()); APPEND_ENTITY_PROPERTY(PROP_SPIN_SPREAD, properties.getSpinSpread()); APPEND_ENTITY_PROPERTY(PROP_SPIN_START, properties.getSpinStart()); @@ -2476,27 +2604,27 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy _staticAmbientLight.setProperties(properties); _staticAmbientLight.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)properties.getShapeType()); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); - _staticSkybox.setProperties(properties); _staticSkybox.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + _staticHaze.setProperties(properties); + _staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + + _staticBloom.setProperties(properties); + _staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + + APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)properties.getShapeType()); + APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); + APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, properties.getFlyingAllowed()); APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, properties.getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, properties.getFilterURL()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)properties.getHazeMode()); - _staticHaze.setProperties(properties); - _staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - - APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); - _staticBloom.setProperties(properties); - _staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode()); + APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)properties.getHazeMode()); + APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); } if (properties.getType() == EntityTypes::PolyVox) { @@ -2537,6 +2665,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy properties.getType() == EntityTypes::Sphere) { APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape()); APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); } // Materials @@ -2552,10 +2681,21 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_MATERIAL_REPEAT, properties.getMaterialRepeat()); } + // Image + if (properties.getType() == EntityTypes::Image) { + APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL()); + APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, properties.getEmissive()); + APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, properties.getKeepAspectRatio()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode()); + APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, properties.getSubImage()); + + APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); + } + APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); // Certifiable Properties APPEND_ENTITY_PROPERTY(PROP_ITEM_NAME, properties.getItemName()); @@ -2586,8 +2726,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy encodedPropertyFlags = propertyFlags; int newPropertyFlagsLength = encodedPropertyFlags.length(); - packetData->updatePriorBytes(propertyFlagsOffset, - (const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length()); + packetData->updatePriorBytes(propertyFlagsOffset, (const unsigned char*)encodedPropertyFlags.constData(), + encodedPropertyFlags.length()); // if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet. if (newPropertyFlagsLength < oldPropertyFlagsLength) { @@ -2798,38 +2938,39 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_COLOR, u8vec3Color, setTextColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, u8vec3Color, setBackgroundColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FACE_CAMERA, bool, setFaceCamera); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); } if (properties.getType() == EntityTypes::Model) { + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_URL, QString, setModelURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - - properties.getAnimation().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS, QVector, setJointRotations); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints); + + properties.getAnimation().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); } if (properties.getType() == EntityTypes::Light) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INTENSITY, float, setIntensity); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FALLOFF_RADIUS, float, setFalloffRadius); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FALLOFF_RADIUS, float, setFalloffRadius); } if (properties.getType() == EntityTypes::ParticleEffect) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, quint32, setMaxParticles); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTING_PARTICLES, bool, setIsEmitting); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_SPEED, float, setEmitSpeed); @@ -2837,24 +2978,33 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ORIENTATION, quat, setEmitOrientation); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_DIMENSIONS, vec3, setEmitDimensions); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POLAR_START, float, setPolarStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POLAR_FINISH, float, setPolarFinish); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AZIMUTH_START, float, setAzimuthStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, vec3, setEmitAcceleration); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, vec3, setAccelerationSpread); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, u8vec3Color, setColorSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, vec3Color, setColorStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, vec3Color, setColorFinish); + + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); + + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_SPIN, float, setParticleSpin); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_SPREAD, float, setSpinSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_START, float, setSpinStart); @@ -2865,24 +3015,22 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int if (properties.getType() == EntityTypes::Zone) { properties.getKeyLight().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); properties.getAmbientLight().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FILTER_URL, QString, setFilterURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); - properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode); - properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode); } if (properties.getType() == EntityTypes::PolyVox) { @@ -2925,6 +3073,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int properties.getType() == EntityTypes::Sphere) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE, QString, setShape); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); } // Materials @@ -2940,10 +3089,21 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_REPEAT, bool, setMaterialRepeat); } + // Image + if (properties.getType() == EntityTypes::Image) { + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMISSIVE, bool, setEmissive); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SUB_IMAGE, QRect, setSubImage); + + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); + } + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); // Certifiable Properties READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_NAME, QString, setItemName); @@ -2986,7 +3146,7 @@ QVector EntityItemProperties::unpackNormals(const QByteArray& normals) { j++; } } else { - qCDebug(entities) << "WARNING - Expected received size for normals does not match. Expected: " << (int)normals[0] + qCDebug(entities) << "WARNING - Expected received size for normals does not match. Expected: " << (int)normals[0] << " Received: " << (normals.size() / 6); } return unpackedNormals; @@ -2999,7 +3159,7 @@ void EntityItemProperties::setPackedStrokeColors(const QByteArray& value) { QVector EntityItemProperties::unpackStrokeColors(const QByteArray& strokeColors) { // the size of the vector is packed first QVector unpackedStrokeColors = QVector((int)strokeColors[0]); - + if ((int)strokeColors[0] == strokeColors.size() / 3) { int j = 0; for (int i = 1; i < strokeColors.size();) { @@ -3010,7 +3170,7 @@ QVector EntityItemProperties::unpackStrokeColors(const QByteArray& strokeC unpackedStrokeColors[j++] = vec3(r, g, b); } } else { - qCDebug(entities) << "WARNING - Expected received size for stroke colors does not match. Expected: " + qCDebug(entities) << "WARNING - Expected received size for stroke colors does not match. Expected: " << (int)strokeColors[0] << " Received: " << (strokeColors.size() / 3); } @@ -3027,7 +3187,7 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt int outputLength = 0; - if (buffer.size() < (int) (sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID)) { + if (buffer.size() < (int)(sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID)) { qCDebug(entities) << "ERROR - encodeEraseEntityMessage() called with buffer that is too small!"; return false; } @@ -3218,7 +3378,7 @@ void EntityItemProperties::markAllChanged() { _hrefChanged = true; _descriptionChanged = true; - _faceCameraChanged = true; + _billboardModeChanged = true; _actionDataChanged = true; _normalsChanged = true; @@ -3268,6 +3428,11 @@ void EntityItemProperties::markAllChanged() { _cloneOriginIDChanged = true; _isVisibleInSecondaryCameraChanged = true; + + _imageURLChanged = true; + _emissiveChanged = true; + _keepAspectRatioChanged = true; + _subImageChanged = true; } // The minimum bounding box for the entity. @@ -3276,7 +3441,7 @@ AABox EntityItemProperties::getAABox() const { // _position represents the position of the registration point. vec3 registrationRemainder = vec3(1.0f) - _registrationPoint; - vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); + vec3 unrotatedMinRelativeToEntity = -(_dimensions * _registrationPoint); vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(_rotation); @@ -3288,7 +3453,7 @@ AABox EntityItemProperties::getAABox() const { } bool EntityItemProperties::hasTransformOrVelocityChanges() const { - return _positionChanged ||_localPositionChanged + return _positionChanged || _localPositionChanged || _rotationChanged || _localRotationChanged || _velocityChanged || _localVelocityChanged || _angularVelocityChanged || _localAngularVelocityChanged @@ -3374,7 +3539,7 @@ uint8_t EntityItemProperties::computeSimulationBidPriority() const { if (_parentIDChanged || _parentJointIndexChanged) { // we need higher simulation ownership priority to chang parenting info priority = SCRIPT_GRAB_SIMULATION_PRIORITY; - } else if ( _positionChanged || _localPositionChanged + } else if (_positionChanged || _localPositionChanged || _rotationChanged || _localRotationChanged || _velocityChanged || _localVelocityChanged || _angularVelocityChanged || _localAngularVelocityChanged) { @@ -3807,6 +3972,23 @@ QList EntityItemProperties::listChangedProperties() { out += "cloneOriginID"; } + if (imageURLChanged()) { + out += "imageURL"; + } + if (emissiveChanged()) { + out += "emissive"; + } + if (keepAspectRatioChanged()) { + out += "keepAspectRatio"; + } + if (subImageChanged()) { + out += "subImage"; + } + + if (billboardModeChanged()) { + out += "billboardMode"; + } + getAnimation().listChangedProperties(out); getKeyLight().listChangedProperties(out); getAmbientLight().listChangedProperties(out); @@ -4004,4 +4186,4 @@ void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityID setCloneLimit(ENTITY_ITEM_DEFAULT_CLONE_LIMIT); setCloneDynamic(ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); setCloneAvatarEntity(ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); -} +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 71dc1606f4..248bdecedb 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -48,6 +48,7 @@ #include "ZoneEntityItem.h" #include "MaterialMappingMode.h" +#include "BillboardMode.h" const quint64 UNKNOWN_CREATED_TIME = 0; @@ -68,18 +69,19 @@ using u8vec3Color = glm::u8vec3; class EntityItemProperties { // TODO: consider removing these friend relationship and use public methods friend class EntityItem; - friend class ModelEntityItem; friend class BoxEntityItem; friend class SphereEntityItem; - friend class LightEntityItem; - friend class TextEntityItem; - friend class ParticleEffectEntityItem; - friend class ZoneEntityItem; - friend class WebEntityItem; - friend class LineEntityItem; - friend class PolyVoxEntityItem; - friend class PolyLineEntityItem; friend class ShapeEntityItem; + friend class ModelEntityItem; + friend class TextEntityItem; + friend class ImageEntityItem; + friend class WebEntityItem; + friend class ParticleEffectEntityItem; + friend class LineEntityItem; + friend class PolyLineEntityItem; + friend class PolyVoxEntityItem; + friend class LightEntityItem; + friend class ZoneEntityItem; friend class MaterialEntityItem; public: EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); @@ -213,7 +215,7 @@ public: DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString, ""); DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString, ""); - DEFINE_PROPERTY(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool, TextEntityItem::DEFAULT_FACE_CAMERA); + DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE); DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray, QByteArray()); DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); DEFINE_PROPERTY(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); @@ -251,6 +253,11 @@ public: DEFINE_PROPERTY(PROP_SPIN_FINISH, SpinFinish, spinFinish, float, particle::DEFAULT_SPIN_FINISH); DEFINE_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, RotateWithEntity, rotateWithEntity, bool, particle::DEFAULT_ROTATE_WITH_ENTITY); + DEFINE_PROPERTY_REF(PROP_IMAGE_URL, ImageURL, imageURL, QString, ""); + DEFINE_PROPERTY_REF(PROP_EMISSIVE, Emissive, emissive, bool, false); + DEFINE_PROPERTY_REF(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool, true); + DEFINE_PROPERTY_REF(PROP_SUB_IMAGE, SubImage, subImage, QRect, QRect()); + // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION); @@ -299,7 +306,6 @@ public: DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); - static QString getComponentModeString(uint32_t mode); static QString getComponentModeAsString(uint32_t mode); std::array::const_iterator findComponent(const QString& mode); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index d3a2dc6cec..225b77bd97 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -122,6 +122,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); } + inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); return QScriptValue(QString(b64)); @@ -323,6 +325,13 @@ inline glm::quat quat_convertFromScriptValue(const QScriptValue& v, bool& isVali return glm::quat(); } +inline QRect QRect_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = true; + QRect rect; + qRectFromScriptValue(v, rect); + return rect; +} + #define COPY_PROPERTY_IF_CHANGED(P) \ { \ if (other._##P##Changed) { \ diff --git a/libraries/entities/src/EntityPropertyFlags.cpp b/libraries/entities/src/EntityPropertyFlags.cpp index 4977cdc537..dbb8463141 100644 --- a/libraries/entities/src/EntityPropertyFlags.cpp +++ b/libraries/entities/src/EntityPropertyFlags.cpp @@ -67,7 +67,7 @@ QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) { result = f.getHasProperty(PROP_LINE_POINTS) ? result + "linePoints " : result; result = f.getHasProperty(PROP_HREF) ? result + "href " : result; result = f.getHasProperty(PROP_DESCRIPTION) ? result + "description " : result; - result = f.getHasProperty(PROP_FACE_CAMERA) ? result + "faceCamera " : result; + result = f.getHasProperty(PROP_BILLBOARD_MODE) ? result + "billboardMode " : result; result = f.getHasProperty(PROP_SCRIPT_TIMESTAMP) ? result + "scriptTimestamp " : result; result = f.getHasProperty(PROP_ACTION_DATA) ? result + "actionData " : result; result = f.getHasProperty(PROP_X_TEXTURE_URL) ? result + "xTextureUrl " : result; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 49e5980ffe..5ba75fd006 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -99,7 +99,7 @@ enum EntityPropertyList { PROP_HREF, PROP_DESCRIPTION, // 61 - PROP_FACE_CAMERA, + PROP_BILLBOARD_MODE, PROP_SCRIPT_TIMESTAMP, PROP_ACTION_DATA, @@ -277,6 +277,9 @@ enum EntityPropertyList { PROP_MATERIAL_REPEAT, + PROP_EMISSIVE, + PROP_SUB_IMAGE, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, @@ -310,6 +313,11 @@ enum EntityPropertyList { // other properties which will never overlap with each other. PROP_EMITTING_PARTICLES = PROP_ANIMATION_PLAYING, + // Aliases/Piggyback properties for Image. These properties intentionally reuse the enum values for + // other properties which will never overlap with each other. + PROP_IMAGE_URL = PROP_MODEL_URL, + PROP_KEEP_ASPECT_RATIO = PROP_ANIMATION_PLAYING, + // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above }; diff --git a/libraries/entities/src/EntityPsuedoPropertyFlags.h b/libraries/entities/src/EntityPsuedoPropertyFlags.h index 26c2a14015..d0af945215 100644 --- a/libraries/entities/src/EntityPsuedoPropertyFlags.h +++ b/libraries/entities/src/EntityPsuedoPropertyFlags.h @@ -34,6 +34,8 @@ namespace EntityPsuedoPropertyFlag { OwningAvatarID, AvatarEntity, LocalEntity, + FaceCamera, + IsFacingAvatar, NumFlags }; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7f7a628890..33ec92b8de 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -698,6 +698,10 @@ QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScri psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::AvatarEntity); } else if (extendedPropertyString == "localEntity") { psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::LocalEntity); + } else if (extendedPropertyString == "faceCamera") { + psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FaceCamera); + } else if (extendedPropertyString == "isFacingAvatar") { + psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::IsFacingAvatar); } }; diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 9611063f8b..30f9d9b541 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -20,38 +20,40 @@ #include "EntityItemProperties.h" #include "EntitiesLogging.h" -#include "LightEntityItem.h" +#include "ShapeEntityItem.h" #include "ModelEntityItem.h" #include "ParticleEffectEntityItem.h" #include "TextEntityItem.h" +#include "ImageEntityItem.h" #include "WebEntityItem.h" -#include "ZoneEntityItem.h" #include "LineEntityItem.h" -#include "PolyVoxEntityItem.h" #include "PolyLineEntityItem.h" -#include "ShapeEntityItem.h" +#include "PolyVoxEntityItem.h" +#include "LightEntityItem.h" +#include "ZoneEntityItem.h" #include "MaterialEntityItem.h" QMap EntityTypes::_typeToNameMap; QMap EntityTypes::_nameToTypeMap; -EntityTypeFactory EntityTypes::_factories[EntityTypes::LAST + 1]; +EntityTypeFactory EntityTypes::_factories[EntityTypes::NUM_TYPES]; bool EntityTypes::_factoriesInitialized = false; const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown"; // Register Entity the default implementations of entity types here... -REGISTER_ENTITY_TYPE(Model) -REGISTER_ENTITY_TYPE(Web) -REGISTER_ENTITY_TYPE(Light) -REGISTER_ENTITY_TYPE(Text) -REGISTER_ENTITY_TYPE(ParticleEffect) -REGISTER_ENTITY_TYPE(Zone) -REGISTER_ENTITY_TYPE(Line) -REGISTER_ENTITY_TYPE(PolyVox) -REGISTER_ENTITY_TYPE(PolyLine) -REGISTER_ENTITY_TYPE(Shape) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory) +REGISTER_ENTITY_TYPE(Shape) +REGISTER_ENTITY_TYPE(Model) +REGISTER_ENTITY_TYPE(Text) +REGISTER_ENTITY_TYPE(Image) +REGISTER_ENTITY_TYPE(Web) +REGISTER_ENTITY_TYPE(ParticleEffect) +REGISTER_ENTITY_TYPE(Line) +REGISTER_ENTITY_TYPE(PolyLine) +REGISTER_ENTITY_TYPE(PolyVox) +REGISTER_ENTITY_TYPE(Light) +REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Material) const QString& EntityTypes::getEntityTypeName(EntityType entityType) { @@ -80,7 +82,7 @@ bool EntityTypes::registerEntityType(EntityType entityType, const char* name, En memset(&_factories,0,sizeof(_factories)); _factoriesInitialized = true; } - if (entityType >= 0 && entityType <= LAST) { + if (entityType >= 0 && entityType < NUM_TYPES) { _factories[entityType] = factoryMethod; return true; } @@ -91,7 +93,7 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const const EntityItemProperties& properties) { EntityItemPointer newEntityItem = NULL; EntityTypeFactory factory = NULL; - if (entityType >= 0 && entityType <= LAST) { + if (entityType >= 0 && entityType < NUM_TYPES) { factory = _factories[entityType]; } if (factory) { diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 954bdf8f17..c85cb5b2dd 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -49,25 +49,6 @@ public: * "Cube". If an entity of type Shape or Sphere has its shape set * to "Cube" then its type will be reported as "Box". * {@link Entities.EntityProperties-Box|EntityProperties-Box} - * "Light"A local lighting effect. - * {@link Entities.EntityProperties-Light|EntityProperties-Light} - * "Line"A sequence of one or more simple straight lines. - * {@link Entities.EntityProperties-Line|EntityProperties-Line} - * "Material"Modifies the existing materials on Model entities, Shape entities (albedo - * only), {@link Overlays.OverlayType|model overlays}, and avatars. - * {@link Entities.EntityProperties-Material|EntityProperties-Material} - * "Model"A mesh model from an FBX or OBJ file. - * {@link Entities.EntityProperties-Model|EntityProperties-Model} - * "ParticleEffect"A particle system that can be used to simulate things such as fire, - * smoke, snow, magic spells, etc. - * {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} - * "PolyLine"A sequence of one or more textured straight lines. - * {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} - * "PolyVox"A set of textured voxels. - * {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} - * "Shape"A basic entity such as a cube. - * See also, the "Box" and "Sphere" entity types. - * {@link Entities.EntityProperties-Shape|EntityProperties-Shape} * "Sphere"A sphere. This is a synonym of "Shape" for the case * where the entity's shape property value is "Sphere".
* If an entity is created with its type @@ -75,32 +56,54 @@ public: * "Sphere". If an entity of type Box or Shape has its shape set * to "Sphere" then its type will be reported as "Sphere". * {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} + * "Shape"A basic entity such as a cube. + * See also, the "Box" and "Sphere" entity types. + * {@link Entities.EntityProperties-Shape|EntityProperties-Shape} + * "Model"A mesh model from an FBX or OBJ file. + * {@link Entities.EntityProperties-Model|EntityProperties-Model} * "Text"A pane of text oriented in space. * {@link Entities.EntityProperties-Text|EntityProperties-Text} + * "Image"An image oriented in space. + * {@link Entities.EntityProperties-Image|EntityProperties-Image} * "Web"A browsable Web page. * {@link Entities.EntityProperties-Web|EntityProperties-Web} + * "ParticleEffect"A particle system that can be used to simulate things such as fire, + * smoke, snow, magic spells, etc. + * {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} + * "Line"A sequence of one or more simple straight lines. + * {@link Entities.EntityProperties-Line|EntityProperties-Line} + * "PolyLine"A sequence of one or more textured straight lines. + * {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} + * "PolyVox"A set of textured voxels. + * {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} + * "Light"A local lighting effect. + * {@link Entities.EntityProperties-Light|EntityProperties-Light} * "Zone"A volume of lighting effects and avatar permissions. * {@link Entities.EntityProperties-Zone|EntityProperties-Zone} + * "Material"Modifies the existing materials on Model entities, Shape entities, + * {@link Overlays.OverlayType|model overlays}, and avatars. + * {@link Entities.EntityProperties-Material|EntityProperties-Material} * * * @typedef {string} Entities.EntityType */ typedef enum EntityType_t { Unknown, - Model, Box, Sphere, - Light, - Text, - ParticleEffect, - Zone, - Web, - Line, - PolyVox, - PolyLine, Shape, + Model, + Text, + Image, + Web, + ParticleEffect, + Line, + PolyLine, + PolyVox, + Light, + Zone, Material, - LAST = Material + NUM_TYPES } EntityType; static const QString& getEntityTypeName(EntityType entityType); @@ -112,7 +115,7 @@ public: private: static QMap _typeToNameMap; static QMap _nameToTypeMap; - static EntityTypeFactory _factories[LAST + 1]; + static EntityTypeFactory _factories[NUM_TYPES]; static bool _factoriesInitialized; }; diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp new file mode 100644 index 0000000000..98817a63ba --- /dev/null +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -0,0 +1,269 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 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 "ImageEntityItem.h" + +#include "EntityItemProperties.h" + +EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new ImageEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Image; +} + +void ImageEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float IMAGE_ENTITY_ITEM_FIXED_DEPTH = 0.01f; + // NOTE: Image Entities always have a "depth" of 1cm. + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, IMAGE_ENTITY_ITEM_FIXED_DEPTH)); +} + +EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(keepAspectRatio, getKeepAspectRatio); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(subImage, getSubImage); + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); + + return properties; +} + +bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(keepAspectRatio, setKeepAspectRatio); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(subImage, setSubImage); + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "ImageEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL); + READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive); + READ_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); + READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); + READ_ENTITY_PROPERTY(PROP_SUB_IMAGE, QRect, setSubImage); + + READ_ENTITY_PROPERTY(PROP_COLOR, u8vec3Color, setColor); + READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); + + return bytesRead; +} + +EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + + requestedProperties += PROP_IMAGE_URL; + requestedProperties += PROP_EMISSIVE; + requestedProperties += PROP_KEEP_ASPECT_RATIO; + requestedProperties += PROP_BILLBOARD_MODE; + requestedProperties += PROP_SUB_IMAGE; + + requestedProperties += PROP_COLOR; + requestedProperties += PROP_ALPHA; + + return requestedProperties; +} + +void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL()); + APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive()); + APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, getKeepAspectRatio()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode()); + APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubImage()); + + APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); +} + +bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& element, + float& distance, BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + 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())); + + if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { + glm::vec3 forward = rotation * Vectors::FRONT; + if (glm::dot(forward, direction) > 0.0f) { + face = MAX_Z_FACE; + surfaceNormal = -forward; + } else { + face = MIN_Z_FACE; + surfaceNormal = forward; + } + return true; + } + return false; +} + +bool ImageEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, + OctreeElementPointer& element, float& parabolicDistance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + 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())); + + glm::quat inverseRot = glm::inverse(rotation); + glm::vec3 localOrigin = inverseRot * (origin - position); + glm::vec3 localVelocity = inverseRot * velocity; + glm::vec3 localAcceleration = inverseRot * acceleration; + + if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) { + float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance; + glm::vec3 forward = rotation * Vectors::FRONT; + if (localIntersectionVelocityZ > 0.0f) { + face = MIN_Z_FACE; + surfaceNormal = forward; + } else { + face = MAX_Z_FACE; + surfaceNormal = -forward; + } + return true; + } + return false; +} + +QString ImageEntityItem::getImageURL() const { + QString result; + withReadLock([&] { + result = _imageURL; + }); + return result; +} + +void ImageEntityItem::setImageURL(const QString& url) { + withWriteLock([&] { + _imageURL = url; + }); +} + +bool ImageEntityItem::getEmissive() const { + bool result; + withReadLock([&] { + result = _emissive; + }); + return result; +} + +void ImageEntityItem::setEmissive(bool emissive) { + withWriteLock([&] { + _emissive = emissive; + }); +} + +bool ImageEntityItem::getKeepAspectRatio() const { + bool result; + withReadLock([&] { + result = _keepAspectRatio; + }); + return result; +} + +void ImageEntityItem::setKeepAspectRatio(bool keepAspectRatio) { + withWriteLock([&] { + _keepAspectRatio = keepAspectRatio; + }); +} + +BillboardMode ImageEntityItem::getBillboardMode() const { + BillboardMode result; + withReadLock([&] { + result = _billboardMode; + }); + return result; +} + +void ImageEntityItem::setBillboardMode(BillboardMode value) { + withWriteLock([&] { + _billboardMode = value; + }); +} + +QRect ImageEntityItem::getSubImage() const { + QRect result; + withReadLock([&] { + result = _subImage; + }); + return result; +} + +void ImageEntityItem::setSubImage(const QRect& subImage) { + withWriteLock([&] { + _subImage = subImage; + }); +} + +void ImageEntityItem::setColor(const glm::u8vec3& color) { + withWriteLock([&] { + _color = color; + }); +} + +glm::u8vec3 ImageEntityItem::getColor() const { + return resultWithReadLock([&] { + return _color; + }); +} + +void ImageEntityItem::setAlpha(float alpha) { + withWriteLock([&] { + _alpha = alpha; + }); +} + +float ImageEntityItem::getAlpha() const { + return resultWithReadLock([&] { + return _alpha; + }); +} \ No newline at end of file diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h new file mode 100644 index 0000000000..228f86ca03 --- /dev/null +++ b/libraries/entities/src/ImageEntityItem.h @@ -0,0 +1,86 @@ +// +// Created by Sam Gondelman on 11/29/18 +// Copyright 2018 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_ImageEntityItem_h +#define hifi_ImageEntityItem_h + +#include "EntityItem.h" + +class ImageEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + ImageEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + + virtual void setUnscaledDimensions(const glm::vec3& value) override; + + // methods for getting/setting all properties of an entity + EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; + bool setProperties(const EntityItemProperties& properties) override; + + EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + virtual bool supportsDetailedIntersection() const override { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; + virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, + const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; + + void setImageURL(const QString& imageUrl); + QString getImageURL() const; + + void setEmissive(bool emissive); + bool getEmissive() const; + + void setKeepAspectRatio(bool keepAspectRatio); + bool getKeepAspectRatio() const; + + void setBillboardMode(BillboardMode value); + BillboardMode getBillboardMode() const; + + void setSubImage(const QRect& subImage); + QRect getSubImage() const; + + void setColor(const glm::u8vec3& color); + glm::u8vec3 getColor() const; + + void setAlpha(float alpha); + float getAlpha() const; + +protected: + QString _imageURL; + bool _emissive { false }; + bool _keepAspectRatio { true }; + BillboardMode _billboardMode; + QRect _subImage; + + glm::u8vec3 _color; + float _alpha; +}; + +#endif // hifi_ImageEntityItem_h diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index e68e287ee2..067a9e0b19 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -120,6 +120,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL); READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); + READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); + READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); + READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector, setJointRotations); + READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); + READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints); // grab a local copy of _animationProperties to avoid multiple locks @@ -140,13 +145,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, bytesRead += bytesFromAnimation; dataAt += bytesFromAnimation; - READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); - - READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); - READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector, setJointRotations); - READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); - READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); - return bytesRead; } @@ -158,12 +156,12 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& requestedProperties += PROP_COMPOUND_SHAPE_URL; requestedProperties += PROP_TEXTURES; requestedProperties += PROP_SHAPE_TYPE; - requestedProperties += _animationProperties.getEntityProperties(params); requestedProperties += PROP_JOINT_ROTATIONS_SET; requestedProperties += PROP_JOINT_ROTATIONS; requestedProperties += PROP_JOINT_TRANSLATIONS_SET; requestedProperties += PROP_JOINT_TRANSLATIONS; requestedProperties += PROP_RELAY_PARENT_JOINTS; + requestedProperties += _animationProperties.getEntityProperties(params); return requestedProperties; } @@ -182,19 +180,17 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); + APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, getJointRotationsSet()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, getJointRotations()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, getJointTranslations()); APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, getRelayParentJoints()); withReadLock([&] { _animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); }); - - APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); - - APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, getJointRotationsSet()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, getJointRotations()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, getJointTranslations()); } diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index acdeac0e93..2cafbd017e 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -409,11 +409,10 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() { EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); // FIXME - this doesn't appear to get used + COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxParticles, getMaxParticles); COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(isEmitting, getIsEmitting); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitSpeed, getEmitSpeed); @@ -421,24 +420,33 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropert COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitOrientation, getEmitOrientation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitDimensions, getEmitDimensions); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRadiusStart, getEmitRadiusStart); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(polarStart, getPolarStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(polarFinish, getPolarFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(azimuthStart, getAzimuthStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(azimuthFinish, getAzimuthFinish); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitAcceleration, getEmitAcceleration); COPY_ENTITY_PROPERTY_TO_PROPERTIES(accelerationSpread, getAccelerationSpread); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish); + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorStart, getColorStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorFinish, getColorFinish); + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleSpin, getParticleSpin); COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinSpread, getSpinSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinStart, getSpinStart); @@ -451,11 +459,10 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropert bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(isEmitting, setIsEmitting); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitSpeed, setEmitSpeed); @@ -463,24 +470,33 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitOrientation, setEmitOrientation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitDimensions, setEmitDimensions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRadiusStart, setEmitRadiusStart); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(polarStart, setPolarStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(polarFinish, setPolarFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(azimuthStart, setAzimuthStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(azimuthFinish, setAzimuthFinish); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitAcceleration, setEmitAcceleration); SET_ENTITY_PROPERTY_FROM_PROPERTIES(accelerationSpread, setAccelerationSpread); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish); + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorStart, setColorStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorFinish, setColorFinish); + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleSpin, setParticleSpin); SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinSpread, setSpinSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinStart, setSpinStart); @@ -514,40 +530,42 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch int bytesRead = 0; const unsigned char* dataAt = data; - READ_ENTITY_PROPERTY(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles); READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan); + + READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate); - - READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); - READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); - READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - - READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); - READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); - READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); - - READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, u8vec3Color, setColorSpread); - READ_ENTITY_PROPERTY(PROP_COLOR_START, vec3Color, setColorStart); - READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, vec3Color, setColorFinish); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); - READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); - READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); - READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed); READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread); READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, quat, setEmitOrientation); READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions); READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); + READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart); READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish); READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart); READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); + READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); + READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); + + READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); + READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); + READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); + + READ_ENTITY_PROPERTY(PROP_COLOR, u8vec3Color, setColor); + READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, u8vec3Color, setColorSpread); + READ_ENTITY_PROPERTY(PROP_COLOR_START, vec3Color, setColorStart); + READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, vec3Color, setColorFinish); + + READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); + READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); + READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); + READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); + + READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); READ_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, float, setParticleSpin); @@ -562,36 +580,44 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_MAX_PARTICLES; requestedProperties += PROP_LIFESPAN; + requestedProperties += PROP_EMITTING_PARTICLES; requestedProperties += PROP_EMIT_RATE; - requestedProperties += PROP_EMIT_ACCELERATION; - requestedProperties += PROP_ACCELERATION_SPREAD; - requestedProperties += PROP_PARTICLE_RADIUS; - requestedProperties += PROP_TEXTURES; - requestedProperties += PROP_RADIUS_SPREAD; - requestedProperties += PROP_RADIUS_START; - requestedProperties += PROP_RADIUS_FINISH; - requestedProperties += PROP_COLOR_SPREAD; - requestedProperties += PROP_COLOR_START; - requestedProperties += PROP_COLOR_FINISH; - requestedProperties += PROP_ALPHA; - requestedProperties += PROP_ALPHA_SPREAD; - requestedProperties += PROP_ALPHA_START; - requestedProperties += PROP_ALPHA_FINISH; requestedProperties += PROP_EMIT_SPEED; requestedProperties += PROP_SPEED_SPREAD; requestedProperties += PROP_EMIT_ORIENTATION; requestedProperties += PROP_EMIT_DIMENSIONS; requestedProperties += PROP_EMIT_RADIUS_START; + requestedProperties += PROP_POLAR_START; requestedProperties += PROP_POLAR_FINISH; requestedProperties += PROP_AZIMUTH_START; requestedProperties += PROP_AZIMUTH_FINISH; + + requestedProperties += PROP_EMIT_ACCELERATION; + requestedProperties += PROP_ACCELERATION_SPREAD; + + requestedProperties += PROP_PARTICLE_RADIUS; + requestedProperties += PROP_RADIUS_SPREAD; + requestedProperties += PROP_RADIUS_START; + requestedProperties += PROP_RADIUS_FINISH; + + requestedProperties += PROP_COLOR; + requestedProperties += PROP_COLOR_SPREAD; + requestedProperties += PROP_COLOR_START; + requestedProperties += PROP_COLOR_FINISH; + + requestedProperties += PROP_ALPHA; + requestedProperties += PROP_ALPHA_SPREAD; + requestedProperties += PROP_ALPHA_START; + requestedProperties += PROP_ALPHA_FINISH; + + requestedProperties += PROP_TEXTURES; requestedProperties += PROP_EMITTER_SHOULD_TRAIL; + requestedProperties += PROP_PARTICLE_SPIN; requestedProperties += PROP_SPIN_SPREAD; requestedProperties += PROP_SPIN_START; @@ -610,36 +636,44 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, getIsEmitting()); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, getMaxParticles()); APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, getLifespan()); + APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, getIsEmitting()); + APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, getEmitRate()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, getEmitAcceleration()); - APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, getAccelerationSpread()); - APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius()); - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, getColorSpread()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish()); APPEND_ENTITY_PROPERTY(PROP_EMIT_SPEED, getEmitSpeed()); APPEND_ENTITY_PROPERTY(PROP_SPEED_SPREAD, getSpeedSpread()); APPEND_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, getEmitOrientation()); APPEND_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, getEmitDimensions()); APPEND_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, getEmitRadiusStart()); + APPEND_ENTITY_PROPERTY(PROP_POLAR_START, getPolarStart()); APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish()); + + APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, getEmitAcceleration()); + APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, getAccelerationSpread()); + + APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart()); + APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish()); + + APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); + APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, getColorSpread()); + APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart()); + APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish()); + + APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish()); + + APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail()); + APPEND_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, getParticleSpin()); APPEND_ENTITY_PROPERTY(PROP_SPIN_SPREAD, getSpinSpread()); APPEND_ENTITY_PROPERTY(PROP_SPIN_START, getSpinStart()); @@ -647,8 +681,6 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, getRotateWithEntity()); } - - void ParticleEffectEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << "PA EFFECT EntityItem id:" << getEntityItemID() << "---------------------------------------------"; @@ -749,4 +781,4 @@ particle::Properties ParticleEffectEntityItem::getParticleProperties() const { } return result; -} +} \ No newline at end of file diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index c72256822d..d16a2f93d4 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -43,6 +43,7 @@ EntityItemProperties PolyLineEntityItem::getProperties(const EntityPropertyFlags COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth); COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(normals, getNormals); COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeColors, getStrokeColors); COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeWidths, getStrokeWidths); @@ -59,6 +60,7 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineWidth, setLineWidth); SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(normals, setNormals); SET_ENTITY_PROPERTY_FROM_PROPERTIES(strokeColors, setStrokeColors); SET_ENTITY_PROPERTY_FROM_PROPERTIES(strokeWidths, setStrokeWidths); @@ -203,6 +205,7 @@ int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_COLOR, glm::u8vec3, setColor); READ_ENTITY_PROPERTY(PROP_LINE_WIDTH, float, setLineWidth); READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector, setLinePoints); + READ_ENTITY_PROPERTY(PROP_NORMALS, QVector, setNormals); READ_ENTITY_PROPERTY(PROP_STROKE_COLORS, QVector, setStrokeColors); READ_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, QVector, setStrokeWidths); @@ -217,6 +220,7 @@ EntityPropertyFlags PolyLineEntityItem::getEntityProperties(EncodeBitstreamParam requestedProperties += PROP_COLOR; requestedProperties += PROP_LINE_WIDTH; requestedProperties += PROP_LINE_POINTS; + requestedProperties += PROP_NORMALS; requestedProperties += PROP_STROKE_COLORS; requestedProperties += PROP_STROKE_WIDTHS; @@ -239,6 +243,7 @@ void PolyLineEntityItem::appendSubclassData(OctreePacketData* packetData, Encode APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, getLineWidth()); APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints()); + APPEND_ENTITY_PROPERTY(PROP_NORMALS, getNormals()); APPEND_ENTITY_PROPERTY(PROP_STROKE_COLORS, getStrokeColors()); APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, getStrokeWidths()); diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index f67134da0a..08af12a289 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -158,9 +158,9 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); if (somethingChanged) { bool wantDebug = false; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 8dd4877ce2..b178ce33c3 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -27,7 +27,6 @@ const QString TextEntityItem::DEFAULT_TEXT(""); const float TextEntityItem::DEFAULT_LINE_HEIGHT = 0.1f; const glm::u8vec3 TextEntityItem::DEFAULT_TEXT_COLOR = { 255, 255, 255 }; const glm::u8vec3 TextEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0}; -const bool TextEntityItem::DEFAULT_FACE_CAMERA = false; EntityItemPointer TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity(new TextEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); @@ -39,9 +38,8 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en _type = EntityTypes::Text; } -const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; - void TextEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; // NOTE: Text Entities always have a "depth" of 1cm. EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } @@ -53,7 +51,7 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textColor, getTextColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundColor, getBackgroundColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(faceCamera, getFaceCamera); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode); return properties; } @@ -65,7 +63,7 @@ bool TextEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textColor, setTextColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundColor, setBackgroundColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(faceCamera, setFaceCamera); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode); if (somethingChanged) { bool wantDebug = false; @@ -93,7 +91,7 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight); READ_ENTITY_PROPERTY(PROP_TEXT_COLOR, glm::u8vec3, setTextColor); READ_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, glm::u8vec3, setBackgroundColor); - READ_ENTITY_PROPERTY(PROP_FACE_CAMERA, bool, setFaceCamera); + READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); return bytesRead; } @@ -104,7 +102,7 @@ EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& p requestedProperties += PROP_LINE_HEIGHT; requestedProperties += PROP_TEXT_COLOR; requestedProperties += PROP_BACKGROUND_COLOR; - requestedProperties += PROP_FACE_CAMERA; + requestedProperties += PROP_BILLBOARD_MODE; return requestedProperties; } @@ -122,7 +120,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, getTextColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor()); - APPEND_ENTITY_PROPERTY(PROP_FACE_CAMERA, getFaceCamera()); + APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode()); } @@ -230,17 +228,17 @@ glm::u8vec3 TextEntityItem::getBackgroundColor() const { }); } -bool TextEntityItem::getFaceCamera() const { - bool result; +BillboardMode TextEntityItem::getBillboardMode() const { + BillboardMode result; withReadLock([&] { - result = _faceCamera; + result = _billboardMode; }); return result; } -void TextEntityItem::setFaceCamera(bool value) { +void TextEntityItem::setBillboardMode(BillboardMode value) { withWriteLock([&] { - _faceCamera = value; + _billboardMode = value; }); } diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 357697fdec..9abef4d198 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -71,16 +71,15 @@ public: glm::u8vec3 getBackgroundColor() const; void setBackgroundColor(const glm::u8vec3& value); - static const bool DEFAULT_FACE_CAMERA; - bool getFaceCamera() const; - void setFaceCamera(bool value); + BillboardMode getBillboardMode() const; + void setBillboardMode(BillboardMode value); private: QString _text; float _lineHeight; glm::u8vec3 _textColor; glm::u8vec3 _backgroundColor; - bool _faceCamera; + BillboardMode _billboardMode; }; #endif // hifi_TextEntityItem_h diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 1b8675caac..ffd1dbba40 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -64,10 +64,10 @@ EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& de COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode); return properties; @@ -110,10 +110,10 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode); somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || @@ -185,10 +185,10 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL); - READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); + READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode); return bytesRead; @@ -197,11 +197,9 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - withReadLock([&] { - requestedProperties += _keyLightProperties.getEntityProperties(params); - requestedProperties += _ambientLightProperties.getEntityProperties(params); - requestedProperties += _skyboxProperties.getEntityProperties(params); - }); + requestedProperties += _keyLightProperties.getEntityProperties(params); + requestedProperties += _ambientLightProperties.getEntityProperties(params); + requestedProperties += _skyboxProperties.getEntityProperties(params); requestedProperties += _hazeProperties.getEntityProperties(params); requestedProperties += _bloomProperties.getEntityProperties(params); @@ -212,10 +210,10 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p requestedProperties += PROP_GHOSTING_ALLOWED; requestedProperties += PROP_FILTER_URL; - requestedProperties += PROP_HAZE_MODE; requestedProperties += PROP_KEY_LIGHT_MODE; requestedProperties += PROP_AMBIENT_LIGHT_MODE; requestedProperties += PROP_SKYBOX_MODE; + requestedProperties += PROP_HAZE_MODE; requestedProperties += PROP_BLOOM_MODE; return requestedProperties; @@ -231,12 +229,14 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits bool successPropertyFits = true; - _keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - _ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); + withReadLock([&] { + _keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + }); _hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); _bloomProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, @@ -249,10 +249,10 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode()); + APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode()); } @@ -262,11 +262,11 @@ void ZoneEntityItem::debugDump() const { qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode); - qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); - qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); - qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); - qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeString(_bloomMode); + qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeAsString(_hazeMode); + qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeAsString(_keyLightMode); + qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeAsString(_ambientLightMode); + qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeAsString(_skyboxMode); + qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeAsString(_bloomMode); _keyLightProperties.debugDump(); _ambientLightProperties.debugDump(); diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index b425b6795d..d1b5033461 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -126,26 +126,6 @@ QString getID(const QVariantList& properties, int index = 0) { return processID(properties.at(index).toString()); } -/// The names of the joints in the Maya HumanIK rig -static const std::array HUMANIK_JOINTS = {{ - "RightHand", - "RightForeArm", - "RightArm", - "Head", - "LeftArm", - "LeftForeArm", - "LeftHand", - "Neck", - "Spine", - "Hips", - "RightUpLeg", - "LeftUpLeg", - "RightLeg", - "LeftLeg", - "RightFoot", - "LeftFoot" -}}; - class FBXModel { public: QString name; @@ -478,32 +458,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr std::map lights; QVariantHash joints = mapping.value("joint").toHash(); - QString jointEyeLeftName = "EyeLeft"; - QString jointEyeRightName = "EyeRight"; - QString jointNeckName = "Neck"; - QString jointRootName = "Hips"; - QString jointLeanName = "Spine"; - QString jointHeadName = "Head"; - QString jointLeftHandName = "LeftHand"; - QString jointRightHandName = "RightHand"; - QString jointEyeLeftID; - QString jointEyeRightID; - QString jointNeckID; - QString jointRootID; - QString jointLeanID; - QString jointHeadID; - QString jointLeftHandID; - QString jointRightHandID; - QString jointLeftToeID; - QString jointRightToeID; - - - QVector humanIKJointNames; - for (int i = 0; i < (int) HUMANIK_JOINTS.size(); i++) { - QByteArray jointName = HUMANIK_JOINTS[i]; - humanIKJointNames.append(processID(getString(joints.value(jointName, jointName)))); - } - QVector humanIKJointIDs(humanIKJointNames.size()); QVariantHash blendshapeMappings = mapping.value("bs").toHash(); @@ -602,42 +556,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr hifiGlobalNodeID = id; } - if (name == jointEyeLeftName || name == "EyeL" || name == "joint_Leye" || (hfmModel.hfmToHifiJointNameMapping.contains(jointEyeLeftName) && (name == hfmModel.hfmToHifiJointNameMapping[jointEyeLeftName]))) { - jointEyeLeftID = getID(object.properties); - - } else if (name == jointEyeRightName || name == "EyeR" || name == "joint_Reye" || (hfmModel.hfmToHifiJointNameMapping.contains(jointEyeRightName) && (name == hfmModel.hfmToHifiJointNameMapping[jointEyeRightName]))) { - jointEyeRightID = getID(object.properties); - - } else if (name == jointNeckName || name == "NeckRot" || name == "joint_neck" || (hfmModel.hfmToHifiJointNameMapping.contains(jointNeckName) && (name == hfmModel.hfmToHifiJointNameMapping[jointNeckName]))) { - jointNeckID = getID(object.properties); - - } else if (name == jointRootName || (hfmModel.hfmToHifiJointNameMapping.contains(jointRootName) && (name == hfmModel.hfmToHifiJointNameMapping[jointRootName]))) { - jointRootID = getID(object.properties); - - } else if (name == jointLeanName || (hfmModel.hfmToHifiJointNameMapping.contains(jointLeanName) && (name == hfmModel.hfmToHifiJointNameMapping[jointLeanName]))) { - jointLeanID = getID(object.properties); - - } else if ((name == jointHeadName) || (hfmModel.hfmToHifiJointNameMapping.contains(jointHeadName) && (name == hfmModel.hfmToHifiJointNameMapping[jointHeadName]))) { - jointHeadID = getID(object.properties); - - } else if (name == jointLeftHandName || name == "LeftHand" || name == "joint_L_hand" || (hfmModel.hfmToHifiJointNameMapping.contains(jointLeftHandName) && (name == hfmModel.hfmToHifiJointNameMapping[jointLeftHandName]))) { - jointLeftHandID = getID(object.properties); - - } else if (name == jointRightHandName || name == "RightHand" || name == "joint_R_hand" || (hfmModel.hfmToHifiJointNameMapping.contains(jointRightHandName) && (name == hfmModel.hfmToHifiJointNameMapping[jointRightHandName]))) { - jointRightHandID = getID(object.properties); - - } else if (name == "LeftToe" || name == "joint_L_toe" || name == "LeftToe_End" || (hfmModel.hfmToHifiJointNameMapping.contains("LeftToe") && (name == hfmModel.hfmToHifiJointNameMapping["LeftToe"]))) { - jointLeftToeID = getID(object.properties); - - } else if (name == "RightToe" || name == "joint_R_toe" || name == "RightToe_End" || (hfmModel.hfmToHifiJointNameMapping.contains("RightToe") && (name == hfmModel.hfmToHifiJointNameMapping["RightToe"]))) { - jointRightToeID = getID(object.properties); - } - - int humanIKJointIndex = humanIKJointNames.indexOf(name); - if (humanIKJointIndex != -1) { - humanIKJointIDs[humanIKJointIndex] = getID(object.properties); - } - glm::vec3 translation; // NOTE: the euler angles as supplied by the FBX file are in degrees glm::vec3 rotationOffset; @@ -1449,28 +1367,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr std::vector shapeVertices; shapeVertices.resize(std::max(1, hfmModel.joints.size()) ); - // find our special joints - hfmModel.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID); - hfmModel.rightEyeJointIndex = modelIDs.indexOf(jointEyeRightID); - hfmModel.neckJointIndex = modelIDs.indexOf(jointNeckID); - hfmModel.rootJointIndex = modelIDs.indexOf(jointRootID); - hfmModel.leanJointIndex = modelIDs.indexOf(jointLeanID); - hfmModel.headJointIndex = modelIDs.indexOf(jointHeadID); - hfmModel.leftHandJointIndex = modelIDs.indexOf(jointLeftHandID); - hfmModel.rightHandJointIndex = modelIDs.indexOf(jointRightHandID); - hfmModel.leftToeJointIndex = modelIDs.indexOf(jointLeftToeID); - hfmModel.rightToeJointIndex = modelIDs.indexOf(jointRightToeID); - - foreach (const QString& id, humanIKJointIDs) { - hfmModel.humanIKJointIndices.append(modelIDs.indexOf(id)); - } - - // extract the translation component of the neck transform - if (hfmModel.neckJointIndex != -1) { - const glm::mat4& transform = hfmModel.joints.at(hfmModel.neckJointIndex).transform; - hfmModel.neckPivot = glm::vec3(transform[3][0], transform[3][1], transform[3][2]); - } - hfmModel.bindExtents.reset(); hfmModel.meshExtents.reset(); diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index e254a91eb0..3e6ba71399 100644 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -533,14 +533,13 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { QJsonDocument d = QJsonDocument::fromJson(data); QJsonObject jsFile = d.object(); - - bool isvalid = setAsset(jsFile); - if (isvalid) { + bool success = setAsset(jsFile); + if (success) { QJsonArray accessors; if (getObjectArrayVal(jsFile, "accessors", accessors, _file.defined)) { foreach(const QJsonValue & accVal, accessors) { if (accVal.isObject()) { - addAccessor(accVal.toObject()); + success = success && addAccessor(accVal.toObject()); } } } @@ -549,7 +548,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "animations", animations, _file.defined)) { foreach(const QJsonValue & animVal, accessors) { if (animVal.isObject()) { - addAnimation(animVal.toObject()); + success = success && addAnimation(animVal.toObject()); } } } @@ -558,7 +557,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "bufferViews", bufferViews, _file.defined)) { foreach(const QJsonValue & bufviewVal, bufferViews) { if (bufviewVal.isObject()) { - addBufferView(bufviewVal.toObject()); + success = success && addBufferView(bufviewVal.toObject()); } } } @@ -567,7 +566,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "buffers", buffers, _file.defined)) { foreach(const QJsonValue & bufVal, buffers) { if (bufVal.isObject()) { - addBuffer(bufVal.toObject()); + success = success && addBuffer(bufVal.toObject()); } } } @@ -576,7 +575,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "cameras", cameras, _file.defined)) { foreach(const QJsonValue & camVal, cameras) { if (camVal.isObject()) { - addCamera(camVal.toObject()); + success = success && addCamera(camVal.toObject()); } } } @@ -585,7 +584,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "images", images, _file.defined)) { foreach(const QJsonValue & imgVal, images) { if (imgVal.isObject()) { - addImage(imgVal.toObject()); + success = success && addImage(imgVal.toObject()); } } } @@ -594,7 +593,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "materials", materials, _file.defined)) { foreach(const QJsonValue & matVal, materials) { if (matVal.isObject()) { - addMaterial(matVal.toObject()); + success = success && addMaterial(matVal.toObject()); } } } @@ -603,7 +602,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "meshes", meshes, _file.defined)) { foreach(const QJsonValue & meshVal, meshes) { if (meshVal.isObject()) { - addMesh(meshVal.toObject()); + success = success && addMesh(meshVal.toObject()); } } } @@ -612,7 +611,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "nodes", nodes, _file.defined)) { foreach(const QJsonValue & nodeVal, nodes) { if (nodeVal.isObject()) { - addNode(nodeVal.toObject()); + success = success && addNode(nodeVal.toObject()); } } } @@ -621,7 +620,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "samplers", samplers, _file.defined)) { foreach(const QJsonValue & samVal, samplers) { if (samVal.isObject()) { - addSampler(samVal.toObject()); + success = success && addSampler(samVal.toObject()); } } } @@ -630,7 +629,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "scenes", scenes, _file.defined)) { foreach(const QJsonValue & sceneVal, scenes) { if (sceneVal.isObject()) { - addScene(sceneVal.toObject()); + success = success && addScene(sceneVal.toObject()); } } } @@ -639,7 +638,7 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "skins", skins, _file.defined)) { foreach(const QJsonValue & skinVal, skins) { if (skinVal.isObject()) { - addSkin(skinVal.toObject()); + success = success && addSkin(skinVal.toObject()); } } } @@ -648,15 +647,12 @@ bool GLTFSerializer::parseGLTF(const QByteArray& data) { if (getObjectArrayVal(jsFile, "textures", textures, _file.defined)) { foreach(const QJsonValue & texVal, textures) { if (texVal.isObject()) { - addTexture(texVal.toObject()); + success = success && addTexture(texVal.toObject()); } } } - } else { - qCDebug(modelformat) << "Error parsing GLTF file."; - return false; - } - return true; + } + return success; } glm::mat4 GLTFSerializer::getModelTransform(const GLTFNode& node) { @@ -927,16 +923,20 @@ HFMModel::Pointer GLTFSerializer::read(const QByteArray& data, const QVariantHas _url = QUrl(QFileInfo(localFileName).absoluteFilePath()); } - parseGLTF(data); - //_file.dump(); - auto hfmModelPtr = std::make_shared(); - HFMModel& hfmModel = *hfmModelPtr; + if (parseGLTF(data)) { + //_file.dump(); + auto hfmModelPtr = std::make_shared(); + HFMModel& hfmModel = *hfmModelPtr; - buildGeometry(hfmModel, _url); - - //hfmDebugDump(data); - return hfmModelPtr; - + buildGeometry(hfmModel, _url); + + //hfmDebugDump(data); + return hfmModelPtr; + } else { + qCDebug(modelformat) << "Error parsing GLTF file."; + } + + return nullptr; } bool GLTFSerializer::readBinary(const QString& url, QByteArray& outdata) { @@ -1188,19 +1188,6 @@ void GLTFSerializer::hfmDebugDump(const HFMModel& hfmModel) { qCDebug(modelformat) << " hasSkeletonJoints =" << hfmModel.hasSkeletonJoints; qCDebug(modelformat) << " offset =" << hfmModel.offset; - qCDebug(modelformat) << " leftEyeJointIndex =" << hfmModel.leftEyeJointIndex; - qCDebug(modelformat) << " rightEyeJointIndex =" << hfmModel.rightEyeJointIndex; - qCDebug(modelformat) << " neckJointIndex =" << hfmModel.neckJointIndex; - qCDebug(modelformat) << " rootJointIndex =" << hfmModel.rootJointIndex; - qCDebug(modelformat) << " leanJointIndex =" << hfmModel.leanJointIndex; - qCDebug(modelformat) << " headJointIndex =" << hfmModel.headJointIndex; - qCDebug(modelformat) << " leftHandJointIndex" << hfmModel.leftHandJointIndex; - qCDebug(modelformat) << " rightHandJointIndex" << hfmModel.rightHandJointIndex; - qCDebug(modelformat) << " leftToeJointIndex" << hfmModel.leftToeJointIndex; - qCDebug(modelformat) << " rightToeJointIndex" << hfmModel.rightToeJointIndex; - qCDebug(modelformat) << " leftEyeSize = " << hfmModel.leftEyeSize; - qCDebug(modelformat) << " rightEyeSize = " << hfmModel.rightEyeSize; - qCDebug(modelformat) << " palmDirection = " << hfmModel.palmDirection; qCDebug(modelformat) << " neckPivot = " << hfmModel.neckPivot; diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index de58d864b3..b6ddbd1e2d 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -270,22 +270,6 @@ public: glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file - int leftEyeJointIndex = -1; - int rightEyeJointIndex = -1; - int neckJointIndex = -1; - int rootJointIndex = -1; - int leanJointIndex = -1; - int headJointIndex = -1; - int leftHandJointIndex = -1; - int rightHandJointIndex = -1; - int leftToeJointIndex = -1; - int rightToeJointIndex = -1; - - float leftEyeSize = 0.0f; // Maximum mesh extents dimension - float rightEyeSize = 0.0f; - - QVector humanIKJointIndices; - glm::vec3 palmDirection; glm::vec3 neckPivot; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 5275c2c78e..43c7b04206 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::EntityHostTypes); + return static_cast(EntityVersion::ImageEntities); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 5da3acdef9..9fbdeabb28 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -246,7 +246,9 @@ enum class EntityVersion : PacketVersion { ScriptGlmVectors, FixedLightSerialization, MaterialRepeat, - EntityHostTypes + EntityHostTypes, + CleanupProperties, + ImageEntities }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 88e83c01c8..6c0bba5ec6 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -546,6 +546,17 @@ bool OctreePacketData::appendValue(const AACube& aaCube) { return success; } +bool OctreePacketData::appendValue(const QRect& value) { + const unsigned char* data = (const unsigned char*)&value; + int length = sizeof(QRect); + bool success = append(data, length); + if (success) { + _bytesOfValues += length; + _totalBytesOfValues += length; + } + return success; +} + bool OctreePacketData::appendPosition(const glm::vec3& value) { const unsigned char* data = (const unsigned char*)&value; int length = sizeof(value); @@ -804,3 +815,8 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, AACube result = AACube(cube.corner, cube.scale); return sizeof(aaCubeData); } + +int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QRect& result) { + memcpy(&result, dataBytes, sizeof(result)); + return sizeof(result); +} \ No newline at end of file diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 46726d83a6..bd1abf8744 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -34,6 +34,7 @@ #include #include "MaterialMappingMode.h" +#include "BillboardMode.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -197,6 +198,9 @@ public: /// appends an AACube value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const AACube& aaCube); + /// appends an QRect value to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const QRect& rect); + /// appends a position to the end of the stream, may fail if new data stream is too long to fit in packet bool appendPosition(const glm::vec3& value); @@ -258,6 +262,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; } static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMappingMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, BillboardMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); @@ -269,6 +274,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); static int unpackDataFromBytes(const unsigned char* dataBytes, AACube& result); + static int unpackDataFromBytes(const unsigned char* dataBytes, QRect& result); private: /// appends raw bytes, might fail if byte would cause packet to be too large diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 86d4793aa5..3e32d19b49 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -137,7 +137,7 @@ void CauterizedModel::updateClusterMatrices() { // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. if (!_cauterizeBoneSet.empty()) { - AnimPose cauterizePose = _rig.getJointPose(hfmModel.neckJointIndex); + AnimPose cauterizePose = _rig.getJointPose(_rig.indexOfJoint("Neck")); cauterizePose.scale() = glm::vec3(0.0001f, 0.0001f, 0.0001f); static const glm::mat4 zeroScale( @@ -145,7 +145,7 @@ void CauterizedModel::updateClusterMatrices() { glm::vec4(0.0f, 0.0001f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0001f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - auto cauterizeMatrix = _rig.getJointTransform(hfmModel.neckJointIndex) * zeroScale; + auto cauterizeMatrix = _rig.getJointTransform(_rig.indexOfJoint("Neck")) * zeroScale; for (int i = 0; i < _cauterizeMeshStates.size(); i++) { Model::MeshState& state = _cauterizeMeshStates[i]; diff --git a/libraries/shared/src/BillboardMode.cpp b/libraries/shared/src/BillboardMode.cpp new file mode 100644 index 0000000000..56251f53f2 --- /dev/null +++ b/libraries/shared/src/BillboardMode.cpp @@ -0,0 +1,25 @@ +// +// Created by Sam Gondelman on 11/30/18 +// Copyright 2018 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 "BillboardMode.h" + +const char* billboardModeNames[] = { + "none", + "yaw", + "full" +}; + +static const size_t MATERIAL_MODE_NAMES = (sizeof(billboardModeNames) / sizeof((billboardModeNames)[0])); + +QString BillboardModeHelpers::getNameForBillboardMode(BillboardMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) { + mode = (BillboardMode)0; + } + + return billboardModeNames[(int)mode]; +} \ No newline at end of file diff --git a/libraries/shared/src/BillboardMode.h b/libraries/shared/src/BillboardMode.h new file mode 100644 index 0000000000..050f939941 --- /dev/null +++ b/libraries/shared/src/BillboardMode.h @@ -0,0 +1,41 @@ +// +// Created by Sam Gondelman on 11/30/18. +// Copyright 2018 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_BillboardMode_h +#define hifi_BillboardMode_h + +#include "QString" + +/**jsdoc + *

How an entity is billboarded.

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
noneThe entity will not be billboarded.
yawThe entity will yaw, but not pitch, to face the camera. Its actual rotation will be ignored.
fullThe entity will be billboarded to face the camera. Its actual rotation will be ignored.
+ * @typedef {string} BillboardMode + */ + +enum class BillboardMode { + NONE = 0, + YAW, + FULL +}; + +class BillboardModeHelpers { +public: + static QString getNameForBillboardMode(BillboardMode mode); +}; + +#endif // hifi_BillboardMode_h + diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index dc84afff93..5394a0f448 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -24,6 +24,7 @@ #include #include #include +#include int vec2MetaTypeId = qRegisterMetaType(); int u8vec3MetaTypeId = qRegisterMetaType(); @@ -1245,3 +1246,31 @@ void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector result << meshFace; } } + +QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures) { + // If textures are unset, revert to original textures + if (textures.isEmpty()) { + return defaultTextures; + } + + // Legacy: a ,\n-delimited list of filename:"texturepath" + if (*textures.cbegin() != '{') { + textures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}"; + } + + QJsonParseError error; + QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error); + // If textures are invalid, revert to original textures + if (error.error != QJsonParseError::NoError) { + qWarning() << "Could not evaluate textures property value:" << textures; + return defaultTextures; + } + + QVariantMap texturesMap = texturesJson.toVariant().toMap(); + // If textures are unset, revert to original textures + if (texturesMap.isEmpty()) { + return defaultTextures; + } + + return texturesJson.toVariant().toMap(); +} \ No newline at end of file diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index ed637fe771..9d5bca6b9f 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -705,5 +705,7 @@ void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResul QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector& vector); void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector& result); +QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures); + #endif // hifi_RegisteredMetaTypes_h diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 13b0498e76..e75687c512 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -377,6 +377,7 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { QObject::connect(quickItem, SIGNAL(windowClosed()), this, SLOT(desktopWindowClosed())); QObject::connect(tabletRootWindow, SIGNAL(webEventReceived(QVariant)), this, SLOT(emitWebEvent(QVariant)), Qt::DirectConnection); + QObject::connect(quickItem, SIGNAL(screenChanged(QVariant, QVariant)), this, SIGNAL(screenChanged(QVariant, QVariant)), Qt::DirectConnection); // forward qml surface events to interface js connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml); @@ -488,6 +489,7 @@ void TabletProxy::setQmlTabletRoot(OffscreenQmlSurface* qmlOffscreenSurface) { _qmlTabletRoot = qmlOffscreenSurface ? qmlOffscreenSurface->getRootItem() : nullptr; if (_qmlTabletRoot && _qmlOffscreenSurface) { QObject::connect(_qmlOffscreenSurface, SIGNAL(webEventReceived(QVariant)), this, SLOT(emitWebEvent(QVariant))); + QObject::connect(_qmlTabletRoot, SIGNAL(screenChanged(QVariant, QVariant)), this, SIGNAL(screenChanged(QVariant, QVariant))); // forward qml surface events to interface js connect(_qmlOffscreenSurface, &OffscreenQmlSurface::fromQml, [this](QVariant message) { @@ -570,7 +572,6 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) { QMetaObject::invokeMethod(root, "setMenuProperties", Q_ARG(QVariant, QVariant::fromValue(menu)), Q_ARG(const QVariant&, QVariant(submenu))); QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL))); _state = State::Menu; - emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL)); _currentPathLoaded = VRMENU_SOURCE_URL; QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); if (_toolbarMode && _desktopWindow) { @@ -640,9 +641,6 @@ void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) { if (root) { QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path)); _state = State::QML; - if (path != _currentPathLoaded) { - emit screenChanged(QVariant("QML"), path); - } _currentPathLoaded = path; QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); if (_toolbarMode && _desktopWindow) { @@ -749,7 +747,6 @@ void TabletProxy::loadHomeScreen(bool forceOntoHomeScreen) { } } _state = State::Home; - emit screenChanged(QVariant("Home"), QVariant(TABLET_HOME_SOURCE_URL)); _currentPathLoaded = TABLET_HOME_SOURCE_URL; } } @@ -810,7 +807,6 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false))); } _state = State::Web; - emit screenChanged(QVariant("Web"), QVariant(url)); _currentPathLoaded = QVariant(url); } else { // tablet is not initialized yet, save information and load when diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index adc09b507f..19efdc042c 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -433,7 +433,6 @@ function fromQml(message) { } break; case 'needsLogIn_loginClicked': - ui.close(); openLoginWindow(); break; case 'disableHmdPreview': diff --git a/scripts/system/edit.js b/scripts/system/edit.js index f9ebe36025..36f9af0ea7 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -42,7 +42,6 @@ var TITLE_OFFSET = 60; var CREATE_TOOLS_WIDTH = 490; var MAX_DEFAULT_ENTITY_LIST_HEIGHT = 942; -var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"; var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg"; var createToolsWindow = new CreateWindow( @@ -398,8 +397,8 @@ const DEFAULT_ENTITY_PROPERTIES = { }, shapeType: "box", collisionless: true, - modelURL: IMAGE_MODEL, - textures: JSON.stringify({ "tex.picture": "" }) + keepAspectRatio: false, + imageURL: DEFAULT_IMAGE }, Web: { dimensions: { @@ -495,9 +494,6 @@ var toolBar = (function () { var type = requestedProperties.type; if (type === "Box" || type === "Sphere") { applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape); - } else if (type === "Image") { - requestedProperties.type = "Model"; - applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Image); } else { applyProperties(properties, DEFAULT_ENTITY_PROPERTIES[type]); } @@ -515,7 +511,7 @@ var toolBar = (function () { } direction = Vec3.multiplyQbyV(direction, Vec3.UNIT_Z); - var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web", "Material"]; + var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web", "Material"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { // Adjust position of entity per bounding box prior to creating it. diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index 89b56c7f7b..406f434a65 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -11,7 +11,6 @@ const DESCENDING_SORT = -1; const ASCENDING_STRING = '▴'; const DESCENDING_STRING = '▾'; const BYTES_PER_MEGABYTE = 1024 * 1024; -const IMAGE_MODEL_NAME = 'default-image-model.fbx'; const COLLAPSE_EXTRA_INFO = "E"; const EXPAND_EXTRA_INFO = "D"; const FILTER_IN_VIEW_ATTRIBUTE = "pressed"; @@ -628,9 +627,6 @@ function loaded() { entityData.forEach(function(entity) { let type = entity.type; let filename = getFilename(entity.url); - if (filename === IMAGE_MODEL_NAME) { - type = "Image"; - } let entityData = { id: entity.id, diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 4e4e73df92..78ef8ac313 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -476,7 +476,7 @@ const GROUPS = [ label: "Image", type: "string", placeholder: "URL", - propertyID: "image", + propertyID: "imageURL", }, ] }, @@ -1821,14 +1821,6 @@ function updateCheckedSubProperty(propertyName, propertyValue, subPropertyElemen updateProperty(propertyName, propertyValue, isParticleProperty); } -function createImageURLUpdateFunction(property) { - return function () { - let newTextures = JSON.stringify({ "tex.picture": this.value }); - updateProperty(property.name, newTextures, property.isParticleProperty); - }; -} - - /** * PROPERTY ELEMENT CREATION FUNCTIONS */ @@ -3132,17 +3124,6 @@ function loaded() { // the event bridge and json parsing handle our avatar id string differently. lastEntityID = '"' + selectedEntityProperties.id + '"'; - // HTML workaround since image is not yet a separate entity type - let IMAGE_MODEL_NAME = 'default-image-model.fbx'; - if (selectedEntityProperties.type === "Model") { - let urlParts = selectedEntityProperties.modelURL.split('/'); - let propsFilename = urlParts[urlParts.length - 1]; - - if (propsFilename === IMAGE_MODEL_NAME) { - selectedEntityProperties.type = "Image"; - } - } - showGroupsForType(selectedEntityProperties.type); if (selectedEntityProperties.locked) { @@ -3290,10 +3271,7 @@ function loaded() { updateVisibleSpaceModeProperties(); - if (selectedEntityProperties.type === "Image") { - let imageLink = JSON.parse(selectedEntityProperties.textures)["tex.picture"]; - getPropertyInputElement("image").value = imageLink; - } else if (selectedEntityProperties.type === "Material") { + if (selectedEntityProperties.type === "Material") { let elParentMaterialNameString = getPropertyInputElement("materialNameToReplace"); let elParentMaterialNameNumber = getPropertyInputElement("submeshToReplace"); let elParentMaterialNameCheckbox = getPropertyInputElement("selectSubmesh"); @@ -3456,8 +3434,6 @@ function loaded() { } }); - getPropertyInputElement("image").addEventListener('change', createImageURLUpdateFunction(properties['textures'])); - // Collapsible sections let elCollapsible = document.getElementsByClassName("collapse-icon"); diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index f27ab6caf2..d19da2b342 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -164,7 +164,7 @@ EntityListTool = function(shouldUseEditTabletApp) { var cameraPosition = Camera.position; PROFILE("getMultipleProperties", function () { var multipleProperties = Entities.getMultipleEntityProperties(ids, ['name', 'type', 'locked', - 'visible', 'renderInfo', 'modelURL', 'materialURL', 'script', 'certificateID']); + 'visible', 'renderInfo', 'modelURL', 'materialURL', 'imageURL', 'script', 'certificateID']); for (var i = 0; i < multipleProperties.length; i++) { var properties = multipleProperties[i]; @@ -174,6 +174,8 @@ EntityListTool = function(shouldUseEditTabletApp) { url = properties.modelURL; } else if (properties.type === "Material") { url = properties.materialURL; + } else if (properties.type === "Image") { + url = properties.imageURL; } entities.push({ id: ids[i],