From 3de7222007e3431232ee25962156aa6070427c04 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 23 Mar 2015 09:06:15 -0700 Subject: [PATCH 01/24] Make Sixense emulate mouse only if controllers aren't at the base --- interface/src/devices/SixenseManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index ce6ca57c69..0a89ad0e37 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -223,7 +223,7 @@ void SixenseManager::update(float deltaTime) { palm->setJoystick(data->joystick_x, data->joystick_y); // Emulate the mouse so we can use scripts - if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) { emulateMouse(palm, numActiveControllers - 1); } From 61dc31ffe76fafea99fa20177311bd256910ab98 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 23 Mar 2015 14:09:45 -0700 Subject: [PATCH 02/24] Update export entities to export as JSON --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ff41e1b6f..840e8388c7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1751,7 +1751,7 @@ bool Application::exportEntities(const QString& filename, const QVectorgetEntityItemID(), properties); } - exportTree.writeToSVOFile(filename.toLocal8Bit().constData()); + exportTree.writeToJSONFile(filename.toLocal8Bit().constData()); // restore the main window's active state _window->activateWindow(); From 6d932508ffbe66ddd9e2fe1066868f3d0e0b1e96 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Mar 2015 10:27:53 -0700 Subject: [PATCH 03/24] Add support for .svo.json extension --- interface/src/Application.h | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.h b/interface/src/Application.h index 4038b21739..6e0c3cebd2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -95,6 +95,7 @@ static const float NODE_KILLED_BLUE = 0.0f; static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString SVO_EXTENSION = ".svo"; +static const QString SVO_JSON_EXTENSION = ".svo.json"; static const QString JS_EXTENSION = ".js"; static const QString FST_EXTENSION = ".fst"; From a901bc4b11ba199879cafa6b766012b44deab33f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Mar 2015 10:28:12 -0700 Subject: [PATCH 04/24] Update edit.js to export as .svo.json --- examples/edit.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 72938e5ed4..2179fe5342 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -910,8 +910,8 @@ function handeMenuEvent(menuItem) { if (!selectionManager.hasSelection()) { Window.alert("No entities have been selected."); } else { - var filename = "models__" + Window.location.hostname + "__.svo"; - filename = Window.save("Select where to save", filename, "*.svo") + var filename = "entities__" + Window.location.hostname + ".svo.json"; + filename = Window.save("Select where to save", filename, "*.json") if (filename) { var success = Clipboard.exportEntities(filename, selectionManager.selections); if (!success) { @@ -923,7 +923,7 @@ function handeMenuEvent(menuItem) { var importURL; if (menuItem == "Import Entities") { - importURL = Window.browse("Select models to import", "", "*.svo"); + importURL = Window.browse("Select models to import", "", "*.json"); } else { importURL = Window.prompt("URL of SVO to import", ""); } From 2fc0ef80d0eb4b42521355b058d04e880c0378aa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Mar 2015 10:40:46 -0700 Subject: [PATCH 05/24] Add SVO_JSON_EXTENSION to accepted extensions --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 840e8388c7..cf9d583945 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3599,6 +3599,7 @@ void Application::initializeAcceptedFiles() { if (_acceptedExtensions.size() == 0) { _acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot; _acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL; + _acceptedExtensions[SVO_JSON_EXTENSION] = &Application::importSVOFromURL; _acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript; _acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl; } From 3563efb584d7b56b25beee653ded7b39ddabd05d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 24 Mar 2015 21:52:53 +0100 Subject: [PATCH 06/24] extra ; --- libraries/entities/src/EntityItemID.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/entities/src/EntityItemID.cpp index aaf6e33128..cd2202eead 100644 --- a/libraries/entities/src/EntityItemID.cpp +++ b/libraries/entities/src/EntityItemID.cpp @@ -25,7 +25,7 @@ EntityItemID::EntityItemID() : creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(false) { -}; +} EntityItemID::EntityItemID(const EntityItemID& other) : id(other.id), From 92d394404463012c6c2ef9e05d774545c4efa725 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Mar 2015 15:01:22 +0100 Subject: [PATCH 07/24] Use preOp function for all common checks/updates --- examples/entityScripts/lightController.js | 70 ++++++++++++++--------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 624fc929b3..1ff41df16c 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -4,6 +4,27 @@ this.lightID = null; this.sound = null; + var DEFAULT_USER_DATA = { + creatingLight: false, + lightID: null, + lightDefaultProperties: { + type: "Light", + position: { x: 0, y: 0, z: 0 }, + dimensions: { x: 5, y: 5, z: 5 }, + isSpotlight: false, + color: { red: 255, green: 48, blue: 0 }, + diffuseColor: { red: 255, green: 255, blue: 255 }, + ambientColor: { red: 255, green: 255, blue: 255 }, + specularColor: { red: 0, green: 0, blue: 0 }, + constantAttenuation: 1, + linearAttenuation: 0, + quadraticAttenuation: 0, + intensity: 10, + exponent: 0, + cutoff: 180, // in degrees + } + }; + function copyObject(object) { return JSON.parse(JSON.stringify(object)); } @@ -30,6 +51,19 @@ Entities.editEntity(entityID, { userData: JSON.stringify(userData) }); } + // Checks whether the userData is well-formed and updates it if not + this.checkUserData = function() { + var userData = getUserData(this.entityID); + if (!userData) { + userData = DEFAULT_USER_DATA; + } else if (!userData.lightDefaultProperties) { + userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; + } else if (typeof userData.creatingLight == 'undefined') { + userData.creatingLight = DEFAULT_USER_DATA.creatingLight; + } + updateUserData(this.entityID, userData); + } + // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { @@ -76,28 +110,6 @@ this.updateLightID = function() { var userData = getUserData(this.entityID); - if (!userData) { - userData = { - lightID: null, - lightDefaultProperties: { - type: "Light", - position: { x: 0, y: 0, z: 0 }, - dimensions: { x: 5, y: 5, z: 5 }, - isSpotlight: false, - color: { red: 255, green: 48, blue: 0 }, - diffuseColor: { red: 255, green: 255, blue: 255 }, - ambientColor: { red: 255, green: 255, blue: 255 }, - specularColor: { red: 0, green: 0, blue: 0 }, - constantAttenuation: 1, - linearAttenuation: 0, - quadraticAttenuation: 0, - intensity: 10, - exponent: 0, - cutoff: 180, // in degrees - } - }; - updateUserData(this.entityID, userData); - } // Find valid light if (doesEntityExistNow(this.lightID)) { @@ -168,15 +180,21 @@ updateUserData(this.entityID, userData); print("Relative properties of light entity saved."); } - - this.preload = function(entityID) { + + // This function should be called before any callback is executed + this.preOperation = function(entityID) { this.entityID = entityID; this.maybeDownloadSound(); + + this.checkUserData(); + } + + this.preload = function(entityID) { + this.preOperation(entityID); }; this.clickReleaseOnEntity = function(entityID, mouseEvent) { - this.entityID = entityID; - this.maybeDownloadSound(); + this.preOperation(entityID); if (mouseEvent.isLeftButton) { this.updateLightID(); From afb96709f19df414534ae6ec60c0e4d021a25989 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Mar 2015 15:44:37 +0100 Subject: [PATCH 08/24] Only update userData when light entity is identified --- examples/entityScripts/lightController.js | 91 +++++++++++++---------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 1ff41df16c..f4ebd17715 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -1,6 +1,5 @@ (function() { this.entityID = null; - this.properties = null; this.lightID = null; this.sound = null; @@ -51,19 +50,6 @@ Entities.editEntity(entityID, { userData: JSON.stringify(userData) }); } - // Checks whether the userData is well-formed and updates it if not - this.checkUserData = function() { - var userData = getUserData(this.entityID); - if (!userData) { - userData = DEFAULT_USER_DATA; - } else if (!userData.lightDefaultProperties) { - userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; - } else if (typeof userData.creatingLight == 'undefined') { - userData.creatingLight = DEFAULT_USER_DATA.creatingLight; - } - updateUserData(this.entityID, userData); - } - // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { @@ -81,17 +67,21 @@ print("Warning: Couldn't play sound."); } } - - // Toggles the associated light entity - this.toggleLight = function() { - if (this.lightID) { - var lightProperties = Entities.getEntityProperties(this.lightID); - Entities.editEntity(this.lightID, { visible: !lightProperties.visible }); - } else { - print("Warning: No light to turn on/off"); + + // Checks whether the userData is well-formed and updates it if not + this.checkUserData = function() { + var userData = getUserData(this.entityID); + if (!userData) { + userData = DEFAULT_USER_DATA; + } else if (!userData.lightDefaultProperties) { + userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; + } else if (typeof userData.creatingLight == 'undefined') { + userData.creatingLight = DEFAULT_USER_DATA.creatingLight; } + updateUserData(this.entityID, userData); } + // Create a Light entity this.createLight = function(userData) { var lightProperties = copyObject(userData.lightDefaultProperties); if (lightProperties) { @@ -108,34 +98,48 @@ } } + // Tries to find a valid light, creates one otherwise this.updateLightID = function() { - var userData = getUserData(this.entityID); - // Find valid light if (doesEntityExistNow(this.lightID)) { - if (!didEntityExist(this.lightID)) { - // Light now has an ID, so update it in userData - this.lightID = getTrueID(this.lightID); - userData.lightID = this.lightID; - updateUserData(this.entityID, userData); - } return; } + var userData = getUserData(this.entityID); if (doesEntityExistNow(userData.lightID)) { - this.lightID = getTrueID(userData.lightID); + this.lightID = userData.lightID; return; } - // No valid light, create one - this.lightID = this.createLight(userData); - print("Created new light entity"); - - // Update user data with new ID + if (!userData.creatingLight) { + // No valid light, create one + userData.creatingLight = true; + updateUserData(this.entityID, userData); + this.lightID = this.createLight(userData); + this.maybeUpdateLightIDInUserData(); + print("Created new light entity"); + } + } + + this.maybeUpdateLightIDInUserData = function() { + this.lightID = getTrueID(this.lightID); + if (this.lightID.isKnownID) { + this.updateLightIDInUserData(); + } else { + var that = this; + Script.setTimeout(function() { that.maybeUpdateLightIDInUserData() }, 500); + } + } + + // Update user data with new lightID + this.updateLightIDInUserData = function() { + var userData = getUserData(this.entityID); userData.lightID = this.lightID; + userData.creatingLight = false; updateUserData(this.entityID, userData); } + // Moves light entity if the lamp entity moved this.maybeMoveLight = function() { var entityProperties = Entities.getEntityProperties(this.entityID); var lightProperties = Entities.getEntityProperties(this.lightID); @@ -151,8 +155,9 @@ } } + // Stores light entity relative position in the lamp metadata this.updateRelativeLightPosition = function() { - if (!doesEntityExistNow(this.entityID) || !doesEntityExistNow(this.lightID)) { + if (!doesEntityExistNow(this.lightID)) { print("Warning: ID invalid, couldn't save relative position."); return; } @@ -189,6 +194,17 @@ this.checkUserData(); } + // Toggles the associated light entity + this.toggleLight = function() { + if (this.lightID) { + var lightProperties = Entities.getEntityProperties(this.lightID); + Entities.editEntity(this.lightID, { visible: !lightProperties.visible }); + this.playSound(); + } else { + print("Warning: No light to turn on/off"); + } + } + this.preload = function(entityID) { this.preOperation(entityID); }; @@ -200,7 +216,6 @@ this.updateLightID(); this.maybeMoveLight(); this.toggleLight(); - this.playSound(); } else if (mouseEvent.isRightButton) { this.updateRelativeLightPosition(); } From 19886bd33c91f6c8a79b51aad7c21f8b834c354e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Mar 2015 16:38:27 +0100 Subject: [PATCH 09/24] Better handling of callback --- examples/entityScripts/lightController.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index f4ebd17715..5b2e2ae8b1 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -75,8 +75,6 @@ userData = DEFAULT_USER_DATA; } else if (!userData.lightDefaultProperties) { userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; - } else if (typeof userData.creatingLight == 'undefined') { - userData.creatingLight = DEFAULT_USER_DATA.creatingLight; } updateUserData(this.entityID, userData); } @@ -122,8 +120,8 @@ } this.maybeUpdateLightIDInUserData = function() { - this.lightID = getTrueID(this.lightID); - if (this.lightID.isKnownID) { + if (getTrueID(this.lightID).isKnownID) { + this.lightID = getTrueID(this.lightID); this.updateLightIDInUserData(); } else { var that = this; From 715fe1096f2331d2c7fcfae55752f3a92c892091 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Mar 2015 17:33:27 +0100 Subject: [PATCH 10/24] Random but persistant switch sound --- examples/entityScripts/lightController.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 5b2e2ae8b1..e6e4998aef 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -2,6 +2,9 @@ this.entityID = null; this.lightID = null; this.sound = null; + this.soundURLs = ["https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_1.wav", + "https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav", + "https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_3.wav"] var DEFAULT_USER_DATA = { creatingLight: false, @@ -21,7 +24,8 @@ intensity: 10, exponent: 0, cutoff: 180, // in degrees - } + }, + soundIndex: Math.floor(Math.random() * this.soundURLs.length) }; function copyObject(object) { @@ -53,7 +57,8 @@ // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { - this.sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav"); + var soundIndex = getUserData(this.entityID).soundIndex; + this.sound = SoundCache.getSound(this.soundURLs[soundIndex]); } } // Play switch sound @@ -75,6 +80,8 @@ userData = DEFAULT_USER_DATA; } else if (!userData.lightDefaultProperties) { userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; + } else if (!userData.soundIndex) { + userData.soundIndex = DEFAULT_USER_DATA.soundIndex; } updateUserData(this.entityID, userData); } @@ -187,9 +194,9 @@ // This function should be called before any callback is executed this.preOperation = function(entityID) { this.entityID = entityID; - this.maybeDownloadSound(); this.checkUserData(); + this.maybeDownloadSound(); } // Toggles the associated light entity From dec89ba96f1ef02e03cc456487174fa7dcb0e78e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Mar 2015 11:22:07 -0700 Subject: [PATCH 11/24] Disable duplicating locked entities --- examples/libraries/entitySelectionTool.js | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index c261e0d8a6..b6c536f063 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1263,11 +1263,13 @@ SelectionDisplay = (function () { duplicatedEntityIDs = []; for (var otherEntityID in SelectionManager.savedProperties) { var properties = SelectionManager.savedProperties[otherEntityID]; - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties, - }); + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties, + }); + } } } else { duplicatedEntityIDs = null; @@ -1361,11 +1363,13 @@ SelectionDisplay = (function () { duplicatedEntityIDs = []; for (var otherEntityID in SelectionManager.savedProperties) { var properties = SelectionManager.savedProperties[otherEntityID]; - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties, - }); + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties, + }); + } } } else { duplicatedEntityIDs = null; From 5b4b78043aa0192eb1e2af1057cb86bd8d20e6fc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Mar 2015 11:22:28 -0700 Subject: [PATCH 12/24] Remove unneeded print messages --- examples/look.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/look.js b/examples/look.js index bcdfcf9e44..6bba57e3ad 100644 --- a/examples/look.js +++ b/examples/look.js @@ -80,7 +80,6 @@ function touchBeginEvent(event) { yawFromTouch = 0; pitchFromTouch = 0; startedTouching = true; - print("TOUCH BEGIN"); } function touchEndEvent(event) { @@ -88,7 +87,6 @@ function touchEndEvent(event) { print("touchEndEvent event.x,y=" + event.x + ", " + event.y); } startedTouching = false; - print("TOUCH END"); } function touchUpdateEvent(event) { From ea3ec91f715542a4f7c49e49dac83051428c4587 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Mar 2015 12:27:15 -0700 Subject: [PATCH 13/24] Remove inspect tool from edit.js --- examples/edit.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 03137310b6..da0a226b93 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -76,7 +76,6 @@ var DEFAULT_DIMENSIONS = { var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS); -var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool"; var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select"; var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus"; var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode"; @@ -553,18 +552,6 @@ function mousePressEvent(event) { // Event handled; do nothing. return; } - } else if (Menu.isOptionChecked(MENU_INSPECT_TOOL_ENABLED)) { - var result = findClickedEntity(event); - if (event.isRightButton) { - if (result !== null) { - var currentProperties = Entities.getEntityProperties(result.entityID); - cameraManager.enable(); - cameraManager.focus(currentProperties.position, null, Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); - cameraManager.mousePressEvent(event); - } - } else { - cameraManager.mousePressEvent(event); - } } } @@ -780,7 +767,7 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities" }); - Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, afterItem: MENU_INSPECT_TOOL_ENABLED, + Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, isCheckable: true, isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_AUTO_FOCUS_ON_SELECT, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); @@ -811,7 +798,6 @@ function cleanupModelMenus() { Menu.removeMenuItem("File", "Import Entities"); Menu.removeMenuItem("File", "Import Entities from URL"); - Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE); From 8eed2b6603ddc160502d052e259c697c139c7df0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Mar 2015 12:28:56 -0700 Subject: [PATCH 14/24] Add PopupMenu to edit.js --- examples/edit.js | 123 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index da0a226b93..fc427a3add 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1210,4 +1210,127 @@ PropertiesTool = function(opts) { return that; }; +PopupMenu = function() { + var self = this; + + var MENU_ITEM_HEIGHT = 21; + var MENU_ITEM_SPACING = 1; + var TEXT_MARGIN = 7; + + var overlays = []; + var overlayInfo = {}; + + var upColor = { red: 0, green: 0, blue: 0 }; + var downColor = { red: 192, green: 192, blue: 192 }; + var overColor = { red: 128, green: 128, blue: 128 }; + + self.onSelectMenuItem = function() { }; + + self.addMenuItem = function(name) { + var id = Overlays.addOverlay("text", { + text: name, + backgroundAlpha: 1.0, + backgroundColor: upColor, + topMargin: TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + width: 210, + height: MENU_ITEM_HEIGHT, + font: { size: 12 }, + visible: false, + }); + overlays.push(id); + overlayInfo[id] = { name: name }; + return id; + }; + + self.updateMenuItemText = function(id, newText) { + Overlays.editOverlay(id, { text: newText }); + }; + + self.setPosition = function(x, y) { + for (var key in overlayInfo) { + Overlays.editOverlay(key, { + x: x, + y: y, + }); + y += MENU_ITEM_HEIGHT + MENU_ITEM_SPACING; + } + }; + + self.onSelected = function() { }; + + var pressingOverlay = null; + var hoveringOverlay = null; + + self.mousePressEvent = function(event) { + if (event.isLeftButton) { + var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if (overlay in overlayInfo) { + pressingOverlay = overlay; + Overlays.editOverlay(pressingOverlay, { backgroundColor: downColor }); + } else { + self.hide(); + } + return false; + } + }; + self.mouseMoveEvent = function(event) { + if (visible) { + var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if (!pressingOverlay) { + if (hoveringOverlay != null && overlay != hoveringOverlay) { + Overlays.editOverlay(hoveringOverlay, { backgroundColor: upColor}); + hoveringOverlay = null; + } + if (overlay != hoveringOverlay && overlay in overlayInfo) { + Overlays.editOverlay(overlay, { backgroundColor: overColor }); + hoveringOverlay = overlay; + } + } + } + return false; + }; + self.mouseReleaseEvent = function(event) { + var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if (pressingOverlay != null) { + if (overlay == pressingOverlay) { + self.onSelectMenuItem(overlayInfo[overlay].name); + } + Overlays.editOverlay(pressingOverlay, { backgroundColor: upColor }); + pressingOverlay = null; + self.hide(); + } + }; + + var visible = false; + + self.setVisible = function(newVisible) { + if (newVisible != visible) { + visible = newVisible; + for (var key in overlayInfo) { + Overlays.editOverlay(key, { visible: newVisible }); + } + } + } + self.show = function() { + self.setVisible(true); + } + self.hide = function() { + self.setVisible(false); + } + + function cleanup() { + for (var i = 0; i < overlays.length; i++) { + Overlays.deleteOverlay(overlays[i]); + } + } + + Controller.mousePressEvent.connect(self.mousePressEvent); + Controller.mouseMoveEvent.connect(self.mouseMoveEvent); + Controller.mouseReleaseEvent.connect(self.mouseReleaseEvent); + Script.scriptEnding.connect(cleanup); + + return this; +}; + propertiesTool = PropertiesTool(); From d07acfe9aceb675e548a378812f94b52a2a97484 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Mar 2015 12:29:38 -0700 Subject: [PATCH 15/24] Add right-click marketplace popup --- examples/edit.js | 177 ++++++++++++++++++++++++++++------------------- 1 file changed, 107 insertions(+), 70 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index fc427a3add..cdc3822fb2 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -543,7 +543,7 @@ function mousePressEvent(event) { mouseHasMovedSincePress = false; mouseCapturedByTool = false; - if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { + if (propertyMenu.mousePressEvent(event) || toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { mouseCapturedByTool = true; return; } @@ -563,6 +563,8 @@ var IDLE_MOUSE_TIMEOUT = 200; var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0; function mouseMoveEvent(event) { + mouseHasMovedSincePress = true; + if (placingEntityID) { if (!placingEntityID.isKnownID) { placingEntityID = Entities.identifyEntity(placingEntityID); @@ -583,10 +585,8 @@ function mouseMoveEvent(event) { Script.clearTimeout(idleMouseTimerId); } - mouseHasMovedSincePress = true; - // allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing - if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) { + if (selectionDisplay.mouseMoveEvent(event) || propertyMenu.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) { return; } @@ -631,7 +631,7 @@ function highlightEntityUnderCursor(position, accurateRay) { function mouseReleaseEvent(event) { - if (toolBar.mouseReleaseEvent(event)) { + if (propertyMenu.mouseReleaseEvent(event) || toolBar.mouseReleaseEvent(event)) { return true; } if (placingEntityID) { @@ -655,74 +655,94 @@ function mouseReleaseEvent(event) { } function mouseClickEvent(event) { - if (!event.isLeftButton || !isActive) { - return; - } - - var result = findClickedEntity(event); - if (result === null) { - if (!event.isShifted) { - selectionManager.clearSelections(); - } - return; - } - toolBar.setActive(true); - var pickRay = result.pickRay; - var foundEntity = result.entityID; - - var properties = Entities.getEntityProperties(foundEntity); - if (isLocked(properties)) { - print("Model locked " + properties.id); - } else { - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal); - // P P - Model - // /| A - Palm - // / | d B - unit vector toward tip - // / | X - base of the perpendicular line - // A---X----->B d - distance fom axis - // x x - distance from A - // - // |X-A| = (P-A).B - // X == A + ((P-A).B)B - // d = |P-X| - - var A = pickRay.origin; - var B = Vec3.normalize(pickRay.direction); - var P = properties.position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (0 < x && sizeOK) { - entitySelected = true; - selectedEntityID = foundEntity; - orientation = MyAvatar.orientation; - intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); - - + print("CLICK"); + if (isActive && event.isLeftButton) { + var result = findClickedEntity(event); + if (result === null) { if (!event.isShifted) { - selectionManager.setSelections([foundEntity]); + selectionManager.clearSelections(); + } + return; + } + toolBar.setActive(true); + var pickRay = result.pickRay; + var foundEntity = result.entityID; + + var properties = Entities.getEntityProperties(foundEntity); + if (isLocked(properties)) { + print("Model locked " + properties.id); + } else { + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; + + print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal); + // P P - Model + // /| A - Palm + // / | d B - unit vector toward tip + // / | X - base of the perpendicular line + // A---X----->B d - distance fom axis + // x x - distance from A + // + // |X-A| = (P-A).B + // X == A + ((P-A).B)B + // d = |P-X| + + var A = pickRay.origin; + var B = Vec3.normalize(pickRay.direction); + var P = properties.position; + + var x = Vec3.dot(Vec3.subtract(P, A), B); + var X = Vec3.sum(A, Vec3.multiply(B, x)); + var d = Vec3.length(Vec3.subtract(P, X)); + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; + + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; + + var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) + && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); + + if (0 < x && sizeOK) { + entitySelected = true; + selectedEntityID = foundEntity; + orientation = MyAvatar.orientation; + intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); + + + if (!event.isShifted) { + selectionManager.setSelections([foundEntity]); + } else { + selectionManager.addEntity(foundEntity, true); + } + + print("Model selected: " + foundEntity.id); + selectionDisplay.select(selectedEntityID, event); + + if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { + cameraManager.focus(selectionManager.worldPosition, + selectionManager.worldDimensions, + Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); + } + } + } + } else if (event.isRightButton) { + var result = findClickedEntity(event); + if (result) { + var properties = Entities.getEntityProperties(result.entityID); + var data = {}; + try { + data = JSON.parse(properties.attribution); + } catch (e) { + } + if (data.marketplaceID) { + propertyMenu.marketplaceID = data.marketplaceID; + propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace"); } else { - selectionManager.addEntity(foundEntity, true); - } - - print("Model selected: " + foundEntity.id); - selectionDisplay.select(selectedEntityID, event); - - if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { - cameraManager.focus(selectionManager.worldPosition, - selectionManager.worldDimensions, - Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); + propertyMenu.marketplaceID = null; + propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info"); } + propertyMenu.setPosition(event.x, event.y); + propertyMenu.show(); + } else { + propertyMenu.hide(); } } } @@ -1137,6 +1157,8 @@ PropertiesTool = function(opts) { if (marketplaceWindow.url != data.url) { marketplaceWindow.setURL(data.url); } + marketplaceWindow.setVisible(true); + marketplaceWindow.raise(); } else if (data.type == "action") { if (data.action == "moveSelectionToGrid") { if (selectionManager.hasSelection()) { @@ -1333,4 +1355,19 @@ PopupMenu = function() { return this; }; +var propertyMenu = PopupMenu(); + +propertyMenu.onSelectMenuItem = function(name) { + if (propertyMenu.marketplaceID) { + var url = "https://metaverse.highfidelity.io/marketplace/items/" + propertyMenu.marketplaceID; + if (marketplaceWindow.url != url) { + marketplaceWindow.setURL(url); + } + marketplaceWindow.setVisible(true); + marketplaceWindow.raise(); + } +}; + +var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace"); + propertiesTool = PropertiesTool(); From b8174b164f06d49fc708ecb7c200ef305dc62d51 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Mar 2015 12:29:57 -0700 Subject: [PATCH 16/24] Update marketplace popup to hide on position or orientation change --- examples/edit.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index cdc3822fb2..fd197349aa 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -839,11 +839,21 @@ Script.scriptEnding.connect(function() { Overlays.deleteOverlay(importingSVOTextOverlay); }); +var lastOrientation = null; +var lastPosition = null; + // Do some stuff regularly, like check for placement of various overlays Script.update.connect(function (deltaTime) { toolBar.move(); progressDialog.move(); selectionDisplay.checkMove(); + var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1); + var dPosition = Vec3.distance(Camera.position, lastPosition); + if (dOrientation > 0.001 || dPosition > 0.001) { + propertyMenu.hide(); + lastOrientation = Camera.orientation; + lastPosition = Camera.position; + } }); function insideBox(center, dimensions, point) { From b5b1c5a90b10ebcb10bb6a519b70c1efcec93099 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 25 Mar 2015 12:30:42 -0700 Subject: [PATCH 17/24] Remove extraneous print --- examples/edit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index fd197349aa..80415ab418 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -655,7 +655,6 @@ function mouseReleaseEvent(event) { } function mouseClickEvent(event) { - print("CLICK"); if (isActive && event.isLeftButton) { var result = findClickedEntity(event); if (result === null) { From ec2b11640ce7606e004cc6909d85b6a9bd3cd390 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 25 Mar 2015 12:51:13 -0700 Subject: [PATCH 18/24] more tweaks to LOD logic --- interface/src/LODManager.cpp | 101 ++++++++++++++++++++++++----------- interface/src/LODManager.h | 39 +++++++++----- 2 files changed, 95 insertions(+), 45 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 8b942dcfe1..751bea8c23 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -40,26 +40,38 @@ float LODManager::getLODIncreaseFPS() { void LODManager::autoAdjustLOD(float currentFPS) { + // NOTE: our first ~100 samples at app startup are completely all over the place, and we don't // really want to count them in our average, so we will ignore the real frame rates and stuff // our moving average with simulated good data const int IGNORE_THESE_SAMPLES = 100; - const float ASSUMED_FPS = 60.0f; - if (_fpsAverage.getSampleCount() < IGNORE_THESE_SAMPLES) { + //const float ASSUMED_FPS = 60.0f; + if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) { currentFPS = ASSUMED_FPS; + _lastUpShift = _lastDownShift = usecTimestampNow(); } - _fpsAverage.updateAverage(currentFPS); - _fastFPSAverage.updateAverage(currentFPS); + _fpsAverageStartWindow.updateAverage(currentFPS); + _fpsAverageDownWindow.updateAverage(currentFPS); + _fpsAverageUpWindow.updateAverage(currentFPS); quint64 now = usecTimestampNow(); bool changed = false; bool octreeChanged = false; - quint64 elapsed = now - _lastAdjust; + quint64 elapsedSinceDownShift = now - _lastDownShift; + quint64 elapsedSinceUpShift = now - _lastUpShift; if (_automaticLODAdjust) { - // LOD Downward adjustment - if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < getLODDecreaseFPS()) { + + // LOD Downward adjustment + // If our last adjust was an upshift, then we don't want to consider any downshifts until we've delayed at least + // our START_DELAY_WINDOW_IN_SECS + bool doDownShift = _lastAdjustWasUpShift + ? (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()) + : (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + + + if (doDownShift) { // Octree items... stepwise adjustment if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { @@ -70,37 +82,58 @@ void LODManager::autoAdjustLOD(float currentFPS) { octreeChanged = changed = true; } - if (changed) { - _lastAdjust = now; - qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; + if (changed) { + if (_lastAdjustWasUpShift) { + qDebug() << "adjusting LOD DOWN after initial delay..." + << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageStartWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() + << "elapsedSinceUpShift:" << elapsedSinceUpShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; + } else { + qDebug() << "adjusting LOD DOWN..." + << "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageDownWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() + << "elapsedSinceDownShift:" << elapsedSinceDownShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; + } + + _lastDownShift = now; + _lastAdjustWasUpShift = false; emit LODDecreased(); } - } + } else { - // LOD Upward adjustment - if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > getLODIncreaseFPS()) { + // LOD Upward adjustment + if (elapsedSinceUpShift > UP_SHIFT_ELPASED && _fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { - // Octee items... stepwise adjustment - if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } else { - _octreeSizeScale *= ADJUST_LOD_UP_BY; + // Octee items... stepwise adjustment + if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { + if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; + } else { + _octreeSizeScale *= ADJUST_LOD_UP_BY; + } + if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; + } + octreeChanged = changed = true; } - if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; - } - octreeChanged = changed = true; - } - if (changed) { - _lastAdjust = now; - qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; + if (changed) { + qDebug() << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageUpWindow.getAverage() + << "upshift point is:" << getLODIncreaseFPS() + << "elapsedSinceUpShift:" << elapsedSinceUpShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; - emit LODIncreased(); + _lastUpShift = now; + _lastAdjustWasUpShift = true; + + emit LODIncreased(); + } } } @@ -116,9 +149,13 @@ void LODManager::autoAdjustLOD(float currentFPS) { } void LODManager::resetLODAdjust() { - _fpsAverage.reset(); - _fastFPSAverage.reset(); + + // TODO: Do we need this??? + /* + _fpsAverageDownWindow.reset(); + _fpsAverageUpWindow.reset(); _lastAdjust = usecTimestampNow(); + */ } QString LODManager::getLODFeedbackText() { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index c14f17ca61..3f9d2046c1 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -19,10 +19,22 @@ const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0; const float DEFAULT_HMD_LOD_DOWN_FPS = 60.0; -const float INCREASE_LOD_GAP = 5.0f; +const float MAX_LIKELY_DESKTOP_FPS = 59.0; // this is essentially, V-synch - 1 fps +const float MAX_LIKELY_HMD_FPS = 74.0; // this is essentially, V-synch - 1 fps +const float INCREASE_LOD_GAP = 15.0f; -const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 0.5; // Consider adjusting LOD down after half a second -const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2; +const float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts +const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f; +const float UP_SHIFT_WINDOW_IN_SECS = 2.5f; + +const int ASSUMED_FPS = 60; +const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS; +const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second +const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS; + +const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS; +const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS; +const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS; const float ADJUST_LOD_DOWN_BY = 0.9f; const float ADJUST_LOD_UP_BY = 1.1f; @@ -37,9 +49,6 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; // do. But both are still culled using the same angular size logic. const float AVATAR_TO_ENTITY_RATIO = 2.0f; -const int ONE_SECOND_OF_FRAMES = 60; -const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; - class LODManager : public QObject, public Dependency { Q_OBJECT @@ -51,11 +60,11 @@ public: Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; } Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; } - Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODDecreaseFPS + INCREASE_LOD_GAP; } + Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return glm::min(_desktopLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS); } Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; } Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; } - Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODDecreaseFPS + INCREASE_LOD_GAP; } + Q_INVOKABLE float getHMDLODIncreaseFPS() const { return glm::min(_hmdLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS); } Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } @@ -68,8 +77,8 @@ public: Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } Q_INVOKABLE void resetLODAdjust(); - Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } - Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } + //Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } + //Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } Q_INVOKABLE float getLODDecreaseFPS(); Q_INVOKABLE float getLODIncreaseFPS(); @@ -96,9 +105,13 @@ private: float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; int _boundaryLevelAdjust = 0; - quint64 _lastAdjust = 0; - SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES; - SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES; + quint64 _lastDownShift = 0; + quint64 _lastUpShift = 0; + bool _lastAdjustWasUpShift = true; // start out as if we've just upshifted + + SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES; + SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES; + SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES; bool _shouldRenderTableNeedsRebuilding = true; QMap _shouldRenderTable; From ef0281ab436e74ddf3de0c3e3c0b493daee49cbd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 Mar 2015 15:30:03 -0700 Subject: [PATCH 19/24] use the new placename entry as entry point --- libraries/networking/src/AddressManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index bfc3ace657..a2522afcbc 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -23,7 +23,7 @@ #include "AccountManager.h" const QString HIFI_URL_SCHEME = "hifi"; -const QString DEFAULT_HIFI_ADDRESS = "hifi://sandbox"; +const QString DEFAULT_HIFI_ADDRESS = "hifi://entry"; typedef const glm::vec3& (*PositionGetter)(); typedef glm::quat (*OrientationGetter)(); From 68e730af454938854d4220c92de521c53b399a18 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 25 Mar 2015 15:48:50 -0700 Subject: [PATCH 20/24] handle throttle render case and clean up code logic to be more obvious --- interface/src/LODManager.cpp | 46 ++++++++++++++++++++---------------- interface/src/LODManager.h | 2 +- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 751bea8c23..e1a82372d2 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -50,6 +50,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { currentFPS = ASSUMED_FPS; _lastUpShift = _lastDownShift = usecTimestampNow(); } + _fpsAverageStartWindow.updateAverage(currentFPS); _fpsAverageDownWindow.updateAverage(currentFPS); _fpsAverageUpWindow.updateAverage(currentFPS); @@ -64,12 +65,17 @@ void LODManager::autoAdjustLOD(float currentFPS) { if (_automaticLODAdjust) { // LOD Downward adjustment - // If our last adjust was an upshift, then we don't want to consider any downshifts until we've delayed at least - // our START_DELAY_WINDOW_IN_SECS - bool doDownShift = _lastAdjustWasUpShift - ? (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()) - : (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + // If we've been downshifting, we watch a shorter downshift window so that we will quickly move toward our + // target frame rate. But if we haven't just done a downshift (either because our last shift was an upshift, + // or because we've just started out) then we look at a much longer window to consider whether or not to start + // downshifting. + bool doDownShift = false; + if (_isDownshifting) { + doDownShift = (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + } else { + doDownShift = (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); + } if (doDownShift) { @@ -83,24 +89,26 @@ void LODManager::autoAdjustLOD(float currentFPS) { } if (changed) { - if (_lastAdjustWasUpShift) { - qDebug() << "adjusting LOD DOWN after initial delay..." - << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " - << _fpsAverageStartWindow.getAverage() - << "minimum is:" << getLODDecreaseFPS() - << "elapsedSinceUpShift:" << elapsedSinceUpShift - << " NEW _octreeSizeScale=" << _octreeSizeScale; - } else { + if (_isDownshifting) { + // subsequent downshift qDebug() << "adjusting LOD DOWN..." << "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was " << _fpsAverageDownWindow.getAverage() << "minimum is:" << getLODDecreaseFPS() << "elapsedSinceDownShift:" << elapsedSinceDownShift << " NEW _octreeSizeScale=" << _octreeSizeScale; + } else { + // first downshift + qDebug() << "adjusting LOD DOWN after initial delay..." + << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageStartWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() + << "elapsedSinceUpShift:" << elapsedSinceUpShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; } _lastDownShift = now; - _lastAdjustWasUpShift = false; + _isDownshifting = true; emit LODDecreased(); } @@ -130,7 +138,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { << " NEW _octreeSizeScale=" << _octreeSizeScale; _lastUpShift = now; - _lastAdjustWasUpShift = true; + _isDownshifting = false; emit LODIncreased(); } @@ -149,13 +157,11 @@ void LODManager::autoAdjustLOD(float currentFPS) { } void LODManager::resetLODAdjust() { - - // TODO: Do we need this??? - /* + _fpsAverageStartWindow.reset(); _fpsAverageDownWindow.reset(); _fpsAverageUpWindow.reset(); - _lastAdjust = usecTimestampNow(); - */ + _lastUpShift = _lastDownShift = usecTimestampNow(); + _isDownshifting = false; } QString LODManager::getLODFeedbackText() { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 3f9d2046c1..d3765c164a 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -107,7 +107,7 @@ private: quint64 _lastDownShift = 0; quint64 _lastUpShift = 0; - bool _lastAdjustWasUpShift = true; // start out as if we've just upshifted + bool _isDownshifting = false; // start out as if we're not downshifting SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES; SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES; From f46067b634b7530ba7f84dc24d4e8469c79ab515 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 25 Mar 2015 16:30:33 -0700 Subject: [PATCH 21/24] better tracking of being done with downshifting --- interface/src/LODManager.cpp | 51 +++++++++++++++++++++++------------- interface/src/LODManager.h | 1 + 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index e1a82372d2..d12fe9147a 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -48,7 +48,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { //const float ASSUMED_FPS = 60.0f; if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) { currentFPS = ASSUMED_FPS; - _lastUpShift = _lastDownShift = usecTimestampNow(); + _lastStable = _lastUpShift = _lastDownShift = usecTimestampNow(); } _fpsAverageStartWindow.updateAverage(currentFPS); @@ -58,9 +58,11 @@ void LODManager::autoAdjustLOD(float currentFPS) { quint64 now = usecTimestampNow(); bool changed = false; - bool octreeChanged = false; quint64 elapsedSinceDownShift = now - _lastDownShift; quint64 elapsedSinceUpShift = now - _lastUpShift; + + quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable); + quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift; if (_automaticLODAdjust) { @@ -72,9 +74,19 @@ void LODManager::autoAdjustLOD(float currentFPS) { bool doDownShift = false; if (_isDownshifting) { - doDownShift = (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + // only consider things if our DOWN_SHIFT time has elapsed... + if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) { + doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS(); + + if (!doDownShift) { + qDebug() << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----"; + _isDownshifting = false; + _lastStable = now; + } + } } else { - doDownShift = (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); + doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED + && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); } if (doDownShift) { @@ -85,7 +97,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } - octreeChanged = changed = true; + changed = true; } if (changed) { @@ -109,25 +121,28 @@ void LODManager::autoAdjustLOD(float currentFPS) { _lastDownShift = now; _isDownshifting = true; - + emit LODDecreased(); } } else { // LOD Upward adjustment - if (elapsedSinceUpShift > UP_SHIFT_ELPASED && _fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { + if (elapsedSinceUpShift > UP_SHIFT_ELPASED) { + + if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { - // Octee items... stepwise adjustment - if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } else { - _octreeSizeScale *= ADJUST_LOD_UP_BY; + // Octee items... stepwise adjustment + if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { + if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; + } else { + _octreeSizeScale *= ADJUST_LOD_UP_BY; + } + if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; + } + changed = true; } - if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; - } - octreeChanged = changed = true; } if (changed) { @@ -139,7 +154,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { _lastUpShift = now; _isDownshifting = false; - + emit LODIncreased(); } } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index d3765c164a..4003d09344 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -107,6 +107,7 @@ private: quint64 _lastDownShift = 0; quint64 _lastUpShift = 0; + quint64 _lastStable = 0; bool _isDownshifting = false; // start out as if we're not downshifting SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES; From 19feeacc51e7db68ac03399be13bb845b9c2829d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 25 Mar 2015 16:38:57 -0700 Subject: [PATCH 22/24] dead code --- interface/src/LODManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index d12fe9147a..cb4913df72 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -45,7 +45,6 @@ void LODManager::autoAdjustLOD(float currentFPS) { // really want to count them in our average, so we will ignore the real frame rates and stuff // our moving average with simulated good data const int IGNORE_THESE_SAMPLES = 100; - //const float ASSUMED_FPS = 60.0f; if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) { currentFPS = ASSUMED_FPS; _lastStable = _lastUpShift = _lastDownShift = usecTimestampNow(); From c031ce15a7908d32496803332b52f8657e3ab47a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 25 Mar 2015 16:45:51 -0700 Subject: [PATCH 23/24] dead code --- interface/src/LODManager.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 4003d09344..77f156531a 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -76,10 +76,6 @@ public: Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust); Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } - Q_INVOKABLE void resetLODAdjust(); - //Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } - //Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } - Q_INVOKABLE float getLODDecreaseFPS(); Q_INVOKABLE float getLODIncreaseFPS(); @@ -88,6 +84,7 @@ public: void loadSettings(); void saveSettings(); + void resetLODAdjust(); signals: void LODIncreased(); From 858dbeb674445c9f1530bec5f84dd5482ea932f7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Mar 2015 13:23:15 -0700 Subject: [PATCH 24/24] remove one line of cruft --- libraries/physics/src/CharacterController.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 84dcf25212..fb2457083a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -357,7 +357,6 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); - bool wasHovering = _isHovering; if (!callback.hasHit()) { _isHovering = true; } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) {