diff --git a/cmake/externals/tbb/CMakeLists.txt b/cmake/externals/tbb/CMakeLists.txt index 54a73dafb8..ad46196b95 100644 --- a/cmake/externals/tbb/CMakeLists.txt +++ b/cmake/externals/tbb/CMakeLists.txt @@ -95,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 () diff --git a/examples/edit.js b/examples/edit.js index 8088b7cd74..2529b617d9 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -88,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; @@ -387,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, @@ -1162,7 +1154,7 @@ PropertiesTool = function(opts) { } pushCommandForSelections(); selectionManager._update(); - } else if (data.type = "showMarketplace") { + } else if (data.type == "showMarketplace") { if (marketplaceWindow.url != data.url) { marketplaceWindow.setURL(data.url); } diff --git a/examples/entityScripts/portal.js b/examples/entityScripts/portal.js index 5dd7849c38..4e2ec6ddaf 100644 --- a/examples/entityScripts/portal.js +++ b/examples/entityScripts/portal.js @@ -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; diff --git a/examples/users.js b/examples/users.js index 22fe89389f..ebd59886aa 100644 --- a/examples/users.js +++ b/examples/users.js @@ -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,6 +44,8 @@ var usersWindow = (function () { usersOnline, // Raw users data linesOfUsers = [], // Array of indexes pointing into usersOnline + numUsersToDisplay = 0, + firstUserToDisplay = 0, API_URL = "https://metaverse.highfidelity.com/api/v1/users?status=online", HTTP_GET_TIMEOUT = 60000, // ms = 1 minute @@ -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); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc8fa08c4e..8cd36b501f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -789,7 +789,7 @@ void Application::paintGL() { DependencyManager::get()->render(); - if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { + { PerformanceTimer perfTimer("renderOverlay"); _applicationOverlay.renderOverlay(true); _applicationOverlay.displayOverlayTexture(); @@ -1127,13 +1127,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: @@ -3019,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(); } diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 791e5667c4..13697ff8be 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -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(); DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); @@ -70,6 +71,10 @@ void DiscoverabilityManager::updateLocation() { 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); } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8d3c01320f..2ec5c12ca0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -230,7 +230,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 +258,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 +536,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 } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 60fe5d4cd2..b3d2d548df 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -184,12 +184,10 @@ 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,7 +231,6 @@ 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"; @@ -251,7 +248,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"; } diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 49d4ae566f..f552d67a98 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include "ModelSelector.h" #include "ModelPropertiesDialog.h" diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index c62388f196..2c90395e56 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -15,8 +15,6 @@ #include #include -#include - #include "ui/ModelsBrowser.h" class ModelPackager : public QObject { diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp index de98407a2a..81fe9ce7fd 100644 --- a/interface/src/ModelPropertiesDialog.cpp +++ b/interface/src/ModelPropertiesDialog.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "ModelPropertiesDialog.h" diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h index 65c5be6c21..5af4d173f1 100644 --- a/interface/src/ModelPropertiesDialog.h +++ b/interface/src/ModelPropertiesDialog.h @@ -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 diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index b5f57301f1..f082c6de47 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -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()->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(); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 0c5941366f..d9adaf02e6 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -176,18 +176,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); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 64161e4a31..58b79adcda 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -114,7 +114,7 @@ private: quint64 _lastMouseMove; bool _magnifier; - float _alpha; + float _alpha = 1.0f; float _oculusUIRadius; float _trailingAudioLoudness; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index b005f67f5e..3faa06fc53 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -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 entitiesContainingAvatar; // find the entities near us + _tree->lockForRead(); // don't let someone else change our tree while we search static_cast(_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) { diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index a2c217c97d..1cd3bba73a 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -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 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 createVec3Vector(const QVector& doubleVector) { QVector 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(&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(&model)); buffer.open(QIODevice::ReadOnly); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index ecce607575..6cb6b19c05 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -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); diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp new file mode 100644 index 0000000000..f1ffe11996 --- /dev/null +++ b/libraries/fbx/src/FSTReader.cpp @@ -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 + +#include "FSTReader.h" + +QVariantHash parseMapping(QIODevice* device) { + QVariantHash properties; + + QByteArray line; + while (!(line = device->readLine()).isEmpty()) { + if ((line = line.trimmed()).startsWith('#')) { + continue; // comment + } + QList 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(&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(); +} \ No newline at end of file diff --git a/libraries/fbx/src/FSTReader.h b/libraries/fbx/src/FSTReader.h new file mode 100644 index 0000000000..59559dea74 --- /dev/null +++ b/libraries/fbx/src/FSTReader.h @@ -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 + +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 \ No newline at end of file diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 29f76291ea..e60409e36f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "TextureCache.h"