diff --git a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml index e0a503fcc8..45872be592 100644 --- a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml +++ b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml @@ -25,6 +25,8 @@ Rectangle { HifiStylesUit.HifiConstants { id: hifi; } id: root; + property bool uiReady: false; + property bool processingStillSnapshot: false; property bool processing360Snapshot: false; // Style color: "#404040"; @@ -58,7 +60,7 @@ Rectangle { // "Spectator" text HifiStylesUit.RalewaySemiBold { id: titleBarText; - text: "Spectator Camera"; + text: "Spectator Camera 2.2"; // Anchors anchors.left: parent.left; anchors.leftMargin: 30; @@ -91,13 +93,16 @@ Rectangle { } onClicked: { + if (!checked) { + flashCheckBox.checked = false; + } sendToScript({method: (checked ? 'spectatorCameraOn' : 'spectatorCameraOff')}); sendToScript({method: 'updateCameravFoV', vFoV: fieldOfViewSlider.value}); } background: Rectangle { color: parent.checked ? "#1FC6A6" : hifi.colors.white; - implicitWidth: masterSwitch.switchWidth; + implicitWidth: masterSwitch.width; implicitHeight: masterSwitch.height; radius: height/2; } @@ -127,7 +132,7 @@ Rectangle { z: 999; id: processingSnapshot; anchors.fill: parent; - visible: root.processing360Snapshot; + visible: root.processing360Snapshot || !root.uiReady; color: Qt.rgba(0.0, 0.0, 0.0, 0.85); // This object is always used in a popup. @@ -149,7 +154,7 @@ Rectangle { } HifiStylesUit.RalewaySemiBold { - text: "Processing..."; + text: root.uiReady ? "Processing..." : ""; // Anchors anchors.top: processingImage.bottom; anchors.topMargin: 4; @@ -202,10 +207,20 @@ Rectangle { verticalAlignment: Text.AlignVCenter; } + HifiStylesUit.FiraSansRegular { + text: ":)"; + size: 28; + color: hifi.colors.white; + visible: root.processing360Snapshot || root.processingStillSnapshot; + anchors.fill: parent; + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + // Spectator Camera Preview Hifi.ResourceImageItem { id: spectatorCameraPreview; - visible: masterSwitch.checked && !root.processing360Snapshot; + visible: masterSwitch.checked && !root.processing360Snapshot && !root.processingStillSnapshot; url: showCameraView.checked || !HMD.active ? "resource://spectatorCameraFrame" : "resource://hmdPreviewFrame"; ready: masterSwitch.checked; mirrorVertically: true; @@ -311,7 +326,30 @@ Rectangle { } } } - + + HifiStylesUit.HiFiGlyphs { + id: flashGlyph; + visible: flashCheckBox.visible; + text: hifi.glyphs.lightning; + size: 26; + color: hifi.colors.white; + anchors.verticalCenter: flashCheckBox.verticalCenter; + anchors.right: flashCheckBox.left; + anchors.rightMargin: -2; + } + HifiControlsUit.CheckBox { + id: flashCheckBox; + visible: masterSwitch.checked; + color: hifi.colors.white; + colorScheme: hifi.colorSchemes.dark; + anchors.right: takeSnapshotButton.left; + anchors.rightMargin: -8; + anchors.verticalCenter: takeSnapshotButton.verticalCenter; + boxSize: 22; + onClicked: { + sendToScript({method: 'setFlashStatus', enabled: checked}); + } + } HifiControlsUit.Button { id: takeSnapshotButton; enabled: masterSwitch.checked; @@ -325,6 +363,7 @@ Rectangle { width: 135; height: 35; onClicked: { + root.processingStillSnapshot = true; sendToScript({method: 'takeSecondaryCameraSnapshot'}); } } @@ -582,8 +621,12 @@ Rectangle { // function fromScript(message) { switch (message.method) { - case 'updateSpectatorCameraCheckbox': - masterSwitch.checked = message.params; + case 'initializeUI': + masterSwitch.checked = message.masterSwitchOn; + flashCheckBox.checked = message.flashCheckboxChecked; + showCameraView.checked = message.monitorShowsCamView; + showHmdPreview.checked = !message.monitorShowsCamView; + root.uiReady = true; break; case 'updateMonitorShowsSwitch': showCameraView.checked = message.params; @@ -611,6 +654,12 @@ Rectangle { case 'finishedProcessing360Snapshot': root.processing360Snapshot = false; break; + case 'startedProcessingStillSnapshot': + root.processingStillSnapshot = true; + break; + case 'finishedProcessingStillSnapshot': + root.processingStillSnapshot = false; + break; default: console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); } diff --git a/unpublishedScripts/marketplace/spectator-camera/flashOff.wav b/unpublishedScripts/marketplace/spectator-camera/flashOff.wav new file mode 100644 index 0000000000..fef7668de8 Binary files /dev/null and b/unpublishedScripts/marketplace/spectator-camera/flashOff.wav differ diff --git a/unpublishedScripts/marketplace/spectator-camera/flashOn.wav b/unpublishedScripts/marketplace/spectator-camera/flashOn.wav new file mode 100644 index 0000000000..f7e95c9607 Binary files /dev/null and b/unpublishedScripts/marketplace/spectator-camera/flashOn.wav differ diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.app.json b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.app.json index e71c657581..6370454f97 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.app.json +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.app.json @@ -1,4 +1,4 @@ { - "scriptURL": "http://mpassets-staging.highfidelity.com/26156ea5-cdff-43c2-9581-d6b0fa5e00ef-v1/spectatorCamera.js", - "homeURL": "http://mpassets-staging.highfidelity.com/26156ea5-cdff-43c2-9581-d6b0fa5e00ef-v1/SpectatorCamera.qml" + "scriptURL": "http://mpassets.highfidelity.com/80d02930-f409-4f1a-824f-ae0109da32d6-v1/spectatorCamera.js", + "homeURL": "http://mpassets.highfidelity.com/80d02930-f409-4f1a-824f-ae0109da32d6-v1/SpectatorCamera.qml" } \ No newline at end of file diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index df4cdfb385..3e749e38a2 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -97,7 +97,7 @@ if (button) { button.editProperties({ isActive: onSpectatorCameraScreen || camera }); } - Audio.playSound(CAMERA_ON_SOUND, { + Audio.playSound(SOUND_CAMERA_ON, { volume: 0.15, position: cameraPosition, localOnly: true @@ -113,8 +113,14 @@ var WAIT_AFTER_DOMAIN_SWITCH_BEFORE_CAMERA_DELETE_MS = 1 * 1000; function spectatorCameraOff(isChangingDomains) { function deleteCamera() { - Entities.deleteEntity(camera); - camera = false; + if (flash) { + Entities.deleteEntity(flash); + flash = false; + } + if (camera) { + Entities.deleteEntity(camera); + camera = false; + } if (button) { // Change button to active when window is first openend OR if the camera is on, false otherwise. button.editProperties({ isActive: onSpectatorCameraScreen || camera }); @@ -391,21 +397,81 @@ } var takeSnapshotControllerMapping; var takeSnapshotControllerMappingName = 'Hifi-SpectatorCamera-Mapping-TakeSnapshot'; + + var flash = false; + function setFlashStatus(enabled) { + var cameraPosition = Entities.getEntityProperties(camera, ["positon"]).position; + if (enabled) { + if (camera) { + Audio.playSound(SOUND_FLASH_ON, { + position: cameraPosition, + localOnly: true, + volume: 0.8 + }); + flash = Entities.addEntity({ + "collidesWith": "", + "collisionMask": 0, + "color": { + "blue": 173, + "green": 252, + "red": 255 + }, + "cutoff": 90, + "dimensions": { + "x": 4, + "y": 4, + "z": 4 + }, + "dynamic": false, + "falloffRadius": 0.20000000298023224, + "intensity": 37, + "isSpotlight": true, + "localRotation": { w: 1, x: 0, y: 0, z: 0 }, + "localPosition": { x: 0, y: -0.005, z: -0.08 }, + "name": "Camera Flash", + "type": "Light", + "parentID": camera, + }, true); + } + } else { + if (flash) { + Audio.playSound(SOUND_FLASH_OFF, { + position: cameraPosition, + localOnly: true, + volume: 0.8 + }); + Entities.deleteEntity(flash); + flash = false; + } + } + } + function onStillSnapshotTaken() { Render.getConfig("SecondaryCameraJob.ToneMapping").curve = 1; + sendToQml({ + method: 'finishedProcessingStillSnapshot' + }); } function maybeTakeSnapshot() { if (camera) { + sendToQml({ + method: 'startedProcessingStillSnapshot' + }); + Render.getConfig("SecondaryCameraJob.ToneMapping").curve = 0; // Wait a moment before taking the snapshot for the tonemapping curve to update Script.setTimeout(function () { - Audio.playSound(SNAPSHOT_SOUND, { + Audio.playSound(SOUND_SNAPSHOT, { position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z }, localOnly: true, volume: 1.0 }); Window.takeSecondaryCameraSnapshot(); }, 250); + } else { + sendToQml({ + method: 'finishedProcessingStillSnapshot' + }); } } function on360SnapshotTaken() { @@ -418,7 +484,7 @@ } function maybeTake360Snapshot() { if (camera) { - Audio.playSound(SNAPSHOT_SOUND, { + Audio.playSound(SOUND_SNAPSHOT, { position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z }, localOnly: true, volume: 1.0 @@ -508,18 +574,8 @@ } function updateSpectatorCameraQML() { - sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); - sendToQml({ method: 'updateMonitorShowsSwitch', params: monitorShowsCameraView }); - if (!switchViewControllerMapping || !takeSnapshotControllerMapping) { - registerButtonMappings(); - } else { - sendToQml({ - method: 'updateControllerMappingCheckbox', - switchViewSetting: switchViewFromController, - takeSnapshotSetting: takeSnapshotFromController, - controller: controllerType - }); - } + sendToQml({ method: 'initializeUI', masterSwitchOn: !!camera, flashCheckboxChecked: !!flash, monitorShowsCamView: monitorShowsCameraView }); + registerButtonMappings(); Menu.setIsOptionChecked("Disable Preview", false); Menu.setIsOptionChecked("Mono Preview", true); } @@ -537,9 +593,13 @@ button.editProperties({ isActive: onSpectatorCameraScreen || camera }); } - if (onSpectatorCameraScreen) { - updateSpectatorCameraQML(); - } + // In the case of a remote QML app, it takes a bit of time + // for the event bridge to actually connect, so we have to wait... + Script.setTimeout(function () { + if (onSpectatorCameraScreen) { + updateSpectatorCameraQML(); + } + }, 700); } // Function Name: sendToQml() @@ -576,6 +636,9 @@ case 'updateCameravFoV': spectatorCameraConfig.vFoV = message.vFoV; break; + case 'setFlashStatus': + setFlashStatus(message.enabled); + break; case 'takeSecondaryCameraSnapshot': maybeTakeSnapshot(); break; @@ -600,9 +663,7 @@ // Description: // -Called from C++ when HMD mode is changed. The argument "isHMDMode" is true if HMD is on; false otherwise. function onHMDChanged(isHMDMode) { - if (!switchViewControllerMapping || !takeSnapshotControllerMapping) { - registerButtonMappings(); - } + registerButtonMappings(); if (!isHMDMode) { setMonitorShowsCameraView(false); } else { @@ -646,8 +707,10 @@ } // These functions will be called when the script is loaded. - var CAMERA_ON_SOUND = SoundCache.getSound(Script.resolvePath("cameraOn.wav")); - var SNAPSHOT_SOUND = SoundCache.getSound(Script.resourcesPath() + "sounds/snapshot/snap.wav"); + var SOUND_CAMERA_ON = SoundCache.getSound(Script.resolvePath("cameraOn.wav")); + var SOUND_SNAPSHOT = SoundCache.getSound(Script.resolvePath("snap.wav")); + var SOUND_FLASH_ON = SoundCache.getSound(Script.resolvePath("flashOn.wav")); + var SOUND_FLASH_OFF = SoundCache.getSound(Script.resolvePath("flashOff.wav")); startup(); Script.scriptEnding.connect(shutdown);