From 1b29946a4839d88b8eae611cd11a12849a95dff3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 27 Apr 2018 17:26:05 -0700 Subject: [PATCH] I feel so close; why isn't this variable capturing? --- interface/src/Application.cpp | 6 ++ interface/src/Application.h | 1 + .../scripting/WindowScriptingInterface.cpp | 4 + .../src/scripting/WindowScriptingInterface.h | 12 +++ interface/src/ui/Snapshot.cpp | 82 +++++++++++++++++++ interface/src/ui/Snapshot.h | 1 + .../spectator-camera/SpectatorCamera.qml | 40 ++++----- .../spectator-camera/spectatorCamera.js | 33 ++++++-- 8 files changed, 147 insertions(+), 32 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c38caca090..6487254e26 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7278,6 +7278,12 @@ void Application::takeSecondaryCameraSnapshot(const QString& filename) { }); } +void Application::takeSecondaryCamera360Snapshot(const QString& filename) { + postLambdaEvent([filename, this] { + Snapshot::save360Snapshot(filename); + }); +} + void Application::shareSnapshot(const QString& path, const QUrl& href) { postLambdaEvent([path, href] { // not much to do here, everything is done in snapshot code... diff --git a/interface/src/Application.h b/interface/src/Application.h index 74b0e5a110..3c0babdc5d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -273,6 +273,7 @@ public: void takeSnapshot(bool notify, bool includeAnimated = false, float aspectRatio = 0.0f, const QString& filename = QString()); void takeSecondaryCameraSnapshot(const QString& filename = QString()); + void takeSecondaryCamera360Snapshot(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 9c46f9e98a..2d94e3e02e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -431,6 +431,10 @@ void WindowScriptingInterface::takeSecondaryCameraSnapshot(const QString& filena qApp->takeSecondaryCameraSnapshot(filename); } +void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const QString& filename) { + qApp->takeSecondaryCamera360Snapshot(filename); +} + void WindowScriptingInterface::shareSnapshot(const QString& path, const QUrl& href) { qApp->shareSnapshot(path, href); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 0b766d2097..d3105acd72 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -366,6 +366,18 @@ public slots: */ void takeSecondaryCameraSnapshot(const QString& filename = QString()); + /**jsdoc + * Takes a 360 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 {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 QString& filename = QString()); + /**jsdoc * Emit a {@link Window.connectionAdded|connectionAdded} or a {@link Window.connectionError|connectionError} signal that * indicates whether or not a user connection was successfully made using the Web API. diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 69103a40b5..5feca7ee70 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -29,8 +29,12 @@ #include #include #include +#include +#include #include "Application.h" +#include "scripting/WindowScriptingInterface.h" +#include "MainWindow.h" #include "Snapshot.h" #include "SnapshotUploader.h" @@ -87,6 +91,84 @@ QString Snapshot::saveSnapshot(QImage image, const QString& filename) { return snapshotPath; } +void Snapshot::save360Snapshot(const QString& filename) { + SecondaryCameraJobConfig* secondaryCameraRenderConfig = static_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera")); + + // Save initial values of secondary camera render config + auto oldAttachedEntityId = secondaryCameraRenderConfig->property("attachedEntityId"); + auto oldOrientation = secondaryCameraRenderConfig->property("orientation"); + auto oldvFoV = secondaryCameraRenderConfig->property("vFoV"); + auto oldNearClipPlaneDistance = secondaryCameraRenderConfig->property("nearClipPlaneDistance"); + auto oldFarClipPlaneDistance = secondaryCameraRenderConfig->property("farClipPlaneDistance"); + + // Initialize some secondary camera render config options for 360 snapshot capture + secondaryCameraRenderConfig->resetSizeSpectatorCamera(2048, 2048); + secondaryCameraRenderConfig->setProperty("attachedEntityId", ""); + secondaryCameraRenderConfig->setProperty("vFoV", 90.0f); + secondaryCameraRenderConfig->setProperty("nearClipPlaneDistance", 0.5f); + secondaryCameraRenderConfig->setProperty("farClipPlaneDistance", 1000.0f); + + secondaryCameraRenderConfig->setOrientation(glm::quat(glm::radians(glm::vec3(-90.0f, 0.0f, 0.0f)))); + + qint16 snapshotIndex = 0; + + QTimer* snapshotTimer = new QTimer(); + snapshotTimer->setSingleShot(false); + snapshotTimer->setInterval(200); + connect(snapshotTimer, &QTimer::timeout, [&] { + SecondaryCameraJobConfig* config = static_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera")); + qDebug() << "ZRF HERE" << snapshotIndex; + if (snapshotIndex == 0) { + QImage downImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(); + Snapshot::saveSnapshot(downImage, "down"); + config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 0.0f, 0.0f)))); + } else if (snapshotIndex == 1) { + QImage frontImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(); + Snapshot::saveSnapshot(frontImage, "front"); + config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 90.0f, 0.0f)))); + } else if (snapshotIndex == 2) { + QImage leftImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(); + Snapshot::saveSnapshot(leftImage, "left"); + config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f)))); + } else if (snapshotIndex == 3) { + QImage backImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(); + Snapshot::saveSnapshot(backImage, "back"); + config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 270.0f, 0.0f)))); + } else if (snapshotIndex == 4) { + QImage rightImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(); + Snapshot::saveSnapshot(rightImage, "right"); + config->setOrientation(glm::quat(glm::radians(glm::vec3(90.0f, 0.0f, 0.0f)))); + } else if (snapshotIndex == 5) { + QImage upImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(); + Snapshot::saveSnapshot(upImage, "up"); + } else if (snapshotIndex == 6) { + // Reset secondary camera render config + config->resetSizeSpectatorCamera(qApp->getWindow()->geometry().width(), qApp->getWindow()->geometry().height()); + config->setProperty("attachedEntityId", oldAttachedEntityId); + config->setProperty("vFoV", oldvFoV); + config->setProperty("nearClipPlaneDistance", oldNearClipPlaneDistance); + config->setProperty("farClipPlaneDistance", oldFarClipPlaneDistance); + + QFile* snapshotFile = savedFileForSnapshot(qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), false, filename); + + // we don't need the snapshot file, so close it, grab its filename and delete it + snapshotFile->close(); + + QString snapshotPath = QFileInfo(*snapshotFile).absoluteFilePath(); + + delete snapshotFile; + + snapshotTimer->stop(); + snapshotTimer->deleteLater(); + + emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, true); + } + + snapshotIndex++; + }); + snapshotTimer->start(); +} + QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) { // return whatever we get back from saved file for snapshot return static_cast(savedFileForSnapshot(image, true)); diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h index 62d3ed3db8..834daea0dc 100644 --- a/interface/src/ui/Snapshot.h +++ b/interface/src/ui/Snapshot.h @@ -38,6 +38,7 @@ class Snapshot : public QObject, public Dependency { SINGLETON_DEPENDENCY public: static QString saveSnapshot(QImage image, const QString& filename); + static void save360Snapshot(const QString& filename); static QTemporaryFile* saveTempSnapshot(QImage image); static SnapshotMetaData* parseSnapshotData(QString snapshotPath); diff --git a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml index c1b62368a9..c4dc2c29f6 100644 --- a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml +++ b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml @@ -185,33 +185,11 @@ Rectangle { // SPECTATOR APP DESCRIPTION END // - Item { - visible: !HMD.active; - height: root.height - spectatorDescriptionContainer.height - titleBarContainer.height; - anchors.top: spectatorDescriptionContainer.bottom; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.leftMargin: 25; - anchors.right: parent.right; - anchors.rightMargin: anchors.leftMargin; - - HifiStylesUit.FiraSansRegular { - text: "Spectator Camera only works in VR mode.\nPlease put on your headset."; - size: 18; - color: hifi.colors.lightGrayText; - anchors.fill: parent; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - wrapMode: Text.Wrap; - } - } - // // SPECTATOR CONTROLS START // Item { id: spectatorControlsContainer; - visible: HMD.active; // Size height: root.height - spectatorDescriptionContainer.height - titleBarContainer.height; // Anchors @@ -332,7 +310,7 @@ Rectangle { colorScheme: hifi.colorSchemes.dark; anchors.left: parent.left; anchors.top: monitorShowsSwitch.bottom; - anchors.topMargin: 25; + anchors.topMargin: 14; text: ""; boxSize: 24; onClicked: { @@ -343,6 +321,7 @@ Rectangle { // "Take Snapshot" Checkbox HifiControlsUit.CheckBox { id: takeSnapshotFromControllerCheckBox; + visible: HMD.active; colorScheme: hifi.colorSchemes.dark; anchors.left: parent.left; anchors.top: switchViewFromControllerCheckBox.bottom; @@ -353,6 +332,21 @@ Rectangle { sendToScript({method: 'changeTakeSnapshotFromControllerPreference', params: checked}); } } + + HifiControlsUit.Button { + id: take360SnapshotButton; + text: "Take 360 Snapshot" + colorScheme: hifi.colorSchemes.dark; + color: hifi.buttons.blue; + anchors.top: takeSnapshotFromControllerCheckBox.visible ? takeSnapshotFromControllerCheckBox.bottom : switchViewFromControllerCheckBox.bottom; + anchors.topMargin: 8; + anchors.left: parent.left; + anchors.right: parent.right; + height: 40; + onClicked: { + sendToScript({method: 'takeSecondaryCamera360Snapshot'}); + } + } } // // SPECTATOR CONTROLS END diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index ce445a5f8e..c95e112d49 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -46,7 +46,6 @@ // -Far clip plane distance // -viewFinderOverlay: The in-world overlay that displays the spectator camera's view. // -camera: The in-world entity that corresponds to the spectator camera. - // -cameraIsDynamic: "false" for now - maybe it shouldn't be? False means that the camera won't drift when you let go... // -cameraRotation: The rotation of the spectator camera. // -cameraPosition: The position of the spectator camera. // -glassPaneWidth: The width of the glass pane above the spectator camera that holds the viewFinderOverlay. @@ -56,7 +55,6 @@ var spectatorCameraConfig = Render.getConfig("SecondaryCamera"); var viewFinderOverlay = false; var camera = false; - var cameraIsDynamic = false; var cameraRotation; var cameraPosition; var glassPaneWidth = 0.16; @@ -70,11 +68,11 @@ spectatorCameraConfig.resetSizeSpectatorCamera(Window.innerWidth, Window.innerHeight); cameraRotation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollDegrees(15, -155, 0)), cameraPosition = inFrontOf(0.85, Vec3.sum(MyAvatar.position, { x: 0, y: 0.28, z: 0 })); camera = Entities.addEntity({ - "angularDamping": 1, - "damping": 1, + "angularDamping": 0.8, + "damping": 0.8, "collidesWith": "static,dynamic,kinematic,", "collisionMask": 7, - "dynamic": cameraIsDynamic, + "dynamic": true, "modelURL": Script.resolvePath("spectator-camera.fbx"), "registrationPoint": { "x": 0.56, @@ -89,8 +87,12 @@ }, true); spectatorCameraConfig.attachedEntityId = camera; updateOverlay(); - setDisplay(monitorShowsCameraView); - // Change button to active when window is first openend OR if the camera is on, false otherwise. + if (!HMD.active) { + setMonitorShowsCameraView(false); + } else { + setDisplay(monitorShowsCameraView); + } + // Change button to active when window is first opened OR if the camera is on, false otherwise. if (button) { button.editProperties({ isActive: onSpectatorCameraScreen || camera }); } @@ -238,7 +240,7 @@ function setDisplay(showCameraView) { var url = (camera) ? (showCameraView ? "resource://spectatorCameraFrame" : "resource://hmdPreviewFrame") : ""; - sendToQml({ method: 'showPreviewTextureNotInstructions', setting: !!url, url: url}); + sendToQml({ method: 'showPreviewTextureNotInstructions', setting: !!url, url: url }); // FIXME: temporary hack to avoid setting the display texture to hmdPreviewFrame // until it is the correct mono. @@ -336,7 +338,7 @@ setSwitchViewControllerMappingStatus(switchViewFromController); Settings.setValue('spectatorCamera/switchViewFromController', setting); } - + const TAKE_SNAPSHOT_FROM_CONTROLLER_DEFAULT = false; var takeSnapshotFromController = !!Settings.getValue('spectatorCamera/takeSnapshotFromController', TAKE_SNAPSHOT_FROM_CONTROLLER_DEFAULT); function setTakeSnapshotControllerMappingStatus(status) { @@ -401,6 +403,16 @@ Window.takeSecondaryCameraSnapshot(); } } + function maybeTake360Snapshot() { + if (camera) { + Audio.playSound(SNAPSHOT_SOUND, { + position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z }, + localOnly: true, + volume: 1.0 + }); + Window.takeSecondaryCamera360Snapshot(); + } + } function registerTakeSnapshotControllerMapping() { takeSnapshotControllerMapping = Controller.newMapping(takeSnapshotControllerMappingName); if (controllerType === "OculusTouch") { @@ -541,6 +553,9 @@ case 'changeTakeSnapshotFromControllerPreference': setTakeSnapshotFromController(message.params); break; + case 'takeSecondaryCamera360Snapshot': + maybeTake360Snapshot(); + break; default: print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); }