diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java index 2165339918..28acc77609 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java @@ -14,12 +14,16 @@ package io.highfidelity.hifiinterface; import android.content.Intent; import android.content.res.AssetManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Vibrator; import android.view.HapticFeedbackConstants; import android.view.WindowManager; import android.util.Log; + +import org.qtproject.qt5.android.QtLayout; +import org.qtproject.qt5.android.QtSurface; import org.qtproject.qt5.android.bindings.QtActivity; /*import com.google.vr.cardboard.DisplaySynchronizer; @@ -31,6 +35,9 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.view.View; +import android.widget.FrameLayout; + +import java.lang.reflect.Field; public class InterfaceActivity extends QtActivity { @@ -134,6 +141,7 @@ public class InterfaceActivity extends QtActivity { protected void onResume() { super.onResume(); nativeEnterForeground(); + surfacesWorkaround(); //gvrApi.resumeTracking(); } @@ -158,6 +166,41 @@ public class InterfaceActivity extends QtActivity { Log.w("[VR]", "Portrait detected but not in VR mode. Should not happen"); } } + surfacesWorkaround(); + } + + private void surfacesWorkaround() { + FrameLayout fl = findViewById(android.R.id.content); + if (fl.getChildCount() > 0) { + QtLayout qtLayout = (QtLayout) fl.getChildAt(0); + if (qtLayout.getChildCount() > 1) { + QtSurface s1 = (QtSurface) qtLayout.getChildAt(0); + QtSurface s2 = (QtSurface) qtLayout.getChildAt(1); + Integer subLayer1 = 0; + Integer subLayer2 = 0; + try { + String field; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + field = "mSubLayer"; + } else { + field = "mWindowType"; + } + Field f = s1.getClass().getSuperclass().getDeclaredField(field); + f.setAccessible(true); + subLayer1 = (Integer) f.get(s1); + subLayer2 = (Integer) f.get(s2); + if (subLayer1 < subLayer2) { + s1.setVisibility(View.VISIBLE); + s2.setVisibility(View.INVISIBLE); + } else { + s1.setVisibility(View.INVISIBLE); + s2.setVisibility(View.VISIBLE); + } + } catch (ReflectiveOperationException e) { + Log.e(TAG, "Workaround failed"); + } + } + } } public void openUrlInAndroidWebView(String urlString) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c4f700fc20..7f834f1c88 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7652,18 +7652,18 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa }); } -void Application::takeSecondaryCameraSnapshot(const QString& filename) { - postLambdaEvent([filename, this] { +void Application::takeSecondaryCameraSnapshot(const bool& notify, const QString& filename) { + postLambdaEvent([notify, filename, this] { QString snapshotPath = DependencyManager::get()->saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, TestScriptingInterface::getInstance()->getTestResultsLocation()); - emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, true); + emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, notify); }); } -void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) { - postLambdaEvent([filename, cubemapOutputFormat, cameraPosition] { - DependencyManager::get()->save360Snapshot(cameraPosition, cubemapOutputFormat, filename); +void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) { + postLambdaEvent([notify, filename, cubemapOutputFormat, cameraPosition] { + DependencyManager::get()->save360Snapshot(cameraPosition, cubemapOutputFormat, notify, filename); }); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 0fea476c07..236edf8bb0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -281,8 +281,11 @@ public: float getGameLoopRate() const { return _gameLoopCounter.rate(); } void takeSnapshot(bool notify, bool includeAnimated = false, float aspectRatio = 0.0f, const QString& filename = QString()); - void takeSecondaryCameraSnapshot(const QString& filename = QString()); - void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename = QString()); + void takeSecondaryCameraSnapshot(const bool& notify, const QString& filename = QString()); + void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, + const bool& cubemapOutputFormat, + const bool& notify, + const QString& filename = QString()); void shareSnapshot(const QString& filename, const QUrl& href = QUrl("")); diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index af9b5c8a46..0aea7a02c5 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -446,12 +446,12 @@ void WindowScriptingInterface::takeSnapshot(bool notify, bool includeAnimated, f qApp->takeSnapshot(notify, includeAnimated, aspectRatio, filename); } -void WindowScriptingInterface::takeSecondaryCameraSnapshot(const QString& filename) { - qApp->takeSecondaryCameraSnapshot(filename); +void WindowScriptingInterface::takeSecondaryCameraSnapshot(const bool& notify, const QString& filename) { + qApp->takeSecondaryCameraSnapshot(notify, filename); } -void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) { - qApp->takeSecondaryCamera360Snapshot(cameraPosition, cubemapOutputFormat, filename); +void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) { + qApp->takeSecondaryCamera360Snapshot(cameraPosition, cubemapOutputFormat, notify, filename); } void WindowScriptingInterface::shareSnapshot(const QString& path, const QUrl& href) { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 5ddbc30dd3..452d9681ca 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -362,27 +362,31 @@ public slots: * Takes a still snapshot of the current view from the secondary camera that can be set up through the {@link Render} API. * NOTE: to provide a non-default value - all previous parameters must be provided. * @function Window.takeSecondaryCameraSnapshot + * @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken} + * signal. * @param {string} [filename=""] - If this parameter is not given, the image will be saved as 'hifi-snap-by--YYYY-MM-DD_HH-MM-SS'. * If this parameter is "" then the image will be saved as ".jpg". * Otherwise, the image will be saved to this filename, with an appended ".jpg". * * var filename = QString(); */ - void takeSecondaryCameraSnapshot(const QString& filename = QString()); + void takeSecondaryCameraSnapshot(const bool& notify = true, const QString& filename = QString()); /**jsdoc * Takes a 360 snapshot given a position of the secondary camera (which does not need to have been previously set up). - * @function Window.takeSecondaryCameraSnapshot + * @function Window.takeSecondaryCamera360Snapshot * @param {vec3} [cameraPosition] - The (x, y, z) position of the camera for the 360 snapshot * @param {boolean} [cubemapOutputFormat=false] - If true then the snapshot is saved as a cube map image, * otherwise is saved as an equirectangular image. + * @param {boolean} [notify=true] - This value is passed on through the {@link Window.stillSnapshotTaken|stillSnapshotTaken} + * signal. * @param {string} [filename=""] - If this parameter is not given, the image will be saved as 'hifi-snap-by--YYYY-MM-DD_HH-MM-SS'. * If this parameter is "" then the image will be saved as ".jpg". * Otherwise, the image will be saved to this filename, with an appended ".jpg". * * var filename = QString(); */ - void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const QString& filename = QString()); + void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const bool& notify = true, const QString& filename = QString()); /**jsdoc * Emit a {@link Window.connectionAdded|connectionAdded} or a {@link Window.connectionError|connectionError} signal that diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index b2c0ee7ce7..2b306ace91 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -122,8 +122,9 @@ static const glm::quat CAMERA_ORIENTATION_LEFT(glm::quat(glm::radians(glm::vec3( static const glm::quat CAMERA_ORIENTATION_BACK(glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f)))); static const glm::quat CAMERA_ORIENTATION_RIGHT(glm::quat(glm::radians(glm::vec3(0.0f, 270.0f, 0.0f)))); static const glm::quat CAMERA_ORIENTATION_UP(glm::quat(glm::radians(glm::vec3(90.0f, 0.0f, 0.0f)))); -void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename) { +void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) { _snapshotFilename = filename; + _notify360 = notify; _cubemapOutputFormat = cubemapOutputFormat; SecondaryCameraJobConfig* secondaryCameraRenderConfig = static_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera")); @@ -247,7 +248,8 @@ void Snapshot::convertToCubemap() { painter.end(); - emit DependencyManager::get()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), true); + emit DependencyManager::get()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), + _notify360); } void Snapshot::convertToEquirectangular() { @@ -327,7 +329,8 @@ void Snapshot::convertToEquirectangular() { } } - emit DependencyManager::get()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), true); + emit DependencyManager::get()->snapshot360Taken(saveSnapshot(outputImage, _snapshotFilename), + _notify360); } QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) { diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h index 2bac857a97..8fc05775bd 100644 --- a/interface/src/ui/Snapshot.h +++ b/interface/src/ui/Snapshot.h @@ -50,7 +50,10 @@ class Snapshot : public QObject, public Dependency { public: Snapshot(); QString saveSnapshot(QImage image, const QString& filename, const QString& pathname = QString()); - void save360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const QString& filename); + void save360Snapshot(const glm::vec3& cameraPosition, + const bool& cubemapOutputFormat, + const bool& notify, + const QString& filename); QTemporaryFile* saveTempSnapshot(QImage image); SnapshotMetaData* parseSnapshotData(QString snapshotPath); @@ -89,6 +92,7 @@ private: const QString& userSelectedFilename = QString(), const QString& userSelectedPathname = QString()); QString _snapshotFilename; + bool _notify360; bool _cubemapOutputFormat; QTimer _snapshotTimer; qint16 _snapshotIndex; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 4ed7072f23..a4ae8bc815 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -361,6 +361,8 @@ vectorType ModelOverlay::mapJoints(mapFunction function) const { * {@link Overlays.findRayIntersection|findRayIntersection} ignores the overlay. * @property {boolean} drawInFront=false - If true, the overlay is rendered in front of other overlays that don't * have drawInFront set to true, and in front of entities. + * @property {boolean} isGroupCulled=false - If true, the mesh parts of the model are LOD culled as a group. + * If false, separate mesh parts will be LOD culled individually. * @property {boolean} grabbable=false - Signal to grabbing scripts whether or not this overlay can be grabbed. * @property {Uuid} parentID=null - The avatar, entity, or overlay that the overlay is parented to. * @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index b61f24972a..ae4c13d96f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -157,16 +157,20 @@ Item::Bound EntityRenderer::getBound() { return _bound; } +render::hifi::Tag EntityRenderer::getTagMask() const { + return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW; +} + ItemKey EntityRenderer::getKey() { if (isTransparent()) { - return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()); } // This allows shapes to cast shadows if (_canCastShadow) { - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).withShadowCaster(); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withShadowCaster(); } else { - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()); } } @@ -380,6 +384,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa _moving = entity->isMovingRelativeToParent(); _visible = entity->getVisible(); + setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera()); _canCastShadow = entity->getCanCastShadow(); _cauterized = entity->getCauterized(); _needsRenderUpdate = false; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index ada57c8ab0..e1ce2ed39e 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -18,6 +18,7 @@ #include "AbstractViewStateInterface.h" #include "EntitiesRendererLogging.h" #include +#include class EntityTreeRenderer; @@ -74,6 +75,7 @@ protected: virtual Item::Bound getBound() override; virtual void render(RenderArgs* args) override final; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; + virtual render::hifi::Tag getTagMask() const; // Returns true if the item in question needs to have updateInScene called because of internal rendering state changes virtual bool needsRenderUpdate() const; @@ -97,6 +99,8 @@ protected: bool isFading() const { return _isFading; } virtual bool isTransparent() const { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; } inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; } + + virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } template T withReadLockResult(const std::function& f) { @@ -129,6 +133,7 @@ protected: bool _isFading{ _entitiesShouldFadeFunction() }; bool _prevIsTransparent { false }; bool _visible { false }; + bool _isVisibleInSecondaryCamera { false }; bool _canCastShadow { false }; bool _cauterized { false }; bool _moving { false }; diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 7cea841bf0..eabcb68e4f 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -43,7 +43,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& ItemKey MaterialEntityRenderer::getKey() { ItemKey::Builder builder; - builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + builder.withTypeShape().withTagBits(getTagMask()); if (!_visible) { builder.withInvisible(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 4026a94f65..a91534668c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1060,9 +1060,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) { if (didVisualGeometryRequestSucceed) { - _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()); } else { - _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(getTagMask()); } } @@ -1070,6 +1070,13 @@ ItemKey ModelEntityRenderer::getKey() { return _itemKey; } +render::hifi::Tag ModelEntityRenderer::getTagMask() const { + // Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint) + return _cauterized ? + (_isVisibleInSecondaryCamera ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE) : + Parent::getTagMask(); // calculate which views to be shown in +} + uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { if (_model) { auto metaSubItems = _subRenderItemIDs; @@ -1329,6 +1336,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce emit DependencyManager::get()-> modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model); } + _didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed; }); connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate); connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate); @@ -1386,11 +1394,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce entity->updateModelBounds(); entity->stopModelOverrideIfNoParent(); - // Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint) - auto tagMask = _cauterized ? - render::hifi::TAG_SECONDARY_VIEW : // draw in every view except the main one (view zero) - render::hifi::TAG_ALL_VIEWS; // draw in all views - + render::hifi::Tag tagMask = getTagMask(); if (model->isVisible() != _visible) { // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state @@ -1478,6 +1482,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } } +void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) { + Parent::setIsVisibleInSecondaryCamera(value); + setKey(_didLastVisualGeometryRequestSucceed); +} + void ModelEntityRenderer::flagForCollisionGeometryUpdate() { _needsCollisionGeometryUpdate = true; emit requestRenderUpdate(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 68bc70c8a9..a48a25b0b2 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -164,6 +164,10 @@ protected: void flagForCollisionGeometryUpdate(); void setCollisionMeshKey(const void* key); + render::hifi::Tag getTagMask() const override; + + void setIsVisibleInSecondaryCamera(bool value) override; + private: void animate(const TypedEntityPointer& entity); void mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames); @@ -202,6 +206,8 @@ private: render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; + bool _didLastVisualGeometryRequestSucceed { false }; + void processMaterials(); }; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index ee77646920..881c39c0bd 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn ItemKey ParticleEffectEntityRenderer::getKey() { if (_visible) { - return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + return ItemKey::Builder::transparentShape().withTagBits(getTagMask()); } else { - return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build(); + return ItemKey::Builder().withInvisible().withTagBits(getTagMask()).build(); } } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index d571eac35c..7cab57123d 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity) } ItemKey PolyLineEntityRenderer::getKey() { - return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()); } ShapeKey PolyLineEntityRenderer::getShapeKey() { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 70c87dca6f..7077ae799b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -169,7 +169,7 @@ public: } protected: - virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } + virtual ItemKey getKey() override { return ItemKey::Builder::opaqueShape().withTagBits(getTagMask()); } virtual ShapeKey getShapeKey() override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 1d34837a58..69068b81d2 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -139,7 +139,7 @@ bool ShapeEntityRenderer::isTransparent() const { ItemKey ShapeEntityRenderer::getKey() { ItemKey::Builder builder; - builder.withTypeShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); + builder.withTypeShape().withTypeMeta().withTagBits(getTagMask()); withReadLock([&] { if (isTransparent()) { diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 5062162b6e..c5035431f6 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe ItemKey ZoneEntityRenderer::getKey() { - return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build(); + return ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).build(); } bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d9365b516f..70881fbc40 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1383,6 +1383,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(isVisibleInSecondaryCamera, setIsVisibleInSecondaryCamera); // Certifiable Properties SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemName, setItemName); @@ -2760,6 +2761,28 @@ void EntityItem::setVisible(bool value) { } } +bool EntityItem::isVisibleInSecondaryCamera() const { + bool result; + withReadLock([&] { + result = _isVisibleInSecondaryCamera; + }); + return result; +} + +void EntityItem::setIsVisibleInSecondaryCamera(bool value) { + bool changed = false; + withWriteLock([&] { + if (_isVisibleInSecondaryCamera != value) { + changed = true; + _isVisibleInSecondaryCamera = value; + } + }); + + if (changed) { + emit requestRenderUpdate(); + } +} + bool EntityItem::getCanCastShadow() const { bool result; withReadLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bc4767d3db..0acf8dbbc1 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -277,6 +277,9 @@ public: bool getVisible() const; void setVisible(bool value); + bool isVisibleInSecondaryCamera() const; + void setIsVisibleInSecondaryCamera(bool value); + bool getCanCastShadow() const; void setCanCastShadow(bool value); @@ -578,6 +581,7 @@ protected: glm::vec3 _registrationPoint { ENTITY_ITEM_DEFAULT_REGISTRATION_POINT }; float _angularDamping { ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING }; bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE }; + bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA }; bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW }; bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS }; uint16_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 84d3e2405d..9aa15ee8a6 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -368,6 +368,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_DATA, materialData); + CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); @@ -490,6 +491,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * {@link Entities.EntityType|Model} and {@link Entities.EntityType|Shape} entities. Shadows are cast if inside a * {@link Entities.EntityType|Zone} entity with castShadows enabled in its * {@link Entities.EntityProperties-Zone|keyLight} property. + * @property {boolean} isVisibleInSecondaryCamera=true - Whether or not the entity is rendered in the secondary camera. If true then the entity is rendered. * * @property {Vec3} position=0,0,0 - The position of the entity. * @property {Quat} rotation=0,0,0,1 - The orientation of the entity with respect to world coordinates. @@ -1226,6 +1228,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool 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 COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_NAME, itemName); @@ -1565,6 +1568,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, glmVec2, setMaterialMappingScale); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData); + COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1944,6 +1948,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_DATA, MaterialData, materialData, QString); + ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool); + // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString); @@ -3041,6 +3047,8 @@ void EntityItemProperties::markAllChanged() { _cloneDynamicChanged = true; _cloneAvatarEntityChanged = true; _cloneOriginIDChanged = true; + + _isVisibleInSecondaryCameraChanged = true; } // The minimum bounding box for the entity. @@ -3319,6 +3327,9 @@ QList EntityItemProperties::listChangedProperties() { if (materialDataChanged()) { out += "materialData"; } + if (isVisibleInSecondaryCameraChanged()) { + out += "isVisibleInSecondaryCamera"; + } // Certifiable Properties if (itemNameChanged()) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 01c43a46b3..e46eb73910 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -233,6 +233,8 @@ public: DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0); DEFINE_PROPERTY_REF(PROP_MATERIAL_DATA, MaterialData, materialData, QString, ""); + DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA); + // 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); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 0fd926e677..6c39e90c91 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -46,6 +46,7 @@ const quint32 ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION = 0; const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const bool ENTITY_ITEM_DEFAULT_VISIBLE = true; +const bool ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA = true; const bool ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW { true }; const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString(""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 2fdcd62949..d43a991f22 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -249,6 +249,8 @@ enum EntityPropertyList { PROP_MATERIAL_MAPPING_ROT, PROP_MATERIAL_DATA, + PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over the wire, only used locally + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index e95c05aef9..df4cdfb385 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -83,7 +83,8 @@ "position": cameraPosition, "shapeType": "simple-compound", "type": "Model", - "userData": "{\"grabbableKey\":{\"grabbable\":true}}" + "userData": "{\"grabbableKey\":{\"grabbable\":true}}", + "isVisibleInSecondaryCamera": false }, true); spectatorCameraConfig.attachedEntityId = camera; updateOverlay();