diff --git a/interface/resources/html/raiseAndLowerKeyboard.js b/interface/resources/html/raiseAndLowerKeyboard.js
index a0aa1eb7fe..f40c0d7376 100644
--- a/interface/resources/html/raiseAndLowerKeyboard.js
+++ b/interface/resources/html/raiseAndLowerKeyboard.js
@@ -7,6 +7,9 @@
//
// Sends messages over the EventBridge when text input is required.
//
+
+/* global document, window, console, setTimeout, setInterval, EventBridge */
+
(function () {
var POLL_FREQUENCY = 500; // ms
var MAX_WARNINGS = 3;
@@ -37,22 +40,24 @@
}
return false;
}
- };
+ }
function shouldSetNumeric() {
return document.activeElement.type === "number";
- };
+ }
function scheduleBringToView(timeout) {
-
- var timer = setTimeout(function () {
- clearTimeout(timer);
-
+ setTimeout(function () {
+ // If the element is not visible because the keyboard has been raised over the top of it, scroll it up into view.
+ // If the element is not visible because the keyboard raising has moved it off screen, scroll it down into view.
var elementRect = document.activeElement.getBoundingClientRect();
- var absoluteElementTop = elementRect.top + window.scrollY;
- var middle = absoluteElementTop - (window.innerHeight / 2);
-
- window.scrollTo(0, middle);
+ var VISUAL_MARGIN = 3;
+ var delta = elementRect.y + elementRect.height + VISUAL_MARGIN - window.innerHeight;
+ if (delta > 0) {
+ window.scrollBy(0, delta);
+ } else if (elementRect.y < VISUAL_MARGIN) {
+ window.scrollBy(0, elementRect.y - VISUAL_MARGIN);
+ }
}, timeout);
}
@@ -62,11 +67,13 @@
var passwordField = shouldSetPasswordField();
if (isWindowFocused &&
- (keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard || passwordField !== window.isPasswordField)) {
+ (keyboardRaised !== window.isKeyboardRaised || numericKeyboard !== window.isNumericKeyboard
+ || passwordField !== window.isPasswordField)) {
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
EventBridge.emitWebEvent(
- keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "") + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
+ keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "")
+ + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
);
} else {
if (numWarnings < MAX_WARNINGS) {
@@ -77,7 +84,7 @@
if (!window.isKeyboardRaised) {
scheduleBringToView(250); // Allow time for keyboard to be raised in QML.
- // 2DO: should it be rather done from 'client area height changed' event?
+ // 2DO: should it be rather done from 'client area height changed' event?
}
window.isKeyboardRaised = keyboardRaised;
diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
index 4db98091c1..19b57354dc 100644
--- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
@@ -49,6 +49,7 @@ Item {
property string upgradeTitle;
property bool updateAvailable: root.upgradeUrl !== "" && !root.isShowingMyItems;
property bool isShowingMyItems;
+ property bool valid;
property string originalStatusText;
property string originalStatusColor;
@@ -239,6 +240,7 @@ Item {
width: 62;
onLoaded: {
+ item.enabled = root.valid;
item.buttonGlyphText = hifi.glyphs.gift;
item.buttonText = "Gift";
item.buttonClicked = function() {
@@ -463,7 +465,7 @@ Item {
Item {
id: statusContainer;
- visible: root.purchaseStatus === "pending" || root.purchaseStatus === "invalidated" || root.numberSold > -1;
+ visible: root.purchaseStatus === "pending" || !root.valid || root.numberSold > -1;
anchors.left: itemName.left;
anchors.right: itemName.right;
anchors.top: itemName.bottom;
@@ -480,7 +482,7 @@ Item {
text: {
if (root.purchaseStatus === "pending") {
"PENDING..."
- } else if (root.purchaseStatus === "invalidated") {
+ } else if (!root.valid) {
"INVALIDATED"
} else if (root.numberSold > -1) {
("Sales: " + root.numberSold + "/" + (root.limitedRun === -1 ? "\u221e" : root.limitedRun))
@@ -492,7 +494,7 @@ Item {
color: {
if (root.purchaseStatus === "pending") {
hifi.colors.blueAccent
- } else if (root.purchaseStatus === "invalidated") {
+ } else if (!root.valid) {
hifi.colors.redAccent
} else {
hifi.colors.baseGray
@@ -506,7 +508,7 @@ Item {
text: {
if (root.purchaseStatus === "pending") {
hifi.glyphs.question
- } else if (root.purchaseStatus === "invalidated") {
+ } else if (!root.valid) {
hifi.glyphs.question
} else {
""
@@ -523,7 +525,7 @@ Item {
color: {
if (root.purchaseStatus === "pending") {
hifi.colors.blueAccent
- } else if (root.purchaseStatus === "invalidated") {
+ } else if (!root.valid) {
hifi.colors.redAccent
} else {
hifi.colors.baseGray
@@ -538,7 +540,7 @@ Item {
onClicked: {
if (root.purchaseStatus === "pending") {
sendToPurchases({method: 'showPendingLightbox'});
- } else if (root.purchaseStatus === "invalidated") {
+ } else if (!root.valid) {
sendToPurchases({method: 'showInvalidatedLightbox'});
}
}
@@ -546,7 +548,7 @@ Item {
if (root.purchaseStatus === "pending") {
statusText.color = hifi.colors.blueHighlight;
statusIcon.color = hifi.colors.blueHighlight;
- } else if (root.purchaseStatus === "invalidated") {
+ } else if (!root.valid) {
statusText.color = hifi.colors.redAccent;
statusIcon.color = hifi.colors.redAccent;
}
@@ -555,7 +557,7 @@ Item {
if (root.purchaseStatus === "pending") {
statusText.color = hifi.colors.blueAccent;
statusIcon.color = hifi.colors.blueAccent;
- } else if (root.purchaseStatus === "invalidated") {
+ } else if (!root.valid) {
statusText.color = hifi.colors.redHighlight;
statusIcon.color = hifi.colors.redHighlight;
}
@@ -645,8 +647,8 @@ Item {
width: 160;
height: 40;
enabled: root.hasPermissionToRezThis &&
- root.purchaseStatus !== "invalidated" &&
- MyAvatar.skeletonModelURL !== root.itemHref;
+ MyAvatar.skeletonModelURL !== root.itemHref &&
+ root.valid;
onHoveredChanged: {
if (hovered) {
diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
index d79b8d09fa..8fe1ebe6c9 100644
--- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
@@ -616,6 +616,7 @@ Rectangle {
upgradeTitle: model.upgrade_title;
itemType: model.itemType;
isShowingMyItems: root.isShowingMyItems;
+ valid: model.valid;
anchors.topMargin: 10;
anchors.bottomMargin: 10;
@@ -995,10 +996,6 @@ Rectangle {
for (var i = 0; i < purchasesModel.count; i++) {
if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) {
- if (!purchasesModel.get(i).valid) {
- continue;
- }
-
if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems) {
tempPurchasesModel.insert(0, purchasesModel.get(i));
} else if ((root.isShowingMyItems && purchasesModel.get(i).edition_number === "0") ||
@@ -1055,10 +1052,6 @@ Rectangle {
var currentId;
for (var i = 0; i < tempPurchasesModel.count; i++) {
currentId = tempPurchasesModel.get(i).id;
-
- if (!purchasesModel.get(i).valid) {
- continue;
- }
filteredPurchasesModel.append(tempPurchasesModel.get(i));
filteredPurchasesModel.setProperty(i, 'cardBackVisible', false);
filteredPurchasesModel.setProperty(i, 'isInstalled', ((root.installedApps).indexOf(currentId) > -1));
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 42a6cbc790..61ed5acdd2 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -735,9 +735,9 @@ extern InputPluginList getInputPlugins();
extern void saveInputPluginSettings(const InputPluginList& plugins);
// Parameters used for running tests from teh command line
-const QString TEST_SCRIPT_COMMAND { "--testScript" };
-const QString TEST_QUIT_WHEN_FINISHED_OPTION { "quitWhenFinished" };
-const QString TEST_SNAPSHOT_LOCATION_COMMAND { "--testSnapshotLocation" };
+const QString TEST_SCRIPT_COMMAND{ "--testScript" };
+const QString TEST_QUIT_WHEN_FINISHED_OPTION{ "quitWhenFinished" };
+const QString TEST_RESULTS_LOCATION_COMMAND{ "--testResultsLocation" };
bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
const char** constArgv = const_cast(argv);
@@ -1015,22 +1015,25 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// If the URL scheme is http(s) or ftp, then use as is, else - treat it as a local file
// This is done so as not break previous command line scripts
- if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP || testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) {
+ if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP ||
+ testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) {
+
setProperty(hifi::properties::TEST, QUrl::fromUserInput(testScriptPath));
} else if (QFileInfo(testScriptPath).exists()) {
setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath));
}
- // quite when finished parameter must directly follow the test script
+ // quite when finished parameter must directly follow the test script
if ((i + 2) < args.size() && args.at(i + 2) == TEST_QUIT_WHEN_FINISHED_OPTION) {
quitWhenFinished = true;
}
- } else if (args.at(i) == TEST_SNAPSHOT_LOCATION_COMMAND) {
+ } else if (args.at(i) == TEST_RESULTS_LOCATION_COMMAND) {
// Set test snapshot location only if it is a writeable directory
- QString pathname(args.at(i + 1));
- QFileInfo fileInfo(pathname);
+ QString path(args.at(i + 1));
+
+ QFileInfo fileInfo(path);
if (fileInfo.isDir() && fileInfo.isWritable()) {
- testSnapshotLocation = pathname;
+ TestScriptingInterface::getInstance()->setTestResultsLocation(path);
}
}
}
@@ -7588,7 +7591,9 @@ void Application::loadAvatarBrowser() const {
void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) {
postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] {
// Get a screenshot and save it
- QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, testSnapshotLocation);
+ QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename,
+ TestScriptingInterface::getInstance()->getTestResultsLocation());
+
// If we're not doing an animated snapshot as well...
if (!includeAnimated) {
// Tell the dependency manager that the capture of the still snapshot has taken place.
@@ -7602,7 +7607,9 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa
void Application::takeSecondaryCameraSnapshot(const QString& filename) {
postLambdaEvent([filename, this] {
- QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, testSnapshotLocation);
+ QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename,
+ TestScriptingInterface::getInstance()->getTestResultsLocation());
+
emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, true);
});
}
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 4946dd7ad9..17e28f0e6e 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -419,7 +419,6 @@ public slots:
void updateVerboseLogging();
Q_INVOKABLE void openAndroidActivity(const QString& activityName);
-
private slots:
void onDesktopRootItemCreated(QQuickItem* qmlContext);
void onDesktopRootContextCreated(QQmlContext* qmlContext);
@@ -753,7 +752,6 @@ private:
std::atomic _pendingIdleEvent { true };
std::atomic _pendingRenderEvent { true };
- QString testSnapshotLocation;
bool quitWhenFinished { false };
};
#endif // hifi_Application_h
diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp
index d06ba14bcf..da1f14c450 100644
--- a/interface/src/LODManager.cpp
+++ b/interface/src/LODManager.cpp
@@ -70,7 +70,7 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
// Note: we MUST clamp the blend to 1.0 for stability
float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec
- if (!_automaticLODAdjust) {
+ if (!_automaticLODAdjust || _avgRenderTime == 0.0f) {
// early exit
return;
}
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index 20375a71b2..be3dd705f7 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -193,7 +193,6 @@ namespace MenuOption {
const QString ShowOtherLookAtVectors = "Show Other Eye Vectors";
const QString EnableLookAtSnapping = "Enable LookAt Snapping";
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
- const QString StandingHMDSensorMode = "Standing HMD Sensor Mode";
const QString SimulateEyeTracking = "Simulate";
const QString SMIEyeTracking = "SMI Eye Tracking";
const QString SparseTextureManagement = "Enable Sparse Texture Management";
diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp
index 9e7c0e142e..700994c517 100644
--- a/interface/src/scripting/TestScriptingInterface.cpp
+++ b/interface/src/scripting/TestScriptingInterface.cpp
@@ -160,3 +160,29 @@ void TestScriptingInterface::clearCaches() {
qApp->reloadResourceCaches();
}
+// Writes a JSON object from javascript to a file
+void TestScriptingInterface::saveObject(QVariant variant, const QString& filename) {
+ if (_testResultsLocation.isNull()) {
+ return;
+ }
+
+ QJsonDocument jsonDocument;
+ jsonDocument = QJsonDocument::fromVariant(variant);
+ if (jsonDocument.isNull()) {
+ return;
+ }
+
+ QByteArray jsonData = jsonDocument.toJson();
+
+ // Append trailing slash if needed
+ if (_testResultsLocation.right(1) != "/") {
+ _testResultsLocation += "/";
+ }
+
+ QString filepath = QDir::cleanPath(_testResultsLocation + filename);
+ QFile file(filepath);
+
+ file.open(QFile::WriteOnly);
+ file.write(jsonData);
+ file.close();
+}
diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h
index 687cb41689..5666417727 100644
--- a/interface/src/scripting/TestScriptingInterface.h
+++ b/interface/src/scripting/TestScriptingInterface.h
@@ -18,6 +18,10 @@ class QScriptValue;
class TestScriptingInterface : public QObject {
Q_OBJECT
+public:
+ void setTestResultsLocation(const QString path) { _testResultsLocation = path; }
+ const QString& getTestResultsLocation() { return _testResultsLocation; };
+
public slots:
static TestScriptingInterface* getInstance();
@@ -46,7 +50,6 @@ public slots:
*/
void waitIdle();
-
bool waitForConnection(qint64 maxWaitMs = 10000);
void wait(int milliseconds);
@@ -83,8 +86,14 @@ public slots:
*/
void clearCaches();
+ /**jsdoc
+ * Save a JSON object to a file in the test results location
+ */
+ void saveObject(QVariant v, const QString& filename);
+
private:
bool waitForCondition(qint64 maxWaitMs, std::function condition);
+ QString _testResultsLocation;
};
-#endif // hifi_TestScriptingInterface_h
+#endif // hifi_TestScriptingInterface_h
diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h
index 8adb5138f2..7e47d9e2d4 100644
--- a/libraries/entities/src/EntityScriptingInterface.h
+++ b/libraries/entities/src/EntityScriptingInterface.h
@@ -481,8 +481,8 @@ public slots:
/**jsdoc
* Gets the status of server entity script attached to an entity
* @function Entities.getServerScriptStatus
- * @property {Uuid} entityID - The ID of the entity to get the server entity script status for.
- * @property {Entities~getServerScriptStatusCallback} callback - The function to call upon completion.
+ * @param {Uuid} entityID - The ID of the entity to get the server entity script status for.
+ * @param {Entities~getServerScriptStatusCallback} callback - The function to call upon completion.
* @returns {boolean} true
always.
*/
/**jsdoc
diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp
index 9f067e51c6..7a0ead3e0d 100644
--- a/libraries/physics/src/EntityMotionState.cpp
+++ b/libraries/physics/src/EntityMotionState.cpp
@@ -731,7 +731,9 @@ void EntityMotionState::measureBodyAcceleration() {
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
glm::vec3 velocity = getBodyLinearVelocityGTSigma();
- _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt;
+ const float MIN_DAMPING_FACTOR = 0.01f;
+ float invDampingAttenuationFactor = 1.0f / glm::max(powf(1.0f - _body->getLinearDamping(), dt), MIN_DAMPING_FACTOR);
+ _measuredAcceleration = (velocity * invDampingAttenuationFactor - _lastVelocity) * invDt;
_lastVelocity = velocity;
if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) {
// we fall in here when _lastMeasureStep is old: the body has just become active
diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp
index 69c5b3c689..fbb4bba263 100644
--- a/libraries/render-utils/src/RenderShadowTask.cpp
+++ b/libraries/render-utils/src/RenderShadowTask.cpp
@@ -149,9 +149,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
batch.setStateScissorRect(viewport);
batch.setFramebuffer(fbo);
- batch.clearFramebuffer(
- gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,
- vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true);
+ batch.clearDepthFramebuffer(1.0, false);
glm::mat4 projMat;
Transform viewMat;
@@ -232,12 +230,11 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
const auto queryResolution = setupOutput.getN(2);
// Fetch and cull the items from the scene
- // Enable models to not cast shadows (otherwise, models will always cast shadows)
- static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask).withShadowCaster();
+ static const auto shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(tagBits, tagMask);
- const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterFilter, queryResolution).asVarying();
+ const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterReceiverFilter, queryResolution).asVarying();
const auto shadowSelection = task.addJob("FetchShadowTree", fetchInput);
- const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying();
+ const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterReceiverFilter).asVarying();
const auto shadowItems = task.addJob("FetchShadowSelection", selectionInputs);
// Cull objects that are not visible in camera view. Hopefully the cull functor only performs LOD culling, not
@@ -261,21 +258,22 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
char jobName[64];
sprintf(jobName, "ShadowCascadeSetup%d", i);
const auto cascadeSetupOutput = task.addJob(jobName, i, _cullFunctor, tagBits, tagMask);
- const auto shadowFilter = cascadeSetupOutput.getN(0);
+ const auto shadowRenderFilter = cascadeSetupOutput.getN(0);
+ const auto shadowBoundsFilter = cascadeSetupOutput.getN(1);
auto antiFrustum = render::Varying(ViewFrustumPointer());
- cascadeFrustums[i] = cascadeSetupOutput.getN(1);
+ cascadeFrustums[i] = cascadeSetupOutput.getN(2);
if (i > 1) {
antiFrustum = cascadeFrustums[i - 2];
}
// CPU jobs: finer grained culling
- const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter, antiFrustum).asVarying();
+ const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowRenderFilter, shadowBoundsFilter, antiFrustum).asVarying();
const auto culledShadowItemsAndBounds = task.addJob("CullShadowCascade", cullInputs, shadowCullFunctor, RenderDetails::SHADOW);
// GPU jobs: Render to shadow map
sprintf(jobName, "RenderShadowMap%d", i);
task.addJob(jobName, culledShadowItemsAndBounds, shapePlumber, i);
- task.addJob("ShadowCascadeTeardown", shadowFilter);
+ task.addJob("ShadowCascadeTeardown", shadowRenderFilter);
}
task.addJob("ShadowTeardown", setupOutput);
@@ -406,7 +404,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
const auto globalShadow = lightStage->getCurrentKeyShadow();
if (globalShadow && _cascadeIndexgetCascadeCount()) {
- output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask).withShadowCaster();
+ auto baseFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask);
+ // Second item filter is to filter items to keep in shadow frustum computation (here we need to keep shadow receivers)
+ output.edit1() = baseFilter;
+ // First item filter is to filter items to render in shadow map (so only keep casters)
+ output.edit0() = baseFilter.withShadowCaster();
// Set the keylight render args
auto& cascade = globalShadow->getCascade(_cascadeIndex);
@@ -419,10 +421,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
texelSize *= minTexelCount;
_cullFunctor._minSquareSize = texelSize * texelSize;
- output.edit1() = cascadeFrustum;
+ output.edit2() = cascadeFrustum;
} else {
output.edit0() = ItemFilter::Builder::nothing();
- output.edit1() = ViewFrustumPointer();
+ output.edit1() = ItemFilter::Builder::nothing();
+ output.edit2() = ViewFrustumPointer();
}
}
diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h
index 98b70c0c9f..19ffcb4234 100644
--- a/libraries/render-utils/src/RenderShadowTask.h
+++ b/libraries/render-utils/src/RenderShadowTask.h
@@ -118,7 +118,7 @@ private:
class RenderShadowCascadeSetup {
public:
- using Outputs = render::VaryingSet2;
+ using Outputs = render::VaryingSet3;
using JobModel = render::Job::ModelO;
RenderShadowCascadeSetup(unsigned int cascadeIndex, RenderShadowTask::CullFunctor& cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) :
diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp
index f04427540a..b5819f114f 100644
--- a/libraries/render/src/render/CullTask.cpp
+++ b/libraries/render/src/render/CullTask.cpp
@@ -368,17 +368,19 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
RenderArgs* args = renderContext->args;
const auto& inShapes = inputs.get0();
- const auto& filter = inputs.get1();
- const auto& antiFrustum = inputs.get2();
+ const auto& cullFilter = inputs.get1();
+ const auto& boundsFilter = inputs.get2();
+ const auto& antiFrustum = inputs.get3();
auto& outShapes = outputs.edit0();
auto& outBounds = outputs.edit1();
outShapes.clear();
outBounds = AABox();
- if (!filter.selectsNothing()) {
+ if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) {
auto& details = args->_details.edit(_detailType);
Test test(_cullFunctor, args, details, antiFrustum);
+ auto scene = args->_scene;
for (auto& inItems : inShapes) {
auto key = inItems.first;
@@ -393,16 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
if (antiFrustum == nullptr) {
for (auto& item : inItems.second) {
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) {
- outItems->second.emplace_back(item);
- outBounds += item.bound;
+ const auto shapeKey = scene->getItem(item.id).getKey();
+ if (cullFilter.test(shapeKey)) {
+ outItems->second.emplace_back(item);
+ }
+ if (boundsFilter.test(shapeKey)) {
+ outBounds += item.bound;
+ }
}
}
} else {
for (auto& item : inItems.second) {
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) {
- outItems->second.emplace_back(item);
- outBounds += item.bound;
- }
+ const auto shapeKey = scene->getItem(item.id).getKey();
+ if (cullFilter.test(shapeKey)) {
+ outItems->second.emplace_back(item);
+ }
+ if (boundsFilter.test(shapeKey)) {
+ outBounds += item.bound;
+ }
+ }
}
}
details._rendered += (int)outItems->second.size();
diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h
index 3c5a30de89..47abe8a960 100644
--- a/libraries/render/src/render/CullTask.h
+++ b/libraries/render/src/render/CullTask.h
@@ -110,7 +110,7 @@ namespace render {
class CullShapeBounds {
public:
- using Inputs = render::VaryingSet3;
+ using Inputs = render::VaryingSet4;
using Outputs = render::VaryingSet2;
using JobModel = Job::ModelIO;
diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h
index eb9a628ae3..7f7a3a68b0 100644
--- a/libraries/script-engine/src/AssetScriptingInterface.h
+++ b/libraries/script-engine/src/AssetScriptingInterface.h
@@ -186,36 +186,36 @@ public:
/**jsdoc
* @function Assets.deleteAsset
- * @property {} options
- * @property {} scope
- * @property {} [callback = ""]
+ * @param {} options
+ * @param {} scope
+ * @param {} [callback = ""]
*/
Q_INVOKABLE void deleteAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
/**jsdoc
* @function Assets.resolveAsset
- * @property {} options
- * @property {} scope
- * @property {} [callback = ""]
+ * @param {} options
+ * @param {} scope
+ * @param {} [callback = ""]
*/
Q_INVOKABLE void resolveAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
/**jsdoc
* @function Assets.decompressData
- * @property {} options
- * @property {} scope
- * @property {} [callback = ""]
+ * @param {} options
+ * @param {} scope
+ * @param {} [callback = ""]
*/
Q_INVOKABLE void decompressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
/**jsdoc
* @function Assets.compressData
- * @property {} options
- * @property {} scope
- * @property {} [callback = ""]
+ * @param {} options
+ * @param {} scope
+ * @param {} [callback = ""]
*/
Q_INVOKABLE void compressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
@@ -229,7 +229,7 @@ public:
/**jsdoc
* @function Assets.canWriteCacheValue
- * @property {string} url
+ * @param {string} url
* @returns {boolean}
*/
@@ -237,8 +237,8 @@ public:
/**jsdoc
* @function Assets.getCacheStatus
- * @property {} scope
- * @property {} [callback=undefined]
+ * @param {} scope
+ * @param {} [callback=undefined]
*/
Q_INVOKABLE void getCacheStatus(QScriptValue scope, QScriptValue callback = QScriptValue()) {
@@ -247,38 +247,38 @@ public:
/**jsdoc
* @function Assets.queryCacheMeta
- * @property {} options
- * @property {} scope
- * @property {} [callback=undefined]
+ * @param {} options
+ * @param {} scope
+ * @param {} [callback=undefined]
*/
Q_INVOKABLE void queryCacheMeta(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
/**jsdoc
* @function Assets.loadFromCache
- * @property {} options
- * @property {} scope
- * @property {} [callback=undefined]
+ * @param {} options
+ * @param {} scope
+ * @param {} [callback=undefined]
*/
Q_INVOKABLE void loadFromCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
/**jsdoc
* @function Assets.saveToCache
- * @property {} options
- * @property {} scope
- * @property {} [callback=undefined]
+ * @param {} options
+ * @param {} scope
+ * @param {} [callback=undefined]
*/
Q_INVOKABLE void saveToCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
/**jsdoc
* @function Assets.saveToCache
- * @property {} url
- * @property {} data
- * @property {} metadata
- * @property {} scope
- * @property {} [callback=undefined]
+ * @param {} url
+ * @param {} data
+ * @param {} metadata
+ * @param {} scope
+ * @param {} [callback=undefined]
*/
Q_INVOKABLE void saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& metadata,
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index 714cb91b3f..5a7417cb49 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -36,7 +36,6 @@
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
-const char* StandingHMDSensorMode { "Standing HMD Sensor Mode" }; // this probably shouldn't be hardcoded here
const char* OpenVrThreadedSubmit { "OpenVR Threaded Submit" }; // this probably shouldn't be hardcoded here
PoseData _nextRenderPoseData;
@@ -451,7 +450,6 @@ bool OpenVrDisplayPlugin::internalActivate() {
qDebug() << "OpenVR Threaded submit enabled: " << _threadedSubmit;
_openVrDisplayActive = true;
- _container->setIsOptionChecked(StandingHMDSensorMode, true);
_system->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
// Recommended render target size is per-eye, so double the X size for
// left + right eyes
@@ -507,7 +505,6 @@ void OpenVrDisplayPlugin::internalDeactivate() {
Parent::internalDeactivate();
_openVrDisplayActive = false;
- _container->setIsOptionChecked(StandingHMDSensorMode, false);
if (_system) {
// TODO: Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and
// we don't want ViveControllerManager to consider old values to be valid.
diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js
index 1fce772ec8..1f9a95c819 100644
--- a/scripts/system/controllers/controllerModules/equipEntity.js
+++ b/scripts/system/controllers/controllerModules/equipEntity.js
@@ -6,11 +6,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
- getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
+/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera,
+ getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther,
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
- cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid, unhighlightTargetEntity
+ cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode
*/
Script.include("/~/system/libraries/Xform.js");
@@ -781,7 +781,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
}
};
-
+
var clearGrabActions = function(entityID) {
var actionIDs = Entities.getActionIDs(entityID);
var myGrabTag = "grab-" + MyAvatar.sessionUUID;
@@ -794,7 +794,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
}
}
};
-
+
var onMousePress = function(event) {
if (isInEditMode() || !event.isLeftButton) { // don't consider any left clicks on the entity while in edit
return;
@@ -808,7 +808,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
if (hasEquipData && entityProperties.parentID === EMPTY_PARENT_ID && !entityIsFarGrabbedByOther(entityID)) {
entityProperties.id = entityID;
var rightHandPosition = MyAvatar.getJointPosition("RightHand");
- var leftHandPosition = MyAvatar.getJointPosition("LeftHand");
+ var leftHandPosition = MyAvatar.getJointPosition("LeftHand");
var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition);
var distanceToLeftHand = Vec3.distance(entityProperties.position, leftHandPosition);
var leftHandAvailable = leftEquipEntity.targetEntityID === null;
@@ -828,7 +828,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
};
var onKeyPress = function(event) {
- if (event.text === UNEQUIP_KEY) {
+ if (event.text.toLowerCase() === UNEQUIP_KEY) {
if (rightEquipEntity.targetEntityID) {
rightEquipEntity.endEquipEntity();
}
diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js
index a4e439fe2f..274a4264cd 100644
--- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js
+++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js
@@ -10,7 +10,7 @@
propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues,
TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity,
- HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity
+ HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, unhighlightTargetEntity, Uuid
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
diff --git a/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js b/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js
index 59ce79cfd1..962ae89bb9 100644
--- a/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js
+++ b/scripts/system/controllers/controllerModules/nearGrabHyperLinkEntity.js
@@ -7,12 +7,8 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
- getControllerJointIndex, getGrabbableData, enableDispatcherModule, disableDispatcherModule,
- propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
- Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues,
- TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity,
- HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, AddressManager
+/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
+ makeDispatcherModuleParameters, makeRunningValues, TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, BUMPER_ON_VALUE, AddressManager
*/
(function() {
diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js
index d454d20a02..cf3a9cf14b 100644
--- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js
+++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js
@@ -11,8 +11,7 @@
TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS,
findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH,
HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME,
- TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Selection, DISPATCHER_HOVERING_LIST, Uuid,
- highlightTargetEntity, unhighlightTargetEntity
+ TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, highlightTargetEntity, unhighlightTargetEntity
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@@ -43,11 +42,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
[],
100);
-
- // XXX does handJointIndex change if the avatar changes?
- this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
- this.controllerJointIndex = getControllerJointIndex(this.hand);
-
this.thisHandIsParent = function(props) {
if (!props) {
return false;
@@ -62,8 +56,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
return true;
}
- var controllerJointIndex = this.controllerJointIndex;
- if (props.parentJointIndex === controllerJointIndex) {
+ if (props.parentJointIndex === getControllerJointIndex(this.hand)) {
return true;
}
@@ -102,7 +95,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
// } else {
// handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
// }
- handJointIndex = this.controllerJointIndex;
+ handJointIndex = getControllerJointIndex(this.hand);
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(targetProps.id, "startNearGrab", args);
diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js
index 0f876816b3..368d5c483b 100644
--- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js
+++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js
@@ -9,7 +9,7 @@
/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex,
enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings,
- NEAR_GRAB_RADIUS
+ NEAR_GRAB_RADIUS, HMD, Uuid
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@@ -37,7 +37,6 @@ Script.include("/~/system/libraries/utils.js");
// XXX does handJointIndex change if the avatar changes?
this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
- this.controllerJointIndex = getControllerJointIndex(this.hand);
this.getOtherModule = function() {
return (this.hand === RIGHT_HAND) ? leftNearParentingGrabOverlay : rightNearParentingGrabOverlay;
diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js
index 560da57b20..3bf99ca26a 100644
--- a/scripts/system/controllers/controllerModules/teleport.js
+++ b/scripts/system/controllers/controllerModules/teleport.js
@@ -10,7 +10,7 @@
/* jslint bitwise: true */
-/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex,
+/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3,
HMD, Uuid, AvatarList, Picks, Pointers, PickType
*/
diff --git a/scripts/system/html/entityList.html b/scripts/system/html/entityList.html
index d608ab63e5..7906a3c97f 100644
--- a/scripts/system/html/entityList.html
+++ b/scripts/system/html/entityList.html
@@ -14,7 +14,6 @@
-
diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html
index 8647dca035..8d63261f4c 100644
--- a/scripts/system/html/entityProperties.html
+++ b/scripts/system/html/entityProperties.html
@@ -20,7 +20,6 @@
-
diff --git a/scripts/system/html/gridControls.html b/scripts/system/html/gridControls.html
index c0bd87988d..cd646fed51 100644
--- a/scripts/system/html/gridControls.html
+++ b/scripts/system/html/gridControls.html
@@ -16,7 +16,6 @@
-
diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js
index 625aa26b00..88b3ccbf7c 100644
--- a/scripts/system/html/js/entityList.js
+++ b/scripts/system/html/js/entityList.js
@@ -444,8 +444,6 @@ function loaded() {
augmentSpinButtons();
- setUpKeyboardControl();
-
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js
index 4b6329db44..2194b539ef 100644
--- a/scripts/system/html/js/entityProperties.js
+++ b/scripts/system/html/js/entityProperties.js
@@ -7,7 +7,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global alert, augmentSpinButtons, clearTimeout, console, document, Element, EventBridge,
- HifiEntityUI, JSONEditor, openEventBridge, setUpKeyboardControl, setTimeout, window, _ $ */
+ HifiEntityUI, JSONEditor, openEventBridge, setTimeout, window, _ $ */
var PI = 3.14159265358979;
var DEGREES_TO_RADIANS = PI / 180.0;
@@ -2157,8 +2157,6 @@ function loaded() {
augmentSpinButtons();
- setUpKeyboardControl();
-
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function(event) {
event.preventDefault();
diff --git a/scripts/system/html/js/gridControls.js b/scripts/system/html/js/gridControls.js
index be4271788e..79a169400a 100644
--- a/scripts/system/html/js/gridControls.js
+++ b/scripts/system/html/js/gridControls.js
@@ -129,8 +129,6 @@ function loaded() {
augmentSpinButtons();
- setUpKeyboardControl();
-
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
});
document.addEventListener("keydown", function (keyDown) {
diff --git a/scripts/system/html/js/keyboardControl.js b/scripts/system/html/js/keyboardControl.js
deleted file mode 100644
index 7a8a314c62..0000000000
--- a/scripts/system/html/js/keyboardControl.js
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// keyboardControl.js
-//
-// Created by David Rowe on 28 Sep 2016.
-// Copyright 2016 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
-//
-
-function setUpKeyboardControl() {
-
- var lowerTimer = null;
- var isRaised = false;
- var KEYBOARD_HEIGHT = 200;
-
- function raiseKeyboard() {
- window.isKeyboardRaised = true;
- window.isNumericKeyboard = this.type === "number";
-
- if (lowerTimer !== null) {
- clearTimeout(lowerTimer);
- lowerTimer = null;
- }
-
- EventBridge.emitWebEvent("_RAISE_KEYBOARD" + (this.type === "number" ? "_NUMERIC" : ""));
-
- if (!isRaised) {
- var delta = this.getBoundingClientRect().bottom + 10 - (document.body.clientHeight - KEYBOARD_HEIGHT);
- if (delta > 0) {
- setTimeout(function () {
- document.body.scrollTop += delta;
- }, 500); // Allow time for keyboard to be raised in QML.
- }
- }
-
- isRaised = true;
- }
-
- function doLowerKeyboard() {
- window.isKeyboardRaised = false;
- window.isNumericKeyboard = false;
-
- EventBridge.emitWebEvent("_LOWER_KEYBOARD");
- lowerTimer = null;
- isRaised = false;
- }
-
- function lowerKeyboard() {
- // Delay lowering keyboard a little in case immediately raise it again.
- if (lowerTimer === null) {
- lowerTimer = setTimeout(doLowerKeyboard, 20);
- }
- }
-
- function documentBlur() {
- // Action any pending Lower keyboard event immediately upon leaving document window so that they don't interfere with
- // other Entities Editor tab.
- if (lowerTimer !== null) {
- clearTimeout(lowerTimer);
- doLowerKeyboard();
- }
- }
-
- var inputs = document.querySelectorAll("input[type=text], input[type=password], input[type=number], textarea");
- for (var i = 0, length = inputs.length; i < length; i++) {
- inputs[i].addEventListener("focus", raiseKeyboard);
- inputs[i].addEventListener("blur", lowerKeyboard);
- }
-
- window.addEventListener("blur", documentBlur);
-}
-
diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js
index 71dc5e4273..04ae01bad6 100644
--- a/scripts/system/libraries/controllerDispatcherUtils.js
+++ b/scripts/system/libraries/controllerDispatcherUtils.js
@@ -7,7 +7,7 @@
/* global module, Camera, HMD, MyAvatar, controllerDispatcherPlugins:true, Quat, Vec3, Overlays, Xform,
- Selection,
+ Selection, Uuid,
MSECS_PER_SEC:true , LEFT_HAND:true, RIGHT_HAND:true, FORBIDDEN_GRAB_TYPES:true,
HAPTIC_PULSE_STRENGTH:true, HAPTIC_PULSE_DURATION:true, ZERO_VEC:true, ONE_VEC:true,
DEFAULT_REGISTRATION_POINT:true, INCHES_TO_METERS:true,
@@ -34,11 +34,12 @@
getGrabbableData:true,
entityIsGrabbable:true,
entityIsDistanceGrabbable:true,
+ getControllerJointIndexCacheTime:true,
+ getControllerJointIndexCache:true,
getControllerJointIndex:true,
propsArePhysical:true,
controllerDispatcherPluginsNeedSort:true,
projectOntoXYPlane:true,
- getChildrenProps:true,
projectOntoEntityXYPlane:true,
projectOntoOverlayXYPlane:true,
makeLaserLockInfo:true,
@@ -53,6 +54,8 @@
TEAR_AWAY_COUNT:true,
TEAR_AWAY_CHECK_TIME:true,
distanceBetweenPointAndEntityBoundingBox:true,
+ entityIsEquipped:true,
+ entityIsFarGrabbedByOther:true,
highlightTargetEntity:true,
clearHighlightedEntities:true,
unhighlightTargetEntity:true
@@ -265,20 +268,32 @@ entityIsDistanceGrabbable = function(props) {
return true;
};
-getControllerJointIndex = function (hand) {
- if (HMD.isHandControllerAvailable()) {
- var controllerJointIndex = -1;
- if (Camera.mode === "first person") {
- controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
- "_CONTROLLER_RIGHTHAND" :
- "_CONTROLLER_LEFTHAND");
- } else if (Camera.mode === "third person") {
- controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
- "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" :
- "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
- }
+getControllerJointIndexCacheTime = [0, 0];
+getControllerJointIndexCache = [-1, -1];
- return controllerJointIndex;
+getControllerJointIndex = function (hand) {
+ var GET_CONTROLLERJOINTINDEX_CACHE_REFRESH_TIME = 3000; // msecs
+
+ var now = Date.now();
+ if (now - getControllerJointIndexCacheTime[hand] > GET_CONTROLLERJOINTINDEX_CACHE_REFRESH_TIME) {
+ if (HMD.isHandControllerAvailable()) {
+ var controllerJointIndex = -1;
+ if (Camera.mode === "first person") {
+ controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
+ "_CONTROLLER_RIGHTHAND" :
+ "_CONTROLLER_LEFTHAND");
+ } else if (Camera.mode === "third person") {
+ controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
+ "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" :
+ "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
+ }
+
+ getControllerJointIndexCacheTime[hand] = now;
+ getControllerJointIndexCache[hand] = controllerJointIndex;
+ return controllerJointIndex;
+ }
+ } else {
+ return getControllerJointIndexCache[hand];
}
return -1;
diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js
index c3edee264f..dc4d5aa844 100644
--- a/scripts/system/marketplaces/marketplaces.js
+++ b/scripts/system/marketplaces/marketplaces.js
@@ -19,6 +19,7 @@ var selectionDisplay = null; // for gridTool.js to ignore
Script.include("/~/system/libraries/WebTablet.js");
Script.include("/~/system/libraries/gridTool.js");
+ Script.include("/~/system/libraries/connectionUtils.js");
var METAVERSE_SERVER_URL = Account.metaverseServerURL;
var MARKETPLACE_URL = METAVERSE_SERVER_URL + "/marketplace";
diff --git a/scripts/system/pal.js b/scripts/system/pal.js
index 0a01007ee9..c70c2729f5 100644
--- a/scripts/system/pal.js
+++ b/scripts/system/pal.js
@@ -251,6 +251,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
});
}
break;
+ case 'refresh': // old name for refreshNearby
case 'refreshNearby':
data = {};
ExtendedOverlay.some(function (overlay) { // capture the audio data
@@ -743,10 +744,13 @@ function receiveMessage(channel, messageString, senderID) {
var message = JSON.parse(messageString);
switch (message.method) {
case 'select':
- sendToQml(message); // Accepts objects, not just strings.
+ if (!onPalScreen) {
+ tablet.loadQMLSource(PAL_QML_SOURCE);
+ Script.setTimeout(function () { sendToQml(message); }, 1000);
+ } else {
+ sendToQml(message); // Accepts objects, not just strings.
+ }
break;
- default:
- print('Unrecognized PAL message', messageString);
}
}
diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp
index 0eec03a782..078a66aa6a 100644
--- a/tools/auto-tester/src/Test.cpp
+++ b/tools/auto-tester/src/Test.cpp
@@ -175,40 +175,39 @@ void Test::appendTestResultsToFile(const QString& testResultsFolderPath, TestFai
}
void Test::startTestsEvaluation(const QString& testFolder) {
- QString pathToTestResultsDirectory;
- if (testFolder.isNull()) {
- // Get list of JPEG images in folder, sorted by name
- pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly);
- } else {
- pathToTestResultsDirectory = testFolder;
- }
+ // Get list of JPEG images in folder, sorted by name
+ QString previousSelection = snapshotDirectory;
- if (pathToTestResultsDirectory == QString()) {
+ snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images",
+ previousSelection, QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
+ if (snapshotDirectory == "") {
+ snapshotDirectory = previousSelection;
return;
}
// Quit if test results folder could not be created
- if (!createTestResultsFolderPath(pathToTestResultsDirectory)) {
+ if (!createTestResultsFolderPath(snapshotDirectory)) {
return;
}
// Before any processing - all images are converted to PNGs, as this is the format stored on GitHub
- QStringList sortedSnapshotFilenames = createListOfAll_imagesInDirectory("jpg", pathToTestResultsDirectory);
+ QStringList sortedSnapshotFilenames = createListOfAll_imagesInDirectory("jpg", snapshotDirectory);
foreach(QString filename, sortedSnapshotFilenames) {
QStringList stringParts = filename.split(".");
- copyJPGtoPNG(
- pathToTestResultsDirectory + "/" + stringParts[0] + ".jpg",
- pathToTestResultsDirectory + "/" + stringParts[0] + ".png"
+ copyJPGtoPNG(snapshotDirectory + "/" + stringParts[0] + ".jpg",
+ snapshotDirectory + "/" + stringParts[0] + ".png"
);
- QFile::remove(pathToTestResultsDirectory + "/" + stringParts[0] + ".jpg");
+ QFile::remove(snapshotDirectory + "/" + stringParts[0] + ".jpg");
}
// Create two lists. The first is the test results, the second is the expected images
// The expected images are represented as a URL to enable download from GitHub
// Images that are in the wrong format are ignored.
- QStringList sortedTestResultsFilenames = createListOfAll_imagesInDirectory("png", pathToTestResultsDirectory);
+ QStringList sortedTestResultsFilenames = createListOfAll_imagesInDirectory("png", snapshotDirectory);
QStringList expectedImagesURLs;
resultImagesFullFilenames.clear();
@@ -216,7 +215,7 @@ void Test::startTestsEvaluation(const QString& testFolder) {
expectedImagesFullFilenames.clear();
foreach(QString currentFilename, sortedTestResultsFilenames) {
- QString fullCurrentFilename = pathToTestResultsDirectory + "/" + currentFilename;
+ QString fullCurrentFilename = snapshotDirectory + "/" + currentFilename;
if (isInSnapshotFilenameFormat("png", currentFilename)) {
resultImagesFullFilenames << fullCurrentFilename;
@@ -236,11 +235,11 @@ void Test::startTestsEvaluation(const QString& testFolder) {
QString expectedImageFilename = currentFilename.replace("/", "_").replace(".", "_EI.");
expectedImagesFilenames << expectedImageFilename;
- expectedImagesFullFilenames << pathToTestResultsDirectory + "/" + expectedImageFilename;
+ expectedImagesFullFilenames << snapshotDirectory + "/" + expectedImageFilename;
}
}
- autoTester->downloadImages(expectedImagesURLs, pathToTestResultsDirectory, expectedImagesFilenames);
+ autoTester->downloadImages(expectedImagesURLs, snapshotDirectory, expectedImagesFilenames);
}
void Test::finishTestsEvaluation(bool isRunningFromCommandline, bool interactiveMode, QProgressBar* progressBar) {
@@ -303,25 +302,39 @@ void Test::importTest(QTextStream& textStream, const QString& testPathname) {
// This script will run all text.js scripts in every applicable sub-folder
void Test::createRecursiveScript() {
// Select folder to start recursing from
- QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder that will contain the top level test script", ".", QFileDialog::ShowDirsOnly);
- if (topLevelDirectory == "") {
+ QString previousSelection = testDirectory;
+
+ testDirectory =
+ QFileDialog::getExistingDirectory(nullptr, "Please select folder that will contain the top level test script",
+ previousSelection, QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
+ if (testDirectory == "") {
+ testDirectory = previousSelection;
return;
}
- createRecursiveScript(topLevelDirectory, true);
+ createRecursiveScript(testDirectory, true);
}
// This method creates a `testRecursive.js` script in every sub-folder.
void Test::createAllRecursiveScripts() {
// Select folder to start recursing from
- QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the recursive scripts", ".", QFileDialog::ShowDirsOnly);
- if (topLevelDirectory == "") {
+ QString previousSelection = testDirectory;
+
+ testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the recursive scripts",
+ previousSelection,
+ QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
+ if (testDirectory == "") {
+ testDirectory = previousSelection;
return;
}
- createRecursiveScript(topLevelDirectory, false);
+ createRecursiveScript(testDirectory, false);
- QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
+ QDirIterator it(testDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
while (it.hasNext()) {
QString directory = it.next();
@@ -427,29 +440,42 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact
void Test::createTest() {
// Rename files sequentially, as ExpectedResult_00000.jpeg, ExpectedResult_00001.jpg and so on
// Any existing expected result images will be deleted
- QString imageSourceDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly);
- if (imageSourceDirectory == "") {
+ QString previousSelection = snapshotDirectory;
+
+ snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images",
+ previousSelection,
+ QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
+ if (snapshotDirectory == "") {
+ snapshotDirectory = previousSelection;
return;
}
- QString imageDestinationDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder to save the test images", ".", QFileDialog::ShowDirsOnly);
- if (imageDestinationDirectory == "") {
+ previousSelection = testDirectory;
+
+ QString testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder to save the test images",
+ previousSelection, QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
+ if (testDirectory == "") {
+ testDirectory = previousSelection;
return;
}
- QStringList sortedImageFilenames = createListOfAll_imagesInDirectory("jpg", imageSourceDirectory);
+ QStringList sortedImageFilenames = createListOfAll_imagesInDirectory("jpg", snapshotDirectory);
int i = 1;
const int maxImages = pow(10, NUM_DIGITS);
foreach (QString currentFilename, sortedImageFilenames) {
- QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename;
+ QString fullCurrentFilename = snapshotDirectory + "/" + currentFilename;
if (isInSnapshotFilenameFormat("jpg", currentFilename)) {
if (i >= maxImages) {
QMessageBox::critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported");
exit(-1);
}
QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".png";
- QString fullNewFileName = imageDestinationDirectory + "/" + newFilename;
+ QString fullNewFileName = testDirectory + "/" + newFilename;
try {
copyJPGtoPNG(fullCurrentFilename, fullNewFileName);
@@ -489,31 +515,6 @@ ExtractedText Test::getTestScriptLines(QString testFileName) {
QString regexTestTitle(ws + functionPerformName + "\\(" + quotedString + "\\," + ws + ownPath + "\\," + ws + functionParameter + ws + "{" + ".*");
QRegularExpression lineContainingTitle = QRegularExpression(regexTestTitle);
- // Assert platform checks that test is running on the correct OS
- const QString functionAssertPlatform(ws + "autoTester" + ws + "\\." + ws + "assertPlatform");
- const QString regexAssertPlatform(ws + functionAssertPlatform + ws + "\\(" + ws + quotedString + ".*");
- const QRegularExpression lineAssertPlatform = QRegularExpression(regexAssertPlatform);
-
- // Assert display checks that test is running on the correct display
- const QString functionAssertDisplay(ws + "autoTester" + ws + "\\." + ws + "assertDisplay");
- const QString regexAssertDisplay(ws + functionAssertDisplay + ws + "\\(" + ws + quotedString + ".*");
- const QRegularExpression lineAssertDisplay = QRegularExpression(regexAssertDisplay);
-
- // Assert CPU checks that test is running on the correct type of CPU
- const QString functionAssertCPU(ws + "autoTester" + ws + "\\." + ws + "assertCPU");
- const QString regexAssertCPU(ws + functionAssertCPU + ws + "\\(" + ws + quotedString + ".*");
- const QRegularExpression lineAssertCPU = QRegularExpression(regexAssertCPU);
-
- // Assert GPU checks that test is running on the correct type of GPU
- const QString functionAssertGPU(ws + "autoTester" + ws + "\\." + ws + "assertGPU");
- const QString regexAssertGPU(ws + functionAssertGPU + ws + "\\(" + ws + quotedString + ".*");
- const QRegularExpression lineAssertGPU = QRegularExpression(regexAssertGPU);
-
- // Assert the correct amount of memory
- const QString functionAssertPhysicalMemoryGB(ws + "autoTester" + ws + "\\." + ws + "assertPhysicalMemoryGB");
- const QString regexAssertPhysicalMemoryGB(ws + functionAssertPhysicalMemoryGB + ws + "\\(" + ws + quotedString + ".*");
- const QRegularExpression lineAssertPhysicalMemoryGB = QRegularExpression(regexAssertPhysicalMemoryGB);
-
// Each step is either of the following forms:
// autoTester.addStepSnapshot("Take snapshot"...
@@ -523,7 +524,7 @@ ExtractedText Test::getTestScriptLines(QString testFileName) {
const QRegularExpression lineStepSnapshot = QRegularExpression(regexStepSnapshot);
const QString functionAddStepName(ws + "autoTester" + ws + "\\." + ws + "addStep");
- const QString regexStep(ws + functionAddStepName + ws + "\\(" + ws + quotedString + ws + "\\)" + ".*");
+ const QString regexStep(ws + functionAddStepName + ws + "\\(" + ws + quotedString + ".*");
const QRegularExpression lineStep = QRegularExpression(regexStep);
while (!line.isNull()) {
@@ -531,7 +532,6 @@ ExtractedText Test::getTestScriptLines(QString testFileName) {
if (lineContainingTitle.match(line).hasMatch()) {
QStringList tokens = line.split('"');
relevantTextFromTest.title = tokens[1];
-
} else if (lineStepSnapshot.match(line).hasMatch()) {
QStringList tokens = line.split('"');
QString nameOfStep = tokens[1];
@@ -561,29 +561,43 @@ ExtractedText Test::getTestScriptLines(QString testFileName) {
// The folder selected must contain a script named "test.js", the file produced is named "test.md"
void Test::createMDFile() {
// Folder selection
- QString testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test", ".", QFileDialog::ShowDirsOnly);
+ QString previousSelection = testDirectory;
+
+ testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test", previousSelection,
+ QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
if (testDirectory == "") {
+ testDirectory = previousSelection;
return;
}
createMDFile(testDirectory);
+
+ QMessageBox::information(0, "Success", "MD file has been created");
}
void Test::createAllMDFiles() {
// Select folder to start recursing from
- QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the MD files", ".", QFileDialog::ShowDirsOnly);
- if (topLevelDirectory == "") {
+ QString previousSelection = testDirectory;
+
+ testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the MD files",
+ previousSelection, QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
+ if (testDirectory == "") {
+ testDirectory = previousSelection;
return;
}
// First test if top-level folder has a test.js file
- const QString testPathname{ topLevelDirectory + "/" + TEST_FILENAME };
+ const QString testPathname { testDirectory + "/" + TEST_FILENAME };
QFileInfo fileInfo(testPathname);
if (fileInfo.exists()) {
- createMDFile(topLevelDirectory);
+ createMDFile(testDirectory);
}
- QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
+ QDirIterator it(testDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
while (it.hasNext()) {
QString directory = it.next();
@@ -638,31 +652,33 @@ void Test::createMDFile(const QString& testDirectory) {
stream << "## Steps\n";
stream << "Press space bar to advance step by step\n\n";
- // Note that snapshots of step n are taken in step n+1
- // (this implies that if the LAST step requests a snapshot then this will not work - caveat emptor)
int snapShotIndex { 0 };
for (size_t i = 0; i < testScriptLines.stepList.size(); ++i) {
stream << "### Step " << QString::number(i + 1) << "\n";
stream << "- " << testScriptLines.stepList[i]->text << "\n";
- if ((i + 1 < testScriptLines.stepList.size()) && testScriptLines.stepList[i + 1]->takeSnapshot) {
+ if ((i + 1 < testScriptLines.stepList.size()) && testScriptLines.stepList[i]->takeSnapshot) {
stream << "- .rightJustified(5, '0') << ".png)\n";
++snapShotIndex;
}
}
mdFile.close();
-
- QMessageBox::information(0, "Success", "Test MD file " + mdFilename + " has been created");
}
void Test::createTestsOutline() {
- QString testsRootDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the tests root folder", ".", QFileDialog::ShowDirsOnly);
- if (testsRootDirectory == "") {
+ QString previousSelection = testDirectory;
+
+ testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the tests root folder", previousSelection,
+ QFileDialog::ShowDirsOnly);
+
+ // If user cancelled then restore previous selection and return
+ if (testDirectory == "") {
+ testDirectory = previousSelection;
return;
}
const QString testsOutlineFilename { "testsOutline.md" };
- QString mdFilename(testsRootDirectory + "/" + testsOutlineFilename);
+ QString mdFilename(testDirectory + "/" + testsOutlineFilename);
QFile mdFile(mdFilename);
if (!mdFile.open(QIODevice::WriteOnly)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename);
@@ -676,10 +692,10 @@ void Test::createTestsOutline() {
stream << "Directories with an appended (*) have an automatic test\n\n";
// We need to know our current depth, as this isn't given by QDirIterator
- int rootDepth { testsRootDirectory.count('/') };
+ int rootDepth { testDirectory.count('/') };
// Each test is shown as the folder name linking to the matching GitHub URL, and the path to the associated test.md file
- QDirIterator it(testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
+ QDirIterator it(testDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
while (it.hasNext()) {
QString directory = it.next();
diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h
index bc28d6ad0a..0fb957d309 100644
--- a/tools/auto-tester/src/Test.h
+++ b/tools/auto-tester/src/Test.h
@@ -89,6 +89,12 @@ private:
const int NUM_DIGITS { 5 };
const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" };
+ // We have two directories to work with.
+ // The first is the directory containing the test we are working with
+ // The second contains the snapshots taken for test runs that need to be evaluated
+ QString testDirectory;
+ QString snapshotDirectory;
+
QStringList expectedImagesFilenames;
QStringList expectedImagesFullFilenames;
QStringList resultImagesFullFilenames;