mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into temp1
This commit is contained in:
commit
cb0b185f07
11 changed files with 480 additions and 214 deletions
17
cmake/externals/tbb/CMakeLists.txt
vendored
17
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -8,8 +8,8 @@ if (ANDROID)
|
||||||
|
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150209oss_src.tgz
|
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz
|
||||||
URL_MD5 f09c9abe8ec74e6558c1f89cebbe2893
|
URL_MD5 bf090eaa86cf89ea014b7b462786a440
|
||||||
BUILD_COMMAND ${NDK_BUILD_COMMAND} --directory=jni target=android tbb tbbmalloc arch=arm
|
BUILD_COMMAND ${NDK_BUILD_COMMAND} --directory=jni target=android tbb tbbmalloc arch=arm
|
||||||
BUILD_IN_SOURCE 1
|
BUILD_IN_SOURCE 1
|
||||||
CONFIGURE_COMMAND ""
|
CONFIGURE_COMMAND ""
|
||||||
|
@ -20,19 +20,20 @@ if (ANDROID)
|
||||||
)
|
)
|
||||||
else ()
|
else ()
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_osx.tgz)
|
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_osx.tgz)
|
||||||
set(DOWNLOAD_MD5 3e683c19792582b61382e0d760ea5db2)
|
set(DOWNLOAD_MD5 25a36ebff070ff801760ec658079f6aa)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_win.zip)
|
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_win.zip)
|
||||||
set(DOWNLOAD_MD5 e19c184f2bb0e944fc5f397f1e34ca84)
|
set(DOWNLOAD_MD5 d250d40bb93b255f75bcbb19e976a440)
|
||||||
else ()
|
else ()
|
||||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_lin.tgz)
|
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_lin.tgz)
|
||||||
set(DOWNLOAD_MD5 d9c2a6f7807df364be44a8c3c05e8457)
|
set(DOWNLOAD_MD5 7830ba2bc62438325fba2ec0c95367a5)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL ${DOWNLOAD_URL}
|
URL ${DOWNLOAD_URL}
|
||||||
|
URL_MD5 ${DOWNLOAD_MD5}
|
||||||
BUILD_COMMAND ""
|
BUILD_COMMAND ""
|
||||||
CONFIGURE_COMMAND ""
|
CONFIGURE_COMMAND ""
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
|
331
examples/edit.js
331
examples/edit.js
|
@ -76,7 +76,6 @@ var DEFAULT_DIMENSIONS = {
|
||||||
|
|
||||||
var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
|
var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
|
||||||
|
|
||||||
var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool";
|
|
||||||
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
|
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
|
||||||
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
|
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
|
||||||
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
|
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
|
||||||
|
@ -544,7 +543,7 @@ function mousePressEvent(event) {
|
||||||
mouseHasMovedSincePress = false;
|
mouseHasMovedSincePress = false;
|
||||||
mouseCapturedByTool = false;
|
mouseCapturedByTool = false;
|
||||||
|
|
||||||
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
|
if (propertyMenu.mousePressEvent(event) || toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
|
||||||
mouseCapturedByTool = true;
|
mouseCapturedByTool = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -553,18 +552,6 @@ function mousePressEvent(event) {
|
||||||
// Event handled; do nothing.
|
// Event handled; do nothing.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (Menu.isOptionChecked(MENU_INSPECT_TOOL_ENABLED)) {
|
|
||||||
var result = findClickedEntity(event);
|
|
||||||
if (event.isRightButton) {
|
|
||||||
if (result !== null) {
|
|
||||||
var currentProperties = Entities.getEntityProperties(result.entityID);
|
|
||||||
cameraManager.enable();
|
|
||||||
cameraManager.focus(currentProperties.position, null, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
|
||||||
cameraManager.mousePressEvent(event);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cameraManager.mousePressEvent(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,6 +563,8 @@ var IDLE_MOUSE_TIMEOUT = 200;
|
||||||
var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0;
|
var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0;
|
||||||
|
|
||||||
function mouseMoveEvent(event) {
|
function mouseMoveEvent(event) {
|
||||||
|
mouseHasMovedSincePress = true;
|
||||||
|
|
||||||
if (placingEntityID) {
|
if (placingEntityID) {
|
||||||
if (!placingEntityID.isKnownID) {
|
if (!placingEntityID.isKnownID) {
|
||||||
placingEntityID = Entities.identifyEntity(placingEntityID);
|
placingEntityID = Entities.identifyEntity(placingEntityID);
|
||||||
|
@ -596,10 +585,8 @@ function mouseMoveEvent(event) {
|
||||||
Script.clearTimeout(idleMouseTimerId);
|
Script.clearTimeout(idleMouseTimerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseHasMovedSincePress = true;
|
|
||||||
|
|
||||||
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
|
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
|
||||||
if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
if (selectionDisplay.mouseMoveEvent(event) || propertyMenu.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,7 +631,7 @@ function highlightEntityUnderCursor(position, accurateRay) {
|
||||||
|
|
||||||
|
|
||||||
function mouseReleaseEvent(event) {
|
function mouseReleaseEvent(event) {
|
||||||
if (toolBar.mouseReleaseEvent(event)) {
|
if (propertyMenu.mouseReleaseEvent(event) || toolBar.mouseReleaseEvent(event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (placingEntityID) {
|
if (placingEntityID) {
|
||||||
|
@ -668,74 +655,93 @@ function mouseReleaseEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function mouseClickEvent(event) {
|
function mouseClickEvent(event) {
|
||||||
if (!event.isLeftButton || !isActive) {
|
if (isActive && event.isLeftButton) {
|
||||||
return;
|
var result = findClickedEntity(event);
|
||||||
}
|
if (result === null) {
|
||||||
|
|
||||||
var result = findClickedEntity(event);
|
|
||||||
if (result === null) {
|
|
||||||
if (!event.isShifted) {
|
|
||||||
selectionManager.clearSelections();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toolBar.setActive(true);
|
|
||||||
var pickRay = result.pickRay;
|
|
||||||
var foundEntity = result.entityID;
|
|
||||||
|
|
||||||
var properties = Entities.getEntityProperties(foundEntity);
|
|
||||||
if (isLocked(properties)) {
|
|
||||||
print("Model locked " + properties.id);
|
|
||||||
} else {
|
|
||||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
|
||||||
|
|
||||||
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
|
|
||||||
// P P - Model
|
|
||||||
// /| A - Palm
|
|
||||||
// / | d B - unit vector toward tip
|
|
||||||
// / | X - base of the perpendicular line
|
|
||||||
// A---X----->B d - distance fom axis
|
|
||||||
// x x - distance from A
|
|
||||||
//
|
|
||||||
// |X-A| = (P-A).B
|
|
||||||
// X == A + ((P-A).B)B
|
|
||||||
// d = |P-X|
|
|
||||||
|
|
||||||
var A = pickRay.origin;
|
|
||||||
var B = Vec3.normalize(pickRay.direction);
|
|
||||||
var P = properties.position;
|
|
||||||
|
|
||||||
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
|
||||||
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
|
||||||
var d = Vec3.length(Vec3.subtract(P, X));
|
|
||||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
|
||||||
|
|
||||||
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
|
|
||||||
|
|
||||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
|
||||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
|
||||||
|
|
||||||
if (0 < x && sizeOK) {
|
|
||||||
entitySelected = true;
|
|
||||||
selectedEntityID = foundEntity;
|
|
||||||
orientation = MyAvatar.orientation;
|
|
||||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
|
||||||
|
|
||||||
|
|
||||||
if (!event.isShifted) {
|
if (!event.isShifted) {
|
||||||
selectionManager.setSelections([foundEntity]);
|
selectionManager.clearSelections();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toolBar.setActive(true);
|
||||||
|
var pickRay = result.pickRay;
|
||||||
|
var foundEntity = result.entityID;
|
||||||
|
|
||||||
|
var properties = Entities.getEntityProperties(foundEntity);
|
||||||
|
if (isLocked(properties)) {
|
||||||
|
print("Model locked " + properties.id);
|
||||||
|
} else {
|
||||||
|
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||||
|
|
||||||
|
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
|
||||||
|
// P P - Model
|
||||||
|
// /| A - Palm
|
||||||
|
// / | d B - unit vector toward tip
|
||||||
|
// / | X - base of the perpendicular line
|
||||||
|
// A---X----->B d - distance fom axis
|
||||||
|
// x x - distance from A
|
||||||
|
//
|
||||||
|
// |X-A| = (P-A).B
|
||||||
|
// X == A + ((P-A).B)B
|
||||||
|
// d = |P-X|
|
||||||
|
|
||||||
|
var A = pickRay.origin;
|
||||||
|
var B = Vec3.normalize(pickRay.direction);
|
||||||
|
var P = properties.position;
|
||||||
|
|
||||||
|
var x = Vec3.dot(Vec3.subtract(P, A), B);
|
||||||
|
var X = Vec3.sum(A, Vec3.multiply(B, x));
|
||||||
|
var d = Vec3.length(Vec3.subtract(P, X));
|
||||||
|
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||||
|
|
||||||
|
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
|
||||||
|
|
||||||
|
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||||
|
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||||
|
|
||||||
|
if (0 < x && sizeOK) {
|
||||||
|
entitySelected = true;
|
||||||
|
selectedEntityID = foundEntity;
|
||||||
|
orientation = MyAvatar.orientation;
|
||||||
|
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
|
||||||
|
|
||||||
|
|
||||||
|
if (!event.isShifted) {
|
||||||
|
selectionManager.setSelections([foundEntity]);
|
||||||
|
} else {
|
||||||
|
selectionManager.addEntity(foundEntity, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Model selected: " + foundEntity.id);
|
||||||
|
selectionDisplay.select(selectedEntityID, event);
|
||||||
|
|
||||||
|
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
|
||||||
|
cameraManager.focus(selectionManager.worldPosition,
|
||||||
|
selectionManager.worldDimensions,
|
||||||
|
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event.isRightButton) {
|
||||||
|
var result = findClickedEntity(event);
|
||||||
|
if (result) {
|
||||||
|
var properties = Entities.getEntityProperties(result.entityID);
|
||||||
|
var data = {};
|
||||||
|
try {
|
||||||
|
data = JSON.parse(properties.attribution);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
if (data.marketplaceID) {
|
||||||
|
propertyMenu.marketplaceID = data.marketplaceID;
|
||||||
|
propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace");
|
||||||
} else {
|
} else {
|
||||||
selectionManager.addEntity(foundEntity, true);
|
propertyMenu.marketplaceID = null;
|
||||||
}
|
propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info");
|
||||||
|
|
||||||
print("Model selected: " + foundEntity.id);
|
|
||||||
selectionDisplay.select(selectedEntityID, event);
|
|
||||||
|
|
||||||
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
|
|
||||||
cameraManager.focus(selectionManager.worldPosition,
|
|
||||||
selectionManager.worldDimensions,
|
|
||||||
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
|
||||||
}
|
}
|
||||||
|
propertyMenu.setPosition(event.x, event.y);
|
||||||
|
propertyMenu.show();
|
||||||
|
} else {
|
||||||
|
propertyMenu.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -780,7 +786,7 @@ function setupModelMenus() {
|
||||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities" });
|
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities" });
|
||||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities" });
|
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities" });
|
||||||
|
|
||||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, afterItem: MENU_INSPECT_TOOL_ENABLED,
|
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT,
|
||||||
isCheckable: true, isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" });
|
isCheckable: true, isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" });
|
||||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_AUTO_FOCUS_ON_SELECT,
|
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_AUTO_FOCUS_ON_SELECT,
|
||||||
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
|
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
|
||||||
|
@ -811,7 +817,6 @@ function cleanupModelMenus() {
|
||||||
Menu.removeMenuItem("File", "Import Entities");
|
Menu.removeMenuItem("File", "Import Entities");
|
||||||
Menu.removeMenuItem("File", "Import Entities from URL");
|
Menu.removeMenuItem("File", "Import Entities from URL");
|
||||||
|
|
||||||
Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED);
|
|
||||||
Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT);
|
Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT);
|
||||||
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
|
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
|
||||||
Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE);
|
Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE);
|
||||||
|
@ -833,11 +838,21 @@ Script.scriptEnding.connect(function() {
|
||||||
Overlays.deleteOverlay(importingSVOTextOverlay);
|
Overlays.deleteOverlay(importingSVOTextOverlay);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var lastOrientation = null;
|
||||||
|
var lastPosition = null;
|
||||||
|
|
||||||
// Do some stuff regularly, like check for placement of various overlays
|
// Do some stuff regularly, like check for placement of various overlays
|
||||||
Script.update.connect(function (deltaTime) {
|
Script.update.connect(function (deltaTime) {
|
||||||
toolBar.move();
|
toolBar.move();
|
||||||
progressDialog.move();
|
progressDialog.move();
|
||||||
selectionDisplay.checkMove();
|
selectionDisplay.checkMove();
|
||||||
|
var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);
|
||||||
|
var dPosition = Vec3.distance(Camera.position, lastPosition);
|
||||||
|
if (dOrientation > 0.001 || dPosition > 0.001) {
|
||||||
|
propertyMenu.hide();
|
||||||
|
lastOrientation = Camera.orientation;
|
||||||
|
lastPosition = Camera.position;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function insideBox(center, dimensions, point) {
|
function insideBox(center, dimensions, point) {
|
||||||
|
@ -914,8 +929,8 @@ function handeMenuEvent(menuItem) {
|
||||||
if (!selectionManager.hasSelection()) {
|
if (!selectionManager.hasSelection()) {
|
||||||
Window.alert("No entities have been selected.");
|
Window.alert("No entities have been selected.");
|
||||||
} else {
|
} else {
|
||||||
var filename = "models__" + Window.location.hostname + "__.svo";
|
var filename = "entities__" + Window.location.hostname + ".svo.json";
|
||||||
filename = Window.save("Select where to save", filename, "*.svo")
|
filename = Window.save("Select where to save", filename, "*.json")
|
||||||
if (filename) {
|
if (filename) {
|
||||||
var success = Clipboard.exportEntities(filename, selectionManager.selections);
|
var success = Clipboard.exportEntities(filename, selectionManager.selections);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -927,7 +942,7 @@ function handeMenuEvent(menuItem) {
|
||||||
|
|
||||||
var importURL;
|
var importURL;
|
||||||
if (menuItem == "Import Entities") {
|
if (menuItem == "Import Entities") {
|
||||||
importURL = Window.browse("Select models to import", "", "*.svo");
|
importURL = Window.browse("Select models to import", "", "*.json");
|
||||||
} else {
|
} else {
|
||||||
importURL = Window.prompt("URL of SVO to import", "");
|
importURL = Window.prompt("URL of SVO to import", "");
|
||||||
}
|
}
|
||||||
|
@ -1151,6 +1166,8 @@ PropertiesTool = function(opts) {
|
||||||
if (marketplaceWindow.url != data.url) {
|
if (marketplaceWindow.url != data.url) {
|
||||||
marketplaceWindow.setURL(data.url);
|
marketplaceWindow.setURL(data.url);
|
||||||
}
|
}
|
||||||
|
marketplaceWindow.setVisible(true);
|
||||||
|
marketplaceWindow.raise();
|
||||||
} else if (data.type == "action") {
|
} else if (data.type == "action") {
|
||||||
if (data.action == "moveSelectionToGrid") {
|
if (data.action == "moveSelectionToGrid") {
|
||||||
if (selectionManager.hasSelection()) {
|
if (selectionManager.hasSelection()) {
|
||||||
|
@ -1224,4 +1241,142 @@ PropertiesTool = function(opts) {
|
||||||
return that;
|
return that;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PopupMenu = function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var MENU_ITEM_HEIGHT = 21;
|
||||||
|
var MENU_ITEM_SPACING = 1;
|
||||||
|
var TEXT_MARGIN = 7;
|
||||||
|
|
||||||
|
var overlays = [];
|
||||||
|
var overlayInfo = {};
|
||||||
|
|
||||||
|
var upColor = { red: 0, green: 0, blue: 0 };
|
||||||
|
var downColor = { red: 192, green: 192, blue: 192 };
|
||||||
|
var overColor = { red: 128, green: 128, blue: 128 };
|
||||||
|
|
||||||
|
self.onSelectMenuItem = function() { };
|
||||||
|
|
||||||
|
self.addMenuItem = function(name) {
|
||||||
|
var id = Overlays.addOverlay("text", {
|
||||||
|
text: name,
|
||||||
|
backgroundAlpha: 1.0,
|
||||||
|
backgroundColor: upColor,
|
||||||
|
topMargin: TEXT_MARGIN,
|
||||||
|
leftMargin: TEXT_MARGIN,
|
||||||
|
width: 210,
|
||||||
|
height: MENU_ITEM_HEIGHT,
|
||||||
|
font: { size: 12 },
|
||||||
|
visible: false,
|
||||||
|
});
|
||||||
|
overlays.push(id);
|
||||||
|
overlayInfo[id] = { name: name };
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.updateMenuItemText = function(id, newText) {
|
||||||
|
Overlays.editOverlay(id, { text: newText });
|
||||||
|
};
|
||||||
|
|
||||||
|
self.setPosition = function(x, y) {
|
||||||
|
for (var key in overlayInfo) {
|
||||||
|
Overlays.editOverlay(key, {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
});
|
||||||
|
y += MENU_ITEM_HEIGHT + MENU_ITEM_SPACING;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onSelected = function() { };
|
||||||
|
|
||||||
|
var pressingOverlay = null;
|
||||||
|
var hoveringOverlay = null;
|
||||||
|
|
||||||
|
self.mousePressEvent = function(event) {
|
||||||
|
if (event.isLeftButton) {
|
||||||
|
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
if (overlay in overlayInfo) {
|
||||||
|
pressingOverlay = overlay;
|
||||||
|
Overlays.editOverlay(pressingOverlay, { backgroundColor: downColor });
|
||||||
|
} else {
|
||||||
|
self.hide();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.mouseMoveEvent = function(event) {
|
||||||
|
if (visible) {
|
||||||
|
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
if (!pressingOverlay) {
|
||||||
|
if (hoveringOverlay != null && overlay != hoveringOverlay) {
|
||||||
|
Overlays.editOverlay(hoveringOverlay, { backgroundColor: upColor});
|
||||||
|
hoveringOverlay = null;
|
||||||
|
}
|
||||||
|
if (overlay != hoveringOverlay && overlay in overlayInfo) {
|
||||||
|
Overlays.editOverlay(overlay, { backgroundColor: overColor });
|
||||||
|
hoveringOverlay = overlay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
self.mouseReleaseEvent = function(event) {
|
||||||
|
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
if (pressingOverlay != null) {
|
||||||
|
if (overlay == pressingOverlay) {
|
||||||
|
self.onSelectMenuItem(overlayInfo[overlay].name);
|
||||||
|
}
|
||||||
|
Overlays.editOverlay(pressingOverlay, { backgroundColor: upColor });
|
||||||
|
pressingOverlay = null;
|
||||||
|
self.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var visible = false;
|
||||||
|
|
||||||
|
self.setVisible = function(newVisible) {
|
||||||
|
if (newVisible != visible) {
|
||||||
|
visible = newVisible;
|
||||||
|
for (var key in overlayInfo) {
|
||||||
|
Overlays.editOverlay(key, { visible: newVisible });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.show = function() {
|
||||||
|
self.setVisible(true);
|
||||||
|
}
|
||||||
|
self.hide = function() {
|
||||||
|
self.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
for (var i = 0; i < overlays.length; i++) {
|
||||||
|
Overlays.deleteOverlay(overlays[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.mousePressEvent.connect(self.mousePressEvent);
|
||||||
|
Controller.mouseMoveEvent.connect(self.mouseMoveEvent);
|
||||||
|
Controller.mouseReleaseEvent.connect(self.mouseReleaseEvent);
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
var propertyMenu = PopupMenu();
|
||||||
|
|
||||||
|
propertyMenu.onSelectMenuItem = function(name) {
|
||||||
|
if (propertyMenu.marketplaceID) {
|
||||||
|
var url = "https://metaverse.highfidelity.io/marketplace/items/" + propertyMenu.marketplaceID;
|
||||||
|
if (marketplaceWindow.url != url) {
|
||||||
|
marketplaceWindow.setURL(url);
|
||||||
|
}
|
||||||
|
marketplaceWindow.setVisible(true);
|
||||||
|
marketplaceWindow.raise();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
|
||||||
|
|
||||||
propertiesTool = PropertiesTool();
|
propertiesTool = PropertiesTool();
|
||||||
|
|
|
@ -1,8 +1,32 @@
|
||||||
(function() {
|
(function() {
|
||||||
this.entityID = null;
|
this.entityID = null;
|
||||||
this.properties = null;
|
|
||||||
this.lightID = null;
|
this.lightID = null;
|
||||||
this.sound = null;
|
this.sound = null;
|
||||||
|
this.soundURLs = ["https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_1.wav",
|
||||||
|
"https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav",
|
||||||
|
"https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_3.wav"]
|
||||||
|
|
||||||
|
var DEFAULT_USER_DATA = {
|
||||||
|
creatingLight: false,
|
||||||
|
lightID: null,
|
||||||
|
lightDefaultProperties: {
|
||||||
|
type: "Light",
|
||||||
|
position: { x: 0, y: 0, z: 0 },
|
||||||
|
dimensions: { x: 5, y: 5, z: 5 },
|
||||||
|
isSpotlight: false,
|
||||||
|
color: { red: 255, green: 48, blue: 0 },
|
||||||
|
diffuseColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
ambientColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
specularColor: { red: 0, green: 0, blue: 0 },
|
||||||
|
constantAttenuation: 1,
|
||||||
|
linearAttenuation: 0,
|
||||||
|
quadraticAttenuation: 0,
|
||||||
|
intensity: 10,
|
||||||
|
exponent: 0,
|
||||||
|
cutoff: 180, // in degrees
|
||||||
|
},
|
||||||
|
soundIndex: Math.floor(Math.random() * this.soundURLs.length)
|
||||||
|
};
|
||||||
|
|
||||||
function copyObject(object) {
|
function copyObject(object) {
|
||||||
return JSON.parse(JSON.stringify(object));
|
return JSON.parse(JSON.stringify(object));
|
||||||
|
@ -33,7 +57,8 @@
|
||||||
// Download sound if needed
|
// Download sound if needed
|
||||||
this.maybeDownloadSound = function() {
|
this.maybeDownloadSound = function() {
|
||||||
if (this.sound === null) {
|
if (this.sound === null) {
|
||||||
this.sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav");
|
var soundIndex = getUserData(this.entityID).soundIndex;
|
||||||
|
this.sound = SoundCache.getSound(this.soundURLs[soundIndex]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Play switch sound
|
// Play switch sound
|
||||||
|
@ -47,17 +72,21 @@
|
||||||
print("Warning: Couldn't play sound.");
|
print("Warning: Couldn't play sound.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggles the associated light entity
|
// Checks whether the userData is well-formed and updates it if not
|
||||||
this.toggleLight = function() {
|
this.checkUserData = function() {
|
||||||
if (this.lightID) {
|
var userData = getUserData(this.entityID);
|
||||||
var lightProperties = Entities.getEntityProperties(this.lightID);
|
if (!userData) {
|
||||||
Entities.editEntity(this.lightID, { visible: !lightProperties.visible });
|
userData = DEFAULT_USER_DATA;
|
||||||
} else {
|
} else if (!userData.lightDefaultProperties) {
|
||||||
print("Warning: No light to turn on/off");
|
userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties;
|
||||||
|
} else if (!userData.soundIndex) {
|
||||||
|
userData.soundIndex = DEFAULT_USER_DATA.soundIndex;
|
||||||
}
|
}
|
||||||
|
updateUserData(this.entityID, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a Light entity
|
||||||
this.createLight = function(userData) {
|
this.createLight = function(userData) {
|
||||||
var lightProperties = copyObject(userData.lightDefaultProperties);
|
var lightProperties = copyObject(userData.lightDefaultProperties);
|
||||||
if (lightProperties) {
|
if (lightProperties) {
|
||||||
|
@ -74,56 +103,48 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tries to find a valid light, creates one otherwise
|
||||||
this.updateLightID = function() {
|
this.updateLightID = function() {
|
||||||
var userData = getUserData(this.entityID);
|
|
||||||
if (!userData) {
|
|
||||||
userData = {
|
|
||||||
lightID: null,
|
|
||||||
lightDefaultProperties: {
|
|
||||||
type: "Light",
|
|
||||||
position: { x: 0, y: 0, z: 0 },
|
|
||||||
dimensions: { x: 5, y: 5, z: 5 },
|
|
||||||
isSpotlight: false,
|
|
||||||
color: { red: 255, green: 48, blue: 0 },
|
|
||||||
diffuseColor: { red: 255, green: 255, blue: 255 },
|
|
||||||
ambientColor: { red: 255, green: 255, blue: 255 },
|
|
||||||
specularColor: { red: 0, green: 0, blue: 0 },
|
|
||||||
constantAttenuation: 1,
|
|
||||||
linearAttenuation: 0,
|
|
||||||
quadraticAttenuation: 0,
|
|
||||||
intensity: 10,
|
|
||||||
exponent: 0,
|
|
||||||
cutoff: 180, // in degrees
|
|
||||||
}
|
|
||||||
};
|
|
||||||
updateUserData(this.entityID, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find valid light
|
// Find valid light
|
||||||
if (doesEntityExistNow(this.lightID)) {
|
if (doesEntityExistNow(this.lightID)) {
|
||||||
if (!didEntityExist(this.lightID)) {
|
|
||||||
// Light now has an ID, so update it in userData
|
|
||||||
this.lightID = getTrueID(this.lightID);
|
|
||||||
userData.lightID = this.lightID;
|
|
||||||
updateUserData(this.entityID, userData);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userData = getUserData(this.entityID);
|
||||||
if (doesEntityExistNow(userData.lightID)) {
|
if (doesEntityExistNow(userData.lightID)) {
|
||||||
this.lightID = getTrueID(userData.lightID);
|
this.lightID = userData.lightID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No valid light, create one
|
if (!userData.creatingLight) {
|
||||||
this.lightID = this.createLight(userData);
|
// No valid light, create one
|
||||||
print("Created new light entity");
|
userData.creatingLight = true;
|
||||||
|
updateUserData(this.entityID, userData);
|
||||||
// Update user data with new ID
|
this.lightID = this.createLight(userData);
|
||||||
|
this.maybeUpdateLightIDInUserData();
|
||||||
|
print("Created new light entity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maybeUpdateLightIDInUserData = function() {
|
||||||
|
if (getTrueID(this.lightID).isKnownID) {
|
||||||
|
this.lightID = getTrueID(this.lightID);
|
||||||
|
this.updateLightIDInUserData();
|
||||||
|
} else {
|
||||||
|
var that = this;
|
||||||
|
Script.setTimeout(function() { that.maybeUpdateLightIDInUserData() }, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update user data with new lightID
|
||||||
|
this.updateLightIDInUserData = function() {
|
||||||
|
var userData = getUserData(this.entityID);
|
||||||
userData.lightID = this.lightID;
|
userData.lightID = this.lightID;
|
||||||
|
userData.creatingLight = false;
|
||||||
updateUserData(this.entityID, userData);
|
updateUserData(this.entityID, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Moves light entity if the lamp entity moved
|
||||||
this.maybeMoveLight = function() {
|
this.maybeMoveLight = function() {
|
||||||
var entityProperties = Entities.getEntityProperties(this.entityID);
|
var entityProperties = Entities.getEntityProperties(this.entityID);
|
||||||
var lightProperties = Entities.getEntityProperties(this.lightID);
|
var lightProperties = Entities.getEntityProperties(this.lightID);
|
||||||
|
@ -139,8 +160,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stores light entity relative position in the lamp metadata
|
||||||
this.updateRelativeLightPosition = function() {
|
this.updateRelativeLightPosition = function() {
|
||||||
if (!doesEntityExistNow(this.entityID) || !doesEntityExistNow(this.lightID)) {
|
if (!doesEntityExistNow(this.lightID)) {
|
||||||
print("Warning: ID invalid, couldn't save relative position.");
|
print("Warning: ID invalid, couldn't save relative position.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -168,21 +190,37 @@
|
||||||
updateUserData(this.entityID, userData);
|
updateUserData(this.entityID, userData);
|
||||||
print("Relative properties of light entity saved.");
|
print("Relative properties of light entity saved.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function should be called before any callback is executed
|
||||||
|
this.preOperation = function(entityID) {
|
||||||
|
this.entityID = entityID;
|
||||||
|
|
||||||
|
this.checkUserData();
|
||||||
|
this.maybeDownloadSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggles the associated light entity
|
||||||
|
this.toggleLight = function() {
|
||||||
|
if (this.lightID) {
|
||||||
|
var lightProperties = Entities.getEntityProperties(this.lightID);
|
||||||
|
Entities.editEntity(this.lightID, { visible: !lightProperties.visible });
|
||||||
|
this.playSound();
|
||||||
|
} else {
|
||||||
|
print("Warning: No light to turn on/off");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
this.preload = function(entityID) {
|
||||||
this.entityID = entityID;
|
this.preOperation(entityID);
|
||||||
this.maybeDownloadSound();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.clickReleaseOnEntity = function(entityID, mouseEvent) {
|
this.clickReleaseOnEntity = function(entityID, mouseEvent) {
|
||||||
this.entityID = entityID;
|
this.preOperation(entityID);
|
||||||
this.maybeDownloadSound();
|
|
||||||
|
|
||||||
if (mouseEvent.isLeftButton) {
|
if (mouseEvent.isLeftButton) {
|
||||||
this.updateLightID();
|
this.updateLightID();
|
||||||
this.maybeMoveLight();
|
this.maybeMoveLight();
|
||||||
this.toggleLight();
|
this.toggleLight();
|
||||||
this.playSound();
|
|
||||||
} else if (mouseEvent.isRightButton) {
|
} else if (mouseEvent.isRightButton) {
|
||||||
this.updateRelativeLightPosition();
|
this.updateRelativeLightPosition();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1263,11 +1263,13 @@ SelectionDisplay = (function () {
|
||||||
duplicatedEntityIDs = [];
|
duplicatedEntityIDs = [];
|
||||||
for (var otherEntityID in SelectionManager.savedProperties) {
|
for (var otherEntityID in SelectionManager.savedProperties) {
|
||||||
var properties = SelectionManager.savedProperties[otherEntityID];
|
var properties = SelectionManager.savedProperties[otherEntityID];
|
||||||
var entityID = Entities.addEntity(properties);
|
if (!properties.locked) {
|
||||||
duplicatedEntityIDs.push({
|
var entityID = Entities.addEntity(properties);
|
||||||
entityID: entityID,
|
duplicatedEntityIDs.push({
|
||||||
properties: properties,
|
entityID: entityID,
|
||||||
});
|
properties: properties,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
duplicatedEntityIDs = null;
|
duplicatedEntityIDs = null;
|
||||||
|
@ -1361,11 +1363,13 @@ SelectionDisplay = (function () {
|
||||||
duplicatedEntityIDs = [];
|
duplicatedEntityIDs = [];
|
||||||
for (var otherEntityID in SelectionManager.savedProperties) {
|
for (var otherEntityID in SelectionManager.savedProperties) {
|
||||||
var properties = SelectionManager.savedProperties[otherEntityID];
|
var properties = SelectionManager.savedProperties[otherEntityID];
|
||||||
var entityID = Entities.addEntity(properties);
|
if (!properties.locked) {
|
||||||
duplicatedEntityIDs.push({
|
var entityID = Entities.addEntity(properties);
|
||||||
entityID: entityID,
|
duplicatedEntityIDs.push({
|
||||||
properties: properties,
|
entityID: entityID,
|
||||||
});
|
properties: properties,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
duplicatedEntityIDs = null;
|
duplicatedEntityIDs = null;
|
||||||
|
|
|
@ -80,7 +80,6 @@ function touchBeginEvent(event) {
|
||||||
yawFromTouch = 0;
|
yawFromTouch = 0;
|
||||||
pitchFromTouch = 0;
|
pitchFromTouch = 0;
|
||||||
startedTouching = true;
|
startedTouching = true;
|
||||||
print("TOUCH BEGIN");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function touchEndEvent(event) {
|
function touchEndEvent(event) {
|
||||||
|
@ -88,7 +87,6 @@ function touchEndEvent(event) {
|
||||||
print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
|
print("touchEndEvent event.x,y=" + event.x + ", " + event.y);
|
||||||
}
|
}
|
||||||
startedTouching = false;
|
startedTouching = false;
|
||||||
print("TOUCH END");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function touchUpdateEvent(event) {
|
function touchUpdateEvent(event) {
|
||||||
|
|
|
@ -1755,7 +1755,7 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
|
||||||
exportTree.addEntity(entityItem->getEntityItemID(), properties);
|
exportTree.addEntity(entityItem->getEntityItemID(), properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
exportTree.writeToSVOFile(filename.toLocal8Bit().constData());
|
exportTree.writeToJSONFile(filename.toLocal8Bit().constData());
|
||||||
|
|
||||||
// restore the main window's active state
|
// restore the main window's active state
|
||||||
_window->activateWindow();
|
_window->activateWindow();
|
||||||
|
@ -3599,6 +3599,7 @@ void Application::initializeAcceptedFiles() {
|
||||||
if (_acceptedExtensions.size() == 0) {
|
if (_acceptedExtensions.size() == 0) {
|
||||||
_acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot;
|
_acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot;
|
||||||
_acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL;
|
_acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL;
|
||||||
|
_acceptedExtensions[SVO_JSON_EXTENSION] = &Application::importSVOFromURL;
|
||||||
_acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript;
|
_acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript;
|
||||||
_acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl;
|
_acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ static const float NODE_KILLED_BLUE = 0.0f;
|
||||||
|
|
||||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||||
static const QString SVO_EXTENSION = ".svo";
|
static const QString SVO_EXTENSION = ".svo";
|
||||||
|
static const QString SVO_JSON_EXTENSION = ".svo.json";
|
||||||
static const QString JS_EXTENSION = ".js";
|
static const QString JS_EXTENSION = ".js";
|
||||||
static const QString FST_EXTENSION = ".fst";
|
static const QString FST_EXTENSION = ".fst";
|
||||||
|
|
||||||
|
|
|
@ -40,26 +40,55 @@ float LODManager::getLODIncreaseFPS() {
|
||||||
|
|
||||||
|
|
||||||
void LODManager::autoAdjustLOD(float currentFPS) {
|
void LODManager::autoAdjustLOD(float currentFPS) {
|
||||||
|
|
||||||
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
|
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
|
||||||
// really want to count them in our average, so we will ignore the real frame rates and stuff
|
// really want to count them in our average, so we will ignore the real frame rates and stuff
|
||||||
// our moving average with simulated good data
|
// our moving average with simulated good data
|
||||||
const int IGNORE_THESE_SAMPLES = 100;
|
const int IGNORE_THESE_SAMPLES = 100;
|
||||||
const float ASSUMED_FPS = 60.0f;
|
if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) {
|
||||||
if (_fpsAverage.getSampleCount() < IGNORE_THESE_SAMPLES) {
|
|
||||||
currentFPS = ASSUMED_FPS;
|
currentFPS = ASSUMED_FPS;
|
||||||
|
_lastStable = _lastUpShift = _lastDownShift = usecTimestampNow();
|
||||||
}
|
}
|
||||||
_fpsAverage.updateAverage(currentFPS);
|
|
||||||
_fastFPSAverage.updateAverage(currentFPS);
|
_fpsAverageStartWindow.updateAverage(currentFPS);
|
||||||
|
_fpsAverageDownWindow.updateAverage(currentFPS);
|
||||||
|
_fpsAverageUpWindow.updateAverage(currentFPS);
|
||||||
|
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
bool octreeChanged = false;
|
quint64 elapsedSinceDownShift = now - _lastDownShift;
|
||||||
quint64 elapsed = now - _lastAdjust;
|
quint64 elapsedSinceUpShift = now - _lastUpShift;
|
||||||
|
|
||||||
|
quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable);
|
||||||
|
quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift;
|
||||||
|
|
||||||
if (_automaticLODAdjust) {
|
if (_automaticLODAdjust) {
|
||||||
// LOD Downward adjustment
|
|
||||||
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < getLODDecreaseFPS()) {
|
// LOD Downward adjustment
|
||||||
|
// If we've been downshifting, we watch a shorter downshift window so that we will quickly move toward our
|
||||||
|
// target frame rate. But if we haven't just done a downshift (either because our last shift was an upshift,
|
||||||
|
// or because we've just started out) then we look at a much longer window to consider whether or not to start
|
||||||
|
// downshifting.
|
||||||
|
bool doDownShift = false;
|
||||||
|
|
||||||
|
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
|
// Octree items... stepwise adjustment
|
||||||
if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
|
if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||||
|
@ -67,40 +96,66 @@ void LODManager::autoAdjustLOD(float currentFPS) {
|
||||||
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||||
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||||
}
|
}
|
||||||
octreeChanged = changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
_lastAdjust = now;
|
if (_isDownshifting) {
|
||||||
qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
// subsequent downshift
|
||||||
<< "_octreeSizeScale=" << _octreeSizeScale;
|
qDebug() << "adjusting LOD DOWN..."
|
||||||
|
<< "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was "
|
||||||
|
<< _fpsAverageDownWindow.getAverage()
|
||||||
|
<< "minimum is:" << getLODDecreaseFPS()
|
||||||
|
<< "elapsedSinceDownShift:" << elapsedSinceDownShift
|
||||||
|
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
||||||
|
} else {
|
||||||
|
// first downshift
|
||||||
|
qDebug() << "adjusting LOD DOWN after initial delay..."
|
||||||
|
<< "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was "
|
||||||
|
<< _fpsAverageStartWindow.getAverage()
|
||||||
|
<< "minimum is:" << getLODDecreaseFPS()
|
||||||
|
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
|
||||||
|
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastDownShift = now;
|
||||||
|
_isDownshifting = true;
|
||||||
|
|
||||||
emit LODDecreased();
|
emit LODDecreased();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
// LOD Upward adjustment
|
// LOD Upward adjustment
|
||||||
if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > getLODIncreaseFPS()) {
|
if (elapsedSinceUpShift > UP_SHIFT_ELPASED) {
|
||||||
|
|
||||||
|
if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) {
|
||||||
|
|
||||||
// Octee items... stepwise adjustment
|
// Octee items... stepwise adjustment
|
||||||
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||||
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||||
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||||
} else {
|
} else {
|
||||||
_octreeSizeScale *= ADJUST_LOD_UP_BY;
|
_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) {
|
if (changed) {
|
||||||
_lastAdjust = now;
|
qDebug() << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was "
|
||||||
qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
|
<< _fpsAverageUpWindow.getAverage()
|
||||||
<< "_octreeSizeScale=" << _octreeSizeScale;
|
<< "upshift point is:" << getLODIncreaseFPS()
|
||||||
|
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
|
||||||
|
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
||||||
|
|
||||||
emit LODIncreased();
|
_lastUpShift = now;
|
||||||
|
_isDownshifting = false;
|
||||||
|
|
||||||
|
emit LODIncreased();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,9 +171,11 @@ void LODManager::autoAdjustLOD(float currentFPS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LODManager::resetLODAdjust() {
|
void LODManager::resetLODAdjust() {
|
||||||
_fpsAverage.reset();
|
_fpsAverageStartWindow.reset();
|
||||||
_fastFPSAverage.reset();
|
_fpsAverageDownWindow.reset();
|
||||||
_lastAdjust = usecTimestampNow();
|
_fpsAverageUpWindow.reset();
|
||||||
|
_lastUpShift = _lastDownShift = usecTimestampNow();
|
||||||
|
_isDownshifting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LODManager::getLODFeedbackText() {
|
QString LODManager::getLODFeedbackText() {
|
||||||
|
|
|
@ -19,10 +19,22 @@
|
||||||
|
|
||||||
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0;
|
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0;
|
||||||
const float DEFAULT_HMD_LOD_DOWN_FPS = 60.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 float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts
|
||||||
const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2;
|
const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f;
|
||||||
|
const float UP_SHIFT_WINDOW_IN_SECS = 2.5f;
|
||||||
|
|
||||||
|
const int ASSUMED_FPS = 60;
|
||||||
|
const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS;
|
||||||
|
const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second
|
||||||
|
const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS;
|
||||||
|
|
||||||
|
const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS;
|
||||||
|
const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS;
|
||||||
|
const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS;
|
||||||
|
|
||||||
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
||||||
const float ADJUST_LOD_UP_BY = 1.1f;
|
const float ADJUST_LOD_UP_BY = 1.1f;
|
||||||
|
@ -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.
|
// do. But both are still culled using the same angular size logic.
|
||||||
const float AVATAR_TO_ENTITY_RATIO = 2.0f;
|
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 {
|
class LODManager : public QObject, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -51,11 +60,11 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; }
|
Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; }
|
||||||
Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; }
|
Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; }
|
||||||
Q_INVOKABLE 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 void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; }
|
||||||
Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; }
|
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; }
|
Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
||||||
|
|
||||||
|
@ -67,10 +76,6 @@ public:
|
||||||
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||||
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||||
|
|
||||||
Q_INVOKABLE void resetLODAdjust();
|
|
||||||
Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); }
|
|
||||||
Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); }
|
|
||||||
|
|
||||||
Q_INVOKABLE float getLODDecreaseFPS();
|
Q_INVOKABLE float getLODDecreaseFPS();
|
||||||
Q_INVOKABLE float getLODIncreaseFPS();
|
Q_INVOKABLE float getLODIncreaseFPS();
|
||||||
|
|
||||||
|
@ -79,6 +84,7 @@ public:
|
||||||
|
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
|
void resetLODAdjust();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void LODIncreased();
|
void LODIncreased();
|
||||||
|
@ -96,9 +102,14 @@ private:
|
||||||
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
|
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
|
||||||
int _boundaryLevelAdjust = 0;
|
int _boundaryLevelAdjust = 0;
|
||||||
|
|
||||||
quint64 _lastAdjust = 0;
|
quint64 _lastDownShift = 0;
|
||||||
SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES;
|
quint64 _lastUpShift = 0;
|
||||||
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES;
|
quint64 _lastStable = 0;
|
||||||
|
bool _isDownshifting = false; // start out as if we're not downshifting
|
||||||
|
|
||||||
|
SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES;
|
||||||
|
SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES;
|
||||||
|
SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES;
|
||||||
|
|
||||||
bool _shouldRenderTableNeedsRebuilding = true;
|
bool _shouldRenderTableNeedsRebuilding = true;
|
||||||
QMap<float, float> _shouldRenderTable;
|
QMap<float, float> _shouldRenderTable;
|
||||||
|
|
|
@ -25,7 +25,7 @@ EntityItemID::EntityItemID() :
|
||||||
creatorTokenID(UNKNOWN_ENTITY_TOKEN),
|
creatorTokenID(UNKNOWN_ENTITY_TOKEN),
|
||||||
isKnownID(false)
|
isKnownID(false)
|
||||||
{
|
{
|
||||||
};
|
}
|
||||||
|
|
||||||
EntityItemID::EntityItemID(const EntityItemID& other) :
|
EntityItemID::EntityItemID(const EntityItemID& other) :
|
||||||
id(other.id),
|
id(other.id),
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "AccountManager.h"
|
#include "AccountManager.h"
|
||||||
|
|
||||||
const QString HIFI_URL_SCHEME = "hifi";
|
const QString HIFI_URL_SCHEME = "hifi";
|
||||||
const QString DEFAULT_HIFI_ADDRESS = "hifi://sandbox";
|
const QString DEFAULT_HIFI_ADDRESS = "hifi://entry";
|
||||||
|
|
||||||
typedef const glm::vec3& (*PositionGetter)();
|
typedef const glm::vec3& (*PositionGetter)();
|
||||||
typedef glm::quat (*OrientationGetter)();
|
typedef glm::quat (*OrientationGetter)();
|
||||||
|
|
Loading…
Reference in a new issue