mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
5f633a6b24
47 changed files with 3562 additions and 3087 deletions
|
@ -6,7 +6,7 @@
|
|||
{
|
||||
"name": "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",
|
||||
|
@ -30,7 +30,7 @@
|
|||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -652,7 +652,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
|
|||
clickedButton.attr('disabled', 'disabled')
|
||||
|
||||
// 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){
|
||||
|
||||
modal_buttons = {
|
||||
|
@ -682,7 +682,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
|
|||
modal_buttons["success"] = {
|
||||
label: 'Create new domain',
|
||||
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." +
|
||||
|
@ -708,4 +708,4 @@ function chooseFromHighFidelityDomains(clickedButton) {
|
|||
title: "Access token required"
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -814,8 +814,9 @@ void DomainServer::requestUserPublicKey(const QString& username) {
|
|||
|
||||
qDebug() << "Requesting public key for user" << username;
|
||||
|
||||
AccountManager::getInstance().unauthenticatedRequest(USER_PUBLIC_KEY_PATH.arg(username),
|
||||
QNetworkAccessManager::GetOperation, callbackParams);
|
||||
AccountManager::getInstance().sendRequest(USER_PUBLIC_KEY_PATH.arg(username),
|
||||
AccountManagerAuth::None,
|
||||
QNetworkAccessManager::GetOperation, callbackParams);
|
||||
}
|
||||
|
||||
QUrl DomainServer::oauthRedirectURL() {
|
||||
|
@ -1116,8 +1117,10 @@ void DomainServer::sendPendingTransactionsToServer() {
|
|||
transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback";
|
||||
|
||||
while (i != _pendingAssignmentCredits.end()) {
|
||||
accountManager.authenticatedRequest("api/v1/transactions", QNetworkAccessManager::PostOperation,
|
||||
transactionCallbackParams, i.value()->postJson().toJson());
|
||||
accountManager.sendRequest("api/v1/transactions",
|
||||
AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PostOperation,
|
||||
transactionCallbackParams, i.value()->postJson().toJson());
|
||||
|
||||
// set this transaction to finalized so we don't add additional credits to it
|
||||
i.value()->setIsFinalized(true);
|
||||
|
@ -1240,10 +1243,11 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
|
|||
|
||||
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
|
||||
|
||||
AccountManager::getInstance().authenticatedRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
|
||||
QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(),
|
||||
domainUpdateJSON.toUtf8());
|
||||
AccountManager::getInstance().sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
|
||||
AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(),
|
||||
domainUpdateJSON.toUtf8());
|
||||
}
|
||||
|
||||
// todo: have data-web respond with ice-server hostname to use
|
||||
|
|
|
@ -18,4 +18,3 @@ Script.load("lobby.js");
|
|||
Script.load("notifications.js");
|
||||
Script.load("look.js");
|
||||
Script.load("users.js");
|
||||
Script.load("utilities/LODWarning.js");
|
||||
|
|
341
examples/edit.js
341
examples/edit.js
|
@ -76,7 +76,6 @@ var DEFAULT_DIMENSIONS = {
|
|||
|
||||
var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
|
||||
|
||||
var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool";
|
||||
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
|
||||
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
|
||||
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
|
||||
|
@ -130,7 +129,7 @@ var importingSVOTextOverlay = Overlays.addOverlay("text", {
|
|||
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);
|
||||
marketplaceWindow.setVisible(false);
|
||||
|
||||
|
@ -338,7 +337,11 @@ var toolBar = (function () {
|
|||
return true;
|
||||
}
|
||||
if (browseModelsButton === toolBar.clicked(clickedOverlay)) {
|
||||
if (marketplaceWindow.url != MARKETPLACE_URL) {
|
||||
marketplaceWindow.setURL(MARKETPLACE_URL);
|
||||
}
|
||||
marketplaceWindow.setVisible(true);
|
||||
marketplaceWindow.raise();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -540,7 +543,7 @@ function mousePressEvent(event) {
|
|||
mouseHasMovedSincePress = false;
|
||||
mouseCapturedByTool = false;
|
||||
|
||||
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
|
||||
if (propertyMenu.mousePressEvent(event) || toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
|
||||
mouseCapturedByTool = true;
|
||||
return;
|
||||
}
|
||||
|
@ -549,18 +552,6 @@ function mousePressEvent(event) {
|
|||
// Event handled; do nothing.
|
||||
return;
|
||||
}
|
||||
} else if (Menu.isOptionChecked(MENU_INSPECT_TOOL_ENABLED)) {
|
||||
var result = findClickedEntity(event);
|
||||
if (event.isRightButton) {
|
||||
if (result !== null) {
|
||||
var currentProperties = Entities.getEntityProperties(result.entityID);
|
||||
cameraManager.enable();
|
||||
cameraManager.focus(currentProperties.position, null, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
cameraManager.mousePressEvent(event);
|
||||
}
|
||||
} else {
|
||||
cameraManager.mousePressEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -572,6 +563,8 @@ var IDLE_MOUSE_TIMEOUT = 200;
|
|||
var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0;
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
mouseHasMovedSincePress = true;
|
||||
|
||||
if (placingEntityID) {
|
||||
if (!placingEntityID.isKnownID) {
|
||||
placingEntityID = Entities.identifyEntity(placingEntityID);
|
||||
|
@ -592,10 +585,8 @@ function mouseMoveEvent(event) {
|
|||
Script.clearTimeout(idleMouseTimerId);
|
||||
}
|
||||
|
||||
mouseHasMovedSincePress = true;
|
||||
|
||||
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
|
||||
if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
||||
if (selectionDisplay.mouseMoveEvent(event) || propertyMenu.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -640,7 +631,7 @@ function highlightEntityUnderCursor(position, accurateRay) {
|
|||
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
if (toolBar.mouseReleaseEvent(event)) {
|
||||
if (propertyMenu.mouseReleaseEvent(event) || toolBar.mouseReleaseEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
if (placingEntityID) {
|
||||
|
@ -664,74 +655,93 @@ function mouseReleaseEvent(event) {
|
|||
}
|
||||
|
||||
function mouseClickEvent(event) {
|
||||
if (!event.isLeftButton || !isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = findClickedEntity(event);
|
||||
if (result === null) {
|
||||
if (!event.isShifted) {
|
||||
selectionManager.clearSelections();
|
||||
}
|
||||
return;
|
||||
}
|
||||
toolBar.setActive(true);
|
||||
var pickRay = result.pickRay;
|
||||
var foundEntity = result.entityID;
|
||||
|
||||
var properties = Entities.getEntityProperties(foundEntity);
|
||||
if (isLocked(properties)) {
|
||||
print("Model locked " + properties.id);
|
||||
} else {
|
||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||
|
||||
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
|
||||
// P P - Model
|
||||
// /| A - Palm
|
||||
// / | d B - unit vector toward tip
|
||||
// / | X - base of the perpendicular line
|
||||
// A---X----->B d - distance fom axis
|
||||
// x x - distance from A
|
||||
//
|
||||
// |X-A| = (P-A).B
|
||||
// X == A + ((P-A).B)B
|
||||
// d = |P-X|
|
||||
|
||||
var A = pickRay.origin;
|
||||
var B = Vec3.normalize(pickRay.direction);
|
||||
var P = properties.position;
|
||||
|
||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
||||
var d = Vec3.length(Vec3.subtract(P, X));
|
||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||
|
||||
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
|
||||
|
||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||
|
||||
if (0 < x && sizeOK) {
|
||||
entitySelected = true;
|
||||
selectedEntityID = foundEntity;
|
||||
orientation = MyAvatar.orientation;
|
||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
||||
|
||||
|
||||
if (isActive && event.isLeftButton) {
|
||||
var result = findClickedEntity(event);
|
||||
if (result === null) {
|
||||
if (!event.isShifted) {
|
||||
selectionManager.setSelections([foundEntity]);
|
||||
selectionManager.clearSelections();
|
||||
}
|
||||
return;
|
||||
}
|
||||
toolBar.setActive(true);
|
||||
var pickRay = result.pickRay;
|
||||
var foundEntity = result.entityID;
|
||||
|
||||
var properties = Entities.getEntityProperties(foundEntity);
|
||||
if (isLocked(properties)) {
|
||||
print("Model locked " + properties.id);
|
||||
} else {
|
||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||
|
||||
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
|
||||
// P P - Model
|
||||
// /| A - Palm
|
||||
// / | d B - unit vector toward tip
|
||||
// / | X - base of the perpendicular line
|
||||
// A---X----->B d - distance fom axis
|
||||
// x x - distance from A
|
||||
//
|
||||
// |X-A| = (P-A).B
|
||||
// X == A + ((P-A).B)B
|
||||
// d = |P-X|
|
||||
|
||||
var A = pickRay.origin;
|
||||
var B = Vec3.normalize(pickRay.direction);
|
||||
var P = properties.position;
|
||||
|
||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
||||
var d = Vec3.length(Vec3.subtract(P, X));
|
||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||
|
||||
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
|
||||
|
||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||
|
||||
if (0 < x && sizeOK) {
|
||||
entitySelected = true;
|
||||
selectedEntityID = foundEntity;
|
||||
orientation = MyAvatar.orientation;
|
||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
||||
|
||||
|
||||
if (!event.isShifted) {
|
||||
selectionManager.setSelections([foundEntity]);
|
||||
} else {
|
||||
selectionManager.addEntity(foundEntity, true);
|
||||
}
|
||||
|
||||
print("Model selected: " + foundEntity.id);
|
||||
selectionDisplay.select(selectedEntityID, event);
|
||||
|
||||
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
|
||||
cameraManager.focus(selectionManager.worldPosition,
|
||||
selectionManager.worldDimensions,
|
||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event.isRightButton) {
|
||||
var result = findClickedEntity(event);
|
||||
if (result) {
|
||||
var properties = Entities.getEntityProperties(result.entityID);
|
||||
var data = {};
|
||||
try {
|
||||
data = JSON.parse(properties.attribution);
|
||||
} catch (e) {
|
||||
}
|
||||
if (data.marketplaceID) {
|
||||
propertyMenu.marketplaceID = data.marketplaceID;
|
||||
propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace");
|
||||
} else {
|
||||
selectionManager.addEntity(foundEntity, true);
|
||||
}
|
||||
|
||||
print("Model selected: " + foundEntity.id);
|
||||
selectionDisplay.select(selectedEntityID, event);
|
||||
|
||||
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
|
||||
cameraManager.focus(selectionManager.worldPosition,
|
||||
selectionManager.worldDimensions,
|
||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
propertyMenu.marketplaceID = null;
|
||||
propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info");
|
||||
}
|
||||
propertyMenu.setPosition(event.x, event.y);
|
||||
propertyMenu.show();
|
||||
} else {
|
||||
propertyMenu.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities" });
|
||||
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, afterItem: MENU_INSPECT_TOOL_ENABLED,
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT,
|
||||
isCheckable: true, isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" });
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_AUTO_FOCUS_ON_SELECT,
|
||||
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
|
||||
|
@ -807,7 +817,6 @@ function cleanupModelMenus() {
|
|||
Menu.removeMenuItem("File", "Import Entities");
|
||||
Menu.removeMenuItem("File", "Import Entities from URL");
|
||||
|
||||
Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED);
|
||||
Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT);
|
||||
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
|
||||
Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE);
|
||||
|
@ -829,11 +838,21 @@ Script.scriptEnding.connect(function() {
|
|||
Overlays.deleteOverlay(importingSVOTextOverlay);
|
||||
});
|
||||
|
||||
var lastOrientation = null;
|
||||
var lastPosition = null;
|
||||
|
||||
// Do some stuff regularly, like check for placement of various overlays
|
||||
Script.update.connect(function (deltaTime) {
|
||||
toolBar.move();
|
||||
progressDialog.move();
|
||||
selectionDisplay.checkMove();
|
||||
var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);
|
||||
var dPosition = Vec3.distance(Camera.position, lastPosition);
|
||||
if (dOrientation > 0.001 || dPosition > 0.001) {
|
||||
propertyMenu.hide();
|
||||
lastOrientation = Camera.orientation;
|
||||
lastPosition = Camera.position;
|
||||
}
|
||||
});
|
||||
|
||||
function insideBox(center, dimensions, point) {
|
||||
|
@ -910,8 +929,8 @@ function handeMenuEvent(menuItem) {
|
|||
if (!selectionManager.hasSelection()) {
|
||||
Window.alert("No entities have been selected.");
|
||||
} else {
|
||||
var filename = "models__" + Window.location.hostname + "__.svo";
|
||||
filename = Window.save("Select where to save", filename, "*.svo")
|
||||
var filename = "entities__" + Window.location.hostname + ".svo.json";
|
||||
filename = Window.save("Select where to save", filename, "*.json")
|
||||
if (filename) {
|
||||
var success = Clipboard.exportEntities(filename, selectionManager.selections);
|
||||
if (!success) {
|
||||
|
@ -923,7 +942,7 @@ function handeMenuEvent(menuItem) {
|
|||
|
||||
var importURL;
|
||||
if (menuItem == "Import Entities") {
|
||||
importURL = Window.browse("Select models to import", "", "*.svo");
|
||||
importURL = Window.browse("Select models to import", "", "*.json");
|
||||
} else {
|
||||
importURL = Window.prompt("URL of SVO to import", "");
|
||||
}
|
||||
|
@ -1143,6 +1162,12 @@ PropertiesTool = function(opts) {
|
|||
}
|
||||
pushCommandForSelections();
|
||||
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") {
|
||||
if (data.action == "moveSelectionToGrid") {
|
||||
if (selectionManager.hasSelection()) {
|
||||
|
@ -1216,4 +1241,142 @@ PropertiesTool = function(opts) {
|
|||
return that;
|
||||
};
|
||||
|
||||
PopupMenu = function() {
|
||||
var self = this;
|
||||
|
||||
var MENU_ITEM_HEIGHT = 21;
|
||||
var MENU_ITEM_SPACING = 1;
|
||||
var TEXT_MARGIN = 7;
|
||||
|
||||
var overlays = [];
|
||||
var overlayInfo = {};
|
||||
|
||||
var upColor = { red: 0, green: 0, blue: 0 };
|
||||
var downColor = { red: 192, green: 192, blue: 192 };
|
||||
var overColor = { red: 128, green: 128, blue: 128 };
|
||||
|
||||
self.onSelectMenuItem = function() { };
|
||||
|
||||
self.addMenuItem = function(name) {
|
||||
var id = Overlays.addOverlay("text", {
|
||||
text: name,
|
||||
backgroundAlpha: 1.0,
|
||||
backgroundColor: upColor,
|
||||
topMargin: TEXT_MARGIN,
|
||||
leftMargin: TEXT_MARGIN,
|
||||
width: 210,
|
||||
height: MENU_ITEM_HEIGHT,
|
||||
font: { size: 12 },
|
||||
visible: false,
|
||||
});
|
||||
overlays.push(id);
|
||||
overlayInfo[id] = { name: name };
|
||||
return id;
|
||||
};
|
||||
|
||||
self.updateMenuItemText = function(id, newText) {
|
||||
Overlays.editOverlay(id, { text: newText });
|
||||
};
|
||||
|
||||
self.setPosition = function(x, y) {
|
||||
for (var key in overlayInfo) {
|
||||
Overlays.editOverlay(key, {
|
||||
x: x,
|
||||
y: y,
|
||||
});
|
||||
y += MENU_ITEM_HEIGHT + MENU_ITEM_SPACING;
|
||||
}
|
||||
};
|
||||
|
||||
self.onSelected = function() { };
|
||||
|
||||
var pressingOverlay = null;
|
||||
var hoveringOverlay = null;
|
||||
|
||||
self.mousePressEvent = function(event) {
|
||||
if (event.isLeftButton) {
|
||||
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
if (overlay in overlayInfo) {
|
||||
pressingOverlay = overlay;
|
||||
Overlays.editOverlay(pressingOverlay, { backgroundColor: downColor });
|
||||
} else {
|
||||
self.hide();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
self.mouseMoveEvent = function(event) {
|
||||
if (visible) {
|
||||
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
if (!pressingOverlay) {
|
||||
if (hoveringOverlay != null && overlay != hoveringOverlay) {
|
||||
Overlays.editOverlay(hoveringOverlay, { backgroundColor: upColor});
|
||||
hoveringOverlay = null;
|
||||
}
|
||||
if (overlay != hoveringOverlay && overlay in overlayInfo) {
|
||||
Overlays.editOverlay(overlay, { backgroundColor: overColor });
|
||||
hoveringOverlay = overlay;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
self.mouseReleaseEvent = function(event) {
|
||||
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
if (pressingOverlay != null) {
|
||||
if (overlay == pressingOverlay) {
|
||||
self.onSelectMenuItem(overlayInfo[overlay].name);
|
||||
}
|
||||
Overlays.editOverlay(pressingOverlay, { backgroundColor: upColor });
|
||||
pressingOverlay = null;
|
||||
self.hide();
|
||||
}
|
||||
};
|
||||
|
||||
var visible = false;
|
||||
|
||||
self.setVisible = function(newVisible) {
|
||||
if (newVisible != visible) {
|
||||
visible = newVisible;
|
||||
for (var key in overlayInfo) {
|
||||
Overlays.editOverlay(key, { visible: newVisible });
|
||||
}
|
||||
}
|
||||
}
|
||||
self.show = function() {
|
||||
self.setVisible(true);
|
||||
}
|
||||
self.hide = function() {
|
||||
self.setVisible(false);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
for (var i = 0; i < overlays.length; i++) {
|
||||
Overlays.deleteOverlay(overlays[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(self.mousePressEvent);
|
||||
Controller.mouseMoveEvent.connect(self.mouseMoveEvent);
|
||||
Controller.mouseReleaseEvent.connect(self.mouseReleaseEvent);
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
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();
|
||||
|
|
|
@ -1,8 +1,32 @@
|
|||
(function() {
|
||||
this.entityID = null;
|
||||
this.properties = null;
|
||||
this.lightID = null;
|
||||
this.sound = null;
|
||||
this.soundURLs = ["https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_1.wav",
|
||||
"https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav",
|
||||
"https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_3.wav"]
|
||||
|
||||
var DEFAULT_USER_DATA = {
|
||||
creatingLight: false,
|
||||
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) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
|
@ -33,7 +57,8 @@
|
|||
// Download sound if needed
|
||||
this.maybeDownloadSound = function() {
|
||||
if (this.sound === null) {
|
||||
this.sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav");
|
||||
var soundIndex = getUserData(this.entityID).soundIndex;
|
||||
this.sound = SoundCache.getSound(this.soundURLs[soundIndex]);
|
||||
}
|
||||
}
|
||||
// Play switch sound
|
||||
|
@ -47,17 +72,21 @@
|
|||
print("Warning: Couldn't play sound.");
|
||||
}
|
||||
}
|
||||
|
||||
// Toggles the associated light entity
|
||||
this.toggleLight = function() {
|
||||
if (this.lightID) {
|
||||
var lightProperties = Entities.getEntityProperties(this.lightID);
|
||||
Entities.editEntity(this.lightID, { visible: !lightProperties.visible });
|
||||
} else {
|
||||
print("Warning: No light to turn on/off");
|
||||
|
||||
// Checks whether the userData is well-formed and updates it if not
|
||||
this.checkUserData = function() {
|
||||
var userData = getUserData(this.entityID);
|
||||
if (!userData) {
|
||||
userData = DEFAULT_USER_DATA;
|
||||
} else if (!userData.lightDefaultProperties) {
|
||||
userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties;
|
||||
} else if (!userData.soundIndex) {
|
||||
userData.soundIndex = DEFAULT_USER_DATA.soundIndex;
|
||||
}
|
||||
updateUserData(this.entityID, userData);
|
||||
}
|
||||
|
||||
// Create a Light entity
|
||||
this.createLight = function(userData) {
|
||||
var lightProperties = copyObject(userData.lightDefaultProperties);
|
||||
if (lightProperties) {
|
||||
|
@ -74,56 +103,48 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Tries to find a valid light, creates one otherwise
|
||||
this.updateLightID = function() {
|
||||
var userData = getUserData(this.entityID);
|
||||
if (!userData) {
|
||||
userData = {
|
||||
lightID: null,
|
||||
lightDefaultProperties: {
|
||||
type: "Light",
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
dimensions: { x: 5, y: 5, z: 5 },
|
||||
isSpotlight: false,
|
||||
color: { red: 255, green: 48, blue: 0 },
|
||||
diffuseColor: { red: 255, green: 255, blue: 255 },
|
||||
ambientColor: { red: 255, green: 255, blue: 255 },
|
||||
specularColor: { red: 0, green: 0, blue: 0 },
|
||||
constantAttenuation: 1,
|
||||
linearAttenuation: 0,
|
||||
quadraticAttenuation: 0,
|
||||
intensity: 10,
|
||||
exponent: 0,
|
||||
cutoff: 180, // in degrees
|
||||
}
|
||||
};
|
||||
updateUserData(this.entityID, userData);
|
||||
}
|
||||
|
||||
// Find valid light
|
||||
if (doesEntityExistNow(this.lightID)) {
|
||||
if (!didEntityExist(this.lightID)) {
|
||||
// Light now has an ID, so update it in userData
|
||||
this.lightID = getTrueID(this.lightID);
|
||||
userData.lightID = this.lightID;
|
||||
updateUserData(this.entityID, userData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var userData = getUserData(this.entityID);
|
||||
if (doesEntityExistNow(userData.lightID)) {
|
||||
this.lightID = getTrueID(userData.lightID);
|
||||
this.lightID = userData.lightID;
|
||||
return;
|
||||
}
|
||||
|
||||
// No valid light, create one
|
||||
this.lightID = this.createLight(userData);
|
||||
print("Created new light entity");
|
||||
|
||||
// Update user data with new ID
|
||||
if (!userData.creatingLight) {
|
||||
// No valid light, create one
|
||||
userData.creatingLight = true;
|
||||
updateUserData(this.entityID, userData);
|
||||
this.lightID = this.createLight(userData);
|
||||
this.maybeUpdateLightIDInUserData();
|
||||
print("Created new light entity");
|
||||
}
|
||||
}
|
||||
|
||||
this.maybeUpdateLightIDInUserData = function() {
|
||||
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.creatingLight = false;
|
||||
updateUserData(this.entityID, userData);
|
||||
}
|
||||
|
||||
// Moves light entity if the lamp entity moved
|
||||
this.maybeMoveLight = function() {
|
||||
var entityProperties = Entities.getEntityProperties(this.entityID);
|
||||
var lightProperties = Entities.getEntityProperties(this.lightID);
|
||||
|
@ -139,8 +160,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Stores light entity relative position in the lamp metadata
|
||||
this.updateRelativeLightPosition = function() {
|
||||
if (!doesEntityExistNow(this.entityID) || !doesEntityExistNow(this.lightID)) {
|
||||
if (!doesEntityExistNow(this.lightID)) {
|
||||
print("Warning: ID invalid, couldn't save relative position.");
|
||||
return;
|
||||
}
|
||||
|
@ -168,21 +190,37 @@
|
|||
updateUserData(this.entityID, userData);
|
||||
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.entityID = entityID;
|
||||
this.maybeDownloadSound();
|
||||
this.preOperation(entityID);
|
||||
};
|
||||
|
||||
this.clickReleaseOnEntity = function(entityID, mouseEvent) {
|
||||
this.entityID = entityID;
|
||||
this.maybeDownloadSound();
|
||||
this.preOperation(entityID);
|
||||
|
||||
if (mouseEvent.isLeftButton) {
|
||||
this.updateLightID();
|
||||
this.maybeMoveLight();
|
||||
this.toggleLight();
|
||||
this.playSound();
|
||||
} else if (mouseEvent.isRightButton) {
|
||||
this.updateRelativeLightPosition();
|
||||
}
|
||||
|
|
157
examples/example/entities/makeHouses.js
Normal file
157
examples/example/entities/makeHouses.js
Normal 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);
|
||||
})();
|
|
@ -13,5 +13,4 @@ Script.load("progress.js");
|
|||
Script.load("lobby.js");
|
||||
Script.load("notifications.js");
|
||||
Script.load("controllers/oculus/goTo.js");
|
||||
Script.load("utilities/LODWarning.js");
|
||||
//Script.load("scripts.js"); // Not created yet
|
||||
|
|
|
@ -1263,11 +1263,13 @@ SelectionDisplay = (function () {
|
|||
duplicatedEntityIDs = [];
|
||||
for (var otherEntityID in SelectionManager.savedProperties) {
|
||||
var properties = SelectionManager.savedProperties[otherEntityID];
|
||||
var entityID = Entities.addEntity(properties);
|
||||
duplicatedEntityIDs.push({
|
||||
entityID: entityID,
|
||||
properties: properties,
|
||||
});
|
||||
if (!properties.locked) {
|
||||
var entityID = Entities.addEntity(properties);
|
||||
duplicatedEntityIDs.push({
|
||||
entityID: entityID,
|
||||
properties: properties,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
duplicatedEntityIDs = null;
|
||||
|
@ -1361,11 +1363,13 @@ SelectionDisplay = (function () {
|
|||
duplicatedEntityIDs = [];
|
||||
for (var otherEntityID in SelectionManager.savedProperties) {
|
||||
var properties = SelectionManager.savedProperties[otherEntityID];
|
||||
var entityID = Entities.addEntity(properties);
|
||||
duplicatedEntityIDs.push({
|
||||
entityID: entityID,
|
||||
properties: properties,
|
||||
});
|
||||
if (!properties.locked) {
|
||||
var entityID = Entities.addEntity(properties);
|
||||
duplicatedEntityIDs.push({
|
||||
entityID: entityID,
|
||||
properties: properties,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
duplicatedEntityIDs = null;
|
||||
|
|
|
@ -21,8 +21,8 @@ modelUploader = (function () {
|
|||
//svoBuffer,
|
||||
mapping,
|
||||
geometry,
|
||||
API_URL = "https://metaverse.highfidelity.io/api/v1/models",
|
||||
MODEL_URL = "http://public.highfidelity.io/models/content",
|
||||
API_URL = "https://metaverse.highfidelity.com/api/v1/models",
|
||||
MODEL_URL = "http://public.highfidelity.com/models/content",
|
||||
NAME_FIELD = "name",
|
||||
SCALE_FIELD = "scale",
|
||||
FILENAME_FIELD = "filename",
|
||||
|
@ -690,4 +690,4 @@ modelUploader = (function () {
|
|||
};
|
||||
|
||||
return that;
|
||||
}());
|
||||
}());
|
||||
|
|
|
@ -158,7 +158,7 @@ var places = {};
|
|||
|
||||
function changeLobbyTextures() {
|
||||
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();
|
||||
|
||||
places = JSON.parse(req.responseText).data.places;
|
||||
|
|
|
@ -80,7 +80,6 @@ function touchBeginEvent(event) {
|
|||
yawFromTouch = 0;
|
||||
pitchFromTouch = 0;
|
||||
startedTouching = true;
|
||||
print("TOUCH BEGIN");
|
||||
}
|
||||
|
||||
function touchEndEvent(event) {
|
||||
|
@ -88,7 +87,6 @@ function touchEndEvent(event) {
|
|||
print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
startedTouching = false;
|
||||
print("TOUCH END");
|
||||
}
|
||||
|
||||
function touchUpdateEvent(event) {
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
// 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.
|
||||
|
||||
|
||||
// To add a keypress driven notification:
|
||||
//
|
||||
// 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 PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds";
|
||||
var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_";
|
||||
var lodTextID = false;
|
||||
|
||||
var NotificationType = {
|
||||
UNKNOWN: 0,
|
||||
MUTE_TOGGLE: 1,
|
||||
SNAPSHOT: 2,
|
||||
WINDOW_RESIZE: 3,
|
||||
LOD_WARNING: 4,
|
||||
properties: [
|
||||
{ text: "Mute Toggle" },
|
||||
{ text: "Snapshot" },
|
||||
{ text: "Window Resize" }
|
||||
{ text: "Window Resize" },
|
||||
{ text: "Level of Detail" }
|
||||
],
|
||||
getTypeFromMenuItem: function(menuItemName) {
|
||||
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
|
||||
function dismiss(firstNoteOut, firstButOut, firstOut) {
|
||||
if (firstNoteOut == lodTextID) {
|
||||
lodTextID = false;
|
||||
}
|
||||
|
||||
Overlays.deleteOverlay(firstNoteOut);
|
||||
Overlays.deleteOverlay(firstButOut);
|
||||
notifications.splice(firstOut, 1);
|
||||
|
@ -261,7 +267,8 @@ function notify(notice, button, height) {
|
|||
height: noticeHeight
|
||||
});
|
||||
} else {
|
||||
notifications.push((Overlays.addOverlay("text", notice)));
|
||||
var notificationText = Overlays.addOverlay("text", notice);
|
||||
notifications.push((notificationText));
|
||||
buttons.push((Overlays.addOverlay("image", button)));
|
||||
}
|
||||
|
||||
|
@ -272,6 +279,7 @@ function notify(notice, button, height) {
|
|||
last = notifications.length - 1;
|
||||
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
|
||||
fadeIn(notifications[last], buttons[last]);
|
||||
return notificationText;
|
||||
}
|
||||
|
||||
// This function creates and sizes the overlays
|
||||
|
@ -331,11 +339,15 @@ function createNotification(text, notificationType) {
|
|||
randomSounds.playRandom();
|
||||
}
|
||||
|
||||
notify(noticeProperties, buttonProperties, height);
|
||||
return notify(noticeProperties, buttonProperties, height);
|
||||
}
|
||||
|
||||
function deleteNotification(index) {
|
||||
Overlays.deleteOverlay(notifications[index]);
|
||||
var notificationTextID = notifications[index];
|
||||
if (notificationTextID == lodTextID) {
|
||||
lodTextID = false;
|
||||
}
|
||||
Overlays.deleteOverlay(notificationTextID);
|
||||
Overlays.deleteOverlay(buttons[index]);
|
||||
notifications.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);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
|
|
|
@ -34,7 +34,7 @@ var usersWindow = (function () {
|
|||
usersOnline, // Raw users data
|
||||
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
|
||||
usersRequest,
|
||||
processUsers,
|
||||
|
|
|
@ -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);
|
||||
});
|
2058
interface/resources/html/edit-commands.html
Normal file
2058
interface/resources/html/edit-commands.html
Normal file
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 |
|
@ -382,6 +382,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
|
||||
connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
|
||||
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::nodeKilled, this, &Application::nodeKilled);
|
||||
|
@ -1751,7 +1755,7 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
|
|||
exportTree.addEntity(entityItem->getEntityItemID(), properties);
|
||||
}
|
||||
|
||||
exportTree.writeToSVOFile(filename.toLocal8Bit().constData());
|
||||
exportTree.writeToJSONFile(filename.toLocal8Bit().constData());
|
||||
|
||||
// restore the main window's active state
|
||||
_window->activateWindow();
|
||||
|
@ -1786,6 +1790,7 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa
|
|||
void Application::loadSettings() {
|
||||
|
||||
DependencyManager::get<AudioClient>()->loadSettings();
|
||||
DependencyManager::get<LODManager>()->loadSettings();
|
||||
|
||||
Menu::getInstance()->loadSettings();
|
||||
_myAvatar->loadData();
|
||||
|
@ -1793,6 +1798,7 @@ void Application::loadSettings() {
|
|||
|
||||
void Application::saveSettings() {
|
||||
DependencyManager::get<AudioClient>()->saveSettings();
|
||||
DependencyManager::get<LODManager>()->saveSettings();
|
||||
|
||||
Menu::getInstance()->saveSettings();
|
||||
_myAvatar->saveData();
|
||||
|
@ -1903,8 +1909,6 @@ void Application::init() {
|
|||
_physicsEngine.init(&_entityEditSender);
|
||||
|
||||
|
||||
_physicsEngine.setAvatarData(_myAvatar);
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
|
||||
|
@ -2191,6 +2195,7 @@ void Application::update(float deltaTime) {
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("physics");
|
||||
_myAvatar->preSimulation();
|
||||
_physicsEngine.stepSimulation();
|
||||
}
|
||||
|
||||
|
@ -3295,11 +3300,6 @@ void Application::connectedToDomain(const QString& hostname) {
|
|||
const QUuid& domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -3599,6 +3599,7 @@ void Application::initializeAcceptedFiles() {
|
|||
if (_acceptedExtensions.size() == 0) {
|
||||
_acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot;
|
||||
_acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL;
|
||||
_acceptedExtensions[SVO_JSON_EXTENSION] = &Application::importSVOFromURL;
|
||||
_acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript;
|
||||
_acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl;
|
||||
}
|
||||
|
@ -4207,7 +4208,7 @@ void Application::checkSkeleton() {
|
|||
_myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
} else {
|
||||
_myAvatar->updateLocalAABox();
|
||||
_physicsEngine.setAvatarData(_myAvatar);
|
||||
_myAvatar->updateCharacterController();
|
||||
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ static const float NODE_KILLED_BLUE = 0.0f;
|
|||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
static const QString SVO_EXTENSION = ".svo";
|
||||
static const QString SVO_JSON_EXTENSION = ".svo.json";
|
||||
static const QString JS_EXTENSION = ".js";
|
||||
static const QString FST_EXTENSION = ".fst";
|
||||
|
||||
|
@ -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 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
|
||||
static const UINT UWM_IDENTIFY_INSTANCES =
|
||||
|
|
|
@ -61,17 +61,21 @@ void DiscoverabilityManager::updateLocation() {
|
|||
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);
|
||||
|
||||
accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(), QJsonDocument(rootObject).toJson());
|
||||
accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(), QJsonDocument(rootObject).toJson());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::removeLocation() {
|
||||
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) {
|
||||
|
|
|
@ -17,18 +17,12 @@
|
|||
|
||||
#include "LODManager.h"
|
||||
|
||||
Setting::Handle<bool> automaticLODAdjust("automaticLODAdjust", true);
|
||||
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> 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() {
|
||||
if (Application::getInstance()->isHMDMode()) {
|
||||
|
@ -46,41 +40,55 @@ float LODManager::getLODIncreaseFPS() {
|
|||
|
||||
|
||||
void LODManager::autoAdjustLOD(float currentFPS) {
|
||||
|
||||
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
|
||||
// really want to count them in our average, so we will ignore the real frame rates and stuff
|
||||
// our moving average with simulated good data
|
||||
const int IGNORE_THESE_SAMPLES = 100;
|
||||
const float ASSUMED_FPS = 60.0f;
|
||||
if (_fpsAverage.getSampleCount() < IGNORE_THESE_SAMPLES) {
|
||||
if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) {
|
||||
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();
|
||||
|
||||
bool changed = false;
|
||||
bool octreeChanged = false;
|
||||
quint64 elapsed = now - _lastAdjust;
|
||||
quint64 elapsedSinceDownShift = now - _lastDownShift;
|
||||
quint64 elapsedSinceUpShift = now - _lastUpShift;
|
||||
|
||||
quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable);
|
||||
quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift;
|
||||
|
||||
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
|
||||
float targetFps = (getLODDecreaseFPS() + getLODIncreaseFPS()) * 0.5f;
|
||||
float averageFps = _fastFPSAverage.getAverage();
|
||||
const float MAXIMUM_MULTIPLIER_SCALE = 2.0f;
|
||||
float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier;
|
||||
_avatarLODDistanceMultiplier = qMin(MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier *
|
||||
(averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE :
|
||||
qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps)));
|
||||
|
||||
if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) {
|
||||
qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
||||
<< "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier;
|
||||
changed = true;
|
||||
if (_isDownshifting) {
|
||||
// only consider things if our DOWN_SHIFT time has elapsed...
|
||||
if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) {
|
||||
doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS();
|
||||
|
||||
if (!doDownShift) {
|
||||
qDebug() << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----";
|
||||
_isDownshifting = false;
|
||||
_lastStable = now;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED
|
||||
&& _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS());
|
||||
}
|
||||
|
||||
if (doDownShift) {
|
||||
|
||||
// Octree items... stepwise adjustment
|
||||
if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||
|
@ -88,58 +96,71 @@ void LODManager::autoAdjustLOD(float currentFPS) {
|
|||
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||
}
|
||||
octreeChanged = changed = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
_lastAdjust = now;
|
||||
qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
||||
<< "_octreeSizeScale=" << _octreeSizeScale;
|
||||
|
||||
if (changed) {
|
||||
if (_isDownshifting) {
|
||||
// subsequent downshift
|
||||
qDebug() << "adjusting LOD DOWN..."
|
||||
<< "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was "
|
||||
<< _fpsAverageDownWindow.getAverage()
|
||||
<< "minimum is:" << getLODDecreaseFPS()
|
||||
<< "elapsedSinceDownShift:" << elapsedSinceDownShift
|
||||
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
||||
} else {
|
||||
// first downshift
|
||||
qDebug() << "adjusting LOD DOWN after initial delay..."
|
||||
<< "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was "
|
||||
<< _fpsAverageStartWindow.getAverage()
|
||||
<< "minimum is:" << getLODDecreaseFPS()
|
||||
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
|
||||
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
||||
}
|
||||
|
||||
_lastDownShift = now;
|
||||
_isDownshifting = true;
|
||||
|
||||
emit LODDecreased();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// LOD Upward adjustment
|
||||
if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > getLODIncreaseFPS()) {
|
||||
// LOD Upward adjustment
|
||||
if (elapsedSinceUpShift > UP_SHIFT_ELPASED) {
|
||||
|
||||
if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) {
|
||||
|
||||
// Avatars... let the detail level creep slowly upwards
|
||||
if (_avatarLODDistanceMultiplier < MAXIMUM_AUTO_ADJUST_AVATAR_LOD_DISTANCE_MULTIPLIER) {
|
||||
const float DISTANCE_DECREASE_RATE = 0.05f;
|
||||
float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier;
|
||||
_avatarLODDistanceMultiplier = qMax(MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER,
|
||||
_avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE);
|
||||
|
||||
if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) {
|
||||
qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
||||
<< "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier;
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
_lastAdjust = now;
|
||||
qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
||||
<< "_octreeSizeScale=" << _octreeSizeScale;
|
||||
if (changed) {
|
||||
qDebug() << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was "
|
||||
<< _fpsAverageUpWindow.getAverage()
|
||||
<< "upshift point is:" << getLODIncreaseFPS()
|
||||
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
|
||||
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
||||
|
||||
emit LODIncreased();
|
||||
_lastUpShift = now;
|
||||
_isDownshifting = false;
|
||||
|
||||
emit LODIncreased();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
calculateAvatarLODDistanceMultiplier();
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
|
||||
if (lodToolsDialog) {
|
||||
|
@ -150,9 +171,11 @@ void LODManager::autoAdjustLOD(float currentFPS) {
|
|||
}
|
||||
|
||||
void LODManager::resetLODAdjust() {
|
||||
_fpsAverage.reset();
|
||||
_fastFPSAverage.reset();
|
||||
_lastAdjust = usecTimestampNow();
|
||||
_fpsAverageStartWindow.reset();
|
||||
_fpsAverageDownWindow.reset();
|
||||
_fpsAverageUpWindow.reset();
|
||||
_lastUpShift = _lastDownShift = usecTimestampNow();
|
||||
_isDownshifting = false;
|
||||
}
|
||||
|
||||
QString LODManager::getLODFeedbackText() {
|
||||
|
@ -234,9 +257,14 @@ bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera
|
|||
|
||||
void LODManager::setOctreeSizeScale(float sizeScale) {
|
||||
_octreeSizeScale = sizeScale;
|
||||
calculateAvatarLODDistanceMultiplier();
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
}
|
||||
|
||||
void LODManager::calculateAvatarLODDistanceMultiplier() {
|
||||
_avatarLODDistanceMultiplier = AVATAR_TO_ENTITY_RATIO / (_octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE);
|
||||
}
|
||||
|
||||
void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
|
||||
_boundaryLevelAdjust = boundaryLevelAdjust;
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
|
@ -244,27 +272,13 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
|
|||
|
||||
|
||||
void LODManager::loadSettings() {
|
||||
setAutomaticLODAdjust(automaticLODAdjust.get());
|
||||
setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get());
|
||||
setDesktopLODIncreaseFPS(desktopLODIncreaseFPS.get());
|
||||
setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get());
|
||||
setHMDLODIncreaseFPS(hmdLODIncreaseFPS.get());
|
||||
|
||||
setAvatarLODDistanceMultiplier(avatarLODDistanceMultiplier.get());
|
||||
setBoundaryLevelAdjust(boundaryLevelAdjust.get());
|
||||
setOctreeSizeScale(octreeSizeScale.get());
|
||||
}
|
||||
|
||||
void LODManager::saveSettings() {
|
||||
automaticLODAdjust.set(getAutomaticLODAdjust());
|
||||
desktopLODDecreaseFPS.set(getDesktopLODDecreaseFPS());
|
||||
desktopLODIncreaseFPS.set(getDesktopLODIncreaseFPS());
|
||||
hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS());
|
||||
hmdLODIncreaseFPS.set(getHMDLODIncreaseFPS());
|
||||
|
||||
avatarLODDistanceMultiplier.set(getAvatarLODDistanceMultiplier());
|
||||
boundaryLevelAdjust.set(getBoundaryLevelAdjust());
|
||||
octreeSizeScale.set(getOctreeSizeScale());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,12 +18,23 @@
|
|||
#include <SimpleMovingAverage.h>
|
||||
|
||||
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_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 quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2;
|
||||
const float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts
|
||||
const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f;
|
||||
const float UP_SHIFT_WINDOW_IN_SECS = 2.5f;
|
||||
|
||||
const int ASSUMED_FPS = 60;
|
||||
const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS;
|
||||
const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second
|
||||
const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS;
|
||||
|
||||
const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS;
|
||||
const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS;
|
||||
const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS;
|
||||
|
||||
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
||||
const float ADJUST_LOD_UP_BY = 1.1f;
|
||||
|
@ -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_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
|
||||
const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f;
|
||||
const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f;
|
||||
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.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;
|
||||
// The ratio of "visibility" of avatars to other content. A value larger than 1 will mean Avatars "cull" later than entities
|
||||
// do. But both are still culled using the same angular size logic.
|
||||
const float AVATAR_TO_ENTITY_RATIO = 2.0f;
|
||||
|
||||
|
||||
class LODManager : public QObject, public Dependency {
|
||||
|
@ -53,15 +60,12 @@ public:
|
|||
|
||||
Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; }
|
||||
Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; }
|
||||
Q_INVOKABLE void setDesktopLODIncreaseFPS(float value) { _desktopLODIncreaseFPS = value; }
|
||||
Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODIncreaseFPS; }
|
||||
Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return glm::min(_desktopLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS); }
|
||||
|
||||
Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; }
|
||||
Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; }
|
||||
Q_INVOKABLE void setHMDLODIncreaseFPS(float value) { _hmdLODIncreaseFPS = value; }
|
||||
Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODIncreaseFPS; }
|
||||
Q_INVOKABLE float getHMDLODIncreaseFPS() const { return glm::min(_hmdLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS); }
|
||||
|
||||
Q_INVOKABLE void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; }
|
||||
Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
||||
|
||||
// User Tweakable LOD Items
|
||||
|
@ -72,10 +76,6 @@ public:
|
|||
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||
|
||||
Q_INVOKABLE void resetLODAdjust();
|
||||
Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); }
|
||||
Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); }
|
||||
|
||||
Q_INVOKABLE float getLODDecreaseFPS();
|
||||
Q_INVOKABLE float getLODIncreaseFPS();
|
||||
|
||||
|
@ -84,28 +84,32 @@ public:
|
|||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void resetLODAdjust();
|
||||
|
||||
signals:
|
||||
void LODIncreased();
|
||||
void LODDecreased();
|
||||
|
||||
private:
|
||||
LODManager() {}
|
||||
LODManager();
|
||||
void calculateAvatarLODDistanceMultiplier();
|
||||
|
||||
bool _automaticLODAdjust = true;
|
||||
float _desktopLODDecreaseFPS = DEFAULT_DESKTOP_LOD_DOWN_FPS;
|
||||
float _desktopLODIncreaseFPS = DEFAULT_DESKTOP_LOD_UP_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;
|
||||
int _boundaryLevelAdjust = 0;
|
||||
|
||||
quint64 _lastAdjust = 0;
|
||||
SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES;
|
||||
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES;
|
||||
quint64 _lastDownShift = 0;
|
||||
quint64 _lastUpShift = 0;
|
||||
quint64 _lastStable = 0;
|
||||
bool _isDownshifting = false; // start out as if we're not downshifting
|
||||
|
||||
SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES;
|
||||
SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES;
|
||||
SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES;
|
||||
|
||||
bool _shouldRenderTableNeedsRebuilding = true;
|
||||
QMap<float, float> _shouldRenderTable;
|
||||
|
|
|
@ -70,7 +70,6 @@ MyAvatar::MyAvatar() :
|
|||
Avatar(),
|
||||
_turningKeyPressTime(0.0f),
|
||||
_gravity(0.0f, 0.0f, 0.0f),
|
||||
_shouldJump(false),
|
||||
_wasPushing(false),
|
||||
_isPushing(false),
|
||||
_isBraking(false),
|
||||
|
@ -82,6 +81,8 @@ MyAvatar::MyAvatar() :
|
|||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
||||
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
||||
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
||||
_enablePhysics(false),
|
||||
_characterController(this),
|
||||
_lookAtTargetAvatar(),
|
||||
_shouldRender(true),
|
||||
_billboardValid(false),
|
||||
|
@ -954,15 +955,15 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
|
|||
return Avatar::getPosition();
|
||||
}
|
||||
|
||||
void MyAvatar::updateLocalAABox() {
|
||||
void MyAvatar::updateCharacterController() {
|
||||
// compute localAABox
|
||||
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
|
||||
float radius = capsule.getRadius();
|
||||
float height = 2.0f * (capsule.getHalfHeight() + radius);
|
||||
glm::vec3 offset = _skeletonModel.getBoundingShapeOffset();
|
||||
glm::vec3 corner(-radius, -0.5f * height, -radius);
|
||||
corner += offset;
|
||||
corner += _skeletonModel.getBoundingShapeOffset();
|
||||
glm::vec3 scale(2.0f * radius, height, 2.0f * radius);
|
||||
_localAABox.setBox(corner, scale);
|
||||
_characterController.setLocalBoundingBox(corner, scale);
|
||||
}
|
||||
|
||||
QString MyAvatar::getScriptedMotorFrame() const {
|
||||
|
@ -1580,6 +1581,10 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
|
|||
return palm->getPosition();
|
||||
}
|
||||
|
||||
void MyAvatar::preSimulation() {
|
||||
_characterController.setEnabled(_enablePhysics);
|
||||
}
|
||||
|
||||
void MyAvatar::clearDriveKeys() {
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; ++i) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_MyAvatar_h
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <CharacterController.h>
|
||||
|
||||
#include "Avatar.h"
|
||||
|
||||
|
@ -88,7 +89,7 @@ public:
|
|||
void clearDriveKeys();
|
||||
void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
|
||||
bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; };
|
||||
void jump() { _shouldJump = true; };
|
||||
void jump() { _characterController.jump(); }
|
||||
|
||||
bool isMyAvatar() { return true; }
|
||||
|
||||
|
@ -122,6 +123,8 @@ public:
|
|||
|
||||
virtual glm::vec3 getSkeletonPosition() const;
|
||||
void updateLocalAABox();
|
||||
CharacterController* getCharacterController() { return &_characterController; }
|
||||
void updateCharacterController();
|
||||
|
||||
void clearJointAnimationPriorities();
|
||||
|
||||
|
@ -145,6 +148,11 @@ public:
|
|||
|
||||
const RecorderPointer getRecorder() const { return _recorder; }
|
||||
const PlayerPointer getPlayer() const { return _player; }
|
||||
|
||||
void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; }
|
||||
bool isPhysicsEnabled() { return _enablePhysics; }
|
||||
void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; }
|
||||
void preSimulation();
|
||||
|
||||
public slots:
|
||||
void increaseSize();
|
||||
|
@ -186,7 +194,6 @@ private:
|
|||
float _turningKeyPressTime;
|
||||
glm::vec3 _gravity;
|
||||
|
||||
bool _shouldJump;
|
||||
float _driveKeys[MAX_DRIVE_KEYS];
|
||||
bool _wasPushing;
|
||||
bool _isPushing;
|
||||
|
@ -202,6 +209,9 @@ private:
|
|||
int _scriptedMotorFrame;
|
||||
quint32 _motionBehaviors;
|
||||
|
||||
bool _enablePhysics;
|
||||
CharacterController _characterController;
|
||||
|
||||
QWeakPointer<AvatarData> _lookAtTargetAvatar;
|
||||
glm::vec3 _targetAvatarPosition;
|
||||
bool _shouldRender;
|
||||
|
|
|
@ -223,7 +223,7 @@ void SixenseManager::update(float deltaTime) {
|
|||
palm->setJoystick(data->joystick_x, data->joystick_y);
|
||||
|
||||
// Emulate the mouse so we can use scripts
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) {
|
||||
emulateMouse(palm, numActiveControllers - 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid
|
|||
_windowWidget = dockWidget;
|
||||
} else {
|
||||
_windowWidget = new QWidget(Application::getInstance()->getWindow(), Qt::Window);
|
||||
_windowWidget->setWindowTitle(title);
|
||||
_windowWidget->setMinimumSize(width, height);
|
||||
|
||||
auto layout = new QVBoxLayout(_windowWidget);
|
||||
|
@ -96,6 +97,18 @@ void WebWindowClass::setVisible(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) {
|
||||
WebWindowClass* retVal;
|
||||
QString file = context->argument(0).toString();
|
||||
|
|
|
@ -34,6 +34,7 @@ signals:
|
|||
class WebWindowClass : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QObject* eventBridge READ getEventBridge)
|
||||
Q_PROPERTY(QString url READ getURL)
|
||||
public:
|
||||
WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow = false);
|
||||
~WebWindowClass();
|
||||
|
@ -42,6 +43,9 @@ public:
|
|||
|
||||
public slots:
|
||||
void setVisible(bool visible);
|
||||
QString getURL() const { return _webView->url().url(); }
|
||||
void setURL(const QString& url);
|
||||
void raise();
|
||||
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
|
||||
void addEventBridgeToWindowObject();
|
||||
|
||||
|
|
|
@ -46,37 +46,10 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
_feedback->setFixedWidth(FEEDBACK_WIDTH);
|
||||
form->addRow("You can see... ", _feedback);
|
||||
|
||||
form->addRow("Automatic LOD Adjustment:", _automaticLODAdjust = new QCheckBox(this));
|
||||
_automaticLODAdjust->setChecked(lodManager->getAutomaticLODAdjust());
|
||||
connect(_automaticLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust()));
|
||||
form->addRow("Manually Adjust Level of Detail:", _manualLODAdjust = new QCheckBox(this));
|
||||
_manualLODAdjust->setChecked(!lodManager->getAutomaticLODAdjust());
|
||||
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);
|
||||
const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER;
|
||||
const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||
|
@ -92,7 +65,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
_lodSize->setPageStep(PAGE_STEP_LOD_SIZE);
|
||||
int sliderValue = lodManager->getOctreeSizeScale() / TREE_SCALE;
|
||||
_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)));
|
||||
|
||||
// Add a button to reset
|
||||
|
@ -109,27 +82,12 @@ void LodToolsDialog::reloadSliders() {
|
|||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
_lodSize->setValue(lodManager->getOctreeSizeScale() / TREE_SCALE);
|
||||
_feedback->setText(lodManager->getLODFeedbackText());
|
||||
|
||||
_avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier());
|
||||
|
||||
}
|
||||
|
||||
void LodToolsDialog::updateAutomaticLODAdjust() {
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
lodManager->setAutomaticLODAdjust(_automaticLODAdjust->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());
|
||||
lodManager->setAutomaticLODAdjust(!_manualLODAdjust->isChecked());
|
||||
_lodSize->setEnabled(_manualLODAdjust->isChecked());
|
||||
}
|
||||
|
||||
void LodToolsDialog::sizeScaleValueChanged(int value) {
|
||||
|
@ -144,15 +102,9 @@ void LodToolsDialog::resetClicked(bool checked) {
|
|||
|
||||
int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE;
|
||||
_lodSize->setValue(sliderValue);
|
||||
_automaticLODAdjust->setChecked(true);
|
||||
_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);
|
||||
_manualLODAdjust->setChecked(false);
|
||||
|
||||
updateLODValues(); // tell our LOD manager about the reset
|
||||
updateAutomaticLODAdjust(); // tell our LOD manager about the reset
|
||||
}
|
||||
|
||||
void LodToolsDialog::reject() {
|
||||
|
@ -163,6 +115,15 @@ void LodToolsDialog::reject() {
|
|||
void LodToolsDialog::closeEvent(QCloseEvent* event) {
|
||||
this->QDialog::closeEvent(event);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ public slots:
|
|||
void resetClicked(bool checked);
|
||||
void reloadSliders();
|
||||
void updateAutomaticLODAdjust();
|
||||
void updateLODValues();
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -44,16 +43,12 @@ protected:
|
|||
private:
|
||||
QSlider* _lodSize;
|
||||
|
||||
QCheckBox* _automaticLODAdjust;
|
||||
QCheckBox* _manualLODAdjust;
|
||||
|
||||
QDoubleSpinBox* _desktopLODDecreaseFPS;
|
||||
QDoubleSpinBox* _desktopLODIncreaseFPS;
|
||||
|
||||
QDoubleSpinBox* _hmdLODDecreaseFPS;
|
||||
QDoubleSpinBox* _hmdLODIncreaseFPS;
|
||||
|
||||
|
||||
QDoubleSpinBox* _avatarLOD;
|
||||
QLabel* _feedback;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "LoginDialog.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) :
|
||||
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP),
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
#include "LODManager.h"
|
||||
#include "Menu.h"
|
||||
#include "ModelsBrowser.h"
|
||||
#include "PreferencesDialog.h"
|
||||
|
@ -174,6 +175,10 @@ void PreferencesDialog::loadPreferences() {
|
|||
ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed());
|
||||
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() {
|
||||
|
@ -275,4 +280,9 @@ void PreferencesDialog::savePreferences() {
|
|||
audio->setOutputStarveDetectionPeriod(ui.outputStarveDetectionPeriodSpinner->value());
|
||||
|
||||
Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height());
|
||||
|
||||
// LOD items
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value());
|
||||
lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value());
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
<string><style type="text/css">
|
||||
a { text-decoration: none; color: #267077;}
|
||||
</style>
|
||||
Invalid username or password. <a href="https://metaverse.highfidelity.io/password/new">Recover?</a></string>
|
||||
Invalid username or password. <a href="https://metaverse.highfidelity.com/password/new">Recover?</a></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
|
@ -458,7 +458,7 @@ border-radius: 4px; padding-top: 1px;</string>
|
|||
<string><style type="text/css">
|
||||
a { text-decoration: none; color: #267077;}
|
||||
</style>
|
||||
<a href="https://metaverse.highfidelity.io/password/new">Recover password?</a></string>
|
||||
<a href="https://metaverse.highfidelity.com/password/new">Recover password?</a></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
|
|
|
@ -701,6 +701,219 @@
|
|||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="verticalSpacer_8">
|
||||
<property name="orientation">
|
||||
|
@ -717,6 +930,7 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QLabel" name="avatarTitleLabel">
|
||||
<property name="font">
|
||||
|
@ -738,6 +952,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_111">
|
||||
<property name="spacing">
|
||||
|
@ -820,6 +1035,9 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
|
|
|
@ -300,16 +300,6 @@ public:
|
|||
const AABox& getLocalAABox() const { return _localAABox; }
|
||||
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; }
|
||||
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
|
||||
AvatarData(const AvatarData&);
|
||||
AvatarData& operator= (const AvatarData&);
|
||||
|
||||
QReadWriteLock _lock;
|
||||
bool _enablePhysics = false;
|
||||
};
|
||||
Q_DECLARE_METATYPE(AvatarData*)
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ EntityItemID::EntityItemID() :
|
|||
creatorTokenID(UNKNOWN_ENTITY_TOKEN),
|
||||
isKnownID(false)
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
EntityItemID::EntityItemID(const EntityItemID& other) :
|
||||
id(other.id),
|
||||
|
|
|
@ -49,7 +49,10 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= {
|
|||
GL_UNSIGNED_BYTE
|
||||
};
|
||||
|
||||
#if _DEBUG
|
||||
#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError()
|
||||
//#define CHECK_GL_ERROR()
|
||||
#else
|
||||
#define CHECK_GL_ERROR()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -115,7 +115,7 @@ void AccountManager::updateBalance() {
|
|||
callbackParameters.jsonCallbackReceiver = &_accountInfo;
|
||||
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,
|
||||
const JSONCallbackParameters& callbackParams,
|
||||
const QByteArray& dataByteArray,
|
||||
QHttpMultiPart* dataMultiPart,
|
||||
const QVariantMap& propertyMap) {
|
||||
void AccountManager::sendRequest(const QString& path,
|
||||
AccountManagerAuth::Type authType,
|
||||
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, true),
|
||||
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::unauthenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation,
|
||||
const JSONCallbackParameters& callbackParams,
|
||||
const QByteArray& dataByteArray,
|
||||
QHttpMultiPart* dataMultiPart,
|
||||
const QVariantMap& propertyMap) {
|
||||
if (thread() != QThread::currentThread()) {
|
||||
QMetaObject::invokeMethod(this, "sendRequest",
|
||||
Q_ARG(const QString&, path),
|
||||
Q_ARG(AccountManagerAuth::Type, AccountManagerAuth::Required),
|
||||
Q_ARG(QNetworkAccessManager::Operation, operation),
|
||||
Q_ARG(const JSONCallbackParameters&, callbackParams),
|
||||
Q_ARG(const QByteArray&, dataByteArray),
|
||||
Q_ARG(QHttpMultiPart*, dataMultiPart),
|
||||
Q_ARG(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();
|
||||
|
||||
|
||||
QNetworkRequest networkRequest;
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
||||
|
||||
QUrl requestURL = _authURL;
|
||||
|
||||
if (path.startsWith("/")) {
|
||||
|
@ -211,13 +191,17 @@ void AccountManager::invokedRequest(const QString& path,
|
|||
requestURL.setPath("/" + path);
|
||||
}
|
||||
|
||||
if (requiresAuthentication) {
|
||||
if (authType != AccountManagerAuth::None ) {
|
||||
if (hasValidAccessToken()) {
|
||||
networkRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER,
|
||||
_accountInfo.getAccessToken().authorizationHeaderValue());
|
||||
} else {
|
||||
qDebug() << "No valid access token present. Bailing on authenticated invoked request.";
|
||||
return;
|
||||
if (authType == AccountManagerAuth::Required) {
|
||||
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);
|
||||
|
||||
authenticatedRequest(PUBLIC_KEY_UPDATE_PATH, QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(), QByteArray(), requestMultiPart);
|
||||
sendRequest(PUBLIC_KEY_UPDATE_PATH, AccountManagerAuth::Required, QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(), QByteArray(), requestMultiPart);
|
||||
|
||||
// get rid of the keypair generator now that we don't need it anymore
|
||||
sender()->deleteLater();
|
||||
|
|
|
@ -37,6 +37,16 @@ public:
|
|||
QString updateSlot;
|
||||
};
|
||||
|
||||
namespace AccountManagerAuth {
|
||||
enum Type {
|
||||
None,
|
||||
Required,
|
||||
Optional
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(AccountManagerAuth::Type);
|
||||
|
||||
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
class AccountManager : public QObject {
|
||||
|
@ -44,19 +54,13 @@ class AccountManager : public QObject {
|
|||
public:
|
||||
static AccountManager& getInstance(bool forceReset = false);
|
||||
|
||||
void authenticatedRequest(const QString& path,
|
||||
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
|
||||
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
|
||||
const QByteArray& dataByteArray = QByteArray(),
|
||||
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()) ;
|
||||
Q_INVOKABLE void sendRequest(const QString& path,
|
||||
AccountManagerAuth::Type authType,
|
||||
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; }
|
||||
void setAuthURL(const QUrl& authURL);
|
||||
|
@ -107,14 +111,6 @@ private:
|
|||
void passSuccessToCallback(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;
|
||||
QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap;
|
||||
|
||||
|
|
|
@ -294,12 +294,11 @@ void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const Q
|
|||
requestParams.insert(OVERRIDE_PATH_KEY, overridePath);
|
||||
}
|
||||
|
||||
AccountManager::getInstance().unauthenticatedRequest(GET_PLACE.arg(placeName),
|
||||
QNetworkAccessManager::GetOperation,
|
||||
apiCallbackParameters(),
|
||||
QByteArray(),
|
||||
NULL,
|
||||
requestParams);
|
||||
AccountManager::getInstance().sendRequest(GET_PLACE.arg(placeName),
|
||||
AccountManagerAuth::None,
|
||||
QNetworkAccessManager::GetOperation,
|
||||
apiCallbackParameters(),
|
||||
QByteArray(), NULL, requestParams);
|
||||
}
|
||||
|
||||
bool AddressManager::handleNetworkAddress(const QString& lookupString) {
|
||||
|
@ -439,9 +438,10 @@ void AddressManager::setDomainInfo(const QString& hostname, quint16 port) {
|
|||
void AddressManager::goToUser(const QString& username) {
|
||||
QString formattedUsername = QUrl::toPercentEncoding(username);
|
||||
// this is a username - pull the captured name and lookup that user's location
|
||||
AccountManager::getInstance().unauthenticatedRequest(GET_USER_LOCATION.arg(formattedUsername),
|
||||
QNetworkAccessManager::GetOperation,
|
||||
apiCallbackParameters());
|
||||
AccountManager::getInstance().sendRequest(GET_USER_LOCATION.arg(formattedUsername),
|
||||
AccountManagerAuth::Optional,
|
||||
QNetworkAccessManager::GetOperation,
|
||||
apiCallbackParameters());
|
||||
}
|
||||
|
||||
void AddressManager::copyAddress() {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "AccountManager.h"
|
||||
|
||||
const QString HIFI_URL_SCHEME = "hifi";
|
||||
const QString DEFAULT_HIFI_ADDRESS = "hifi://sandbox";
|
||||
const QString DEFAULT_HIFI_ADDRESS = "hifi://entry";
|
||||
|
||||
typedef const glm::vec3& (*PositionGetter)();
|
||||
typedef glm::quat (*OrientationGetter)();
|
||||
|
|
|
@ -36,7 +36,7 @@ const char SOLO_NODE_TYPES[2] = {
|
|||
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) :
|
||||
linkedDataCreateCallback(NULL),
|
||||
|
|
|
@ -62,11 +62,10 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
|
|||
params.errorCallbackMethod = "requestError";
|
||||
}
|
||||
|
||||
accountManager.authenticatedRequest(USER_ACTIVITY_URL,
|
||||
QNetworkAccessManager::PostOperation,
|
||||
params,
|
||||
NULL,
|
||||
multipart);
|
||||
accountManager.sendRequest(USER_ACTIVITY_URL,
|
||||
AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PostOperation,
|
||||
params, NULL, multipart);
|
||||
}
|
||||
|
||||
void UserActivityLogger::requestFinished(QNetworkReply& requestReply) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
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.
|
||||
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.
|
||||
///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user.
|
||||
|
||||
|
||||
ATTRIBUTE_ALIGNED16(class) CharacterController : public btCharacterControllerInterface
|
||||
{
|
||||
protected:
|
||||
|
||||
AvatarData* m_avatarData = NULL;
|
||||
btPairCachingGhostObject* m_ghostObject;
|
||||
glm::vec3 m_shapeLocalOffset;
|
||||
AvatarData* _avatarData = NULL;
|
||||
btPairCachingGhostObject* _ghostObject;
|
||||
|
||||
btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast
|
||||
btScalar m_radius;
|
||||
btScalar m_halfHeight;
|
||||
btConvexShape* _convexShape;//is also in _ghostObject, but it needs to be convex, so we store it here to avoid upcast
|
||||
btScalar _radius;
|
||||
btScalar _halfHeight;
|
||||
|
||||
btScalar m_verticalVelocity;
|
||||
btScalar m_verticalOffset; // fall distance from velocity this frame
|
||||
btScalar m_maxFallSpeed;
|
||||
btScalar m_jumpSpeed;
|
||||
btScalar m_maxJumpHeight;
|
||||
btScalar m_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 m_gravity;
|
||||
btScalar _verticalVelocity;
|
||||
btScalar _verticalOffset; // fall distance from velocity this frame
|
||||
btScalar _maxFallSpeed;
|
||||
btScalar _jumpSpeed;
|
||||
btScalar _maxJumpHeight;
|
||||
btScalar _maxSlopeRadians; // Slope angle that is set (used for returning the exact value)
|
||||
btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization)
|
||||
btScalar _gravity;
|
||||
|
||||
btScalar m_turnAngle;
|
||||
btScalar _stepHeight; // height of stepUp prior to stepForward
|
||||
|
||||
btScalar m_stepHeight; // height of stepUp prior to stepForward
|
||||
|
||||
btScalar m_addedMargin;//@todo: remove this and fix the code
|
||||
btScalar _addedMargin;//@todo: remove this and fix the code
|
||||
|
||||
///this is the desired walk direction, set by the user
|
||||
btVector3 m_walkDirection;
|
||||
btVector3 m_normalizedDirection;
|
||||
btVector3 _walkDirection;
|
||||
btVector3 _normalizedDirection;
|
||||
|
||||
//some internal variables
|
||||
btVector3 m_currentPosition;
|
||||
btVector3 m_targetPosition;
|
||||
btScalar m_lastStepUp;
|
||||
btVector3 _currentPosition;
|
||||
btQuaternion _currentRotation;
|
||||
btVector3 _targetPosition;
|
||||
btScalar _lastStepUp;
|
||||
|
||||
///keep track of the contact manifolds
|
||||
btManifoldArray m_manifoldArray;
|
||||
btManifoldArray _manifoldArray;
|
||||
|
||||
bool m_touchingContact;
|
||||
btVector3 m_floorNormal; // points from object to character
|
||||
bool _touchingContact;
|
||||
btVector3 _floorNormal; // points from object to character
|
||||
|
||||
bool m_enabled;
|
||||
bool m_wasOnGround;
|
||||
bool m_wasJumping;
|
||||
bool m_useWalkDirection;
|
||||
btScalar m_velocityTimeInterval;
|
||||
int m_upAxis;
|
||||
bool _enabled;
|
||||
bool _wasOnGround;
|
||||
bool _wasJumping;
|
||||
btScalar _velocityTimeInterval;
|
||||
uint32_t _pendingFlags;
|
||||
|
||||
static btVector3* getUpAxisDirections();
|
||||
bool m_interpolateUp;
|
||||
bool full_drop;
|
||||
bool bounce_fix;
|
||||
glm::vec3 _shapeLocalOffset;
|
||||
glm::vec3 _boxScale; // used to compute capsule shape
|
||||
|
||||
btDynamicsWorld* _dynamicsWorld = NULL;
|
||||
|
||||
btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal);
|
||||
btVector3 parallelComponent(const btVector3& direction, const btVector3& normal);
|
||||
|
@ -118,14 +117,6 @@ public:
|
|||
///btActionInterface interface
|
||||
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 is neither a direction nor a velocity, but the amount to
|
||||
/// increment the position each simulation iteration, regardless
|
||||
|
@ -141,18 +132,19 @@ public:
|
|||
virtual void setVelocityForTimeInterval(const btVector3& velocity,
|
||||
btScalar timeInterval);
|
||||
|
||||
void reset(btCollisionWorld* collisionWorld );
|
||||
void warp(const btVector3& origin);
|
||||
virtual void reset(btCollisionWorld* collisionWorld );
|
||||
virtual void warp(const btVector3& origin);
|
||||
|
||||
void preStep(btCollisionWorld* collisionWorld);
|
||||
void playerStep(btCollisionWorld* collisionWorld, btScalar dt);
|
||||
virtual void preStep(btCollisionWorld* collisionWorld);
|
||||
virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt);
|
||||
|
||||
virtual bool canJump() const;
|
||||
virtual void jump();
|
||||
virtual bool onGround() const;
|
||||
|
||||
void setMaxFallSpeed(btScalar speed);
|
||||
void setJumpSpeed(btScalar jumpSpeed);
|
||||
void setMaxJumpHeight(btScalar maxJumpHeight);
|
||||
bool canJump() const;
|
||||
|
||||
void jump();
|
||||
|
||||
void setGravity(btScalar gravity);
|
||||
btScalar getGravity() const;
|
||||
|
@ -164,11 +156,16 @@ public:
|
|||
|
||||
btPairCachingGhostObject* getGhostObject();
|
||||
|
||||
bool onGround() const;
|
||||
void setUpInterpolate(bool value);
|
||||
|
||||
bool needsShapeUpdate();
|
||||
void updateShape();
|
||||
bool needsRemoval() const;
|
||||
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 postSimulation();
|
||||
|
|
|
@ -280,12 +280,12 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) {
|
|||
void PhysicsEngine::stepSimulation() {
|
||||
lock();
|
||||
// NOTE: the grand order of operations is:
|
||||
// (1) relay incoming changes
|
||||
// (1) pull incoming changes
|
||||
// (2) step simulation
|
||||
// (3) synchronize outgoing motion states
|
||||
// (4) send outgoing packets
|
||||
|
||||
// This is step (1).
|
||||
// This is step (1) pull incoming changes
|
||||
relayIncomingChangesToSimulation();
|
||||
|
||||
const int MAX_NUM_SUBSTEPS = 4;
|
||||
|
@ -294,16 +294,25 @@ void PhysicsEngine::stepSimulation() {
|
|||
_clock.reset();
|
||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||
|
||||
// This is step (2).
|
||||
// TODO: move character->preSimulation() into relayIncomingChanges
|
||||
if (_characterController) {
|
||||
if (_characterController->needsRemoval()) {
|
||||
_characterController->setDynamicsWorld(NULL);
|
||||
}
|
||||
_characterController->updateShapeIfNecessary();
|
||||
if (_characterController->needsAddition()) {
|
||||
_characterController->setDynamicsWorld(_dynamicsWorld);
|
||||
}
|
||||
_characterController->preSimulation(timeStep);
|
||||
}
|
||||
|
||||
// This is step (2) step simulation
|
||||
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
_numSubsteps += (uint32_t)numSubsteps;
|
||||
stepNonPhysicalKinematics(usecTimestampNow());
|
||||
unlock();
|
||||
|
||||
// TODO: make all of this harvest stuff into one function: relayOutgoingChanges()
|
||||
if (numSubsteps > 0) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
void PhysicsEngine::setAvatarData(AvatarData *avatarData) {
|
||||
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
|
||||
void PhysicsEngine::setCharacterController(CharacterController* character) {
|
||||
if (!_characterController) {
|
||||
lock();
|
||||
_characterController = new CharacterController(avatarData);
|
||||
_dynamicsWorld->addCollisionObject(_characterController->getGhostObject(),
|
||||
btBroadphaseProxy::CharacterFilter,
|
||||
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
|
||||
_dynamicsWorld->addAction(_characterController);
|
||||
_characterController->reset(_dynamicsWorld);
|
||||
_characterController = character;
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
#include <QSet>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
||||
//#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
|
||||
|
||||
#include <AvatarData.h>
|
||||
#include <EntityItem.h>
|
||||
#include <EntitySimulation.h>
|
||||
|
||||
|
@ -86,7 +84,7 @@ public:
|
|||
/// process queue of changed from external sources
|
||||
void relayIncomingChangesToSimulation();
|
||||
|
||||
void setAvatarData(AvatarData *avatarData);
|
||||
void setCharacterController(CharacterController* character);
|
||||
|
||||
private:
|
||||
/// \param motionState pointer to Object's MotionState
|
||||
|
|
|
@ -207,7 +207,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
|
|||
notImplemented();
|
||||
}
|
||||
} 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();
|
||||
|
||||
if (accountManager.hasValidAccessToken()) {
|
||||
|
|
Loading…
Reference in a new issue