Merge branch 'master' of github.com:highfidelity/hifi into vhacd-knobs

This commit is contained in:
Seth Alves 2015-03-30 13:44:39 -07:00
commit 071b6a21de
84 changed files with 1760 additions and 1277 deletions

View file

@ -149,7 +149,8 @@ void AvatarMixer::broadcastAvatarData() {
// about a given otherNode to this node
// FIXME does this mean we should sort the othernodes by distance before iterating
// over them?
float outputBandwidth = node->getOutboundBandwidth();
// float outputBandwidth =
node->getOutboundBandwidth();
// this is an AGENT we have received head data from
// send back a packet with other active node data to this node
@ -169,7 +170,7 @@ void AvatarMixer::broadcastAvatarData() {
return true;
},
[&](const SharedNodePointer& otherNode) {
AvatarMixerClientData* otherNodeData = otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
AvatarMixerClientData* otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
MutexTryLocker lock(otherNodeData->getMutex());
if (!lock.isLocked()) {
return;

View file

@ -8,8 +8,8 @@ if (ANDROID)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150209oss_src.tgz
URL_MD5 f09c9abe8ec74e6558c1f89cebbe2893
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz
URL_MD5 bf090eaa86cf89ea014b7b462786a440
BUILD_COMMAND ${NDK_BUILD_COMMAND} --directory=jni target=android tbb tbbmalloc arch=arm
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND ""
@ -20,19 +20,20 @@ if (ANDROID)
)
else ()
if (APPLE)
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_osx.tgz)
set(DOWNLOAD_MD5 3e683c19792582b61382e0d760ea5db2)
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_osx.tgz)
set(DOWNLOAD_MD5 25a36ebff070ff801760ec658079f6aa)
elseif (WIN32)
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_win.zip)
set(DOWNLOAD_MD5 e19c184f2bb0e944fc5f397f1e34ca84)
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_win.zip)
set(DOWNLOAD_MD5 d250d40bb93b255f75bcbb19e976a440)
else ()
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_lin.tgz)
set(DOWNLOAD_MD5 d9c2a6f7807df364be44a8c3c05e8457)
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_lin.tgz)
set(DOWNLOAD_MD5 7830ba2bc62438325fba2ec0c95367a5)
endif ()
ExternalProject_Add(
${EXTERNAL_NAME}
URL ${DOWNLOAD_URL}
URL_MD5 ${DOWNLOAD_MD5}
BUILD_COMMAND ""
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
@ -94,9 +95,15 @@ elseif (UNIX)
endif ()
if (DEFINED _TBB_LIB_DIR)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb_debug.${_LIB_EXT} CACHE FILEPATH "TBB debug library location")
if (NOT APPLE)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb_debug.${_LIB_EXT} CACHE FILEPATH "TBB debug library location")
set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc_debug.${_LIB_EXT} CACHE FILEPATH "TBB malloc debug library location")
else ()
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "TBB debug library location")
set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_DEBUG "" CACHE FILEPATH "TBB malloc debug library location")
endif ()
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb.${_LIB_EXT} CACHE FILEPATH "TBB release library location")
set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc_debug.${_LIB_EXT} CACHE FILEPATH "TBB malloc debug library location")
set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_RELEASE ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc.${_LIB_EXT} CACHE FILEPATH "TBB malloc release library location")
endif ()

View file

@ -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"
}
]
},

View file

@ -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"
})
}
}
}

View file

@ -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

View file

@ -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";
@ -89,13 +88,7 @@ var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode";
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
var modelURLs = [
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx",
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx",
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush6.fbx",
HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed.fbx",
HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed2.fbx",
HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed4.fbx",
HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed7.fbx"
"Insert the URL to your FBX"
];
var mode = 0;
@ -130,7 +123,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 +331,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;
}
@ -384,9 +381,7 @@ var toolBar = (function () {
position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_LIGHT_DIMENSIONS), DEFAULT_LIGHT_DIMENSIONS),
dimensions: DEFAULT_LIGHT_DIMENSIONS,
isSpotlight: false,
diffuseColor: { red: 255, green: 255, blue: 255 },
ambientColor: { red: 255, green: 255, blue: 255 },
specularColor: { red: 0, green: 0, blue: 0 },
color: { red: 150, green: 150, blue: 150 },
constantAttenuation: 1,
linearAttenuation: 0,
@ -540,7 +535,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 +544,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 +555,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 +577,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 +623,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 +647,88 @@ 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);
if (properties.marketplaceID) {
propertyMenu.marketplaceID = properties.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 +773,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 +804,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 +825,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 +916,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 +929,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 +1149,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 +1228,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();

View file

@ -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();
}

View file

@ -9,15 +9,20 @@
this.preload = function(entityID) {
teleport = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/birarda/teleport.raw");
var properties = Entities.getEntityProperties(entityID);
portalDestination = properties.userData;
animationURL = properties.modelURL;
print("The portal destination is " + portalDestination);
}
this.enterEntity = function(entityID) {
var properties = Entities.getEntityProperties(entityID); // in case the userData/portalURL has changed
portalDestination = properties.userData;
print("enterEntity() .... The portal destination is " + portalDestination);
if (portalDestination.length > 0) {
print("Teleporting to hifi://" + portalDestination);
Window.location = "hifi://" + portalDestination;

View file

@ -140,7 +140,6 @@
var elLifetime = document.getElementById("property-lifetime");
var elScriptURL = document.getElementById("property-script-url");
var elUserData = document.getElementById("property-user-data");
var elAttribution = document.getElementById("property-attribution");
var elBoxSections = document.querySelectorAll(".box-section");
var elBoxColorRed = document.getElementById("property-box-red");
@ -264,7 +263,6 @@
elLifetime.value = properties.lifetime;
elScriptURL.value = properties.script;
elUserData.value = properties.userData;
elAttribution.value = properties.attribution;
if (properties.type != "Box") {
for (var i = 0; i < elBoxSections.length; i++) {
@ -395,7 +393,6 @@
elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime'));
elScriptURL.addEventListener('change', createEmitTextPropertyUpdateFunction('script'));
elUserData.addEventListener('change', createEmitTextPropertyUpdateFunction('userData'));
elAttribution.addEventListener('change', createEmitTextPropertyUpdateFunction('attribution'));
var boxColorChangeFunction = createEmitColorPropertyUpdateFunction(
'color', elBoxColorRed, elBoxColorGreen, elBoxColorBlue);
@ -630,13 +627,6 @@
</div>
</div>
<div class="property">
<div class="label">Attribution</div>
<div class="value">
<textarea id="property-attribution"></textarea>
</div>
</div>
<div class="box-section property">
<div class="label">Color</div>

View file

@ -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;

View file

@ -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;
}());
}());

View file

@ -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;

View file

@ -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) {

View file

@ -92,11 +92,13 @@ var NotificationType = {
SNAPSHOT: 2,
WINDOW_RESIZE: 3,
LOD_WARNING: 4,
CONNECTION_REFUSED: 5,
properties: [
{ text: "Mute Toggle" },
{ text: "Snapshot" },
{ text: "Window Resize" },
{ text: "Level of Detail" }
{ text: "Level of Detail" },
{ text: "Connection Refused" }
],
getTypeFromMenuItem: function(menuItemName) {
if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) {
@ -501,6 +503,10 @@ function onMuteStateChanged() {
createNotification(muteString, NotificationType.MUTE_TOGGLE);
}
function onDomainConnectionRefused(reason) {
createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED );
}
// handles mouse clicks on buttons
function mousePressEvent(event) {
var pickRay,
@ -608,5 +614,6 @@ Controller.keyReleaseEvent.connect(keyReleaseEvent);
Script.update.connect(update);
Script.scriptEnding.connect(scriptEnding);
Menu.menuItemEvent.connect(menuItemEvent);
Window.domainConnectionRefused.connect(onDomainConnectionRefused);
setup();

View file

@ -11,7 +11,7 @@
var usersWindow = (function () {
var WINDOW_WIDTH_2D = 150,
var WINDOW_WIDTH_2D = 160,
WINDOW_MARGIN_2D = 12,
WINDOW_FONT_2D = { size: 12 },
WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 },
@ -22,6 +22,17 @@ var usersWindow = (function () {
WINDOW_BACKGROUND_ALPHA_2D = 0.7,
windowPane2D,
windowHeading2D,
SCROLLBAR_BACKGROUND_WIDTH_2D = 12,
SCROLLBAR_BACKGROUND_COLOR_2D = { red: 80, green: 80, blue: 80 },
SCROLLBAR_BACKGROUND_ALPHA_2D = 0.8,
scrollbarBackground2D,
SCROLLBAR_BAR_MIN_HEIGHT = 5,
SCROLLBAR_BAR_COLOR_2D = { red: 180, green: 180, blue: 180 },
SCROLLBAR_BAR_ALPHA_2D = 0.8,
SCROLLBAR_BAR_SELECTED_ALPHA_2D = 0.9,
scrollbarBar2D,
scrollbarBackgroundHeight,
scrollbarBarHeight,
VISIBILITY_SPACER_2D = 12, // Space between list of users and visibility controls
visibilityHeading2D,
VISIBILITY_RADIO_SPACE = 16,
@ -33,8 +44,10 @@ var usersWindow = (function () {
usersOnline, // Raw users data
linesOfUsers = [], // Array of indexes pointing into usersOnline
numUsersToDisplay = 0,
firstUserToDisplay = 0,
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,
@ -54,6 +67,15 @@ var usersWindow = (function () {
isVisible = true,
viewportHeight,
isMirrorDisplay = false,
isFullscreenMirror = false,
isUsingScrollbars = false,
isMovingScrollbar = false,
scrollbarBackgroundPosition = {},
scrollbarBarPosition = {},
scrollbarBarClickedAt, // 0.0 .. 1.0
scrollbarValue = 0.0, // 0.0 .. 1.0
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/",
RADIO_BUTTON_SVG = HIFI_PUBLIC_BUCKET + "images/radio-button.svg",
@ -62,10 +84,32 @@ var usersWindow = (function () {
radioButtonDiameter;
function calculateWindowHeight() {
var AUDIO_METER_HEIGHT = 52,
MIRROR_HEIGHT = 220,
nonUsersHeight,
maxWindowHeight;
// Reserve 5 lines for window heading plus visibility heading and controls
// Subtract windowLineSpacing for both end of user list and end of controls
windowHeight = (linesOfUsers.length > 0 ? linesOfUsers.length + 5 : 5) * windowLineHeight
- 2 * windowLineSpacing + VISIBILITY_SPACER_2D + 2 * WINDOW_MARGIN_2D;
nonUsersHeight = 5 * windowLineHeight - 2 * windowLineSpacing + VISIBILITY_SPACER_2D + 2 * WINDOW_MARGIN_2D;
// Limit window to height of viewport minus VU meter and mirror if displayed
windowHeight = linesOfUsers.length * windowLineHeight + nonUsersHeight;
maxWindowHeight = viewportHeight - AUDIO_METER_HEIGHT;
if (isMirrorDisplay && !isFullscreenMirror) {
maxWindowHeight -= MIRROR_HEIGHT;
}
windowHeight = Math.max(Math.min(windowHeight, maxWindowHeight), nonUsersHeight);
// Corresponding number of users to actually display
numUsersToDisplay = Math.max(Math.round((windowHeight - nonUsersHeight) / windowLineHeight), 0);
isUsingScrollbars = 0 < numUsersToDisplay && numUsersToDisplay < linesOfUsers.length;
if (isUsingScrollbars) {
firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay));
} else {
firstUserToDisplay = 0;
scrollbarValue = 0.0;
}
}
function updateOverlayPositions() {
@ -78,6 +122,16 @@ var usersWindow = (function () {
Overlays.editOverlay(windowHeading2D, {
y: viewportHeight - windowHeight + WINDOW_MARGIN_2D
});
scrollbarBackgroundPosition.y = viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight;
Overlays.editOverlay(scrollbarBackground2D, {
y: scrollbarBackgroundPosition.y
});
scrollbarBarPosition.y = scrollbarBackgroundPosition.y + 1
+ scrollbarValue * (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
Overlays.editOverlay(scrollbarBar2D, {
y: scrollbarBarPosition.y
});
Overlays.editOverlay(visibilityHeading2D, {
y: viewportHeight - 4 * windowLineHeight + windowLineSpacing - WINDOW_MARGIN_2D
});
@ -104,57 +158,59 @@ var usersWindow = (function () {
function updateUsersDisplay() {
var displayText = "",
myUsername,
user,
userText,
textWidth,
maxTextWidth,
ellipsisWidth,
reducedTextWidth,
i;
myUsername = GlobalServices.username;
linesOfUsers = [];
for (i = 0; i < usersOnline.length; i += 1) {
user = usersOnline[i];
if (user.username !== myUsername && user.online) {
userText = user.username;
if (user.location.root) {
userText += " @ " + user.location.root.name;
}
textWidth = Overlays.textSize(windowPane2D, userText).width;
maxTextWidth = WINDOW_WIDTH_2D - (isUsingScrollbars ? SCROLLBAR_BACKGROUND_WIDTH_2D : 0) - 2 * WINDOW_MARGIN_2D;
ellipsisWidth = Overlays.textSize(windowPane2D, "...").width;
reducedTextWidth = maxTextWidth - ellipsisWidth;
maxTextWidth = WINDOW_WIDTH_2D - 2 * WINDOW_MARGIN_2D;
if (textWidth > maxTextWidth) {
// Trim and append "..." to fit window width
maxTextWidth = maxTextWidth - Overlays.textSize(windowPane2D, "...").width;
while (textWidth > maxTextWidth) {
userText = userText.slice(0, -1);
textWidth = Overlays.textSize(windowPane2D, userText).width;
}
userText += "...";
for (i = 0; i < numUsersToDisplay; i += 1) {
user = usersOnline[linesOfUsers[firstUserToDisplay + i]];
userText = user.text;
textWidth = user.textWidth;
if (textWidth > maxTextWidth) {
// Trim and append "..." to fit window width
maxTextWidth = maxTextWidth - Overlays.textSize(windowPane2D, "...").width;
while (textWidth > reducedTextWidth) {
userText = userText.slice(0, -1);
textWidth = Overlays.textSize(windowPane2D, userText).width;
}
usersOnline[i].textWidth = textWidth;
linesOfUsers.push(i);
displayText += "\n" + userText;
userText += "...";
}
displayText += "\n" + userText;
}
displayText = displayText.slice(1); // Remove leading "\n".
calculateWindowHeight();
Overlays.editOverlay(windowPane2D, {
y: viewportHeight - windowHeight,
height: windowHeight,
text: displayText
});
Overlays.editOverlay(windowHeading2D, {
y: viewportHeight - windowHeight + WINDOW_MARGIN_2D,
text: linesOfUsers.length > 0 ? "Users online" : "No users online"
});
scrollbarBackgroundHeight = numUsersToDisplay * windowLineHeight - windowLineSpacing / 2;
Overlays.editOverlay(scrollbarBackground2D, {
height: scrollbarBackgroundHeight,
visible: isUsingScrollbars
});
scrollbarBarHeight = Math.max(numUsersToDisplay / linesOfUsers.length * scrollbarBackgroundHeight,
SCROLLBAR_BAR_MIN_HEIGHT);
Overlays.editOverlay(scrollbarBar2D, {
height: scrollbarBarHeight,
visible: isUsingScrollbars
});
updateOverlayPositions();
}
@ -168,7 +224,11 @@ var usersWindow = (function () {
}
processUsers = function () {
var response;
var response,
myUsername,
user,
userText,
i;
if (usersRequest.readyState === usersRequest.DONE) {
if (usersRequest.status === 200) {
@ -185,7 +245,26 @@ var usersWindow = (function () {
}
usersOnline = response.data.users;
myUsername = GlobalServices.username;
linesOfUsers = [];
for (i = 0; i < usersOnline.length; i += 1) {
user = usersOnline[i];
if (user.username !== myUsername && user.online) {
userText = user.username;
if (user.location.root) {
userText += " @ " + user.location.root.name;
}
usersOnline[i].text = userText;
usersOnline[i].textWidth = Overlays.textSize(windowPane2D, userText).width;
linesOfUsers.push(i);
}
}
calculateWindowHeight();
updateUsersDisplay();
} else {
print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText);
usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
@ -226,6 +305,8 @@ var usersWindow = (function () {
Overlays.editOverlay(windowPane2D, { visible: isVisible });
Overlays.editOverlay(windowHeading2D, { visible: isVisible });
Overlays.editOverlay(scrollbarBackground2D, { visible: isVisible && isUsingScrollbars });
Overlays.editOverlay(scrollbarBar2D, { visible: isVisible && isUsingScrollbars });
Overlays.editOverlay(visibilityHeading2D, { visible: isVisible });
for (i = 0; i < visibilityControls2D.length; i += 1) {
Overlays.editOverlay(visibilityControls2D[i].radioOverlay, { visible: isVisible });
@ -247,8 +328,10 @@ var usersWindow = (function () {
minY,
maxY,
lineClicked,
userClicked,
i,
visibilityChanged;
visibilityChanged,
delta;
if (!isVisible) {
return;
@ -261,7 +344,7 @@ var usersWindow = (function () {
overlayX = event.x - WINDOW_MARGIN_2D;
overlayY = event.y - viewportHeight + windowHeight - WINDOW_MARGIN_2D - windowLineHeight;
numLinesBefore = Math.floor(overlayY / windowLineHeight);
numLinesBefore = Math.round(overlayY / windowLineHeight);
minY = numLinesBefore * windowLineHeight;
maxY = minY + windowTextHeight;
@ -270,10 +353,12 @@ var usersWindow = (function () {
lineClicked = numLinesBefore;
}
if (0 <= lineClicked && lineClicked < linesOfUsers.length
&& 0 <= overlayX && overlayX <= usersOnline[linesOfUsers[lineClicked]].textWidth) {
//print("Go to " + usersOnline[linesOfUsers[lineClicked]].username);
location.goToUser(usersOnline[linesOfUsers[lineClicked]].username);
userClicked = firstUserToDisplay + lineClicked;
if (0 <= userClicked && userClicked < linesOfUsers.length
&& 0 <= overlayX && overlayX <= usersOnline[linesOfUsers[userClicked]].textWidth) {
//print("Go to " + usersOnline[linesOfUsers[userClicked]].username);
location.goToUser(usersOnline[linesOfUsers[userClicked]].username);
}
}
@ -292,13 +377,74 @@ var usersWindow = (function () {
}
updateVisibilityControls();
}
if (clickedOverlay === scrollbarBar2D) {
scrollbarBarClickedAt = (event.y - scrollbarBarPosition.y) / scrollbarBarHeight;
Overlays.editOverlay(scrollbarBar2D, {
backgroundAlpha: SCROLLBAR_BAR_SELECTED_ALPHA_2D
});
isMovingScrollbar = true;
}
if (clickedOverlay === scrollbarBackground2D) {
delta = scrollbarBarHeight / (scrollbarBackgroundHeight - scrollbarBarHeight);
if (event.y < scrollbarBarPosition.y) {
scrollbarValue = Math.max(scrollbarValue - delta, 0.0);
} else {
scrollbarValue = Math.min(scrollbarValue + delta, 1.0);
}
firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay));
updateOverlayPositions();
updateUsersDisplay();
}
}
function onMouseMoveEvent(event) {
if (isMovingScrollbar) {
if (scrollbarBackgroundPosition.x - WINDOW_MARGIN_2D <= event.x
&& event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH_2D + WINDOW_MARGIN_2D
&& scrollbarBackgroundPosition.y - WINDOW_MARGIN_2D <= event.y
&& event.y <= scrollbarBackgroundPosition.y + scrollbarBackgroundHeight + WINDOW_MARGIN_2D) {
scrollbarValue = (event.y - scrollbarBarClickedAt * scrollbarBarHeight - scrollbarBackgroundPosition.y)
/ (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
scrollbarValue = Math.min(Math.max(scrollbarValue, 0.0), 1.0);
firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay));
updateOverlayPositions();
updateUsersDisplay();
} else {
Overlays.editOverlay(scrollbarBar2D, {
backgroundAlpha: SCROLLBAR_BAR_ALPHA_2D
});
isMovingScrollbar = false;
}
}
}
function onMouseReleaseEvent() {
Overlays.editOverlay(scrollbarBar2D, {
backgroundAlpha: SCROLLBAR_BAR_ALPHA_2D
});
isMovingScrollbar = false;
}
function onScriptUpdate() {
var oldViewportHeight = viewportHeight;
var oldViewportHeight = viewportHeight,
oldIsMirrorDisplay = isMirrorDisplay,
oldIsFullscreenMirror = isFullscreenMirror,
MIRROR_MENU_ITEM = "Mirror",
FULLSCREEN_MIRROR_MENU_ITEM = "Fullscreen Mirror";
viewportHeight = Controller.getViewportDimensions().y;
if (viewportHeight !== oldViewportHeight) {
isMirrorDisplay = Menu.isOptionChecked(MIRROR_MENU_ITEM);
isFullscreenMirror = Menu.isOptionChecked(FULLSCREEN_MIRROR_MENU_ITEM);
if (viewportHeight !== oldViewportHeight
|| isMirrorDisplay !== oldIsMirrorDisplay
|| isFullscreenMirror !== oldIsFullscreenMirror) {
calculateWindowHeight();
updateUsersDisplay();
updateOverlayPositions();
}
}
@ -314,10 +460,10 @@ var usersWindow = (function () {
radioButtonDiameter = RADIO_BUTTON_DISPLAY_SCALE * windowTextHeight;
Overlays.deleteOverlay(textSizeOverlay);
calculateWindowHeight();
viewportHeight = Controller.getViewportDimensions().y;
calculateWindowHeight();
windowPane2D = Overlays.addOverlay("text", {
x: 0,
y: viewportHeight, // Start up off-screen
@ -349,6 +495,36 @@ var usersWindow = (function () {
visible: isVisible
});
scrollbarBackgroundPosition = {
x: WINDOW_WIDTH_2D - 0.5 * WINDOW_MARGIN_2D - SCROLLBAR_BACKGROUND_WIDTH_2D,
y: viewportHeight
};
scrollbarBackground2D = Overlays.addOverlay("text", {
x: scrollbarBackgroundPosition.x,
y: scrollbarBackgroundPosition.y,
width: SCROLLBAR_BACKGROUND_WIDTH_2D,
height: windowTextHeight,
backgroundColor: SCROLLBAR_BACKGROUND_COLOR_2D,
backgroundAlpha: SCROLLBAR_BACKGROUND_ALPHA_2D,
text: "",
visible: isVisible && isUsingScrollbars
});
scrollbarBarPosition = {
x: WINDOW_WIDTH_2D - 0.5 * WINDOW_MARGIN_2D - SCROLLBAR_BACKGROUND_WIDTH_2D + 1,
y: viewportHeight
};
scrollbarBar2D = Overlays.addOverlay("text", {
x: scrollbarBarPosition.x,
y: scrollbarBarPosition.y,
width: SCROLLBAR_BACKGROUND_WIDTH_2D - 2,
height: windowTextHeight,
backgroundColor: SCROLLBAR_BAR_COLOR_2D,
backgroundAlpha: SCROLLBAR_BAR_ALPHA_2D,
text: "",
visible: isVisible && isUsingScrollbars
});
visibilityHeading2D = Overlays.addOverlay("text", {
x: WINDOW_MARGIN_2D,
y: viewportHeight,
@ -390,7 +566,7 @@ var usersWindow = (function () {
textOverlay: Overlays.addOverlay("text", {
x: WINDOW_MARGIN_2D,
y: viewportHeight,
width: WINDOW_WIDTH_2D - 2 * WINDOW_MARGIN_2D,
width: WINDOW_WIDTH_2D - SCROLLBAR_BACKGROUND_WIDTH_2D - 2 * WINDOW_MARGIN_2D,
height: windowTextHeight,
topMargin: 0,
leftMargin: VISIBILITY_RADIO_SPACE,
@ -429,6 +605,8 @@ var usersWindow = (function () {
updateVisibilityControls();
Controller.mousePressEvent.connect(onMousePressEvent);
Controller.mouseMoveEvent.connect(onMouseMoveEvent);
Controller.mouseReleaseEvent.connect(onMouseReleaseEvent);
Menu.addMenuItem({
menuName: MENU_NAME,
@ -456,6 +634,8 @@ var usersWindow = (function () {
Script.clearTimeout(usersTimer);
Overlays.deleteOverlay(windowPane2D);
Overlays.deleteOverlay(windowHeading2D);
Overlays.deleteOverlay(scrollbarBackground2D);
Overlays.deleteOverlay(scrollbarBar2D);
Overlays.deleteOverlay(visibilityHeading2D);
for (i = 0; i <= visibilityControls2D.length; i += 1) {
Overlays.deleteOverlay(visibilityControls2D[i].textOverlay);

View file

@ -138,7 +138,7 @@
<h3>Import models</h3>
<img class="grid-img" src="img/models.png" alt"Import models"></img>
<p>
Use the editEntitles.js script to<br>
Use the <strong>edit.js</strong> script to<br>
add FBX models in-world. You<br>
can use grids and fine tune<br>
placement-related parameters<br>

View file

@ -297,7 +297,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_lastSendDownstreamAudioStats(usecTimestampNow()),
_isVSyncOn(true),
_aboutToQuit(false),
_notifiedPacketVersionMismatchThisDomain(false)
_notifiedPacketVersionMismatchThisDomain(false),
_domainConnectionRefusals(QList<QString>())
{
#ifdef Q_OS_WIN
installNativeEventFilter(&MyNativeEventFilter::getInstance());
@ -344,6 +345,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// put the NodeList and datagram processing on the node thread
nodeList->moveToThread(nodeThread);
// geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
// downloads.
QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>();
ResourceCache *geometryCache = geometryCacheP.data();
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams);
@ -789,7 +797,7 @@ void Application::paintGL() {
DependencyManager::get<GlowEffect>()->render();
if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
{
PerformanceTimer perfTimer("renderOverlay");
_applicationOverlay.renderOverlay(true);
_applicationOverlay.displayOverlayTexture();
@ -987,12 +995,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
resetSensors();
break;
case Qt::Key_G:
if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::ObeyEnvironmentalGravity);
}
break;
case Qt::Key_A:
if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::Atmosphere);
@ -1127,13 +1129,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror);
}
break;
case Qt::Key_Slash:
Menu::getInstance()->triggerOption(MenuOption::UserInterface);
break;
case Qt::Key_P:
Menu::getInstance()->triggerOption(MenuOption::FirstPerson);
break;
case Qt::Key_Percent:
case Qt::Key_Slash:
Menu::getInstance()->triggerOption(MenuOption::Stats);
break;
case Qt::Key_Plus:
@ -1168,10 +1167,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
break;
}
case Qt::Key_Comma: {
_myAvatar->togglePhysicsEnabled();
}
default:
event->ignore();
break;
@ -1569,6 +1564,9 @@ void Application::idle() {
idleTimer->start(2);
}
}
// check for any requested background downloads.
emit checkBackgroundDownloads();
}
void Application::setFullscreen(bool fullscreen) {
@ -1755,7 +1753,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();
@ -1909,8 +1907,6 @@ void Application::init() {
_physicsEngine.init(&_entityEditSender);
_physicsEngine.setAvatarData(_myAvatar);
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
@ -3020,8 +3016,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
_nodeBoundsDisplay.draw();
// Render the world box
if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
PerformanceTimer perfTimer("worldBox");
renderWorldBox();
}
@ -3141,7 +3136,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
bool eyeRelativeCamera = false;
// bool eyeRelativeCamera = false;
if (billboard) {
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees
_mirrorCamera.setPosition(_myAvatar->getPosition() +
@ -3294,6 +3289,14 @@ void Application::clearDomainOctreeDetails() {
void Application::domainChanged(const QString& domainHostname) {
updateWindowTitle();
clearDomainOctreeDetails();
_domainConnectionRefusals.clear();
}
void Application::domainConnectionDenied(const QString& reason) {
if (!_domainConnectionRefusals.contains(reason)) {
_domainConnectionRefusals.append(reason);
emit domainConnectionRefused(reason);
}
}
void Application::connectedToDomain(const QString& hostname) {
@ -3600,6 +3603,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;
}
@ -4208,7 +4212,7 @@ void Application::checkSkeleton() {
_myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL);
_myAvatar->sendIdentityPacket();
} else {
_myAvatar->updateLocalAABox();
_physicsEngine.setAvatarData(_myAvatar);
_myAvatar->updateCharacterController();
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
}
}

View file

@ -95,6 +95,7 @@ static const float NODE_KILLED_BLUE = 0.0f;
static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString SVO_EXTENSION = ".svo";
static const QString SVO_JSON_EXTENSION = ".svo.json";
static const QString JS_EXTENSION = ".js";
static const QString FST_EXTENSION = ".fst";
@ -332,6 +333,9 @@ signals:
void svoImportRequested(const QString& url);
void checkBackgroundDownloads();
void domainConnectionRefused(const QString& reason);
public slots:
void domainChanged(const QString& domainHostname);
void updateWindowTitle();
@ -382,6 +386,8 @@ public slots:
void setActiveFaceTracker();
void domainConnectionDenied(const QString& reason);
private slots:
void clearDomainOctreeDetails();
void checkFPS();
@ -606,6 +612,8 @@ private:
int _menuBarHeight;
QHash<QString, AcceptURLMethod> _acceptedExtensions;
QList<QString> _domainConnectionRefusals;
};
#endif // hifi_Application_h

View file

@ -127,6 +127,7 @@ void DatagramProcessor::processDatagrams() {
// and check and signal for an access token so that we can make sure they are logged in
qDebug() << "The domain-server denied a connection request: " << reason;
qDebug() << "You may need to re-log to generate a keypair so you can provide a username signature.";
application->domainConnectionDenied(reason);
AccountManager::getInstance().checkAndSignalForAccessToken();
break;
}

View file

@ -30,8 +30,9 @@ DiscoverabilityManager::DiscoverabilityManager() :
const QString API_USER_LOCATION_PATH = "/api/v1/user/location";
void DiscoverabilityManager::updateLocation() {
AccountManager& accountManager = AccountManager::getInstance();
if (_mode.get() != Discoverability::None) {
AccountManager& accountManager = AccountManager::getInstance();
auto addressManager = DependencyManager::get<AddressManager>();
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
@ -61,17 +62,25 @@ 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());
}
} else {
// we still send a heartbeat to the metaverse server for stats collection
const QString API_USER_HEARTBEAT_PATH = "/api/v1/user/heartbeat";
accountManager.sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Required, QNetworkAccessManager::PutOperation);
}
}
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) {

View file

@ -40,26 +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;
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) {
@ -67,40 +96,66 @@ 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()) {
// Octee items... stepwise adjustment
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
} else {
_octreeSizeScale *= ADJUST_LOD_UP_BY;
// Octee items... stepwise adjustment
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
} else {
_octreeSizeScale *= ADJUST_LOD_UP_BY;
}
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
}
changed = true;
}
}
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
}
octreeChanged = changed = true;
}
if (changed) {
_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();
}
}
}
@ -116,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() {

View file

@ -19,10 +19,22 @@
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0;
const float DEFAULT_HMD_LOD_DOWN_FPS = 60.0;
const float INCREASE_LOD_GAP = 5.0f;
const float MAX_LIKELY_DESKTOP_FPS = 59.0; // this is essentially, V-synch - 1 fps
const float MAX_LIKELY_HMD_FPS = 74.0; // this is essentially, V-synch - 1 fps
const float INCREASE_LOD_GAP = 15.0f;
const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 0.5; // Consider adjusting LOD down after half a second
const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2;
const float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts
const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f;
const float UP_SHIFT_WINDOW_IN_SECS = 2.5f;
const int ASSUMED_FPS = 60;
const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS;
const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second
const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS;
const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS;
const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS;
const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS;
const float ADJUST_LOD_DOWN_BY = 0.9f;
const float ADJUST_LOD_UP_BY = 1.1f;
@ -37,9 +49,6 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
// do. But both are still culled using the same angular size logic.
const float AVATAR_TO_ENTITY_RATIO = 2.0f;
const int ONE_SECOND_OF_FRAMES = 60;
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
class LODManager : public QObject, public Dependency {
Q_OBJECT
@ -51,11 +60,11 @@ public:
Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; }
Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; }
Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODDecreaseFPS + INCREASE_LOD_GAP; }
Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return glm::min(_desktopLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS); }
Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; }
Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; }
Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODDecreaseFPS + INCREASE_LOD_GAP; }
Q_INVOKABLE float getHMDLODIncreaseFPS() const { return glm::min(_hmdLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS); }
Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
@ -67,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();
@ -79,6 +84,7 @@ public:
void loadSettings();
void saveSettings();
void resetLODAdjust();
signals:
void LODIncreased();
@ -96,9 +102,14 @@ private:
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
int _boundaryLevelAdjust = 0;
quint64 _lastAdjust = 0;
SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES;
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES;
quint64 _lastDownShift = 0;
quint64 _lastUpShift = 0;
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;

View file

@ -201,9 +201,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true);
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true);
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true);
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false,
avatar, SLOT(updateMotionBehavior()));
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::StandOnNearbyFloors, 0, true,
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true,
avatar, SLOT(updateMotionBehavior()));
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false,
avatar, SLOT(updateMotionBehavior()));
@ -230,7 +228,6 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
qApp, SLOT(cameraMenuChanged()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H,
false,
@ -259,14 +256,13 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
addDisabledActionAndSeparator(viewMenu, "Stats");
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Percent);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog()));
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0,
dialogsManager.data(), SLOT(bandwidthDetails()));
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0,
dialogsManager.data(), SLOT(octreeStatsDetails()));
addActionToQMenuAndActionHash(viewMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp()));
QMenu* developerMenu = addMenu("Developer");
@ -538,10 +534,12 @@ Menu::Menu() {
statsRenderer.data(),
SLOT(toggleShowInjectedStreams()));
#ifndef Q_OS_MAC
QMenu* helpMenu = addMenu("Help");
QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp);
connect(helpAction, SIGNAL(triggered()), qApp, SLOT(aboutApp()));
addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp()));
#ifndef Q_OS_MAC
QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp);
connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp()));
#endif
}

View file

@ -153,6 +153,7 @@ namespace MenuOption {
const QString EchoServerAudio = "Echo Server Audio";
const QString EditEntitiesHelp = "Edit Entities Help...";
const QString Enable3DTVMode = "Enable 3DTV Mode";
const QString EnableCharacterController = "Enable avatar collisions";
const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)";
const QString EnableVRMode = "Enable VR Mode";
const QString Entities = "Entities";
@ -184,12 +185,9 @@ namespace MenuOption {
const QString Mirror = "Mirror";
const QString MuteAudio = "Mute Microphone";
const QString MuteEnvironment = "Mute Environment";
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
const QString NoFaceTracking = "None";
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
const QString OctreeStats = "Voxel and Entity Statistics";
const QString OctreeStats = "Entity Statistics";
const QString OffAxisProjection = "Off-Axis Projection";
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
const QString OnlyDisplayTopTen = "Only Display Top Ten";
const QString Pair = "Pair";
const QString PipelineWarnings = "Log Render Pipeline Warnings";
@ -233,13 +231,11 @@ namespace MenuOption {
const QString ScriptEditor = "Script Editor...";
const QString ScriptedMotorControl = "Enable Scripted Motor Control";
const QString ShowBordersEntityNodes = "Show Entity Nodes";
const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
const QString ShowIKConstraints = "Show IK Constraints";
const QString SimpleShadows = "Simple";
const QString SixenseEnabled = "Enable Hydra Support";
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
const QString SixenseLasers = "Enable Sixense UI Lasers";
const QString StandOnNearbyFloors = "Stand on nearby floors";
const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations";
const QString Stars = "Stars";
const QString Stats = "Stats";
@ -251,7 +247,6 @@ namespace MenuOption {
const QString TransmitterDrive = "Transmitter Drive";
const QString TurnWithHead = "Turn using Head";
const QString PackageModel = "Package Model";
const QString UserInterface = "User Interface";
const QString Visage = "Visage";
const QString Wireframe = "Wireframe";
}

View file

@ -14,6 +14,8 @@
#include <QMessageBox>
#include <QTemporaryDir>
#include <FSTReader.h>
#include "ModelSelector.h"
#include "ModelPropertiesDialog.h"

View file

@ -15,8 +15,6 @@
#include <QFileInfo>
#include <QVariantHash>
#include <FBXReader.h>
#include "ui/ModelsBrowser.h"
class ModelPackager : public QObject {

View file

@ -19,6 +19,7 @@
#include <QMessageBox>
#include <QPushButton>
#include <FSTReader.h>
#include <GLMHelpers.h>
#include "ModelPropertiesDialog.h"

View file

@ -23,19 +23,6 @@ class QComboBox;
class QCheckBox;
class QVBoxLayout;
static const QString NAME_FIELD = "name";
static const QString FILENAME_FIELD = "filename";
static const QString TEXDIR_FIELD = "texdir";
static const QString LOD_FIELD = "lod";
static const QString JOINT_INDEX_FIELD = "jointIndex";
static const QString SCALE_FIELD = "scale";
static const QString TRANSLATION_X_FIELD = "tx";
static const QString TRANSLATION_Y_FIELD = "ty";
static const QString TRANSLATION_Z_FIELD = "tz";
static const QString JOINT_FIELD = "joint";
static const QString FREE_JOINT_FIELD = "freeJoint";
static const QString BLENDSHAPE_FIELD = "bs";
/// A dialog that allows customization of various model properties.
class ModelPropertiesDialog : public QDialog {
Q_OBJECT

View file

@ -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,7 @@ MyAvatar::MyAvatar() :
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
_characterController(this),
_lookAtTargetAvatar(),
_shouldRender(true),
_billboardValid(false),
@ -100,6 +100,7 @@ MyAvatar::MyAvatar() :
// connect to AddressManager signal for location jumps
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
this, &MyAvatar::goToLocation);
_characterController.setEnabled(true);
}
MyAvatar::~MyAvatar() {
@ -146,10 +147,6 @@ void MyAvatar::update(float deltaTime) {
head->setAudioLoudness(audio->getLastInputLoudness());
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) {
setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition()));
}
simulate(deltaTime);
if (_feetTouchFloor) {
_skeletonModel.updateStandingFoot();
@ -173,11 +170,7 @@ void MyAvatar::simulate(float deltaTime) {
{
PerformanceTimer perfTimer("transform");
updateOrientation(deltaTime);
if (isPhysicsEnabled()) {
updatePositionWithPhysics(deltaTime);
} else {
updatePosition(deltaTime);
}
updatePosition(deltaTime);
}
{
@ -483,26 +476,6 @@ void MyAvatar::loadLastRecording() {
_player->loadRecording(_recorder->getRecording());
}
void MyAvatar::setLocalGravity(glm::vec3 gravity) {
_motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY;
// Environmental and Local gravities are incompatible. Since Local is being set here
// the environmental setting must be removed.
_motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
setGravity(gravity);
}
void MyAvatar::setGravity(const glm::vec3& gravity) {
_gravity = gravity;
// use the gravity to determine the new world up direction, if possible
float gravityLength = glm::length(gravity);
if (gravityLength > EPSILON) {
_worldUpDirection = _gravity / -gravityLength;
}
// NOTE: the else case here it to leave _worldUpDirection unchanged
// so it continues to point opposite to the previous gravity setting.
}
AnimationHandlePointer MyAvatar::addAnimationHandle() {
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
_animationHandles.append(handle);
@ -954,15 +927,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 {
@ -1257,128 +1230,38 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe
return localVelocity + motorEfficiency * deltaVelocity;
}
const float NEARBY_FLOOR_THRESHOLD = 5.0f;
void MyAvatar::updatePosition(float deltaTime) {
// check for floor by casting a ray straight down from avatar's position
float heightAboveFloor = FLT_MAX;
bool hasFloor = false;
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
const float maxFloorDistance = boundingShape.getBoundingRadius() * NEARBY_FLOOR_THRESHOLD;
RayIntersectionInfo intersection;
// NOTE: avatar is center of PhysicsSimulation, so rayStart is the origin for the purposes of the raycast
intersection._rayStart = glm::vec3(0.0f);
intersection._rayDirection = - _worldUpDirection;
intersection._rayLength = 4.0f * boundingShape.getBoundingRadius();
// velocity is initialized to the measured _velocity but will be modified by friction, external thrust, etc
glm::vec3 velocity = _velocity;
bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f;
if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) {
const float MAX_SPEED_UNDER_GRAVITY = 2.0f * _scale * MAX_WALKING_SPEED;
if (pushingUp || glm::length2(velocity) > MAX_SPEED_UNDER_GRAVITY * MAX_SPEED_UNDER_GRAVITY) {
// we're pushing up or moving quickly, so disable gravity
setLocalGravity(glm::vec3(0.0f));
hasFloor = false;
} else {
if (heightAboveFloor > maxFloorDistance) {
// disable local gravity when floor is too far away
setLocalGravity(glm::vec3(0.0f));
hasFloor = false;
} else {
// enable gravity
setLocalGravity(-_worldUpDirection);
}
}
}
bool zeroDownwardVelocity = false;
bool gravityEnabled = (glm::length2(_gravity) > EPSILON);
if (gravityEnabled) {
const float SLOP = 0.002f;
if (heightAboveFloor < SLOP) {
if (heightAboveFloor < 0.0) {
// Gravity is in effect so we assume that the avatar is colliding against the world and we need
// to lift avatar out of floor, but we don't want to do it too fast (keep it smooth).
float distanceToLift = glm::min(-heightAboveFloor, MAX_WALKING_SPEED * deltaTime);
// We don't use applyPositionDelta() for this lift distance because we don't want the avatar
// to come flying out of the floor. Instead we update position directly, and set a boolean
// that will remind us later to zero any downward component of the velocity.
_position += distanceToLift * _worldUpDirection;
}
zeroDownwardVelocity = true;
}
if (!zeroDownwardVelocity) {
velocity += (deltaTime * GRAVITY_EARTH) * _gravity;
}
}
// rotate velocity into camera frame
glm::quat rotation = getHead()->getCameraOrientation();
glm::vec3 localVelocity = glm::inverse(rotation) * velocity;
// apply motors in camera frame
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
// rotate back into world-frame
velocity = rotation * newLocalVelocity;
// apply thrust
velocity += _thrust * deltaTime;
_thrust = glm::vec3(0.0f);
// remove downward velocity so we don't push into floor
if (zeroDownwardVelocity) {
float verticalSpeed = glm::dot(velocity, _worldUpDirection);
if (verticalSpeed < 0.0f || !pushingUp) {
velocity -= verticalSpeed * _worldUpDirection;
}
}
// cap avatar speed
float speed = glm::length(velocity);
if (speed > MAX_AVATAR_SPEED) {
velocity *= MAX_AVATAR_SPEED / speed;
speed = MAX_AVATAR_SPEED;
}
// update position
if (speed > MIN_AVATAR_SPEED) {
applyPositionDelta(deltaTime * velocity);
}
// update _moving flag based on speed
const float MOVING_SPEED_THRESHOLD = 0.01f;
_moving = speed > MOVING_SPEED_THRESHOLD;
measureMotionDerivatives(deltaTime);
}
void MyAvatar::updatePositionWithPhysics(float deltaTime) {
// rotate velocity into camera frame
glm::quat rotation = getHead()->getCameraOrientation();
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
bool hasFloor = false;
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
bool isOnGround = _characterController.onGround();
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isOnGround);
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
// cap avatar speed
float speed = glm::length(newLocalVelocity);
if (speed > MAX_WALKING_SPEED) {
newLocalVelocity *= MAX_WALKING_SPEED / speed;
}
// rotate back into world-frame
_velocity = rotation * newLocalVelocity;
_velocity += _thrust * deltaTime;
_thrust = glm::vec3(0.0f);
// cap avatar speed
float speed = glm::length(_velocity);
if (speed > MAX_AVATAR_SPEED) {
_velocity *= MAX_AVATAR_SPEED / speed;
speed = MAX_AVATAR_SPEED;
}
if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
// update position ourselves
applyPositionDelta(deltaTime * _velocity);
measureMotionDerivatives(deltaTime);
} // else physics will move avatar later
// update _moving flag based on speed
const float MOVING_SPEED_THRESHOLD = 0.01f;
_moving = speed > MOVING_SPEED_THRESHOLD;
}
void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
@ -1495,23 +1378,6 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition,
void MyAvatar::updateMotionBehavior() {
Menu* menu = Menu::getInstance();
if (menu->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) {
_motionBehaviors |= AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
// Environmental and Local gravities are incompatible. Environmental setting trumps local.
_motionBehaviors &= ~AVATAR_MOTION_OBEY_LOCAL_GRAVITY;
} else {
_motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
}
if (! (_motionBehaviors & (AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | AVATAR_MOTION_OBEY_LOCAL_GRAVITY))) {
setGravity(glm::vec3(0.0f));
}
if (menu->isOptionChecked(MenuOption::StandOnNearbyFloors)) {
_motionBehaviors |= AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
// standing on floors requires collision with voxels
// TODO: determine what to do with this now that voxels are gone
} else {
_motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
}
if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) {
_motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
} else {
@ -1522,6 +1388,7 @@ void MyAvatar::updateMotionBehavior() {
} else {
_motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
}
_characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
_feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations);
}

View file

@ -13,6 +13,7 @@
#define hifi_MyAvatar_h
#include <SettingHandle.h>
#include <CharacterController.h>
#include "Avatar.h"
@ -24,7 +25,7 @@ class MyAvatar : public Avatar {
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame)
Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setLocalGravity)
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
public:
MyAvatar();
@ -43,13 +44,11 @@ public:
// setters
void setLeanScale(float scale) { _leanScale = scale; }
void setLocalGravity(glm::vec3 gravity);
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); }
// getters
float getLeanScale() const { return _leanScale; }
glm::vec3 getGravity() const { return _gravity; }
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
bool getShouldRenderLocally() const { return _shouldRender; }
float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); }
@ -88,7 +87,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 +121,8 @@ public:
virtual glm::vec3 getSkeletonPosition() const;
void updateLocalAABox();
CharacterController* getCharacterController() { return &_characterController; }
void updateCharacterController();
void clearJointAnimationPriorities();
@ -186,7 +187,6 @@ private:
float _turningKeyPressTime;
glm::vec3 _gravity;
bool _shouldJump;
float _driveKeys[MAX_DRIVE_KEYS];
bool _wasPushing;
bool _isPushing;
@ -202,6 +202,8 @@ private:
int _scriptedMotorFrame;
quint32 _motionBehaviors;
CharacterController _characterController;
QWeakPointer<AvatarData> _lookAtTargetAvatar;
glm::vec3 _targetAvatarPosition;
bool _shouldRender;
@ -224,10 +226,8 @@ private:
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor);
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
void updatePosition(float deltaTime);
void updatePositionWithPhysics(float deltaTime);
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
void maybeUpdateBillboard();
void setGravity(const glm::vec3& gravity);
};
#endif // hifi_MyAvatar_h

View file

@ -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);
}

View file

@ -104,7 +104,6 @@ void TV3DManager::display(Camera& whichCamera) {
// We only need to render the overlays to a texture once, then we just render the texture as a quad
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
applicationOverlay.renderOverlay(true);
const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::UserInterface);
DependencyManager::get<GlowEffect>()->prepare();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -135,9 +134,7 @@ void TV3DManager::display(Camera& whichCamera) {
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
if (displayOverlays) {
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
}
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
_activeEye = NULL;
}
glPopMatrix();
@ -166,9 +163,7 @@ void TV3DManager::display(Camera& whichCamera) {
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
if (displayOverlays) {
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
}
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
_activeEye = NULL;
}
glPopMatrix();

View file

@ -353,7 +353,7 @@ void InputController::update() {
// TODO for now the InputController is only supporting a JointTracker from a MotionTracker
MotionTracker* motionTracker = dynamic_cast< MotionTracker*> (DeviceTracker::getDevice(_deviceTrackerId));
if (motionTracker) {
if (_subTrackerId < motionTracker->numJointTrackers()) {
if ((int)_subTrackerId < motionTracker->numJointTrackers()) {
const MotionTracker::JointTracker* joint = motionTracker->getJointTracker(_subTrackerId);
if (joint->isActive()) {

View file

@ -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();

View file

@ -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();

View file

@ -33,6 +33,7 @@ WindowScriptingInterface::WindowScriptingInterface() :
const DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
connect(&domainHandler, &DomainHandler::hostnameChanged, this, &WindowScriptingInterface::domainChanged);
connect(Application::getInstance(), &Application::svoImportRequested, this, &WindowScriptingInterface::svoImportRequested);
connect(Application::getInstance(), &Application::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused);
}
WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height, bool isToolWindow) {

View file

@ -62,6 +62,7 @@ signals:
void inlineButtonClicked(const QString& name);
void nonBlockingFormClosed();
void svoImportRequested(const QString& url);
void domainConnectionRefused(const QString& reason);
private slots:
QScriptValue showAlert(const QString& message);

View file

@ -139,6 +139,7 @@ ApplicationOverlay::ApplicationOverlay() :
_magnifier(true),
_alpha(1.0f),
_oculusUIRadius(1.0f),
_trailingAudioLoudness(0.0f),
_crosshairTexture(0),
_previousBorderWidth(-1),
_previousBorderHeight(-1),
@ -176,18 +177,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
_textureAspectRatio = (float)glCanvas->getDeviceWidth() / (float)glCanvas->getDeviceHeight();
//Handle fading and deactivation/activation of UI
if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
_alpha += FADE_SPEED;
if (_alpha > 1.0f) {
_alpha = 1.0f;
}
} else {
_alpha -= FADE_SPEED;
if (_alpha <= 0.0f) {
_alpha = 0.0f;
}
}
// Render 2D overlay
glMatrixMode(GL_PROJECTION);
glDisable(GL_DEPTH_TEST);

View file

@ -114,7 +114,7 @@ private:
quint64 _lastMouseMove;
bool _magnifier;
float _alpha;
float _alpha = 1.0f;
float _oculusUIRadius;
float _trailingAudioLoudness;

View file

@ -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),

View file

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

View file

@ -88,9 +88,9 @@ template< typename T >
void AudioFrameBuffer< T >::deallocateFrames() {
if (_frameBuffer) {
for (uint32_t i = 0; i < _channelCountMax; ++i) {
delete _frameBuffer[i];
delete[] _frameBuffer[i];
}
delete _frameBuffer;
delete[] _frameBuffer;
}
_frameBuffer = NULL;
}

View file

@ -88,7 +88,7 @@ public:
}
void loadProfile(int profileIndex) {
if (profileIndex >= 0 && profileIndex < _profileCount) {
if (profileIndex >= 0 && profileIndex < (int)_profileCount) {
for (uint32_t i = 0; i < _filterCount; ++i) {
FilterParameter p = _profiles[profileIndex][i];

View file

@ -61,21 +61,13 @@ typedef unsigned long long quint64;
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
const quint32 AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY = 1U << 2;
const quint32 AVATAR_MOTION_OBEY_LOCAL_GRAVITY = 1U << 3;
const quint32 AVATAR_MOTION_STAND_ON_NEARBY_FLOORS = 1U << 4;
const quint32 AVATAR_MOTION_DEFAULTS =
AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED |
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED |
AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
// these bits will be expanded as features are exposed
const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED |
AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY |
AVATAR_MOTION_OBEY_LOCAL_GRAVITY |
AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
// Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of
@ -300,16 +292,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; }
@ -375,8 +357,8 @@ protected:
HeadData* _headData;
HandData* _handData;
QUrl _faceModelURL = DEFAULT_HEAD_MODEL_URL;
QUrl _skeletonModelURL = DEFAULT_BODY_MODEL_URL;
QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit
QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit
QVector<AttachmentData> _attachmentData;
QString _displayName;
@ -409,9 +391,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*)

View file

@ -277,7 +277,6 @@ void EntityTreeRenderer::update() {
void EntityTreeRenderer::checkEnterLeaveEntities() {
if (_tree && !_shuttingDown) {
_tree->lockForWrite(); // so that our scripts can do edits if they want
glm::vec3 avatarPosition = _viewState->getAvatarPosition();
if (avatarPosition != _lastAvatarPosition) {
@ -286,6 +285,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
QVector<EntityItemID> entitiesContainingAvatar;
// find the entities near us
_tree->lockForRead(); // don't let someone else change our tree while we search
static_cast<EntityTree*>(_tree)->findEntities(avatarPosition, radius, foundEntities);
// create a list of entities that actually contain the avatar's position
@ -294,6 +294,11 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
entitiesContainingAvatar << entity->getEntityItemID();
}
}
_tree->unlock();
// Note: at this point we don't need to worry about the tree being locked, because we only deal with
// EntityItemIDs from here. The loadEntityScript() method is robust against attempting to load scripts
// for entity IDs that no longer exist.
// for all of our previous containing entities, if they are no longer containing then send them a leave event
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
@ -322,14 +327,12 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
_currentEntitiesInside = entitiesContainingAvatar;
_lastAvatarPosition = avatarPosition;
}
_tree->unlock();
}
}
void EntityTreeRenderer::leaveAllEntities() {
if (_tree && !_shuttingDown) {
_tree->lockForWrite(); // so that our scripts can do edits if they want
// for all of our previous containing entities, if they are no longer containing then send them a leave event
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
emit leaveEntity(entityID);
@ -344,7 +347,6 @@ void EntityTreeRenderer::leaveAllEntities() {
// make sure our "last avatar position" is something other than our current position, so that on our
// first chance, we'll check for enter/leave entity events.
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
_tree->unlock();
}
}
void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) {

View file

@ -366,6 +366,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
// multiply each point by scale before handing the point-set off to the physics engine
for (int i = 0; i < _points.size(); i++) {
for (int j = 0; j < _points[i].size(); j++) {
// compensate for registraion
_points[i][j] += _model->getOffset();
// scale so the collision points match the model points
_points[i][j] *= scale;
}
}

View file

@ -57,7 +57,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE;
_locked = ENTITY_ITEM_DEFAULT_LOCKED;
_userData = ENTITY_ITEM_DEFAULT_USER_DATA;
_attribution = ENTITY_ITEM_DEFAULT_ATTRIBUTION;
_marketplaceID = ENTITY_ITEM_DEFAULT_MARKETPLACE_ID;
}
EntityItem::EntityItem(const EntityItemID& entityItemID) {
@ -117,7 +117,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_COLLISIONS_WILL_MOVE;
requestedProperties += PROP_LOCKED;
requestedProperties += PROP_USER_DATA;
requestedProperties += PROP_ATTRIBUTION;
requestedProperties += PROP_MARKETPLACE_ID;
return requestedProperties;
}
@ -240,7 +240,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove());
APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData());
APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, getAttribution());
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, getMarketplaceID());
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties,
@ -555,8 +555,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked);
READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA, setUserData);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_ATTRIBUTION) {
READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
READ_ENTITY_PROPERTY_STRING(PROP_MARKETPLACE_ID, setMarketplaceID);
}
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
@ -568,8 +568,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// by doing this parsing here... but it's not likely going to fully recover the content.
//
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_ATTRIBUTION_DAMAGED) {
READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution);
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
READ_ENTITY_PROPERTY_STRING(PROP_MARKETPLACE_ID, setMarketplaceID);
}
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) {
@ -838,7 +838,7 @@ EntityItemProperties EntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(attribution, getAttribution);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID);
properties._defaultSettings = false;
@ -867,7 +867,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(attribution, setAttribution);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(marketplaceID, setMarketplaceID);
if (somethingChanged) {
somethingChangedNotification(); // notify derived classes that something has changed

View file

@ -251,8 +251,8 @@ public:
const QString& getUserData() const { return _userData; }
void setUserData(const QString& value) { _userData = value; }
const QString& getAttribution() const { return _attribution; }
void setAttribution(const QString& value) { _attribution = value; }
const QString& getMarketplaceID() const { return _marketplaceID; }
void setMarketplaceID(const QString& value) { _marketplaceID = value; }
// TODO: get rid of users of getRadius()...
float getRadius() const;
@ -342,7 +342,7 @@ protected:
bool _collisionsWillMove;
bool _locked;
QString _userData;
QString _attribution;
QString _marketplaceID;
// NOTE: Damping is applied like this: v *= pow(1 - damping, dt)
//

View file

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

View file

@ -70,7 +70,7 @@ EntityItemProperties::EntityItemProperties() :
CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH),
CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY),
CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS),
CONSTRUCT_PROPERTY(attribution, ENTITY_ITEM_DEFAULT_ATTRIBUTION),
CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
@ -260,7 +260,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_EMIT_STRENGTH, emitStrength);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity);
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius);
CHECK_PROPERTY_CHANGE(PROP_ATTRIBUTION, attribution);
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
return changedProperties;
}
@ -323,7 +323,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
COPY_PROPERTY_TO_QSCRIPTVALUE(emitStrength);
COPY_PROPERTY_TO_QSCRIPTVALUE(localGravity);
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
COPY_PROPERTY_TO_QSCRIPTVALUE(attribution);
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
// Sitting properties support
QScriptValue sittingPoints = engine->newObject();
@ -405,7 +405,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitStrength, setEmitStrength);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localGravity, setLocalGravity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(attribution, setAttribution);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(marketplaceID, setMarketplaceID);
_lastEdited = usecTimestampNow();
}
@ -591,7 +591,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius());
}
APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, properties.getAttribution());
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID());
}
if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset();
@ -822,7 +822,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius);
}
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ATTRIBUTION, setAttribution);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID);
return valid;
}
@ -905,7 +905,7 @@ void EntityItemProperties::markAllChanged() {
_localGravityChanged = true;
_particleRadiusChanged = true;
_attributionChanged = true;
_marketplaceIDChanged = true;
}
/// The maximum bounding cube for the entity, independent of it's rotation.

View file

@ -94,11 +94,11 @@ enum EntityPropertyList {
PROP_PARTICLE_RADIUS,
PROP_COLLISION_MODEL_URL,
PROP_ATTRIBUTION,
PROP_MARKETPLACE_ID,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties ABOVE this line and then modify PROP_LAST_ITEM below
PROP_LAST_ITEM = PROP_ATTRIBUTION,
PROP_LAST_ITEM = PROP_MARKETPLACE_ID,
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -205,7 +205,7 @@ public:
DEFINE_PROPERTY(PROP_EMIT_STRENGTH, EmitStrength, emitStrength, float);
DEFINE_PROPERTY(PROP_LOCAL_GRAVITY, LocalGravity, localGravity, float);
DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float);
DEFINE_PROPERTY_REF(PROP_ATTRIBUTION, Attribution, attribution, QString);
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
public:
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); }
@ -333,7 +333,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitStrength, emitStrength, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalGravity, localGravity, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Attribution, attribution, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
debug << " last edited:" << properties.getLastEdited() << "\n";
debug << " edited ago:" << properties.getEditedAgo() << "\n";

View file

@ -22,7 +22,7 @@ const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f);
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
const QString ENTITY_ITEM_DEFAULT_ATTRIBUTION = QString("");
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;

View file

@ -148,6 +148,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
}
}
} else {
QString entityScriptBefore = entity->getScript();
uint32_t preFlags = entity->getDirtyFlags();
UpdateEntityOperator theOperator(this, containingElement, entity, properties);
recurseTreeWithOperator(&theOperator);
@ -166,6 +167,11 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
entity->clearDirtyFlags();
}
}
QString entityScriptAfter = entity->getScript();
if (entityScriptBefore != entityScriptAfter) {
emitEntityScriptChanging(entity->getEntityItemID()); // the entity script has changed
}
}
// TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG).

View file

@ -458,41 +458,6 @@ FBXNode parseFBX(QIODevice* device) {
return top;
}
QVariantHash parseMapping(QIODevice* device) {
QVariantHash properties;
QByteArray line;
while (!(line = device->readLine()).isEmpty()) {
if ((line = line.trimmed()).startsWith('#')) {
continue; // comment
}
QList<QByteArray> sections = line.split('=');
if (sections.size() < 2) {
continue;
}
QByteArray name = sections.at(0).trimmed();
if (sections.size() == 2) {
properties.insertMulti(name, sections.at(1).trimmed());
} else if (sections.size() == 3) {
QVariantHash heading = properties.value(name).toHash();
heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed());
properties.insert(name, heading);
} else if (sections.size() >= 4) {
QVariantHash heading = properties.value(name).toHash();
QVariantList contents;
for (int i = 2; i < sections.size(); i++) {
contents.append(sections.at(i).trimmed());
}
heading.insertMulti(sections.at(1).trimmed(), contents);
properties.insert(name, heading);
}
}
return properties;
}
QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {
QVector<glm::vec3> values;
for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) {
@ -2473,39 +2438,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
return geometry;
}
QVariantHash readMapping(const QByteArray& data) {
QBuffer buffer(const_cast<QByteArray*>(&data));
buffer.open(QIODevice::ReadOnly);
return parseMapping(&buffer);
}
QByteArray writeMapping(const QVariantHash& mapping) {
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
for (QVariantHash::const_iterator first = mapping.constBegin(); first != mapping.constEnd(); first++) {
QByteArray key = first.key().toUtf8() + " = ";
QVariantHash hashValue = first.value().toHash();
if (hashValue.isEmpty()) {
buffer.write(key + first.value().toByteArray() + "\n");
continue;
}
for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) {
QByteArray extendedKey = key + second.key().toUtf8();
QVariantList listValue = second.value().toList();
if (listValue.isEmpty()) {
buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n");
continue;
}
buffer.write(extendedKey);
for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) {
buffer.write(" = " + third->toByteArray());
}
buffer.write("\n");
}
}
return buffer.data();
}
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
QBuffer buffer(const_cast<QByteArray*>(&model));
buffer.open(QIODevice::ReadOnly);

View file

@ -261,12 +261,6 @@ public:
Q_DECLARE_METATYPE(FBXGeometry)
/// Reads an FST mapping from the supplied data.
QVariantHash readMapping(const QByteArray& data);
/// Writes an FST mapping to a byte array.
QByteArray writeMapping(const QVariantHash& mapping);
/// Reads FBX geometry from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f);

View file

@ -0,0 +1,99 @@
//
// FSTReader.cpp
//
//
// Created by Clement on 3/26/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QBuffer>
#include "FSTReader.h"
QVariantHash parseMapping(QIODevice* device) {
QVariantHash properties;
QByteArray line;
while (!(line = device->readLine()).isEmpty()) {
if ((line = line.trimmed()).startsWith('#')) {
continue; // comment
}
QList<QByteArray> sections = line.split('=');
if (sections.size() < 2) {
continue;
}
QByteArray name = sections.at(0).trimmed();
if (sections.size() == 2) {
properties.insertMulti(name, sections.at(1).trimmed());
} else if (sections.size() == 3) {
QVariantHash heading = properties.value(name).toHash();
heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed());
properties.insert(name, heading);
} else if (sections.size() >= 4) {
QVariantHash heading = properties.value(name).toHash();
QVariantList contents;
for (int i = 2; i < sections.size(); i++) {
contents.append(sections.at(i).trimmed());
}
heading.insertMulti(sections.at(1).trimmed(), contents);
properties.insert(name, heading);
}
}
return properties;
}
QVariantHash readMapping(const QByteArray& data) {
QBuffer buffer(const_cast<QByteArray*>(&data));
buffer.open(QIODevice::ReadOnly);
return parseMapping(&buffer);
}
void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) {
QByteArray key = it.key().toUtf8() + " = ";
QVariantHash hashValue = it.value().toHash();
if (hashValue.isEmpty()) {
buffer.write(key + it.value().toByteArray() + "\n");
return;
}
for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) {
QByteArray extendedKey = key + second.key().toUtf8();
QVariantList listValue = second.value().toList();
if (listValue.isEmpty()) {
buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n");
continue;
}
buffer.write(extendedKey);
for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) {
buffer.write(" = " + third->toByteArray());
}
buffer.write("\n");
}
}
QByteArray writeMapping(const QVariantHash& mapping) {
static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD
<< TEXDIR_FIELD << JOINT_FIELD << FREE_JOINT_FIELD
<< BLENDSHAPE_FIELD << JOINT_INDEX_FIELD;
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
for (auto key : PREFERED_ORDER) {
auto it = mapping.find(key);
if (it != mapping.constEnd()) {
writeVariant(buffer, it);
}
}
for (auto it = mapping.constBegin(); it != mapping.constEnd(); it++) {
if (!PREFERED_ORDER.contains(it.key())) {
writeVariant(buffer, it);
}
}
return buffer.data();
}

View file

@ -0,0 +1,36 @@
//
// FSTReader.h
//
//
// Created by Clement on 3/26/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_FSTReader_h
#define hifi_FSTReader_h
#include <QVariantHash>
static const QString NAME_FIELD = "name";
static const QString FILENAME_FIELD = "filename";
static const QString TEXDIR_FIELD = "texdir";
static const QString LOD_FIELD = "lod";
static const QString JOINT_INDEX_FIELD = "jointIndex";
static const QString SCALE_FIELD = "scale";
static const QString TRANSLATION_X_FIELD = "tx";
static const QString TRANSLATION_Y_FIELD = "ty";
static const QString TRANSLATION_Z_FIELD = "tz";
static const QString JOINT_FIELD = "joint";
static const QString FREE_JOINT_FIELD = "freeJoint";
static const QString BLENDSHAPE_FIELD = "bs";
/// Reads an FST mapping from the supplied data.
QVariantHash readMapping(const QByteArray& data);
/// Writes an FST mapping to a byte array.
QByteArray writeMapping(const QVariantHash& mapping);
#endif // hifi_FSTReader_h

View file

@ -249,7 +249,20 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
} else if (indices.count() == 4) {
meshPart.quadIndices << indices;
} else {
qDebug() << "no support for more than 4 vertices on a face in OBJ files";
// some obj writers (maya) will write a face with lots of points.
for (int i = 1; i < indices.count() - 1; i++) {
// break the face into triangles
meshPart.triangleIndices.append(indices[0]);
meshPart.triangleIndices.append(indices[i]);
meshPart.triangleIndices.append(indices[i+1]);
}
if (indices.count() == normalIndices.count()) {
for (int i = 1; i < normalIndices.count() - 1; i++) {
faceNormalIndexes.append(normalIndices[0]);
faceNormalIndexes.append(normalIndices[i]);
faceNormalIndexes.append(normalIndices[i+1]);
}
}
}
} else {
// something we don't (yet) care about

View file

@ -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

View file

@ -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;
}
}
}
@ -298,7 +282,7 @@ void AccountManager::processReply() {
} else {
passErrorToCallback(requestReply);
}
delete requestReply;
requestReply->deleteLater();
}
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
@ -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();

View file

@ -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;

View file

@ -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() {

View file

@ -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)();

View file

@ -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),

View file

@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) {
return 1;
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData:
return VERSION_ENTITIES_HAS_ATTRIBUTION;
return VERSION_ENTITIES_HAS_MARKETPLACE_ID;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:

View file

@ -132,8 +132,8 @@ const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES =
const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10;
const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11;
const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12;
const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION_DAMAGED = 13;
const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION = 14;
const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13;
const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14;
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
#endif // hifi_PacketHeaders_h

View file

@ -18,6 +18,7 @@
#include <QTimer>
#include <SharedUtil.h>
#include <assert.h>
#include "NetworkAccessManager.h"
#include "ResourceCache.h"
@ -48,32 +49,40 @@ void ResourceCache::refresh(const QUrl& url) {
}
}
void ResourceCache::getResourceAsynchronously(const QUrl& url) {
qDebug() << "ResourceCache::getResourceAsynchronously" << url.toString();
_resourcesToBeGottenLock.lockForWrite();
_resourcesToBeGotten.enqueue(QUrl(url));
_resourcesToBeGottenLock.unlock();
}
void ResourceCache::checkAsynchronousGets() {
assert(QThread::currentThread() == thread());
if (!_resourcesToBeGotten.isEmpty()) {
_resourcesToBeGottenLock.lockForWrite();
QUrl url = _resourcesToBeGotten.dequeue();
_resourcesToBeGottenLock.unlock();
getResource(url);
}
}
QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback,
bool delayLoad, void* extra, bool block) {
bool delayLoad, void* extra) {
QSharedPointer<Resource> resource = _resources.value(url);
if (!resource.isNull()) {
return resource;
}
if (QThread::currentThread() != thread()) {
// This will re-call this method in the main thread. If block is true and the main thread
// is waiting on a lock, we'll deadlock here.
if (block) {
QSharedPointer<Resource> result;
QMetaObject::invokeMethod(this, "getResource", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QSharedPointer<Resource>, result), Q_ARG(const QUrl&, url),
Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra));
return result;
} else {
// Queue the re-invocation of this method, but if the main thread is blocked, don't wait. The
// return value may be NULL -- it's expected that this will be called again later, in order
// to receive the actual Resource.
QMetaObject::invokeMethod(this, "getResource", Qt::QueuedConnection,
Q_ARG(const QUrl&, url),
Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra));
return _resources.value(url);
}
assert(delayLoad);
getResourceAsynchronously(url);
return QSharedPointer<Resource>();
}
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
return getResource(fallback, QUrl(), delayLoad);
}
QSharedPointer<Resource> resource = _resources.value(url);
if (resource.isNull()) {
resource = createResource(url, fallback.isValid() ?
getResource(fallback, QUrl(), true) : QSharedPointer<Resource>(), delayLoad, extra);

View file

@ -21,6 +21,8 @@
#include <QSharedPointer>
#include <QUrl>
#include <QWeakPointer>
#include <QReadWriteLock>
#include <QQueue>
#include <DependencyManager.h>
@ -79,6 +81,9 @@ public:
void refresh(const QUrl& url);
public slots:
void checkAsynchronousGets();
protected:
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
qint64 _unusedResourcesSize = 0;
@ -89,7 +94,7 @@ protected:
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
/// \param extra extra data to pass to the creator, if appropriate
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
bool delayLoad = false, void* extra = NULL, bool block = true);
bool delayLoad = false, void* extra = NULL);
/// Creates a new resource.
virtual QSharedPointer<Resource> createResource(const QUrl& url,
@ -109,6 +114,11 @@ private:
int _lastLRUKey = 0;
static int _requestLimit;
void getResourceAsynchronously(const QUrl& url);
QReadWriteLock _resourcesToBeGottenLock;
QQueue<QUrl> _resourcesToBeGotten;
};
/// Base class for resources.

View file

@ -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

View file

@ -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,65 +38,69 @@ 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 _stepUpHeight; // height of stepUp prior to stepForward
btScalar _stepDownHeight; // height of stepDown
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;
glm::vec3 _lastPosition;
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 _isOnGround;
bool _isJumping;
bool _isHovering;
quint64 _jumpToHoverStart;
btScalar _velocityTimeInterval;
btScalar _stepDt;
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);
btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal);
bool recoverFromPenetration(btCollisionWorld* collisionWorld);
void scanDown(btCollisionWorld* collisionWorld);
void stepUp(btCollisionWorld* collisionWorld);
void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0));
void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove);
@ -118,14 +123,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 +138,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 +162,17 @@ public:
btPairCachingGhostObject* getGhostObject();
bool onGround() const;
void setUpInterpolate(bool value);
bool needsShapeUpdate();
void updateShape();
bool needsRemoval() const;
bool needsAddition() const;
void setEnabled(bool enabled);
bool isEnabled() const { return _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();

View file

@ -29,6 +29,12 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset)
PhysicsEngine::~PhysicsEngine() {
// TODO: delete engine components... if we ever plan to create more than one instance
delete _collisionConfig;
delete _collisionDispatcher;
delete _broadphaseFilter;
delete _constraintSolver;
delete _dynamicsWorld;
// delete _ghostPairCallback;
}
// begin EntitySimulation overrides
@ -280,12 +286,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 +300,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 +613,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();
}
}

View file

@ -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

View file

@ -136,28 +136,32 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
}
break;
case SHAPE_TYPE_CONVEX_HULL: {
shape = new btConvexHullShape();
auto hull = new btConvexHullShape();
const QVector<QVector<glm::vec3>>& points = info.getPoints();
foreach (glm::vec3 point, points[0]) {
btVector3 btPoint(point[0], point[1], point[2]);
static_cast<btConvexHullShape*>(shape)->addPoint(btPoint);
hull->addPoint(btPoint, false);
}
hull->recalcLocalAabb();
shape = hull;
}
break;
case SHAPE_TYPE_COMPOUND: {
shape = new btCompoundShape();
auto compound = new btCompoundShape();
const QVector<QVector<glm::vec3>>& points = info.getPoints();
foreach (QVector<glm::vec3> hullPoints, info.getPoints()) {
btTransform trans;
trans.setIdentity();
foreach (QVector<glm::vec3> hullPoints, points) {
auto hull = new btConvexHullShape();
foreach (glm::vec3 point, hullPoints) {
btVector3 btPoint(point[0], point[1], point[2]);
hull->addPoint(btPoint);
hull->addPoint(btPoint, false);
}
btTransform trans;
trans.setIdentity();
static_cast<btCompoundShape*>(shape)->addChildShape (trans, hull);
hull->recalcLocalAabb();
compound->addChildShape (trans, hull);
}
shape = compound;
}
break;
}

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QDebug>
#include <glm/gtx/norm.hpp>
#include "ShapeInfoUtil.h"
@ -35,6 +37,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
// qDebug() << "ShapeManager::getShape -- not making shape due to size" << diagonal;
return NULL;
}
DoubleHashKey key = info.getHash();

View file

@ -134,7 +134,7 @@ void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radi
void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color,
float intensity, const glm::quat& orientation, float exponent, float cutoff) {
int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size();
unsigned int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size();
if (lightID >= _allocatedLights.size()) {
_allocatedLights.push_back(model::LightPointer(new model::Light()));
}

View file

@ -21,6 +21,7 @@
#include <gpu/Batch.h>
#include <gpu/GLBackend.h>
#include <FSTReader.h>
#include <SharedUtil.h>
#include "TextureCache.h"
@ -1770,8 +1771,8 @@ void GeometryCache::renderLine(const glm::vec2& p1, const glm::vec2& p2,
}
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad, bool block) {
return getResource(url, fallback, delayLoad, NULL, block).staticCast<NetworkGeometry>();
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {
return getResource(url, fallback, delayLoad, NULL).staticCast<NetworkGeometry>();
}
QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,

View file

@ -203,8 +203,7 @@ public:
/// Loads geometry from the specified URL.
/// \param fallback a fallback URL to load if the desired one is unavailable
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(),
bool delayLoad = false, bool block = true);
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
protected:

View file

@ -325,6 +325,8 @@ void Model::init() {
_skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel));
makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings);
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
(void) makeResult; // quiet compiler
}
}
@ -1032,12 +1034,22 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
}
}
void Model::setCollisionModelURL(const QUrl& url, const QUrl& fallback, bool delayLoad) {
const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad)
{
if (_collisionGeometry.isNull() && !_collisionUrl.isEmpty()) {
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_collisionUrl, QUrl(), delayLoad);
}
return _collisionGeometry;
}
void Model::setCollisionModelURL(const QUrl& url) {
if (_collisionUrl == url) {
return;
}
_collisionUrl = url;
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, QUrl(), true);
}
bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {

View file

@ -109,7 +109,7 @@ public:
const QUrl& getURL() const { return _url; }
// Set the model to use for collisions
Q_INVOKABLE void setCollisionModelURL(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
Q_INVOKABLE void setCollisionModelURL(const QUrl& url);
const QUrl& getCollisionURL() const { return _collisionUrl; }
/// Sets the distance parameter used for LOD computations.
@ -134,7 +134,7 @@ public:
const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; }
/// Returns a reference to the shared collision geometry.
const QSharedPointer<NetworkGeometry> getCollisionGeometry() {return _collisionGeometry; }
const QSharedPointer<NetworkGeometry> getCollisionGeometry(bool delayLoad = true);
/// Returns the number of joint states in the model.
int getJointStateCount() const { return _jointStates.size(); }

View file

@ -360,10 +360,6 @@ void ScriptEngine::init() {
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS)));
globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY)));
globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY)));
}
QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {

View file

@ -22,6 +22,8 @@
#include "XMLHttpRequestClass.h"
#include "ScriptEngine.h"
const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/";
Q_DECLARE_METATYPE(QByteArray*)
XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
@ -207,7 +209,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(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.hasValidAccessToken()) {

View file

@ -14,6 +14,7 @@
SimpleMovingAverage::SimpleMovingAverage(int numSamplesToAverage) :
_numSamples(0),
_lastEventTimestamp(0),
_average(0.0f),
_eventDeltaAverage(0.0f),
WEIGHTING(1.0f / numSamplesToAverage),

View file

@ -2,13 +2,13 @@
rm -f TAGS
find . -name *.h -print | while read I
find . -name *.h -print | grep -v build-ext |while read I
do
etags --append "$I"
done
find . -name *.cpp -print | grep -v 'moc_' | while read I
find . -name *.cpp -print | grep -v 'moc_' | grep -v build-ext | while read I
do
etags --append "$I"
done