This commit is contained in:
Stephen Birarda 2015-03-26 11:45:46 -07:00
commit 5f633a6b24
47 changed files with 3562 additions and 3087 deletions

View file

@ -6,7 +6,7 @@
{ {
"name": "access_token", "name": "access_token",
"label": "Access Token", "label": "Access Token",
"help": "This is an access token generated on the <a href='https://metaverse.highfidelity.io/user/security' target='_blank'>My Security</a> page of your High Fidelity account.<br/>Generate a token with the 'domains' scope and paste it here.<br/>This is required to associate this domain-server with a domain in your account." "help": "This is an access token generated on the <a href='https://metaverse.highfidelity.com/user/security' target='_blank'>My Security</a> page of your High Fidelity account.<br/>Generate a token with the 'domains' scope and paste it here.<br/>This is required to associate this domain-server with a domain in your account."
}, },
{ {
"name": "id", "name": "id",
@ -30,7 +30,7 @@
}, },
{ {
"value": "disabled", "value": "disabled",
"label": "None: use the network information I have entered for this domain at metaverse.highfidelity.io" "label": "None: use the network information I have entered for this domain at metaverse.highfidelity.com"
} }
] ]
}, },

View file

@ -652,7 +652,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
clickedButton.attr('disabled', 'disabled') clickedButton.attr('disabled', 'disabled')
// get a list of user domains from data-web // get a list of user domains from data-web
data_web_domains_url = "https://metaverse.highfidelity.io/api/v1/domains?access_token=" data_web_domains_url = "https://metaverse.highfidelity.com/api/v1/domains?access_token="
$.getJSON(data_web_domains_url + Settings.initialValues.metaverse.access_token, function(data){ $.getJSON(data_web_domains_url + Settings.initialValues.metaverse.access_token, function(data){
modal_buttons = { modal_buttons = {
@ -682,7 +682,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
modal_buttons["success"] = { modal_buttons["success"] = {
label: 'Create new domain', label: 'Create new domain',
callback: function() { callback: function() {
window.open("https://metaverse.highfidelity.io/user/domains", '_blank'); window.open("https://metaverse.highfidelity.com/user/domains", '_blank');
} }
} }
modal_body = "<p>You do not have any domains in your High Fidelity account." + modal_body = "<p>You do not have any domains in your High Fidelity account." +
@ -708,4 +708,4 @@ function chooseFromHighFidelityDomains(clickedButton) {
title: "Access token required" title: "Access token required"
}) })
} }
} }

View file

@ -814,8 +814,9 @@ void DomainServer::requestUserPublicKey(const QString& username) {
qDebug() << "Requesting public key for user" << username; qDebug() << "Requesting public key for user" << username;
AccountManager::getInstance().unauthenticatedRequest(USER_PUBLIC_KEY_PATH.arg(username), AccountManager::getInstance().sendRequest(USER_PUBLIC_KEY_PATH.arg(username),
QNetworkAccessManager::GetOperation, callbackParams); AccountManagerAuth::None,
QNetworkAccessManager::GetOperation, callbackParams);
} }
QUrl DomainServer::oauthRedirectURL() { QUrl DomainServer::oauthRedirectURL() {
@ -1116,8 +1117,10 @@ void DomainServer::sendPendingTransactionsToServer() {
transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback"; transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback";
while (i != _pendingAssignmentCredits.end()) { while (i != _pendingAssignmentCredits.end()) {
accountManager.authenticatedRequest("api/v1/transactions", QNetworkAccessManager::PostOperation, accountManager.sendRequest("api/v1/transactions",
transactionCallbackParams, i.value()->postJson().toJson()); AccountManagerAuth::Required,
QNetworkAccessManager::PostOperation,
transactionCallbackParams, i.value()->postJson().toJson());
// set this transaction to finalized so we don't add additional credits to it // set this transaction to finalized so we don't add additional credits to it
i.value()->setIsFinalized(true); i.value()->setIsFinalized(true);
@ -1240,10 +1243,11 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson())); QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
AccountManager::getInstance().authenticatedRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), AccountManager::getInstance().sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
QNetworkAccessManager::PutOperation, AccountManagerAuth::Required,
JSONCallbackParameters(), QNetworkAccessManager::PutOperation,
domainUpdateJSON.toUtf8()); JSONCallbackParameters(),
domainUpdateJSON.toUtf8());
} }
// todo: have data-web respond with ice-server hostname to use // todo: have data-web respond with ice-server hostname to use

View file

@ -18,4 +18,3 @@ Script.load("lobby.js");
Script.load("notifications.js"); Script.load("notifications.js");
Script.load("look.js"); Script.load("look.js");
Script.load("users.js"); Script.load("users.js");
Script.load("utilities/LODWarning.js");

View file

@ -76,7 +76,6 @@ var DEFAULT_DIMENSIONS = {
var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, 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_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus"; var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode"; var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
@ -130,7 +129,7 @@ var importingSVOTextOverlay = Overlays.addOverlay("text", {
visible: false, visible: false,
}); });
var MARKETPLACE_URL = "https://metaverse.highfidelity.io/marketplace"; var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace";
var marketplaceWindow = new WebWindow('Marketplace', MARKETPLACE_URL, 900, 700, false); var marketplaceWindow = new WebWindow('Marketplace', MARKETPLACE_URL, 900, 700, false);
marketplaceWindow.setVisible(false); marketplaceWindow.setVisible(false);
@ -338,7 +337,11 @@ var toolBar = (function () {
return true; return true;
} }
if (browseModelsButton === toolBar.clicked(clickedOverlay)) { if (browseModelsButton === toolBar.clicked(clickedOverlay)) {
if (marketplaceWindow.url != MARKETPLACE_URL) {
marketplaceWindow.setURL(MARKETPLACE_URL);
}
marketplaceWindow.setVisible(true); marketplaceWindow.setVisible(true);
marketplaceWindow.raise();
return true; return true;
} }
@ -540,7 +543,7 @@ function mousePressEvent(event) {
mouseHasMovedSincePress = false; mouseHasMovedSincePress = false;
mouseCapturedByTool = false; mouseCapturedByTool = false;
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { if (propertyMenu.mousePressEvent(event) || toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
mouseCapturedByTool = true; mouseCapturedByTool = true;
return; return;
} }
@ -549,18 +552,6 @@ function mousePressEvent(event) {
// Event handled; do nothing. // Event handled; do nothing.
return; 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);
}
} }
} }
@ -572,6 +563,8 @@ var IDLE_MOUSE_TIMEOUT = 200;
var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0; var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0;
function mouseMoveEvent(event) { function mouseMoveEvent(event) {
mouseHasMovedSincePress = true;
if (placingEntityID) { if (placingEntityID) {
if (!placingEntityID.isKnownID) { if (!placingEntityID.isKnownID) {
placingEntityID = Entities.identifyEntity(placingEntityID); placingEntityID = Entities.identifyEntity(placingEntityID);
@ -592,10 +585,8 @@ function mouseMoveEvent(event) {
Script.clearTimeout(idleMouseTimerId); 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 // 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; return;
} }
@ -640,7 +631,7 @@ function highlightEntityUnderCursor(position, accurateRay) {
function mouseReleaseEvent(event) { function mouseReleaseEvent(event) {
if (toolBar.mouseReleaseEvent(event)) { if (propertyMenu.mouseReleaseEvent(event) || toolBar.mouseReleaseEvent(event)) {
return true; return true;
} }
if (placingEntityID) { if (placingEntityID) {
@ -664,74 +655,93 @@ function mouseReleaseEvent(event) {
} }
function mouseClickEvent(event) { function mouseClickEvent(event) {
if (!event.isLeftButton || !isActive) { if (isActive && event.isLeftButton) {
return; var result = findClickedEntity(event);
} if (result === null) {
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));
if (!event.isShifted) { 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 { } else {
selectionManager.addEntity(foundEntity, true); propertyMenu.marketplaceID = null;
} propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info");
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.setPosition(event.x, event.y);
propertyMenu.show();
} else {
propertyMenu.hide();
} }
} }
} }
@ -776,7 +786,7 @@ function setupModelMenus() {
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities" }); 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: "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" }); 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, 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" }); isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
@ -807,7 +817,6 @@ function cleanupModelMenus() {
Menu.removeMenuItem("File", "Import Entities"); Menu.removeMenuItem("File", "Import Entities");
Menu.removeMenuItem("File", "Import Entities from URL"); 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_AUTO_FOCUS_ON_SELECT);
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE); Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE);
@ -829,11 +838,21 @@ Script.scriptEnding.connect(function() {
Overlays.deleteOverlay(importingSVOTextOverlay); Overlays.deleteOverlay(importingSVOTextOverlay);
}); });
var lastOrientation = null;
var lastPosition = null;
// Do some stuff regularly, like check for placement of various overlays // Do some stuff regularly, like check for placement of various overlays
Script.update.connect(function (deltaTime) { Script.update.connect(function (deltaTime) {
toolBar.move(); toolBar.move();
progressDialog.move(); progressDialog.move();
selectionDisplay.checkMove(); 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) { function insideBox(center, dimensions, point) {
@ -910,8 +929,8 @@ function handeMenuEvent(menuItem) {
if (!selectionManager.hasSelection()) { if (!selectionManager.hasSelection()) {
Window.alert("No entities have been selected."); Window.alert("No entities have been selected.");
} else { } else {
var filename = "models__" + Window.location.hostname + "__.svo"; var filename = "entities__" + Window.location.hostname + ".svo.json";
filename = Window.save("Select where to save", filename, "*.svo") filename = Window.save("Select where to save", filename, "*.json")
if (filename) { if (filename) {
var success = Clipboard.exportEntities(filename, selectionManager.selections); var success = Clipboard.exportEntities(filename, selectionManager.selections);
if (!success) { if (!success) {
@ -923,7 +942,7 @@ function handeMenuEvent(menuItem) {
var importURL; var importURL;
if (menuItem == "Import Entities") { if (menuItem == "Import Entities") {
importURL = Window.browse("Select models to import", "", "*.svo"); importURL = Window.browse("Select models to import", "", "*.json");
} else { } else {
importURL = Window.prompt("URL of SVO to import", ""); importURL = Window.prompt("URL of SVO to import", "");
} }
@ -1143,6 +1162,12 @@ PropertiesTool = function(opts) {
} }
pushCommandForSelections(); pushCommandForSelections();
selectionManager._update(); selectionManager._update();
} else if (data.type = "showMarketplace") {
if (marketplaceWindow.url != data.url) {
marketplaceWindow.setURL(data.url);
}
marketplaceWindow.setVisible(true);
marketplaceWindow.raise();
} else if (data.type == "action") { } else if (data.type == "action") {
if (data.action == "moveSelectionToGrid") { if (data.action == "moveSelectionToGrid") {
if (selectionManager.hasSelection()) { if (selectionManager.hasSelection()) {
@ -1216,4 +1241,142 @@ PropertiesTool = function(opts) {
return that; 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;
};
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(); propertiesTool = PropertiesTool();

View file

@ -1,8 +1,32 @@
(function() { (function() {
this.entityID = null; this.entityID = null;
this.properties = null;
this.lightID = null; this.lightID = null;
this.sound = 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,
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
},
soundIndex: Math.floor(Math.random() * this.soundURLs.length)
};
function copyObject(object) { function copyObject(object) {
return JSON.parse(JSON.stringify(object)); return JSON.parse(JSON.stringify(object));
@ -33,7 +57,8 @@
// Download sound if needed // Download sound if needed
this.maybeDownloadSound = function() { this.maybeDownloadSound = function() {
if (this.sound === null) { 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 // Play switch sound
@ -47,17 +72,21 @@
print("Warning: Couldn't play sound."); print("Warning: Couldn't play sound.");
} }
} }
// Toggles the associated light entity // Checks whether the userData is well-formed and updates it if not
this.toggleLight = function() { this.checkUserData = function() {
if (this.lightID) { var userData = getUserData(this.entityID);
var lightProperties = Entities.getEntityProperties(this.lightID); if (!userData) {
Entities.editEntity(this.lightID, { visible: !lightProperties.visible }); userData = DEFAULT_USER_DATA;
} else { } else if (!userData.lightDefaultProperties) {
print("Warning: No light to turn on/off"); userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties;
} else if (!userData.soundIndex) {
userData.soundIndex = DEFAULT_USER_DATA.soundIndex;
} }
updateUserData(this.entityID, userData);
} }
// Create a Light entity
this.createLight = function(userData) { this.createLight = function(userData) {
var lightProperties = copyObject(userData.lightDefaultProperties); var lightProperties = copyObject(userData.lightDefaultProperties);
if (lightProperties) { if (lightProperties) {
@ -74,56 +103,48 @@
} }
} }
// Tries to find a valid light, creates one otherwise
this.updateLightID = function() { 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 // Find valid light
if (doesEntityExistNow(this.lightID)) { 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; return;
} }
var userData = getUserData(this.entityID);
if (doesEntityExistNow(userData.lightID)) { if (doesEntityExistNow(userData.lightID)) {
this.lightID = getTrueID(userData.lightID); this.lightID = userData.lightID;
return; return;
} }
// No valid light, create one if (!userData.creatingLight) {
this.lightID = this.createLight(userData); // No valid light, create one
print("Created new light entity"); userData.creatingLight = true;
updateUserData(this.entityID, userData);
// Update user data with new ID this.lightID = this.createLight(userData);
this.maybeUpdateLightIDInUserData();
print("Created new light entity");
}
}
this.maybeUpdateLightIDInUserData = function() {
if (getTrueID(this.lightID).isKnownID) {
this.lightID = getTrueID(this.lightID);
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.lightID = this.lightID;
userData.creatingLight = false;
updateUserData(this.entityID, userData); updateUserData(this.entityID, userData);
} }
// Moves light entity if the lamp entity moved
this.maybeMoveLight = function() { this.maybeMoveLight = function() {
var entityProperties = Entities.getEntityProperties(this.entityID); var entityProperties = Entities.getEntityProperties(this.entityID);
var lightProperties = Entities.getEntityProperties(this.lightID); var lightProperties = Entities.getEntityProperties(this.lightID);
@ -139,8 +160,9 @@
} }
} }
// Stores light entity relative position in the lamp metadata
this.updateRelativeLightPosition = function() { this.updateRelativeLightPosition = function() {
if (!doesEntityExistNow(this.entityID) || !doesEntityExistNow(this.lightID)) { if (!doesEntityExistNow(this.lightID)) {
print("Warning: ID invalid, couldn't save relative position."); print("Warning: ID invalid, couldn't save relative position.");
return; return;
} }
@ -168,21 +190,37 @@
updateUserData(this.entityID, userData); updateUserData(this.entityID, userData);
print("Relative properties of light entity saved."); print("Relative properties of light entity saved.");
} }
// This function should be called before any callback is executed
this.preOperation = function(entityID) {
this.entityID = entityID;
this.checkUserData();
this.maybeDownloadSound();
}
// 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.preload = function(entityID) {
this.entityID = entityID; this.preOperation(entityID);
this.maybeDownloadSound();
}; };
this.clickReleaseOnEntity = function(entityID, mouseEvent) { this.clickReleaseOnEntity = function(entityID, mouseEvent) {
this.entityID = entityID; this.preOperation(entityID);
this.maybeDownloadSound();
if (mouseEvent.isLeftButton) { if (mouseEvent.isLeftButton) {
this.updateLightID(); this.updateLightID();
this.maybeMoveLight(); this.maybeMoveLight();
this.toggleLight(); this.toggleLight();
this.playSound();
} else if (mouseEvent.isRightButton) { } else if (mouseEvent.isRightButton) {
this.updateRelativeLightPosition(); this.updateRelativeLightPosition();
} }

View file

@ -0,0 +1,157 @@
//
// makeHouses.js
//
//
// Created by Stojce Slavkovski on March 14, 2015
// Copyright 2015 High Fidelity, Inc.
//
// This sample script that creates house entities based on parameters.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function () {
/** options **/
var numHouses = 100;
var xRange = 300;
var yRange = 300;
var sizeOfTheHouse = {
x: 10,
y: 15,
z: 10
};
var randomizeModels = false;
/**/
var modelUrlPrefix = "http://public.highfidelity.io/load_testing/3-Buildings-2-SanFranciscoHouse-";
var modelurlExt = ".fbx";
var modelVariations = 100;
var houses = [];
function addHouseAt(position, rotation) {
// get house model
var modelNumber = randomizeModels ?
1 + Math.floor(Math.random() * (modelVariations - 1)) :
(houses.length + 1) % modelVariations;
if (modelNumber == 0) {
modelNumber = modelVariations;
}
var modelUrl = modelUrlPrefix + (modelNumber + "") + modelurlExt;
print("Model ID:" + modelNumber);
print("Model URL:" + modelUrl);
var properties = {
type: "Model",
position: position,
rotation: rotation,
dimensions: sizeOfTheHouse,
modelURL: modelUrl
};
return Entities.addEntity(properties);
}
// calculate initial position
var posX = MyAvatar.position.x - (xRange / 2);
var measures = calculateParcels(numHouses, xRange, yRange);
var dd = 0;
// avatar facing rotation
var rotEven = Quat.fromPitchYawRollDegrees(0, 270.0 + MyAvatar.bodyYaw, 0.0);
// avatar opposite rotation
var rotOdd = Quat.fromPitchYawRollDegrees(0, 90.0 + MyAvatar.bodyYaw, 0.0);
var housePos = Vec3.sum(MyAvatar.position, Quat.getFront(Camera.getOrientation()));
for (var j = 0; j < measures.rows; j++) {
var posX1 = 0 - (xRange / 2);
dd += measures.parcelLength;
for (var i = 0; i < measures.cols; i++) {
// skip reminder of houses
if (houses.length > numHouses) {
break;
}
var posShift = {
x: posX1,
y: 0,
z: dd
};
print("House nr.:" + (houses.length + 1));
houses.push(
addHouseAt(Vec3.sum(housePos, posShift), (j % 2 == 0) ? rotEven : rotOdd)
);
posX1 += measures.parcelWidth;
}
}
// calculate rows and columns in area, and dimension of single parcel
function calculateParcels(items, areaWidth, areaLength) {
var idealSize = Math.min(Math.sqrt(areaWidth * areaLength / items), areaWidth, areaLength);
var baseWidth = Math.min(Math.floor(areaWidth / idealSize), items);
var baseLength = Math.min(Math.floor(areaLength / idealSize), items);
var sirRows = baseWidth;
var sirCols = Math.ceil(items / sirRows);
var sirW = areaWidth / sirRows;
var sirL = areaLength / sirCols;
var visCols = baseLength;
var visRows = Math.ceil(items / visCols);
var visW = areaWidth / visRows;
var visL = areaLength / visCols;
var rows = 0;
var cols = 0;
var parcelWidth = 0;
var parcelLength = 0;
if (Math.min(sirW, sirL) > Math.min(visW, visL)) {
rows = sirRows;
cols = sirCols;
parcelWidth = sirW;
parcelLength = sirL;
} else {
rows = visRows;
cols = visCols;
parcelWidth = visW;
parcelLength = visL;
}
print("rows:" + rows);
print("cols:" + cols);
print("parcelWidth:" + parcelWidth);
print("parcelLength:" + parcelLength);
return {
rows: rows,
cols: cols,
parcelWidth: parcelWidth,
parcelLength: parcelLength
};
}
function cleanup() {
while (houses.length > 0) {
if (!houses[0].isKnownID) {
houses[0] = Entities.identifyEntity(houses[0]);
}
Entities.deleteEntity(houses.shift());
}
}
Script.scriptEnding.connect(cleanup);
})();

View file

@ -13,5 +13,4 @@ Script.load("progress.js");
Script.load("lobby.js"); Script.load("lobby.js");
Script.load("notifications.js"); Script.load("notifications.js");
Script.load("controllers/oculus/goTo.js"); Script.load("controllers/oculus/goTo.js");
Script.load("utilities/LODWarning.js");
//Script.load("scripts.js"); // Not created yet //Script.load("scripts.js"); // Not created yet

View file

@ -1263,11 +1263,13 @@ SelectionDisplay = (function () {
duplicatedEntityIDs = []; duplicatedEntityIDs = [];
for (var otherEntityID in SelectionManager.savedProperties) { for (var otherEntityID in SelectionManager.savedProperties) {
var properties = SelectionManager.savedProperties[otherEntityID]; var properties = SelectionManager.savedProperties[otherEntityID];
var entityID = Entities.addEntity(properties); if (!properties.locked) {
duplicatedEntityIDs.push({ var entityID = Entities.addEntity(properties);
entityID: entityID, duplicatedEntityIDs.push({
properties: properties, entityID: entityID,
}); properties: properties,
});
}
} }
} else { } else {
duplicatedEntityIDs = null; duplicatedEntityIDs = null;
@ -1361,11 +1363,13 @@ SelectionDisplay = (function () {
duplicatedEntityIDs = []; duplicatedEntityIDs = [];
for (var otherEntityID in SelectionManager.savedProperties) { for (var otherEntityID in SelectionManager.savedProperties) {
var properties = SelectionManager.savedProperties[otherEntityID]; var properties = SelectionManager.savedProperties[otherEntityID];
var entityID = Entities.addEntity(properties); if (!properties.locked) {
duplicatedEntityIDs.push({ var entityID = Entities.addEntity(properties);
entityID: entityID, duplicatedEntityIDs.push({
properties: properties, entityID: entityID,
}); properties: properties,
});
}
} }
} else { } else {
duplicatedEntityIDs = null; duplicatedEntityIDs = null;

View file

@ -21,8 +21,8 @@ modelUploader = (function () {
//svoBuffer, //svoBuffer,
mapping, mapping,
geometry, geometry,
API_URL = "https://metaverse.highfidelity.io/api/v1/models", API_URL = "https://metaverse.highfidelity.com/api/v1/models",
MODEL_URL = "http://public.highfidelity.io/models/content", MODEL_URL = "http://public.highfidelity.com/models/content",
NAME_FIELD = "name", NAME_FIELD = "name",
SCALE_FIELD = "scale", SCALE_FIELD = "scale",
FILENAME_FIELD = "filename", FILENAME_FIELD = "filename",
@ -690,4 +690,4 @@ modelUploader = (function () {
}; };
return that; return that;
}()); }());

View file

@ -158,7 +158,7 @@ var places = {};
function changeLobbyTextures() { function changeLobbyTextures() {
var req = new XMLHttpRequest(); var req = new XMLHttpRequest();
req.open("GET", "https://metaverse.highfidelity.io/api/v1/places?limit=21", false); req.open("GET", "https://metaverse.highfidelity.com/api/v1/places?limit=21", false);
req.send(); req.send();
places = JSON.parse(req.responseText).data.places; places = JSON.parse(req.responseText).data.places;

View file

@ -80,7 +80,6 @@ function touchBeginEvent(event) {
yawFromTouch = 0; yawFromTouch = 0;
pitchFromTouch = 0; pitchFromTouch = 0;
startedTouching = true; startedTouching = true;
print("TOUCH BEGIN");
} }
function touchEndEvent(event) { function touchEndEvent(event) {
@ -88,7 +87,6 @@ function touchEndEvent(event) {
print("touchEndEvent event.x,y=" + event.x + ", " + event.y); print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
} }
startedTouching = false; startedTouching = false;
print("TOUCH END");
} }
function touchUpdateEvent(event) { function touchUpdateEvent(event) {

View file

@ -43,7 +43,6 @@
// after that we will send it to createNotification(text). // after that we will send it to createNotification(text).
// If the message is 42 chars or less you should bypass wordWrap() and call createNotification() directly. // If the message is 42 chars or less you should bypass wordWrap() and call createNotification() directly.
// To add a keypress driven notification: // To add a keypress driven notification:
// //
// 1. Add a key to the keyPressEvent(key). // 1. Add a key to the keyPressEvent(key).
@ -85,16 +84,19 @@ var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds";
var NOTIFICATION_MENU_ITEM_POST = " Notifications"; var NOTIFICATION_MENU_ITEM_POST = " Notifications";
var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds";
var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_";
var lodTextID = false;
var NotificationType = { var NotificationType = {
UNKNOWN: 0, UNKNOWN: 0,
MUTE_TOGGLE: 1, MUTE_TOGGLE: 1,
SNAPSHOT: 2, SNAPSHOT: 2,
WINDOW_RESIZE: 3, WINDOW_RESIZE: 3,
LOD_WARNING: 4,
properties: [ properties: [
{ text: "Mute Toggle" }, { text: "Mute Toggle" },
{ text: "Snapshot" }, { text: "Snapshot" },
{ text: "Window Resize" } { text: "Window Resize" },
{ text: "Level of Detail" }
], ],
getTypeFromMenuItem: function(menuItemName) { getTypeFromMenuItem: function(menuItemName) {
if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) { if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) {
@ -143,6 +145,10 @@ function createArrays(notice, button, createTime, height, myAlpha) {
// This handles the final dismissal of a notification after fading // This handles the final dismissal of a notification after fading
function dismiss(firstNoteOut, firstButOut, firstOut) { function dismiss(firstNoteOut, firstButOut, firstOut) {
if (firstNoteOut == lodTextID) {
lodTextID = false;
}
Overlays.deleteOverlay(firstNoteOut); Overlays.deleteOverlay(firstNoteOut);
Overlays.deleteOverlay(firstButOut); Overlays.deleteOverlay(firstButOut);
notifications.splice(firstOut, 1); notifications.splice(firstOut, 1);
@ -261,7 +267,8 @@ function notify(notice, button, height) {
height: noticeHeight height: noticeHeight
}); });
} else { } else {
notifications.push((Overlays.addOverlay("text", notice))); var notificationText = Overlays.addOverlay("text", notice);
notifications.push((notificationText));
buttons.push((Overlays.addOverlay("image", button))); buttons.push((Overlays.addOverlay("image", button)));
} }
@ -272,6 +279,7 @@ function notify(notice, button, height) {
last = notifications.length - 1; last = notifications.length - 1;
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]); createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
fadeIn(notifications[last], buttons[last]); fadeIn(notifications[last], buttons[last]);
return notificationText;
} }
// This function creates and sizes the overlays // This function creates and sizes the overlays
@ -331,11 +339,15 @@ function createNotification(text, notificationType) {
randomSounds.playRandom(); randomSounds.playRandom();
} }
notify(noticeProperties, buttonProperties, height); return notify(noticeProperties, buttonProperties, height);
} }
function deleteNotification(index) { function deleteNotification(index) {
Overlays.deleteOverlay(notifications[index]); var notificationTextID = notifications[index];
if (notificationTextID == lodTextID) {
lodTextID = false;
}
Overlays.deleteOverlay(notificationTextID);
Overlays.deleteOverlay(buttons[index]); Overlays.deleteOverlay(buttons[index]);
notifications.splice(index, 1); notifications.splice(index, 1);
buttons.splice(index, 1); buttons.splice(index, 1);
@ -575,6 +587,20 @@ function menuItemEvent(menuItem) {
} }
} }
LODManager.LODDecreased.connect(function() {
var warningText = "\n"
+ "Due to the complexity of the content, the \n"
+ "level of detail has been decreased."
+ "You can now see: \n"
+ LODManager.getLODFeedbackText();
if (lodTextID == false) {
lodTextID = createNotification(warningText, NotificationType.LOD_WARNING);
} else {
Overlays.editOverlay(lodTextID, { text: warningText });
}
});
AudioDevice.muteToggled.connect(onMuteStateChanged); AudioDevice.muteToggled.connect(onMuteStateChanged);
Controller.keyPressEvent.connect(keyPressEvent); Controller.keyPressEvent.connect(keyPressEvent);
Controller.mousePressEvent.connect(mousePressEvent); Controller.mousePressEvent.connect(mousePressEvent);

View file

@ -34,7 +34,7 @@ var usersWindow = (function () {
usersOnline, // Raw users data usersOnline, // Raw users data
linesOfUsers = [], // Array of indexes pointing into usersOnline linesOfUsers = [], // Array of indexes pointing into usersOnline
API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online", API_URL = "https://metaverse.highfidelity.com/api/v1/users?status=online",
HTTP_GET_TIMEOUT = 60000, // ms = 1 minute HTTP_GET_TIMEOUT = 60000, // ms = 1 minute
usersRequest, usersRequest,
processUsers, processUsers,

View file

@ -1,115 +0,0 @@
// LODWarning.js
// examples
//
// Created by Brad Hefta-Gaub on 3/17/15.
// Copyright 2015 High Fidelity, Inc.
//
// This script will display a warning when the LOD is adjusted to do scene complexity.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var DISPLAY_WARNING_FOR = 3; // in seconds
var DISTANCE_FROM_CAMERA = 2;
var SHOW_LOD_UP_MESSAGE = false; // By default we only display the LOD message when reducing LOD
var warningIsVisible = false; // initially the warning is hidden
var warningShownAt = 0;
var billboardPosition = Vec3.sum(Camera.getPosition(),
Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation())));
var warningOverlay = Overlays.addOverlay("text3d", {
position: billboardPosition,
dimensions: { x: 2, y: 1.25 },
width: 2,
height: 1.25,
backgroundColor: { red: 0, green: 0, blue: 0 },
color: { red: 255, green: 255, blue: 255},
topMargin: 0.1,
leftMargin: 0.1,
lineHeight: 0.07,
text: "",
alpha: 0.5,
backgroundAlpha: 0.7,
isFacingAvatar: true,
visible: warningIsVisible,
});
// Handle moving the billboard to remain in front of the camera
var billboardNeedsMoving = false;
Script.update.connect(function() {
if (warningIsVisible) {
var bestBillboardPosition = Vec3.sum(Camera.getPosition(),
Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation())));
var MAX_DISTANCE = 0.5;
var CLOSE_ENOUGH = 0.01;
if (!billboardNeedsMoving && Vec3.distance(bestBillboardPosition, billboardPosition) > MAX_DISTANCE) {
billboardNeedsMoving = true;
}
if (billboardNeedsMoving && Vec3.distance(bestBillboardPosition, billboardPosition) <= CLOSE_ENOUGH) {
billboardNeedsMoving = false;
}
if (billboardNeedsMoving) {
// slurp the billboard to the best location
moveVector = Vec3.multiply(0.05, Vec3.subtract(bestBillboardPosition, billboardPosition));
billboardPosition = Vec3.sum(billboardPosition, moveVector);
Overlays.editOverlay(warningOverlay, { position: billboardPosition });
}
var now = new Date();
var sinceWarningShown = now - warningShownAt;
if (sinceWarningShown > 1000 * DISPLAY_WARNING_FOR) {
warningIsVisible = false;
Overlays.editOverlay(warningOverlay, { visible: warningIsVisible });
}
}
});
LODManager.LODIncreased.connect(function() {
if (SHOW_LOD_UP_MESSAGE) {
// if the warning wasn't visible, then move it before showing it.
if (!warningIsVisible) {
billboardPosition = Vec3.sum(Camera.getPosition(),
Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation())));
Overlays.editOverlay(warningOverlay, { position: billboardPosition });
}
warningShownAt = new Date();
warningIsVisible = true;
warningText = "Level of detail has been increased. \n"
+ "You can now see: \n"
+ LODManager.getLODFeedbackText();
Overlays.editOverlay(warningOverlay, { visible: warningIsVisible, text: warningText });
}
});
LODManager.LODDecreased.connect(function() {
// if the warning wasn't visible, then move it before showing it.
if (!warningIsVisible) {
billboardPosition = Vec3.sum(Camera.getPosition(),
Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation())));
Overlays.editOverlay(warningOverlay, { position: billboardPosition });
}
warningShownAt = new Date();
warningIsVisible = true;
warningText = "\n"
+ "Due to the complexity of the content, the \n"
+ "level of detail has been decreased. \n"
+ "You can now see: \n"
+ LODManager.getLODFeedbackText();
Overlays.editOverlay(warningOverlay, { visible: warningIsVisible, text: warningText });
});
Script.scriptEnding.connect(function() {
Overlays.deleteOverlay(warningOverlay);
});

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 197 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 193 KiB

View file

@ -382,6 +382,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>(); auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS);
// if we get a domain change, immediately attempt update location in metaverse server
connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain,
discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded); connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded);
connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled); connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled);
@ -1751,7 +1755,7 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
exportTree.addEntity(entityItem->getEntityItemID(), properties); exportTree.addEntity(entityItem->getEntityItemID(), properties);
} }
exportTree.writeToSVOFile(filename.toLocal8Bit().constData()); exportTree.writeToJSONFile(filename.toLocal8Bit().constData());
// restore the main window's active state // restore the main window's active state
_window->activateWindow(); _window->activateWindow();
@ -1786,6 +1790,7 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa
void Application::loadSettings() { void Application::loadSettings() {
DependencyManager::get<AudioClient>()->loadSettings(); DependencyManager::get<AudioClient>()->loadSettings();
DependencyManager::get<LODManager>()->loadSettings();
Menu::getInstance()->loadSettings(); Menu::getInstance()->loadSettings();
_myAvatar->loadData(); _myAvatar->loadData();
@ -1793,6 +1798,7 @@ void Application::loadSettings() {
void Application::saveSettings() { void Application::saveSettings() {
DependencyManager::get<AudioClient>()->saveSettings(); DependencyManager::get<AudioClient>()->saveSettings();
DependencyManager::get<LODManager>()->saveSettings();
Menu::getInstance()->saveSettings(); Menu::getInstance()->saveSettings();
_myAvatar->saveData(); _myAvatar->saveData();
@ -1903,8 +1909,6 @@ void Application::init() {
_physicsEngine.init(&_entityEditSender); _physicsEngine.init(&_entityEditSender);
_physicsEngine.setAvatarData(_myAvatar);
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
@ -2191,6 +2195,7 @@ void Application::update(float deltaTime) {
{ {
PerformanceTimer perfTimer("physics"); PerformanceTimer perfTimer("physics");
_myAvatar->preSimulation();
_physicsEngine.stepSimulation(); _physicsEngine.stepSimulation();
} }
@ -3295,11 +3300,6 @@ void Application::connectedToDomain(const QString& hostname) {
const QUuid& domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID(); const QUuid& domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID();
if (accountManager.isLoggedIn() && !domainID.isNull()) { if (accountManager.isLoggedIn() && !domainID.isNull()) {
// update our data-server with the domain-server we're logged in with
QString domainPutJsonString = "{\"location\":{\"domain_id\":\"" + uuidStringWithoutCurlyBraces(domainID) + "\"}}";
accountManager.authenticatedRequest("/api/v1/user/location", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), domainPutJsonString.toUtf8());
_notifiedPacketVersionMismatchThisDomain = false; _notifiedPacketVersionMismatchThisDomain = false;
} }
} }
@ -3599,6 +3599,7 @@ void Application::initializeAcceptedFiles() {
if (_acceptedExtensions.size() == 0) { if (_acceptedExtensions.size() == 0) {
_acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot; _acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot;
_acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL; _acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL;
_acceptedExtensions[SVO_JSON_EXTENSION] = &Application::importSVOFromURL;
_acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript; _acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript;
_acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl; _acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl;
} }
@ -4207,7 +4208,7 @@ void Application::checkSkeleton() {
_myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL); _myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL);
_myAvatar->sendIdentityPacket(); _myAvatar->sendIdentityPacket();
} else { } else {
_myAvatar->updateLocalAABox(); _myAvatar->updateCharacterController();
_physicsEngine.setAvatarData(_myAvatar); _physicsEngine.setCharacterController(_myAvatar->getCharacterController());
} }
} }

View file

@ -95,6 +95,7 @@ static const float NODE_KILLED_BLUE = 0.0f;
static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString SVO_EXTENSION = ".svo"; static const QString SVO_EXTENSION = ".svo";
static const QString SVO_JSON_EXTENSION = ".svo.json";
static const QString JS_EXTENSION = ".js"; static const QString JS_EXTENSION = ".js";
static const QString FST_EXTENSION = ".fst"; static const QString FST_EXTENSION = ".fst";
@ -113,7 +114,7 @@ static const float MIRROR_FIELD_OF_VIEW = 30.0f;
static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND;
static const QString INFO_HELP_PATH = "html/interface-welcome.html"; static const QString INFO_HELP_PATH = "html/interface-welcome.html";
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-entities-commands.html"; static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
static const UINT UWM_IDENTIFY_INSTANCES = static const UINT UWM_IDENTIFY_INSTANCES =

View file

@ -61,17 +61,21 @@ void DiscoverabilityManager::updateLocation() {
uuidStringWithoutCurlyBraces(domainHandler.getUUID())); uuidStringWithoutCurlyBraces(domainHandler.getUUID()));
} }
const QString FRIENDS_ONLY_KEY_IN_LOCATION = "friends_only";
locationObject.insert(FRIENDS_ONLY_KEY_IN_LOCATION, (_mode.get() == Discoverability::Friends));
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required,
JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), QJsonDocument(rootObject).toJson());
} }
} }
} }
void DiscoverabilityManager::removeLocation() { void DiscoverabilityManager::removeLocation() {
AccountManager& accountManager = AccountManager::getInstance(); AccountManager& accountManager = AccountManager::getInstance();
accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, QNetworkAccessManager::DeleteOperation);
} }
void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) { void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) {

View file

@ -17,18 +17,12 @@
#include "LODManager.h" #include "LODManager.h"
Setting::Handle<bool> automaticLODAdjust("automaticLODAdjust", true);
Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS);
Setting::Handle<float> desktopLODIncreaseFPS("desktopLODIncreaseFPS", DEFAULT_DESKTOP_LOD_UP_FPS);
Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS);
Setting::Handle<float> hmdLODIncreaseFPS("hmdLODIncreaseFPS", DEFAULT_HMD_LOD_UP_FPS);
Setting::Handle<float> avatarLODDistanceMultiplier("avatarLODDistanceMultiplier",
DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER);
Setting::Handle<int> boundaryLevelAdjust("boundaryLevelAdjust", 0);
Setting::Handle<float> octreeSizeScale("octreeSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
LODManager::LODManager() {
calculateAvatarLODDistanceMultiplier();
}
float LODManager::getLODDecreaseFPS() { float LODManager::getLODDecreaseFPS() {
if (Application::getInstance()->isHMDMode()) { if (Application::getInstance()->isHMDMode()) {
@ -46,41 +40,55 @@ float LODManager::getLODIncreaseFPS() {
void LODManager::autoAdjustLOD(float currentFPS) { void LODManager::autoAdjustLOD(float currentFPS) {
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't // 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 // 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 // our moving average with simulated good data
const int IGNORE_THESE_SAMPLES = 100; const int IGNORE_THESE_SAMPLES = 100;
const float ASSUMED_FPS = 60.0f; if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) {
if (_fpsAverage.getSampleCount() < IGNORE_THESE_SAMPLES) {
currentFPS = ASSUMED_FPS; currentFPS = ASSUMED_FPS;
_lastStable = _lastUpShift = _lastDownShift = usecTimestampNow();
} }
_fpsAverage.updateAverage(currentFPS);
_fastFPSAverage.updateAverage(currentFPS); _fpsAverageStartWindow.updateAverage(currentFPS);
_fpsAverageDownWindow.updateAverage(currentFPS);
_fpsAverageUpWindow.updateAverage(currentFPS);
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
bool changed = false; bool changed = false;
bool octreeChanged = false; quint64 elapsedSinceDownShift = now - _lastDownShift;
quint64 elapsed = now - _lastAdjust; quint64 elapsedSinceUpShift = now - _lastUpShift;
quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable);
quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift;
if (_automaticLODAdjust) { if (_automaticLODAdjust) {
// LOD Downward adjustment
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < getLODDecreaseFPS()) { // LOD Downward adjustment
// 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;
// Avatars... attempt to lower the detail in proportion to the fps difference if (_isDownshifting) {
float targetFps = (getLODDecreaseFPS() + getLODIncreaseFPS()) * 0.5f; // only consider things if our DOWN_SHIFT time has elapsed...
float averageFps = _fastFPSAverage.getAverage(); if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) {
const float MAXIMUM_MULTIPLIER_SCALE = 2.0f; doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS();
float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier;
_avatarLODDistanceMultiplier = qMin(MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier * if (!doDownShift) {
(averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE : qDebug() << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----";
qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps))); _isDownshifting = false;
_lastStable = now;
if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) { }
qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
<< "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier;
changed = true;
} }
} else {
doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED
&& _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS());
}
if (doDownShift) {
// Octree items... stepwise adjustment // Octree items... stepwise adjustment
if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
@ -88,58 +96,71 @@ void LODManager::autoAdjustLOD(float currentFPS) {
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
} }
octreeChanged = changed = true; changed = true;
} }
if (changed) { if (changed) {
_lastAdjust = now; if (_isDownshifting) {
qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() // subsequent downshift
<< "_octreeSizeScale=" << _octreeSizeScale; 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;
_isDownshifting = true;
emit LODDecreased(); emit LODDecreased();
} }
} } else {
// LOD Upward adjustment // LOD Upward adjustment
if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > getLODIncreaseFPS()) { if (elapsedSinceUpShift > UP_SHIFT_ELPASED) {
if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) {
// Avatars... let the detail level creep slowly upwards // Octee items... stepwise adjustment
if (_avatarLODDistanceMultiplier < MAXIMUM_AUTO_ADJUST_AVATAR_LOD_DISTANCE_MULTIPLIER) { if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
const float DISTANCE_DECREASE_RATE = 0.05f; if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier; _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
_avatarLODDistanceMultiplier = qMax(MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, } else {
_avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE); _octreeSizeScale *= ADJUST_LOD_UP_BY;
}
if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) { if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
<< "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier; }
changed = true; changed = true;
}
} }
}
// 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 (changed) { if (changed) {
_lastAdjust = now; qDebug() << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was "
qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() << _fpsAverageUpWindow.getAverage()
<< "_octreeSizeScale=" << _octreeSizeScale; << "upshift point is:" << getLODIncreaseFPS()
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
emit LODIncreased(); _lastUpShift = now;
_isDownshifting = false;
emit LODIncreased();
}
} }
} }
if (changed) { if (changed) {
calculateAvatarLODDistanceMultiplier();
_shouldRenderTableNeedsRebuilding = true; _shouldRenderTableNeedsRebuilding = true;
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog(); auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
if (lodToolsDialog) { if (lodToolsDialog) {
@ -150,9 +171,11 @@ void LODManager::autoAdjustLOD(float currentFPS) {
} }
void LODManager::resetLODAdjust() { void LODManager::resetLODAdjust() {
_fpsAverage.reset(); _fpsAverageStartWindow.reset();
_fastFPSAverage.reset(); _fpsAverageDownWindow.reset();
_lastAdjust = usecTimestampNow(); _fpsAverageUpWindow.reset();
_lastUpShift = _lastDownShift = usecTimestampNow();
_isDownshifting = false;
} }
QString LODManager::getLODFeedbackText() { QString LODManager::getLODFeedbackText() {
@ -234,9 +257,14 @@ bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera
void LODManager::setOctreeSizeScale(float sizeScale) { void LODManager::setOctreeSizeScale(float sizeScale) {
_octreeSizeScale = sizeScale; _octreeSizeScale = sizeScale;
calculateAvatarLODDistanceMultiplier();
_shouldRenderTableNeedsRebuilding = true; _shouldRenderTableNeedsRebuilding = true;
} }
void LODManager::calculateAvatarLODDistanceMultiplier() {
_avatarLODDistanceMultiplier = AVATAR_TO_ENTITY_RATIO / (_octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE);
}
void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
_boundaryLevelAdjust = boundaryLevelAdjust; _boundaryLevelAdjust = boundaryLevelAdjust;
_shouldRenderTableNeedsRebuilding = true; _shouldRenderTableNeedsRebuilding = true;
@ -244,27 +272,13 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
void LODManager::loadSettings() { void LODManager::loadSettings() {
setAutomaticLODAdjust(automaticLODAdjust.get());
setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get()); setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get());
setDesktopLODIncreaseFPS(desktopLODIncreaseFPS.get());
setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get()); setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get());
setHMDLODIncreaseFPS(hmdLODIncreaseFPS.get());
setAvatarLODDistanceMultiplier(avatarLODDistanceMultiplier.get());
setBoundaryLevelAdjust(boundaryLevelAdjust.get());
setOctreeSizeScale(octreeSizeScale.get());
} }
void LODManager::saveSettings() { void LODManager::saveSettings() {
automaticLODAdjust.set(getAutomaticLODAdjust());
desktopLODDecreaseFPS.set(getDesktopLODDecreaseFPS()); desktopLODDecreaseFPS.set(getDesktopLODDecreaseFPS());
desktopLODIncreaseFPS.set(getDesktopLODIncreaseFPS());
hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS()); hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS());
hmdLODIncreaseFPS.set(getHMDLODIncreaseFPS());
avatarLODDistanceMultiplier.set(getAvatarLODDistanceMultiplier());
boundaryLevelAdjust.set(getBoundaryLevelAdjust());
octreeSizeScale.set(getOctreeSizeScale());
} }

View file

@ -18,12 +18,23 @@
#include <SimpleMovingAverage.h> #include <SimpleMovingAverage.h>
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0; const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0;
const float DEFAULT_DESKTOP_LOD_UP_FPS = 50.0;
const float DEFAULT_HMD_LOD_DOWN_FPS = 60.0; const float DEFAULT_HMD_LOD_DOWN_FPS = 60.0;
const float DEFAULT_HMD_LOD_UP_FPS = 65.0; 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 float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts
const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2; 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_DOWN_BY = 0.9f;
const float ADJUST_LOD_UP_BY = 1.1f; const float ADJUST_LOD_UP_BY = 1.1f;
@ -34,13 +45,9 @@ const float ADJUST_LOD_UP_BY = 1.1f;
const float ADJUST_LOD_MIN_SIZE_SCALE = 1.0f; const float ADJUST_LOD_MIN_SIZE_SCALE = 1.0f;
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f; // The ratio of "visibility" of avatars to other content. A value larger than 1 will mean Avatars "cull" later than entities
const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f; // do. But both are still culled using the same angular size logic.
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; const float AVATAR_TO_ENTITY_RATIO = 2.0f;
const float MAXIMUM_AUTO_ADJUST_AVATAR_LOD_DISTANCE_MULTIPLIER = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER;
const int ONE_SECOND_OF_FRAMES = 60;
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
class LODManager : public QObject, public Dependency { class LODManager : public QObject, public Dependency {
@ -53,15 +60,12 @@ public:
Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; } Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; }
Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; } Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; }
Q_INVOKABLE void setDesktopLODIncreaseFPS(float value) { _desktopLODIncreaseFPS = value; } Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return glm::min(_desktopLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS); }
Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODIncreaseFPS; }
Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; } Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; }
Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; } Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; }
Q_INVOKABLE void setHMDLODIncreaseFPS(float value) { _hmdLODIncreaseFPS = value; } Q_INVOKABLE float getHMDLODIncreaseFPS() const { return glm::min(_hmdLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS); }
Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODIncreaseFPS; }
Q_INVOKABLE void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; }
Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
// User Tweakable LOD Items // User Tweakable LOD Items
@ -72,10 +76,6 @@ public:
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust); Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _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 getLODDecreaseFPS();
Q_INVOKABLE float getLODIncreaseFPS(); Q_INVOKABLE float getLODIncreaseFPS();
@ -84,28 +84,32 @@ public:
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
void resetLODAdjust();
signals: signals:
void LODIncreased(); void LODIncreased();
void LODDecreased(); void LODDecreased();
private: private:
LODManager() {} LODManager();
void calculateAvatarLODDistanceMultiplier();
bool _automaticLODAdjust = true; bool _automaticLODAdjust = true;
float _desktopLODDecreaseFPS = DEFAULT_DESKTOP_LOD_DOWN_FPS; float _desktopLODDecreaseFPS = DEFAULT_DESKTOP_LOD_DOWN_FPS;
float _desktopLODIncreaseFPS = DEFAULT_DESKTOP_LOD_UP_FPS;
float _hmdLODDecreaseFPS = DEFAULT_HMD_LOD_DOWN_FPS; float _hmdLODDecreaseFPS = DEFAULT_HMD_LOD_DOWN_FPS;
float _hmdLODIncreaseFPS = DEFAULT_HMD_LOD_UP_FPS;
float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER; float _avatarLODDistanceMultiplier;
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
int _boundaryLevelAdjust = 0; int _boundaryLevelAdjust = 0;
quint64 _lastAdjust = 0; quint64 _lastDownShift = 0;
SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES; quint64 _lastUpShift = 0;
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES; quint64 _lastStable = 0;
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;
SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES;
bool _shouldRenderTableNeedsRebuilding = true; bool _shouldRenderTableNeedsRebuilding = true;
QMap<float, float> _shouldRenderTable; QMap<float, float> _shouldRenderTable;

View file

@ -70,7 +70,6 @@ MyAvatar::MyAvatar() :
Avatar(), Avatar(),
_turningKeyPressTime(0.0f), _turningKeyPressTime(0.0f),
_gravity(0.0f, 0.0f, 0.0f), _gravity(0.0f, 0.0f, 0.0f),
_shouldJump(false),
_wasPushing(false), _wasPushing(false),
_isPushing(false), _isPushing(false),
_isBraking(false), _isBraking(false),
@ -82,6 +81,8 @@ MyAvatar::MyAvatar() :
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
_motionBehaviors(AVATAR_MOTION_DEFAULTS), _motionBehaviors(AVATAR_MOTION_DEFAULTS),
_enablePhysics(false),
_characterController(this),
_lookAtTargetAvatar(), _lookAtTargetAvatar(),
_shouldRender(true), _shouldRender(true),
_billboardValid(false), _billboardValid(false),
@ -954,15 +955,15 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
return Avatar::getPosition(); return Avatar::getPosition();
} }
void MyAvatar::updateLocalAABox() { void MyAvatar::updateCharacterController() {
// compute localAABox
const CapsuleShape& capsule = _skeletonModel.getBoundingShape(); const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
float radius = capsule.getRadius(); float radius = capsule.getRadius();
float height = 2.0f * (capsule.getHalfHeight() + radius); float height = 2.0f * (capsule.getHalfHeight() + radius);
glm::vec3 offset = _skeletonModel.getBoundingShapeOffset();
glm::vec3 corner(-radius, -0.5f * height, -radius); glm::vec3 corner(-radius, -0.5f * height, -radius);
corner += offset; corner += _skeletonModel.getBoundingShapeOffset();
glm::vec3 scale(2.0f * radius, height, 2.0f * radius); glm::vec3 scale(2.0f * radius, height, 2.0f * radius);
_localAABox.setBox(corner, scale); _characterController.setLocalBoundingBox(corner, scale);
} }
QString MyAvatar::getScriptedMotorFrame() const { QString MyAvatar::getScriptedMotorFrame() const {
@ -1580,6 +1581,10 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
return palm->getPosition(); return palm->getPosition();
} }
void MyAvatar::preSimulation() {
_characterController.setEnabled(_enablePhysics);
}
void MyAvatar::clearDriveKeys() { void MyAvatar::clearDriveKeys() {
for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { for (int i = 0; i < MAX_DRIVE_KEYS; ++i) {
_driveKeys[i] = 0.0f; _driveKeys[i] = 0.0f;

View file

@ -13,6 +13,7 @@
#define hifi_MyAvatar_h #define hifi_MyAvatar_h
#include <SettingHandle.h> #include <SettingHandle.h>
#include <CharacterController.h>
#include "Avatar.h" #include "Avatar.h"
@ -88,7 +89,7 @@ public:
void clearDriveKeys(); void clearDriveKeys();
void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; };
void jump() { _shouldJump = true; }; void jump() { _characterController.jump(); }
bool isMyAvatar() { return true; } bool isMyAvatar() { return true; }
@ -122,6 +123,8 @@ public:
virtual glm::vec3 getSkeletonPosition() const; virtual glm::vec3 getSkeletonPosition() const;
void updateLocalAABox(); void updateLocalAABox();
CharacterController* getCharacterController() { return &_characterController; }
void updateCharacterController();
void clearJointAnimationPriorities(); void clearJointAnimationPriorities();
@ -145,6 +148,11 @@ public:
const RecorderPointer getRecorder() const { return _recorder; } const RecorderPointer getRecorder() const { return _recorder; }
const PlayerPointer getPlayer() const { return _player; } const PlayerPointer getPlayer() const { return _player; }
void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; }
bool isPhysicsEnabled() { return _enablePhysics; }
void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; }
void preSimulation();
public slots: public slots:
void increaseSize(); void increaseSize();
@ -186,7 +194,6 @@ private:
float _turningKeyPressTime; float _turningKeyPressTime;
glm::vec3 _gravity; glm::vec3 _gravity;
bool _shouldJump;
float _driveKeys[MAX_DRIVE_KEYS]; float _driveKeys[MAX_DRIVE_KEYS];
bool _wasPushing; bool _wasPushing;
bool _isPushing; bool _isPushing;
@ -202,6 +209,9 @@ private:
int _scriptedMotorFrame; int _scriptedMotorFrame;
quint32 _motionBehaviors; quint32 _motionBehaviors;
bool _enablePhysics;
CharacterController _characterController;
QWeakPointer<AvatarData> _lookAtTargetAvatar; QWeakPointer<AvatarData> _lookAtTargetAvatar;
glm::vec3 _targetAvatarPosition; glm::vec3 _targetAvatarPosition;
bool _shouldRender; bool _shouldRender;

View file

@ -223,7 +223,7 @@ void SixenseManager::update(float deltaTime) {
palm->setJoystick(data->joystick_x, data->joystick_y); palm->setJoystick(data->joystick_x, data->joystick_y);
// Emulate the mouse so we can use scripts // 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); emulateMouse(palm, numActiveControllers - 1);
} }

View file

@ -55,6 +55,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid
_windowWidget = dockWidget; _windowWidget = dockWidget;
} else { } else {
_windowWidget = new QWidget(Application::getInstance()->getWindow(), Qt::Window); _windowWidget = new QWidget(Application::getInstance()->getWindow(), Qt::Window);
_windowWidget->setWindowTitle(title);
_windowWidget->setMinimumSize(width, height); _windowWidget->setMinimumSize(width, height);
auto layout = new QVBoxLayout(_windowWidget); auto layout = new QVBoxLayout(_windowWidget);
@ -96,6 +97,18 @@ void WebWindowClass::setVisible(bool visible) {
QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
} }
void WebWindowClass::setURL(const QString& url) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setURL", Qt::BlockingQueuedConnection, Q_ARG(QString, url));
return;
}
_webView->setUrl(url);
}
void WebWindowClass::raise() {
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::BlockingQueuedConnection);
}
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
WebWindowClass* retVal; WebWindowClass* retVal;
QString file = context->argument(0).toString(); QString file = context->argument(0).toString();

View file

@ -34,6 +34,7 @@ signals:
class WebWindowClass : public QObject { class WebWindowClass : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QObject* eventBridge READ getEventBridge) Q_PROPERTY(QObject* eventBridge READ getEventBridge)
Q_PROPERTY(QString url READ getURL)
public: public:
WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow = false); WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow = false);
~WebWindowClass(); ~WebWindowClass();
@ -42,6 +43,9 @@ public:
public slots: public slots:
void setVisible(bool visible); void setVisible(bool visible);
QString getURL() const { return _webView->url().url(); }
void setURL(const QString& url);
void raise();
ScriptEventBridge* getEventBridge() const { return _eventBridge; } ScriptEventBridge* getEventBridge() const { return _eventBridge; }
void addEventBridgeToWindowObject(); void addEventBridgeToWindowObject();

View file

@ -46,37 +46,10 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
_feedback->setFixedWidth(FEEDBACK_WIDTH); _feedback->setFixedWidth(FEEDBACK_WIDTH);
form->addRow("You can see... ", _feedback); form->addRow("You can see... ", _feedback);
form->addRow("Automatic LOD Adjustment:", _automaticLODAdjust = new QCheckBox(this)); form->addRow("Manually Adjust Level of Detail:", _manualLODAdjust = new QCheckBox(this));
_automaticLODAdjust->setChecked(lodManager->getAutomaticLODAdjust()); _manualLODAdjust->setChecked(!lodManager->getAutomaticLODAdjust());
connect(_automaticLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust())); connect(_manualLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust()));
form->addRow("Desktop Decrease LOD Below FPS:", _desktopLODDecreaseFPS = new QDoubleSpinBox(this));
_desktopLODDecreaseFPS->setValue(lodManager->getDesktopLODDecreaseFPS());
_desktopLODDecreaseFPS->setDecimals(0);
connect(_desktopLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues()));
form->addRow("Desktop Increase LOD Above FPS:", _desktopLODIncreaseFPS = new QDoubleSpinBox(this));
_desktopLODIncreaseFPS->setValue(lodManager->getDesktopLODIncreaseFPS());
_desktopLODIncreaseFPS->setDecimals(0);
connect(_desktopLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues()));
form->addRow("HMD Decrease LOD Below FPS:", _hmdLODDecreaseFPS = new QDoubleSpinBox(this));
_hmdLODDecreaseFPS->setValue(lodManager->getHMDLODDecreaseFPS());
_hmdLODDecreaseFPS->setDecimals(0);
connect(_hmdLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues()));
form->addRow("HMD Increase LOD Above FPS:", _hmdLODIncreaseFPS = new QDoubleSpinBox(this));
_hmdLODIncreaseFPS->setValue(lodManager->getHMDLODIncreaseFPS());
_hmdLODIncreaseFPS->setDecimals(0);
connect(_hmdLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues()));
form->addRow("Avatar LOD:", _avatarLOD = new QDoubleSpinBox(this));
_avatarLOD->setDecimals(3);
_avatarLOD->setRange(1.0 / MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, 1.0 / MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER);
_avatarLOD->setSingleStep(0.001);
_avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier());
connect(_avatarLOD, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues()));
_lodSize = new QSlider(Qt::Horizontal, this); _lodSize = new QSlider(Qt::Horizontal, this);
const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER; const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER;
const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE; const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE;
@ -92,7 +65,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
_lodSize->setPageStep(PAGE_STEP_LOD_SIZE); _lodSize->setPageStep(PAGE_STEP_LOD_SIZE);
int sliderValue = lodManager->getOctreeSizeScale() / TREE_SCALE; int sliderValue = lodManager->getOctreeSizeScale() / TREE_SCALE;
_lodSize->setValue(sliderValue); _lodSize->setValue(sliderValue);
form->addRow("Non-Avatar Content LOD:", _lodSize); form->addRow("Level of Detail:", _lodSize);
connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int))); connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int)));
// Add a button to reset // Add a button to reset
@ -109,27 +82,12 @@ void LodToolsDialog::reloadSliders() {
auto lodManager = DependencyManager::get<LODManager>(); auto lodManager = DependencyManager::get<LODManager>();
_lodSize->setValue(lodManager->getOctreeSizeScale() / TREE_SCALE); _lodSize->setValue(lodManager->getOctreeSizeScale() / TREE_SCALE);
_feedback->setText(lodManager->getLODFeedbackText()); _feedback->setText(lodManager->getLODFeedbackText());
_avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier());
} }
void LodToolsDialog::updateAutomaticLODAdjust() { void LodToolsDialog::updateAutomaticLODAdjust() {
auto lodManager = DependencyManager::get<LODManager>(); auto lodManager = DependencyManager::get<LODManager>();
lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked()); lodManager->setAutomaticLODAdjust(!_manualLODAdjust->isChecked());
} _lodSize->setEnabled(_manualLODAdjust->isChecked());
void LodToolsDialog::updateLODValues() {
auto lodManager = DependencyManager::get<LODManager>();
lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked());
lodManager->setDesktopLODDecreaseFPS(_desktopLODDecreaseFPS->value());
lodManager->setDesktopLODIncreaseFPS(_desktopLODIncreaseFPS->value());
lodManager->setHMDLODDecreaseFPS(_hmdLODDecreaseFPS->value());
lodManager->setHMDLODIncreaseFPS(_hmdLODIncreaseFPS->value());
lodManager->setAvatarLODDistanceMultiplier(1.0 / _avatarLOD->value());
} }
void LodToolsDialog::sizeScaleValueChanged(int value) { void LodToolsDialog::sizeScaleValueChanged(int value) {
@ -144,15 +102,9 @@ void LodToolsDialog::resetClicked(bool checked) {
int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE; int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE;
_lodSize->setValue(sliderValue); _lodSize->setValue(sliderValue);
_automaticLODAdjust->setChecked(true); _manualLODAdjust->setChecked(false);
_desktopLODDecreaseFPS->setValue(DEFAULT_DESKTOP_LOD_DOWN_FPS);
_desktopLODIncreaseFPS->setValue(DEFAULT_DESKTOP_LOD_UP_FPS);
_hmdLODDecreaseFPS->setValue(DEFAULT_HMD_LOD_DOWN_FPS);
_hmdLODIncreaseFPS->setValue(DEFAULT_HMD_LOD_UP_FPS);
_avatarLOD->setValue(1.0 / DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER);
updateLODValues(); // tell our LOD manager about the reset updateAutomaticLODAdjust(); // tell our LOD manager about the reset
} }
void LodToolsDialog::reject() { void LodToolsDialog::reject() {
@ -163,6 +115,15 @@ void LodToolsDialog::reject() {
void LodToolsDialog::closeEvent(QCloseEvent* event) { void LodToolsDialog::closeEvent(QCloseEvent* event) {
this->QDialog::closeEvent(event); this->QDialog::closeEvent(event);
emit closed(); emit closed();
auto lodManager = DependencyManager::get<LODManager>();
// always revert back to automatic LOD adjustment when closed
lodManager->setAutomaticLODAdjust(true);
// if the user adjusted the LOD above "normal" then always revert back to default
if (lodManager->getOctreeSizeScale() > DEFAULT_OCTREE_SIZE_SCALE) {
lodManager->setOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE);
}
} }

View file

@ -34,7 +34,6 @@ public slots:
void resetClicked(bool checked); void resetClicked(bool checked);
void reloadSliders(); void reloadSliders();
void updateAutomaticLODAdjust(); void updateAutomaticLODAdjust();
void updateLODValues();
protected: protected:
@ -44,16 +43,12 @@ protected:
private: private:
QSlider* _lodSize; QSlider* _lodSize;
QCheckBox* _automaticLODAdjust; QCheckBox* _manualLODAdjust;
QDoubleSpinBox* _desktopLODDecreaseFPS; QDoubleSpinBox* _desktopLODDecreaseFPS;
QDoubleSpinBox* _desktopLODIncreaseFPS;
QDoubleSpinBox* _hmdLODDecreaseFPS; QDoubleSpinBox* _hmdLODDecreaseFPS;
QDoubleSpinBox* _hmdLODIncreaseFPS;
QDoubleSpinBox* _avatarLOD;
QLabel* _feedback; QLabel* _feedback;
}; };

View file

@ -23,7 +23,7 @@
#include "LoginDialog.h" #include "LoginDialog.h"
#include "UIUtil.h" #include "UIUtil.h"
const QString FORGOT_PASSWORD_URL = "https://metaverse.highfidelity.io/users/password/new"; const QString FORGOT_PASSWORD_URL = "https://metaverse.highfidelity.com/users/password/new";
LoginDialog::LoginDialog(QWidget* parent) : LoginDialog::LoginDialog(QWidget* parent) :
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP), FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP),

View file

@ -19,6 +19,7 @@
#include "Application.h" #include "Application.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "LODManager.h"
#include "Menu.h" #include "Menu.h"
#include "ModelsBrowser.h" #include "ModelsBrowser.h"
#include "PreferencesDialog.h" #include "PreferencesDialog.h"
@ -174,6 +175,10 @@ void PreferencesDialog::loadPreferences() {
ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed()); ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed());
ui.invertSixenseButtonsCheckBox->setChecked(sixense.getInvertButtons()); ui.invertSixenseButtonsCheckBox->setChecked(sixense.getInvertButtons());
// LOD items
auto lodManager = DependencyManager::get<LODManager>();
ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS());
ui.hmdMinimumFPSSpin->setValue(lodManager->getHMDLODDecreaseFPS());
} }
void PreferencesDialog::savePreferences() { void PreferencesDialog::savePreferences() {
@ -275,4 +280,9 @@ void PreferencesDialog::savePreferences() {
audio->setOutputStarveDetectionPeriod(ui.outputStarveDetectionPeriodSpinner->value()); audio->setOutputStarveDetectionPeriod(ui.outputStarveDetectionPeriodSpinner->value());
Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height()); Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height());
// LOD items
auto lodManager = DependencyManager::get<LODManager>();
lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value());
lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value());
} }

View file

@ -136,7 +136,7 @@
<string>&lt;style type=&quot;text/css&quot;&gt; <string>&lt;style type=&quot;text/css&quot;&gt;
a { text-decoration: none; color: #267077;} a { text-decoration: none; color: #267077;}
&lt;/style&gt; &lt;/style&gt;
Invalid username or password. &lt;a href=&quot;https://metaverse.highfidelity.io/password/new&quot;&gt;Recover?&lt;/a&gt;</string> Invalid username or password. &lt;a href=&quot;https://metaverse.highfidelity.com/password/new&quot;&gt;Recover?&lt;/a&gt;</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
@ -458,7 +458,7 @@ border-radius: 4px; padding-top: 1px;</string>
<string>&lt;style type=&quot;text/css&quot;&gt; <string>&lt;style type=&quot;text/css&quot;&gt;
a { text-decoration: none; color: #267077;} a { text-decoration: none; color: #267077;}
&lt;/style&gt; &lt;/style&gt;
&lt;a href=&quot;https://metaverse.highfidelity.io/password/new&quot;&gt;Recover password?&lt;/a&gt;</string> &lt;a href=&quot;https://metaverse.highfidelity.com/password/new&quot;&gt;Recover password?&lt;/a&gt;</string>
</property> </property>
<property name="openExternalLinks"> <property name="openExternalLinks">
<bool>true</bool> <bool>true</bool>

View file

@ -701,6 +701,219 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="verticalSpacer_10">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="levelOfDetailTitleLabel">
<property name="font">
<font>
<family>Arial</family>
<pointsize>18</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color:#29967e</string>
</property>
<property name="text">
<string>Level of Detail Tuning</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_111x">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_9x">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>Minimum Desktop FPS</string>
</property>
<property name="indent">
<number>0</number>
</property>
<!--
<property name="buddy">
<cstring>fieldOfViewSpin</cstring>
</property>
-->
</widget>
</item>
<item>
<spacer name="horizontalSpacer_111x">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSpinBox" name="desktopMinimumFPSSpin">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>95</width>
<height>36</height>
</size>
</property>
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>120</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_111y">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_9y">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>Minimum HMD FPS</string>
</property>
<property name="indent">
<number>0</number>
</property>
<!--
<property name="buddy">
<cstring>fieldOfViewSpin</cstring>
</property>
-->
</widget>
</item>
<item>
<spacer name="horizontalSpacer_111y">
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSpinBox" name="hmdMinimumFPSSpin">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>95</width>
<height>36</height>
</size>
</property>
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>120</number>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<spacer name="verticalSpacer_8"> <spacer name="verticalSpacer_8">
<property name="orientation"> <property name="orientation">
@ -717,6 +930,7 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="QLabel" name="avatarTitleLabel"> <widget class="QLabel" name="avatarTitleLabel">
<property name="font"> <property name="font">
@ -738,6 +952,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_111"> <layout class="QHBoxLayout" name="horizontalLayout_111">
<property name="spacing"> <property name="spacing">
@ -820,6 +1035,9 @@
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing"> <property name="spacing">

View file

@ -300,16 +300,6 @@ public:
const AABox& getLocalAABox() const { return _localAABox; } const AABox& getLocalAABox() const { return _localAABox; }
const Referential* getReferential() const { return _referential; } const Referential* getReferential() const { return _referential; }
void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; }
bool isPhysicsEnabled() { return _enablePhysics; }
void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; }
void lockForRead() { _lock.lockForRead(); }
bool tryLockForRead() { return _lock.tryLockForRead(); }
void lockForWrite() { _lock.lockForWrite(); }
bool tryLockForWrite() { return _lock.tryLockForWrite(); }
void unlock() { _lock.unlock(); }
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
@ -409,9 +399,6 @@ private:
// privatize the copy constructor and assignment operator so they cannot be called // privatize the copy constructor and assignment operator so they cannot be called
AvatarData(const AvatarData&); AvatarData(const AvatarData&);
AvatarData& operator= (const AvatarData&); AvatarData& operator= (const AvatarData&);
QReadWriteLock _lock;
bool _enablePhysics = false;
}; };
Q_DECLARE_METATYPE(AvatarData*) Q_DECLARE_METATYPE(AvatarData*)

View file

@ -25,7 +25,7 @@ EntityItemID::EntityItemID() :
creatorTokenID(UNKNOWN_ENTITY_TOKEN), creatorTokenID(UNKNOWN_ENTITY_TOKEN),
isKnownID(false) isKnownID(false)
{ {
}; }
EntityItemID::EntityItemID(const EntityItemID& other) : EntityItemID::EntityItemID(const EntityItemID& other) :
id(other.id), id(other.id),

View file

@ -49,7 +49,10 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= {
GL_UNSIGNED_BYTE GL_UNSIGNED_BYTE
}; };
#if _DEBUG
#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError() #define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError()
//#define CHECK_GL_ERROR() #else
#define CHECK_GL_ERROR()
#endif
#endif #endif

View file

@ -115,7 +115,7 @@ void AccountManager::updateBalance() {
callbackParameters.jsonCallbackReceiver = &_accountInfo; callbackParameters.jsonCallbackReceiver = &_accountInfo;
callbackParameters.jsonCallbackMethod = "setBalanceFromJSON"; callbackParameters.jsonCallbackMethod = "setBalanceFromJSON";
authenticatedRequest("/api/v1/wallets/mine", QNetworkAccessManager::GetOperation, callbackParameters); sendRequest("/api/v1/wallets/mine", AccountManagerAuth::Required, QNetworkAccessManager::GetOperation, callbackParameters);
} }
} }
@ -159,50 +159,30 @@ void AccountManager::setAuthURL(const QUrl& authURL) {
} }
} }
void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, void AccountManager::sendRequest(const QString& path,
const JSONCallbackParameters& callbackParams, AccountManagerAuth::Type authType,
const QByteArray& dataByteArray, QNetworkAccessManager::Operation operation,
QHttpMultiPart* dataMultiPart, const JSONCallbackParameters& callbackParams,
const QVariantMap& propertyMap) { const QByteArray& dataByteArray,
QHttpMultiPart* dataMultiPart,
const QVariantMap& propertyMap) {
QMetaObject::invokeMethod(this, "invokedRequest", if (thread() != QThread::currentThread()) {
Q_ARG(const QString&, path), QMetaObject::invokeMethod(this, "sendRequest",
Q_ARG(bool, true), Q_ARG(const QString&, path),
Q_ARG(QNetworkAccessManager::Operation, operation), Q_ARG(AccountManagerAuth::Type, AccountManagerAuth::Required),
Q_ARG(const JSONCallbackParameters&, callbackParams), Q_ARG(QNetworkAccessManager::Operation, operation),
Q_ARG(const QByteArray&, dataByteArray), Q_ARG(const JSONCallbackParameters&, callbackParams),
Q_ARG(QHttpMultiPart*, dataMultiPart), Q_ARG(const QByteArray&, dataByteArray),
Q_ARG(QVariantMap, propertyMap)); Q_ARG(QHttpMultiPart*, dataMultiPart),
} Q_ARG(QVariantMap, propertyMap));
}
void AccountManager::unauthenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray,
QHttpMultiPart* dataMultiPart,
const QVariantMap& propertyMap) {
QMetaObject::invokeMethod(this, "invokedRequest",
Q_ARG(const QString&, path),
Q_ARG(bool, false),
Q_ARG(QNetworkAccessManager::Operation, operation),
Q_ARG(const JSONCallbackParameters&, callbackParams),
Q_ARG(const QByteArray&, dataByteArray),
Q_ARG(QHttpMultiPart*, dataMultiPart),
Q_ARG(QVariantMap, propertyMap));
}
void AccountManager::invokedRequest(const QString& path,
bool requiresAuthentication,
QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart,
const QVariantMap& propertyMap) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest; QNetworkRequest networkRequest;
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QUrl requestURL = _authURL; QUrl requestURL = _authURL;
if (path.startsWith("/")) { if (path.startsWith("/")) {
@ -211,13 +191,17 @@ void AccountManager::invokedRequest(const QString& path,
requestURL.setPath("/" + path); requestURL.setPath("/" + path);
} }
if (requiresAuthentication) { if (authType != AccountManagerAuth::None ) {
if (hasValidAccessToken()) { if (hasValidAccessToken()) {
networkRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, networkRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER,
_accountInfo.getAccessToken().authorizationHeaderValue()); _accountInfo.getAccessToken().authorizationHeaderValue());
} else { } else {
qDebug() << "No valid access token present. Bailing on authenticated invoked request."; if (authType == AccountManagerAuth::Required) {
return; qDebug() << "No valid access token present. Bailing on invoked request to"
<< path << "that requires authentication";
return;
}
} }
} }
@ -540,8 +524,8 @@ void AccountManager::processGeneratedKeypair(const QByteArray& publicKey, const
requestMultiPart->append(keyPart); requestMultiPart->append(keyPart);
authenticatedRequest(PUBLIC_KEY_UPDATE_PATH, QNetworkAccessManager::PutOperation, sendRequest(PUBLIC_KEY_UPDATE_PATH, AccountManagerAuth::Required, QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), QByteArray(), requestMultiPart); JSONCallbackParameters(), QByteArray(), requestMultiPart);
// get rid of the keypair generator now that we don't need it anymore // get rid of the keypair generator now that we don't need it anymore
sender()->deleteLater(); sender()->deleteLater();

View file

@ -37,6 +37,16 @@ public:
QString updateSlot; QString updateSlot;
}; };
namespace AccountManagerAuth {
enum Type {
None,
Required,
Optional
};
}
Q_DECLARE_METATYPE(AccountManagerAuth::Type);
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization"; const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
class AccountManager : public QObject { class AccountManager : public QObject {
@ -44,19 +54,13 @@ class AccountManager : public QObject {
public: public:
static AccountManager& getInstance(bool forceReset = false); static AccountManager& getInstance(bool forceReset = false);
void authenticatedRequest(const QString& path, Q_INVOKABLE void sendRequest(const QString& path,
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, AccountManagerAuth::Type authType,
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const QByteArray& dataByteArray = QByteArray(), const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
QHttpMultiPart* dataMultiPart = NULL, const QByteArray& dataByteArray = QByteArray(),
const QVariantMap& propertyMap = QVariantMap()); QHttpMultiPart* dataMultiPart = NULL,
const QVariantMap& propertyMap = QVariantMap());
void unauthenticatedRequest(const QString& path,
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
const QByteArray& dataByteArray = QByteArray(),
QHttpMultiPart* dataMultiPart = NULL,
const QVariantMap& propertyMap = QVariantMap()) ;
const QUrl& getAuthURL() const { return _authURL; } const QUrl& getAuthURL() const { return _authURL; }
void setAuthURL(const QUrl& authURL); void setAuthURL(const QUrl& authURL);
@ -107,14 +111,6 @@ private:
void passSuccessToCallback(QNetworkReply* reply); void passSuccessToCallback(QNetworkReply* reply);
void passErrorToCallback(QNetworkReply* reply); void passErrorToCallback(QNetworkReply* reply);
Q_INVOKABLE void invokedRequest(const QString& path,
bool requiresAuthentication,
QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray,
QHttpMultiPart* dataMultiPart,
const QVariantMap& propertyMap);
QUrl _authURL; QUrl _authURL;
QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap; QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap;

View file

@ -294,12 +294,11 @@ void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const Q
requestParams.insert(OVERRIDE_PATH_KEY, overridePath); requestParams.insert(OVERRIDE_PATH_KEY, overridePath);
} }
AccountManager::getInstance().unauthenticatedRequest(GET_PLACE.arg(placeName), AccountManager::getInstance().sendRequest(GET_PLACE.arg(placeName),
QNetworkAccessManager::GetOperation, AccountManagerAuth::None,
apiCallbackParameters(), QNetworkAccessManager::GetOperation,
QByteArray(), apiCallbackParameters(),
NULL, QByteArray(), NULL, requestParams);
requestParams);
} }
bool AddressManager::handleNetworkAddress(const QString& lookupString) { bool AddressManager::handleNetworkAddress(const QString& lookupString) {
@ -439,9 +438,10 @@ void AddressManager::setDomainInfo(const QString& hostname, quint16 port) {
void AddressManager::goToUser(const QString& username) { void AddressManager::goToUser(const QString& username) {
QString formattedUsername = QUrl::toPercentEncoding(username); QString formattedUsername = QUrl::toPercentEncoding(username);
// this is a username - pull the captured name and lookup that user's location // this is a username - pull the captured name and lookup that user's location
AccountManager::getInstance().unauthenticatedRequest(GET_USER_LOCATION.arg(formattedUsername), AccountManager::getInstance().sendRequest(GET_USER_LOCATION.arg(formattedUsername),
QNetworkAccessManager::GetOperation, AccountManagerAuth::Optional,
apiCallbackParameters()); QNetworkAccessManager::GetOperation,
apiCallbackParameters());
} }
void AddressManager::copyAddress() { void AddressManager::copyAddress() {

View file

@ -23,7 +23,7 @@
#include "AccountManager.h" #include "AccountManager.h"
const QString HIFI_URL_SCHEME = "hifi"; 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 const glm::vec3& (*PositionGetter)();
typedef glm::quat (*OrientationGetter)(); typedef glm::quat (*OrientationGetter)();

View file

@ -36,7 +36,7 @@ const char SOLO_NODE_TYPES[2] = {
NodeType::AudioMixer NodeType::AudioMixer
}; };
const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://metaverse.highfidelity.io"); const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://metaverse.highfidelity.com");
LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort) : LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort) :
linkedDataCreateCallback(NULL), linkedDataCreateCallback(NULL),

View file

@ -62,11 +62,10 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
params.errorCallbackMethod = "requestError"; params.errorCallbackMethod = "requestError";
} }
accountManager.authenticatedRequest(USER_ACTIVITY_URL, accountManager.sendRequest(USER_ACTIVITY_URL,
QNetworkAccessManager::PostOperation, AccountManagerAuth::Required,
params, QNetworkAccessManager::PostOperation,
NULL, params, NULL, multipart);
multipart);
} }
void UserActivityLogger::requestFinished(QNetworkReply& requestReply) { void UserActivityLogger::requestFinished(QNetworkReply& requestReply) {

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
/* /*
Bullet Continuous Collision Detection and Physics Library Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
2015.03.25 -- modified by Andrew Meadows andrew@highfidelity.io
This software is provided 'as-is', without any express or implied warranty. This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software. In no event will the authors be held liable for any damages arising from the use of this software.
@ -37,59 +38,57 @@ class btPairCachingGhostObject;
///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations.
///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user. ///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user.
ATTRIBUTE_ALIGNED16(class) CharacterController : public btCharacterControllerInterface ATTRIBUTE_ALIGNED16(class) CharacterController : public btCharacterControllerInterface
{ {
protected: protected:
AvatarData* m_avatarData = NULL; AvatarData* _avatarData = NULL;
btPairCachingGhostObject* m_ghostObject; btPairCachingGhostObject* _ghostObject;
glm::vec3 m_shapeLocalOffset;
btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast btConvexShape* _convexShape;//is also in _ghostObject, but it needs to be convex, so we store it here to avoid upcast
btScalar m_radius; btScalar _radius;
btScalar m_halfHeight; btScalar _halfHeight;
btScalar m_verticalVelocity; btScalar _verticalVelocity;
btScalar m_verticalOffset; // fall distance from velocity this frame btScalar _verticalOffset; // fall distance from velocity this frame
btScalar m_maxFallSpeed; btScalar _maxFallSpeed;
btScalar m_jumpSpeed; btScalar _jumpSpeed;
btScalar m_maxJumpHeight; btScalar _maxJumpHeight;
btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value) btScalar _maxSlopeRadians; // Slope angle that is set (used for returning the exact value)
btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization) btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization)
btScalar m_gravity; btScalar _gravity;
btScalar m_turnAngle; btScalar _stepHeight; // height of stepUp prior to stepForward
btScalar m_stepHeight; // height of stepUp prior to stepForward btScalar _addedMargin;//@todo: remove this and fix the code
btScalar m_addedMargin;//@todo: remove this and fix the code
///this is the desired walk direction, set by the user ///this is the desired walk direction, set by the user
btVector3 m_walkDirection; btVector3 _walkDirection;
btVector3 m_normalizedDirection; btVector3 _normalizedDirection;
//some internal variables //some internal variables
btVector3 m_currentPosition; btVector3 _currentPosition;
btVector3 m_targetPosition; btQuaternion _currentRotation;
btScalar m_lastStepUp; btVector3 _targetPosition;
btScalar _lastStepUp;
///keep track of the contact manifolds ///keep track of the contact manifolds
btManifoldArray m_manifoldArray; btManifoldArray _manifoldArray;
bool m_touchingContact; bool _touchingContact;
btVector3 m_floorNormal; // points from object to character btVector3 _floorNormal; // points from object to character
bool m_enabled; bool _enabled;
bool m_wasOnGround; bool _wasOnGround;
bool m_wasJumping; bool _wasJumping;
bool m_useWalkDirection; btScalar _velocityTimeInterval;
btScalar m_velocityTimeInterval; uint32_t _pendingFlags;
int m_upAxis;
static btVector3* getUpAxisDirections(); glm::vec3 _shapeLocalOffset;
bool m_interpolateUp; glm::vec3 _boxScale; // used to compute capsule shape
bool full_drop;
bool bounce_fix; btDynamicsWorld* _dynamicsWorld = NULL;
btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal); btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal);
btVector3 parallelComponent(const btVector3& direction, const btVector3& normal); btVector3 parallelComponent(const btVector3& direction, const btVector3& normal);
@ -118,14 +117,6 @@ public:
///btActionInterface interface ///btActionInterface interface
void debugDraw(btIDebugDraw* debugDrawer); void debugDraw(btIDebugDraw* debugDrawer);
void setUpAxis(int axis) {
if (axis < 0)
axis = 0;
if (axis > 2)
axis = 2;
m_upAxis = axis;
}
/// This should probably be called setPositionIncrementPerSimulatorStep. /// This should probably be called setPositionIncrementPerSimulatorStep.
/// This is neither a direction nor a velocity, but the amount to /// This is neither a direction nor a velocity, but the amount to
/// increment the position each simulation iteration, regardless /// increment the position each simulation iteration, regardless
@ -141,18 +132,19 @@ public:
virtual void setVelocityForTimeInterval(const btVector3& velocity, virtual void setVelocityForTimeInterval(const btVector3& velocity,
btScalar timeInterval); btScalar timeInterval);
void reset(btCollisionWorld* collisionWorld ); virtual void reset(btCollisionWorld* collisionWorld );
void warp(const btVector3& origin); virtual void warp(const btVector3& origin);
void preStep(btCollisionWorld* collisionWorld); virtual void preStep(btCollisionWorld* collisionWorld);
void playerStep(btCollisionWorld* collisionWorld, btScalar dt); virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt);
virtual bool canJump() const;
virtual void jump();
virtual bool onGround() const;
void setMaxFallSpeed(btScalar speed); void setMaxFallSpeed(btScalar speed);
void setJumpSpeed(btScalar jumpSpeed); void setJumpSpeed(btScalar jumpSpeed);
void setMaxJumpHeight(btScalar maxJumpHeight); void setMaxJumpHeight(btScalar maxJumpHeight);
bool canJump() const;
void jump();
void setGravity(btScalar gravity); void setGravity(btScalar gravity);
btScalar getGravity() const; btScalar getGravity() const;
@ -164,11 +156,16 @@ public:
btPairCachingGhostObject* getGhostObject(); btPairCachingGhostObject* getGhostObject();
bool onGround() const;
void setUpInterpolate(bool value); void setUpInterpolate(bool value);
bool needsShapeUpdate(); bool needsRemoval() const;
void updateShape(); bool needsAddition() const;
void setEnabled(bool enabled);
void setDynamicsWorld(btDynamicsWorld* world);
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
bool needsShapeUpdate() const;
void updateShapeIfNecessary();
void preSimulation(btScalar timeStep); void preSimulation(btScalar timeStep);
void postSimulation(); void postSimulation();

View file

@ -280,12 +280,12 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
void PhysicsEngine::stepSimulation() { void PhysicsEngine::stepSimulation() {
lock(); lock();
// NOTE: the grand order of operations is: // NOTE: the grand order of operations is:
// (1) relay incoming changes // (1) pull incoming changes
// (2) step simulation // (2) step simulation
// (3) synchronize outgoing motion states // (3) synchronize outgoing motion states
// (4) send outgoing packets // (4) send outgoing packets
// This is step (1). // This is step (1) pull incoming changes
relayIncomingChangesToSimulation(); relayIncomingChangesToSimulation();
const int MAX_NUM_SUBSTEPS = 4; const int MAX_NUM_SUBSTEPS = 4;
@ -294,16 +294,25 @@ void PhysicsEngine::stepSimulation() {
_clock.reset(); _clock.reset();
float timeStep = btMin(dt, MAX_TIMESTEP); float timeStep = btMin(dt, MAX_TIMESTEP);
// This is step (2). // TODO: move character->preSimulation() into relayIncomingChanges
if (_characterController) { if (_characterController) {
if (_characterController->needsRemoval()) {
_characterController->setDynamicsWorld(NULL);
}
_characterController->updateShapeIfNecessary();
if (_characterController->needsAddition()) {
_characterController->setDynamicsWorld(_dynamicsWorld);
}
_characterController->preSimulation(timeStep); _characterController->preSimulation(timeStep);
} }
// This is step (2) step simulation
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
_numSubsteps += (uint32_t)numSubsteps; _numSubsteps += (uint32_t)numSubsteps;
stepNonPhysicalKinematics(usecTimestampNow()); stepNonPhysicalKinematics(usecTimestampNow());
unlock(); unlock();
// TODO: make all of this harvest stuff into one function: relayOutgoingChanges()
if (numSubsteps > 0) { if (numSubsteps > 0) {
// This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree.
// //
@ -598,34 +607,10 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
return true; return true;
} }
void PhysicsEngine::setAvatarData(AvatarData *avatarData) { void PhysicsEngine::setCharacterController(CharacterController* character) {
if (_characterController) { if (!_characterController) {
bool needsShapeUpdate = _characterController->needsShapeUpdate();
if (needsShapeUpdate) {
lock();
// remove old info
_dynamicsWorld->removeCollisionObject(_characterController->getGhostObject());
_dynamicsWorld->removeAction(_characterController);
// update shape
_characterController->updateShape();
// insert new info
_dynamicsWorld->addCollisionObject(_characterController->getGhostObject(),
btBroadphaseProxy::CharacterFilter,
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
_dynamicsWorld->addAction(_characterController);
_characterController->reset(_dynamicsWorld);
unlock();
}
} else {
// initialize _characterController
assert(avatarData); // don't pass NULL argument
lock(); lock();
_characterController = new CharacterController(avatarData); _characterController = character;
_dynamicsWorld->addCollisionObject(_characterController->getGhostObject(),
btBroadphaseProxy::CharacterFilter,
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
_dynamicsWorld->addAction(_characterController);
_characterController->reset(_dynamicsWorld);
unlock(); unlock();
} }
} }

View file

@ -17,9 +17,7 @@
#include <QSet> #include <QSet>
#include <btBulletDynamicsCommon.h> #include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionDispatch/btGhostObject.h> #include <BulletCollision/CollisionDispatch/btGhostObject.h>
//#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
#include <AvatarData.h>
#include <EntityItem.h> #include <EntityItem.h>
#include <EntitySimulation.h> #include <EntitySimulation.h>
@ -86,7 +84,7 @@ public:
/// process queue of changed from external sources /// process queue of changed from external sources
void relayIncomingChangesToSimulation(); void relayIncomingChangesToSimulation();
void setAvatarData(AvatarData *avatarData); void setCharacterController(CharacterController* character);
private: private:
/// \param motionState pointer to Object's MotionState /// \param motionState pointer to Object's MotionState

View file

@ -207,7 +207,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
notImplemented(); notImplemented();
} }
} else { } else {
if (url.toLower().left(33) == "https://metaverse.highfidelity.io/api/") { if (url.toLower().left(33) == "https://metaverse.highfidelity.com/api/") {
AccountManager& accountManager = AccountManager::getInstance(); AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.hasValidAccessToken()) { if (accountManager.hasValidAccessToken()) {