mirror of
https://github.com/servo/servo.git
synced 2025-08-18 11:55:39 +01:00
Update web-platform-tests to revision 9a4d479ed1347eb9184abc70d628a6da2297657a
This commit is contained in:
parent
b6cc0f60a9
commit
effeb278b6
120 changed files with 3731 additions and 298 deletions
|
@ -0,0 +1,117 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "Input sources are re-created when handedness or target ray mode changes";
|
||||
|
||||
let watcherDone = new Event("watcherdone");
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
let eventWatcher = new EventWatcher(t, session, ["watcherdone"]);
|
||||
let eventPromise = eventWatcher.wait_for(["watcherdone"]);
|
||||
|
||||
let inputChangeEvents = 0;
|
||||
let cached_input_source = null;
|
||||
function onInputSourcesChange(event) {
|
||||
t.step(() => {
|
||||
inputChangeEvents++;
|
||||
assert_equals(event.session, session);
|
||||
|
||||
if (inputChangeEvents == 1) {
|
||||
// The first change event should be adding our controller.
|
||||
validateAdded(event.added, 1);
|
||||
validateRemoved(event.removed, 0);
|
||||
cached_input_source = getInputSources()[0];
|
||||
assert_not_equals(cached_input_source, null);
|
||||
assert_equals(cached_input_source.handedness, "none");
|
||||
assert_equals(cached_input_source.targetRayMode, "gaze");
|
||||
} else if (inputChangeEvents == 2) {
|
||||
// The second event should be replacing the controller with one that has
|
||||
// the updated target ray mode.
|
||||
validateInputSourceChange(event, "none", "tracked-pointer");
|
||||
cached_input_source = getInputSources()[0];
|
||||
} else if (inputChangeEvents == 3) {
|
||||
// The third event should be replacing the controller with one that has
|
||||
// the updated handedness.
|
||||
validateInputSourceChange(event, "left", "tracked-pointer");
|
||||
session.dispatchEvent(watcherDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function validateInputSourceChange(event, expected_hand, expected_mode) {
|
||||
validateAdded(event.added, 1);
|
||||
validateRemoved(event.removed, 1);
|
||||
assert_true(event.removed.includes(cached_input_source));
|
||||
assert_false(event.added.includes(cached_input_source));
|
||||
let source = event.added[0];
|
||||
assert_equals(source.handedness, expected_hand);
|
||||
assert_equals(source.targetRayMode, expected_mode);
|
||||
}
|
||||
|
||||
function validateAdded(added, length) {
|
||||
t.step(() => {
|
||||
assert_not_equals(added, null);
|
||||
assert_equals(added.length, length,
|
||||
"Added length matches expectations");
|
||||
|
||||
let currentSources = getInputSources();
|
||||
added.forEach((source) => {
|
||||
assert_true(currentSources.includes(source),
|
||||
"Every element in added should be in the input source list");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function validateRemoved(removed, length) {
|
||||
t.step(() => {
|
||||
assert_not_equals(removed, null);
|
||||
assert_equals(removed.length, length,
|
||||
"Removed length matches expectations");
|
||||
|
||||
let currentSources = getInputSources();
|
||||
removed.forEach((source) => {
|
||||
assert_false(currentSources.includes(source),
|
||||
"No element in removed should be in the input source list");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getInputSources() {
|
||||
return Array.from(session.inputSources.values());
|
||||
}
|
||||
|
||||
session.addEventListener('inputsourceschange', onInputSourcesChange, false);
|
||||
|
||||
// Create a gaze based input source with no handedness that we can change
|
||||
// to validate SameObject properties.
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "none",
|
||||
targetRayMode: "gaze",
|
||||
pointerOrigin: VALID_POINTER_TRANSFORM,
|
||||
profiles: []
|
||||
});
|
||||
|
||||
// Make our input source change after one frame, and wait an additional
|
||||
// frame for that change to propogate.
|
||||
// Two changes made in total.
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
input_source.setTargetRayMode("tracked-pointer");
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
input_source.setHandedness("left");
|
||||
session.requestAnimationFrame((time, xrFrame) => {});
|
||||
});
|
||||
});
|
||||
|
||||
return eventPromise;
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
</script>
|
|
@ -0,0 +1,96 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "Transient input sources fire events in the right order";
|
||||
|
||||
let watcherDone = new Event("watcherdone");
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
let eventWatcher = new EventWatcher(
|
||||
t, session, ["inputsourceschange", "selectstart", "select", "selectend", "watcherdone"]);
|
||||
let eventPromise = eventWatcher.wait_for(
|
||||
["inputsourceschange", "selectstart", "select", "selectend", "inputsourceschange", "watcherdone"]);
|
||||
|
||||
let inputChangeEvents = 0;
|
||||
let cached_input_source = null;
|
||||
function onInputSourcesChange(event) {
|
||||
t.step(() => {
|
||||
inputChangeEvents++;
|
||||
assert_equals(event.session, session);
|
||||
|
||||
// The first change event should be adding our controller.
|
||||
if (inputChangeEvents === 1) {
|
||||
validateAdded(event.added, 1);
|
||||
validateRemoved(event.removed, 0);
|
||||
cached_input_source = session.inputSources[0];
|
||||
assert_not_equals(cached_input_source, null);
|
||||
} else if (inputChangeEvents === 2) {
|
||||
// The second event should be removing our controller.
|
||||
validateAdded(event.added, 0);
|
||||
validateRemoved(event.removed, 1);
|
||||
assert_true(event.removed.includes(cached_input_source));
|
||||
session.dispatchEvent(watcherDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function validateAdded(added, length) {
|
||||
t.step(() => {
|
||||
assert_not_equals(added, null);
|
||||
assert_equals(added.length, length,
|
||||
"Added length matches expectations");
|
||||
|
||||
let currentSources = Array.from(session.inputSources.values());
|
||||
added.forEach((source) => {
|
||||
assert_true(currentSources.includes(source),
|
||||
"Every element in added should be in the input source list");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function validateRemoved(removed, length) {
|
||||
t.step(() => {
|
||||
assert_not_equals(removed, null);
|
||||
assert_equals(removed.length, length,
|
||||
"Removed length matches expectations");
|
||||
|
||||
let currentSources = Array.from(session.inputSources.values());
|
||||
removed.forEach((source) => {
|
||||
assert_false(currentSources.includes(source),
|
||||
"No element in removed should be in the input source list");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
session.addEventListener('inputsourceschange', onInputSourcesChange, false);
|
||||
|
||||
// Create our input source and immediately toggle the primary input so that
|
||||
// it appears as already needing to send a click event when it appears.
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "right",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: VALID_POINTER_TRANSFORM,
|
||||
profiles: [],
|
||||
selectionClicked: true
|
||||
});
|
||||
|
||||
// Make our input source disappear after one frame, and wait an additional
|
||||
// frame for that disappearance to propogate.
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
input_source.disconnect();
|
||||
session.requestAnimationFrame((time, xrFrame) => {});
|
||||
});
|
||||
|
||||
return eventPromise;
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
</script>
|
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "XRInputSources primary input presses properly fires off the "
|
||||
+ "right events";
|
||||
|
||||
let watcherDone = new Event("watcherdone");
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let xrViewerSpace = null;
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
let eventWatcher = new EventWatcher(
|
||||
t, session, ["selectstart", "select", "selectend", "watcherdone"]);
|
||||
let eventPromise = eventWatcher.wait_for(
|
||||
["selectstart", "select", "selectend", "watcherdone"]);
|
||||
|
||||
function tryCallingFrameMethods(frame) {
|
||||
t.step(() => {
|
||||
// Frame is active but not an animation frame, so calling getPose is
|
||||
// allowed while getViewerPose is not.
|
||||
assert_throws('InvalidStateError', () => frame.getViewerPose(currentReferenceSpace));
|
||||
let pose = frame.getPose(xrViewerSpace, currentReferenceSpace);
|
||||
assert_not_equals(pose, null);
|
||||
assert_true(pose instanceof XRPose);
|
||||
assert_false(pose instanceof XRViewerPose);
|
||||
});
|
||||
}
|
||||
|
||||
function onSessionSelectStart(event) {
|
||||
t.step( () => {
|
||||
let input_sources = session.inputSources;
|
||||
assert_equals(event.frame.session, session);
|
||||
assert_equals(event.inputSource, input_sources[0]);
|
||||
tryCallingFrameMethods(event.frame);
|
||||
});
|
||||
}
|
||||
|
||||
function onSessionSelectEnd(event) {
|
||||
t.step( () => {
|
||||
let input_sources = session.inputSources;
|
||||
assert_equals(event.frame.session, session);
|
||||
assert_equals(event.inputSource, input_sources[0]);
|
||||
tryCallingFrameMethods(event.frame);
|
||||
});
|
||||
session.dispatchEvent(watcherDone);
|
||||
}
|
||||
|
||||
function onSessionSelect(event) {
|
||||
t.step( () => {
|
||||
let input_sources = session.inputSources;
|
||||
assert_equals(event.frame.session, session);
|
||||
assert_equals(event.inputSource, input_sources[0]);
|
||||
tryCallingFrameMethods(event.frame);
|
||||
});
|
||||
}
|
||||
|
||||
session.addEventListener("selectstart", onSessionSelectStart, false);
|
||||
session.addEventListener("selectend", onSessionSelectEnd, false);
|
||||
session.addEventListener("select", onSessionSelect, false);
|
||||
|
||||
let input_source =
|
||||
fakeDeviceController.simulateInputSourceConnection(VALID_CONTROLLER);
|
||||
let currentReferenceSpace = null;
|
||||
|
||||
session.requestReferenceSpace('viewer').then(function(viewerSpace) {
|
||||
xrViewerSpace = viewerSpace;
|
||||
|
||||
session.requestReferenceSpace('local').then((referenceSpace) => {
|
||||
currentReferenceSpace = referenceSpace;
|
||||
|
||||
// Press the primary input button and then release it a short time later.
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
input_source.startSelection();
|
||||
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
input_source.endSelection();
|
||||
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
// Need to process one more frame to allow select to propegate.
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return eventPromise;
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "Ensures that an XRInputSources primary input being pressed and "
|
||||
+ "released in the space of a single frame properly fires off the right "
|
||||
+ "events";
|
||||
|
||||
let watcherDone = new Event("watcherdone");
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
let eventWatcher = new EventWatcher(
|
||||
t, session, ["selectstart", "selectend", "select", "watcherdone"]);
|
||||
let eventPromise = eventWatcher.wait_for(
|
||||
["selectstart", "selectend", "select", "watcherdone"]);
|
||||
|
||||
function onSessionSelectStart(event) {
|
||||
t.step( () => {
|
||||
let input_sources = session.inputSources;
|
||||
assert_equals(event.frame.session, session);
|
||||
assert_equals(event.inputSource, input_sources[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function onSessionSelectEnd(event) {
|
||||
t.step( () => {
|
||||
let input_sources = session.inputSources;
|
||||
assert_equals(event.frame.session, session);
|
||||
assert_equals(event.inputSource, input_sources[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function onSessionSelect(event) {
|
||||
t.step( () => {
|
||||
let input_sources = session.inputSources;
|
||||
assert_equals(event.frame.session, session);
|
||||
assert_equals(event.inputSource, input_sources[0]);
|
||||
});
|
||||
session.dispatchEvent(watcherDone);
|
||||
}
|
||||
session.addEventListener("selectstart", onSessionSelectStart, false);
|
||||
session.addEventListener("selectend", onSessionSelectEnd, false);
|
||||
session.addEventListener("select", onSessionSelect, false);
|
||||
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection(VALID_CONTROLLER);
|
||||
|
||||
// Press the primary input button and then release it a short time later.
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
input_source.simulateSelect();
|
||||
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
// Need to process one more frame to allow select to propegate.
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
let testName = "XRInputSources properly communicate their handedness";
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction =
|
||||
(session, fakeDeviceController, t) => new Promise((resolve) => {
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "none",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: VALID_POINTER_TRANSFORM,
|
||||
profiles: []
|
||||
});
|
||||
|
||||
function CheckNone(time, xrFrame) {
|
||||
let source = session.inputSources[0];
|
||||
|
||||
t.step( () => {
|
||||
assert_not_equals(source, null);
|
||||
// Handedness should be "none" by default.
|
||||
assert_equals(source.handedness, "none");
|
||||
});
|
||||
|
||||
input_source.setHandedness("right");
|
||||
|
||||
session.requestAnimationFrame(CheckRight);
|
||||
}
|
||||
|
||||
function CheckRight(time, xrFrame) {
|
||||
let source = session.inputSources[0];
|
||||
|
||||
t.step( () => {
|
||||
assert_not_equals(source, null);
|
||||
// Handedness was set to "right", make sure it propegates.
|
||||
assert_equals(source.handedness, "right");
|
||||
});
|
||||
|
||||
input_source.setHandedness("left");
|
||||
|
||||
session.requestAnimationFrame(CheckLeft);
|
||||
}
|
||||
|
||||
function CheckLeft(time, xrFrame) {
|
||||
let source = session.inputSources[0];
|
||||
|
||||
t.step( () => {
|
||||
assert_not_equals(source, null);
|
||||
// Handedness was set to "left", make sure it propegates.
|
||||
assert_equals(source.handedness, "left");
|
||||
});
|
||||
|
||||
input_source.setHandedness("none");
|
||||
|
||||
session.requestAnimationFrame(CheckNoneAgain);
|
||||
}
|
||||
|
||||
function CheckNoneAgain(time, xrFrame) {
|
||||
let source = session.inputSources[0];
|
||||
|
||||
t.step( () => {
|
||||
assert_not_equals(source, null);
|
||||
// Handedness was set to "none" again, make sure it propegates.
|
||||
assert_equals(source.handedness, "none");
|
||||
});
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
// Handedness only updates during an XR frame.
|
||||
session.requestAnimationFrame(CheckNone);
|
||||
});
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,98 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
let testName = "XRInputSources with a target ray mode of 'tracked-pointer' "
|
||||
+ "properly communicate their poses";
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction =
|
||||
(session, fakeDeviceController, t) => new Promise((resolve) => {
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "right",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: IDENTITY_TRANSFORM,
|
||||
profiles: []
|
||||
});
|
||||
|
||||
// Don't set a grip matrix yet
|
||||
|
||||
// Must have a reference space to get input poses. eye-level doesn't apply
|
||||
// any transforms to the given matrix.
|
||||
session.requestReferenceSpace('local').then( (referenceSpace) => {
|
||||
|
||||
function CheckInvalidGrip(time, xrFrame) {
|
||||
let source = session.inputSources[0];
|
||||
let grip_pose = xrFrame.getPose(source.gripSpace, referenceSpace);
|
||||
|
||||
t.step( () => {
|
||||
// The input pose should be null when no grip matrix is provided.
|
||||
assert_equals(source.targetRayMode, "tracked-pointer");
|
||||
assert_equals(grip_pose, null);
|
||||
});
|
||||
|
||||
input_source.setGripOrigin(VALID_GRIP_TRANSFORM);
|
||||
|
||||
session.requestAnimationFrame(CheckValidGrip);
|
||||
}
|
||||
|
||||
function CheckValidGrip(time, xrFrame) {
|
||||
let source = session.inputSources[0];
|
||||
|
||||
let grip_pose = xrFrame.getPose(source.gripSpace, referenceSpace);
|
||||
|
||||
let input_pose = xrFrame.getPose(source.targetRaySpace, referenceSpace);
|
||||
|
||||
t.step( () => {
|
||||
// When a grip matrix is present but no pointer offset is specified,
|
||||
// the grip and pointer matrices should be the same.
|
||||
assert_not_equals(grip_pose, null);
|
||||
assert_matrix_approx_equals(grip_pose.transform.matrix, VALID_GRIP,
|
||||
FLOAT_EPSILON, "Grip matrix is not equal to input.");
|
||||
assert_matrix_approx_equals(input_pose.transform.matrix,
|
||||
grip_pose.transform.matrix, FLOAT_EPSILON,
|
||||
"Grip matrix is not equal to target ray matrix.");
|
||||
});
|
||||
|
||||
input_source.setPointerOrigin(VALID_POINTER_TRANSFORM);
|
||||
|
||||
session.requestAnimationFrame(CheckValidGripAndPointer);
|
||||
}
|
||||
|
||||
function CheckValidGripAndPointer(time, xrFrame) {
|
||||
let source = session.inputSources[0];
|
||||
|
||||
let grip_pose = xrFrame.getPose(source.gripSpace, referenceSpace);
|
||||
let input_pose = xrFrame.getPose(source.targetRaySpace, referenceSpace);
|
||||
|
||||
t.step( () => {
|
||||
// When a grip matrix and pointer offset are specified,
|
||||
// pointer matrix should be grip matrix multiplied with the pointer
|
||||
// offset.
|
||||
assert_not_equals(grip_pose, null);
|
||||
assert_matrix_approx_equals(grip_pose.transform.matrix, VALID_GRIP,
|
||||
FLOAT_EPSILON, "Grip matrix is not equal to input valid grip.");
|
||||
assert_matrix_approx_equals(input_pose.transform.matrix,
|
||||
VALID_GRIP_WITH_POINTER_OFFSET, FLOAT_EPSILON,
|
||||
"Grip matrix not multipled properly.");
|
||||
});
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
// Can only request input poses in an xr frame.
|
||||
session.requestAnimationFrame(CheckInvalidGrip);
|
||||
});
|
||||
});
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -1,10 +1,11 @@
|
|||
// Utility assert functions.
|
||||
// Relies on resources/testharness.js to be included before this file.
|
||||
// Relies on webxr_test_constants.js to be included before this file.
|
||||
|
||||
// |p1|, |p2| - objects with x, y, z, w components that are floating point numbers
|
||||
// |epsilon| - float specifying precision
|
||||
// |prefix| - string used as a prefix for logging
|
||||
let assert_point_approx_equals = function(p1, p2, epsilon, prefix = "") {
|
||||
let assert_point_approx_equals = function(p1, p2, epsilon = FLOAT_EPSILON, prefix = "") {
|
||||
assert_approx_equals(p1.x, p2.x, epsilon, prefix + "xs must match");
|
||||
assert_approx_equals(p1.y, p2.y, epsilon, prefix + "ys must match");
|
||||
assert_approx_equals(p1.z, p2.z, epsilon, prefix + "zs must match");
|
||||
|
@ -14,7 +15,7 @@ let assert_point_approx_equals = function(p1, p2, epsilon, prefix = "") {
|
|||
// |m1|, |m2| - arrays of floating point numbers
|
||||
// |epsilon| - float specifying precision
|
||||
// |prefix| - string used as a prefix for logging
|
||||
let assert_matrix_approx_equals = function(m1, m2, epsilon, prefix = "") {
|
||||
let assert_matrix_approx_equals = function(m1, m2, epsilon = FLOAT_EPSILON, prefix = "") {
|
||||
assert_equals(m1.length, m2.length, prefix + "Matrix lengths should match");
|
||||
for(var i = 0; i < m1.length; ++i) {
|
||||
assert_approx_equals(m1[i], m2[i], epsilon, prefix + "Component number " + i + " should match");
|
||||
|
@ -24,7 +25,7 @@ let assert_matrix_approx_equals = function(m1, m2, epsilon, prefix = "") {
|
|||
// |r1|, |r2| - XRRay objects
|
||||
// |epsilon| - float specifying precision
|
||||
// |prefix| - string used as a prefix for logging
|
||||
let assert_ray_approx_equals = function(r1, r2, epsilon, prefix = "") {
|
||||
let assert_ray_approx_equals = function(r1, r2, epsilon = FLOAT_EPSILON, prefix = "") {
|
||||
assert_point_approx_equals(r1.origin, r2.origin, epsilon, prefix + "origin:");
|
||||
assert_point_approx_equals(r1.direction, r2.direction, epsilon, prefix + "direction:");
|
||||
assert_matrix_approx_equals(r1.matrix, r2.matrix, epsilon, prefix + "matrix:");
|
||||
|
|
|
@ -50,8 +50,10 @@ const VALID_POINTER_TRANSFORM = {
|
|||
orientation: [0, 0, 0, 1]
|
||||
};
|
||||
|
||||
const VALID_GRIP_WITH_POINTER_OFFSET =
|
||||
[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4, 3, 3, 1];
|
||||
const VALID_GRIP_WITH_POINTER_OFFSET = [1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
4, 3, 3, 1];
|
||||
|
||||
// A Valid Local to floor matrix/transform for when we don't care about specific
|
||||
// values. Note that these should be identical, just different representations.
|
||||
|
|
|
@ -121,7 +121,7 @@ let loadChromiumResources = Promise.resolve().then(() => {
|
|||
'/gen/mojo/public/mojom/base/time.mojom.js',
|
||||
'/gen/gpu/ipc/common/mailbox_holder.mojom.js',
|
||||
'/gen/gpu/ipc/common/sync_token.mojom.js',
|
||||
'/gen/ui/display/mojo/display.mojom.js',
|
||||
'/gen/ui/display/mojom/display.mojom.js',
|
||||
'/gen/ui/gfx/geometry/mojo/geometry.mojom.js',
|
||||
'/gen/ui/gfx/mojo/gpu_fence_handle.mojom.js',
|
||||
'/gen/ui/gfx/mojo/transform.mojom.js',
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
// Utility assert functions.
|
||||
// Relies on resources/testharness.js to be included before this file.
|
||||
|
||||
// |p1|, |p2| - objects with x, y, z, w components that are floating point numbers
|
||||
// |epsilon| - float specifying precision
|
||||
// |prefix| - string used as a prefix for logging
|
||||
let assert_point_approx_equals = function(p1, p2, epsilon, prefix = "") {
|
||||
assert_approx_equals(p1.x, p2.x, epsilon, prefix + "xs must match");
|
||||
assert_approx_equals(p1.y, p2.y, epsilon, prefix + "ys must match");
|
||||
assert_approx_equals(p1.z, p2.z, epsilon, prefix + "zs must match");
|
||||
assert_approx_equals(p1.w, p2.w, epsilon, prefix + "ws must match");
|
||||
};
|
||||
|
||||
// |m1|, |m2| - arrays of floating point numbers
|
||||
// |epsilon| - float specifying precision
|
||||
// |prefix| - string used as a prefix for logging
|
||||
let assert_matrix_approx_equals = function(m1, m2, epsilon, prefix = "") {
|
||||
assert_equals(m1.length, m2.length, prefix + "Matrix lengths should match");
|
||||
for(var i = 0; i < m1.length; ++i) {
|
||||
assert_approx_equals(m1[i], m2[i], epsilon, prefix + "Component number " + i + " should match");
|
||||
}
|
||||
}
|
||||
|
||||
// |r1|, |r2| - XRRay objects
|
||||
// |epsilon| - float specifying precision
|
||||
// |prefix| - string used as a prefix for logging
|
||||
let assert_ray_approx_equals = function(r1, r2, epsilon, prefix = "") {
|
||||
assert_point_approx_equals(r1.origin, r2.origin, epsilon, prefix + "origin:");
|
||||
assert_point_approx_equals(r1.direction, r2.direction, epsilon, prefix + "direction:");
|
||||
assert_matrix_approx_equals(r1.matrix, r2.matrix, epsilon, prefix + "matrix:");
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/xr-test-asserts.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas></canvas>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/xr-test-asserts.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas></canvas>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
let testName = "XRInputSources can be properly added and removed from the "
|
||||
+ "session";
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction = (session, fakeDeviceController, t) => new Promise((resolve) => {
|
||||
let input_sources = session.inputSources;
|
||||
|
||||
t.step( () => {
|
||||
assert_equals(input_sources.length, 0);
|
||||
});
|
||||
|
||||
let input_source_1 = fakeDeviceController.simulateInputSourceConnection(RIGHT_CONTROLLER);
|
||||
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
let input_sources = session.inputSources;
|
||||
|
||||
t.step( () => {
|
||||
assert_equals(input_sources.length, 1);
|
||||
assert_equals(input_sources[0].targetRayMode, "tracked-pointer");
|
||||
assert_equals(input_sources[0].handedness, "right");
|
||||
});
|
||||
|
||||
let input_source_2 = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "none",
|
||||
targetRayMode: "gaze",
|
||||
pointerOrigin: VALID_POINTER_TRANSFORM,
|
||||
profiles: []
|
||||
});
|
||||
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
let input_sources = session.inputSources;
|
||||
|
||||
t.step( () => {
|
||||
assert_equals(input_sources.length, 2);
|
||||
assert_equals(input_sources[1].targetRayMode, "gaze");
|
||||
assert_equals(input_sources[1].handedness, "none");
|
||||
});
|
||||
|
||||
fakeDeviceController.removeInputSource(input_source_1);
|
||||
|
||||
session.requestAnimationFrame((time, xrFrame) => {
|
||||
let input_sources = session.inputSources;
|
||||
|
||||
t.step( () => {
|
||||
assert_equals(input_sources.length, 1);
|
||||
assert_equals(input_sources[0].targetRayMode, "gaze");
|
||||
assert_equals(input_sources[0].handedness, "none");
|
||||
});
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,152 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "WebXR InputSource's gamepad gets disconnected when the input source is removed";
|
||||
|
||||
let watcherDone = new Event("watcherdone");
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
let eventWatcher = new EventWatcher(t, session, ["watcherdone"]);
|
||||
let eventPromise = eventWatcher.wait_for(["watcherdone"]);
|
||||
|
||||
let inputChangeEvents = 0;
|
||||
let cached_input_source = null;
|
||||
function onInputSourcesChange(event) {
|
||||
t.step(() => {
|
||||
inputChangeEvents++;
|
||||
|
||||
// The first change event should be adding our controller/gamepad.
|
||||
if (inputChangeEvents === 1) {
|
||||
// We should have one input source
|
||||
assert_equals(session.inputSources.length, 1,
|
||||
"should initially have an input source");
|
||||
assertGamepadConnected();
|
||||
} else if (inputChangeEvents === 2) {
|
||||
// The second event should be disconnecting our gamepad, we should still
|
||||
// have an input source.
|
||||
assert_equals(session.inputSources.length, 1,
|
||||
"removing the gamepad shouldn't remove the input source");
|
||||
// However, disconnecting the gamepad from the input source should cause
|
||||
// the input source to be re-created. Verify this.
|
||||
assertInputSourceRecreated(event);
|
||||
assertGamepadDisconnected();
|
||||
cached_input_source = session.inputSources[0];
|
||||
} else if (inputChangeEvents === 3) {
|
||||
assert_equals(session.inputSources.length, 1,
|
||||
"re-adding the gamepad shouldn't add an extra input source");
|
||||
// The third event should be reconnecting our gamepad, we should still
|
||||
// have an input source. However, it should have been re-created.
|
||||
assertInputSourceRecreated(event);
|
||||
assertGamepadConnected();
|
||||
} else if (inputChangeEvents === 4) {
|
||||
// The fourth event should be disconnecting our gamepad, we should no
|
||||
// longer have an input source.
|
||||
assert_equals(session.inputSources.length, 0,
|
||||
"input source should have been disconnected");
|
||||
assertGamepadDisconnected();
|
||||
} else if (inputChangeEvents === 5) {
|
||||
// The fifth event should be re-connecting our gamepad to prep for
|
||||
// ending the session.
|
||||
assert_equals(session.inputSources.length, 1,
|
||||
"input source should have been re-connected");
|
||||
assertGamepadConnected();
|
||||
session.dispatchEvent(watcherDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function assertInputSourceRecreated(event) {
|
||||
assert_equals(event.added.length, 1);
|
||||
assert_equals(event.removed.length, 1);
|
||||
assert_equals(session.inputSources[0], event.added[0]);
|
||||
assert_equals(cached_input_source, event.removed[0]);
|
||||
}
|
||||
|
||||
function assertGamepadConnected() {
|
||||
cached_input_source = session.inputSources[0];
|
||||
assert_not_equals(cached_input_source, null,
|
||||
"Expect to get a cached_input_source, iteration: " + inputChangeEvents);
|
||||
assert_not_equals(cached_input_source.gamepad, null,
|
||||
"Expect to have a gamepad, iteration: " + inputChangeEvents);
|
||||
assert_true(cached_input_source.gamepad.connected,
|
||||
"Expect the gamepad to be connected, iteration: " + inputChangeEvents);
|
||||
}
|
||||
|
||||
function assertGamepadDisconnected() {
|
||||
assert_not_equals(cached_input_source, null,
|
||||
"Expect to have a cached_input_source, iteration: " + inputChangeEvents);
|
||||
assert_not_equals(cached_input_source.gamepad, null,
|
||||
"Expect to have a gamepad on cached_input_source, iteration: " + inputChangeEvents);
|
||||
assert_false(cached_input_source.gamepad.connected,
|
||||
"Expect cached gamepad to be disconnected, iteration: " + inputChangeEvents);
|
||||
}
|
||||
|
||||
session.addEventListener('inputsourceschange', onInputSourcesChange, false);
|
||||
|
||||
// A set of supported buttons which should cause the runtime to treat the
|
||||
// controller as supporting a gamepad.
|
||||
let gamepadButtons = [
|
||||
{
|
||||
buttonType: 'grip',
|
||||
pressed: false,
|
||||
touched: false,
|
||||
pressedValue: 0
|
||||
},
|
||||
{
|
||||
buttonType: 'touchpad',
|
||||
pressed: false,
|
||||
touched: false,
|
||||
pressedValue: 0
|
||||
}
|
||||
];
|
||||
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "right",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: VALID_POINTER_TRANSFORM,
|
||||
profiles: [],
|
||||
supportedButtons: gamepadButtons
|
||||
});
|
||||
|
||||
// Input events need one frame to propagate, so this does (in order and running
|
||||
// a rAF after each step:
|
||||
// 1. Disconnect the gamepad (so we can verify that the gamepad is disconnected)
|
||||
// 2. Reconnect the gamepad (so we can set up to disconnect the controller)
|
||||
// 3. Disconnect the controller (so we can verify that it's gamepad gets disconnected).
|
||||
// 4. Adds the controller back (so we can test the end Session)
|
||||
// 5. Waits for all of the input events to finish propagating, then ends the
|
||||
// session, at which point the controller should be disconnected.
|
||||
return new Promise((resolve) => {
|
||||
session.requestAnimationFrame(() => {
|
||||
input_source.setSupportedButtons([]);
|
||||
session.requestAnimationFrame(() => {
|
||||
input_source.setSupportedButtons(gamepadButtons);
|
||||
session.requestAnimationFrame(() => {
|
||||
input_source.disconnect();
|
||||
session.requestAnimationFrame(() => {
|
||||
input_source.reconnect();
|
||||
session.requestAnimationFrame(() => {
|
||||
eventPromise.then(() => {
|
||||
session.end().then(() => {
|
||||
assertGamepadDisconnected();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
</script>
|
|
@ -0,0 +1,124 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "WebXR InputSource's gamepad properly registers input";
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
|
||||
// There should only be one input source change event, which is from adding
|
||||
// the input source at the start of the test.
|
||||
let inputChangeEvents = 0;
|
||||
function onInputSourcesChange(event) {
|
||||
assert_equals(inputChangeEvents, 0,
|
||||
"Gamepad button or input axis value changes should not fire an input source change event.");
|
||||
inputChangeEvents++;
|
||||
}
|
||||
|
||||
session.addEventListener('inputsourceschange', onInputSourcesChange, false);
|
||||
|
||||
// Create our input source and immediately toggle the primary input so that
|
||||
// it appears as already needing to send a click event when it appears.
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "right",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: VALID_POINTER_TRANSFORM,
|
||||
profiles: [],
|
||||
supportedButtons: [
|
||||
{
|
||||
buttonType: 'grip',
|
||||
pressed: false,
|
||||
touched: false,
|
||||
pressedValue: 0
|
||||
},
|
||||
{
|
||||
buttonType: 'touchpad',
|
||||
pressed: false,
|
||||
touched: false,
|
||||
pressedValue: 0
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
let cached_input_source = null;
|
||||
let cached_gamepad = null;
|
||||
|
||||
function assertSameObjects() {
|
||||
assert_equals(session.inputSources[0], cached_input_source);
|
||||
assert_equals(cached_input_source.gamepad, cached_gamepad);
|
||||
}
|
||||
|
||||
// Input events and gamepad state changes (button presses, axis movements)
|
||||
// need one frame to propagate, so this does (in order and running a rAF after
|
||||
// each step):
|
||||
// 1) Press the mock gamepad's button (so we can verify the button press makes
|
||||
// its way to the WebXR gamepad and that it does not fire an
|
||||
// inputsourceschange event).
|
||||
// 2) Update the mock gamepad's input axes values (so we can verify the
|
||||
// updated values make their way to the WebXR gamepad and that it does not
|
||||
// fire an inputsourceschange event).
|
||||
return new Promise((resolve) => {
|
||||
session.requestAnimationFrame(() => {
|
||||
// Make sure the exposed gamepad has the number of buttons and axes we
|
||||
// requested.
|
||||
// 3 Buttons: trigger, grip, touchpad
|
||||
// 2 Axes from the touchpad
|
||||
cached_input_source = session.inputSources[0];
|
||||
cached_gamepad = cached_input_source.gamepad;
|
||||
t.step(() => {
|
||||
assert_equals(cached_gamepad.buttons.length, 3);
|
||||
assert_equals(cached_gamepad.axes.length, 2);
|
||||
// Initially, the button should not be pressed and the axes values should
|
||||
// be set to 0.
|
||||
assert_false(cached_gamepad.buttons[1].pressed);
|
||||
assert_equals(cached_gamepad.axes[0], 0);
|
||||
assert_equals(cached_gamepad.axes[1], 0);
|
||||
}, "Verify initial state");
|
||||
// Simulate button press.
|
||||
input_source.updateButtonState({
|
||||
buttonType: 'grip',
|
||||
pressed: true,
|
||||
touched: true,
|
||||
value: 1.0
|
||||
});
|
||||
session.requestAnimationFrame(() => {
|
||||
t.step(() => {
|
||||
assertSameObjects();
|
||||
assert_true(cached_gamepad.buttons[1].pressed);
|
||||
}, "Gamepad is updated in place when a button is pressed");
|
||||
|
||||
// Simulate input axes movement.
|
||||
input_source.updateButtonState({
|
||||
buttonType: 'touchpad',
|
||||
pressed: false,
|
||||
touched: true,
|
||||
value: 0,
|
||||
xValue: 0.5,
|
||||
yValue: -0.5
|
||||
});
|
||||
session.requestAnimationFrame(() => {
|
||||
// Input source and gamepad should not be re-created. They should be
|
||||
// updated in place when input axes values change.
|
||||
t.step(() => {
|
||||
assertSameObjects();
|
||||
assert_equals(cached_gamepad.axes[0], 0.5);
|
||||
assert_equals(cached_gamepad.axes[1], -0.5);
|
||||
// Button that was pressed last frame should still be pressed.
|
||||
assert_true(cached_gamepad.buttons[1].pressed);
|
||||
}, "Gamepad is updated in place when axes values change");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
</script>
|
|
@ -0,0 +1,133 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "Updating XRReferenceSpace origin offset updates view and input matrices.";
|
||||
|
||||
const VIEW_OFFSET_WITH_ROTATION = {
|
||||
position: [4, 3, 2],
|
||||
orientation: [0, -0.71, 0, 0.71 ]
|
||||
};
|
||||
|
||||
const VIEWS_WITH_OFFSET = [{
|
||||
eye:"left",
|
||||
projectionMatrix: VALID_PROJECTION_MATRIX,
|
||||
viewOffset: VIEW_OFFSET_WITH_ROTATION,
|
||||
resolution: VALID_RESOLUTION
|
||||
}, {
|
||||
eye:"right",
|
||||
projectionMatrix: VALID_PROJECTION_MATRIX,
|
||||
viewOffset: VIEW_OFFSET_WITH_ROTATION,
|
||||
resolution: VALID_RESOLUTION
|
||||
}];
|
||||
|
||||
let fakeDeviceInitParams = {
|
||||
supportsImmersive: true,
|
||||
viewerOrigin: VALID_POSE_TRANSFORM,
|
||||
views: VIEWS_WITH_OFFSET
|
||||
};
|
||||
|
||||
let testFunction =
|
||||
(session, fakeDeviceController, t) => new Promise((resolve) => {
|
||||
const GRIP_TRANSFORM_WITH_ROTATION = {
|
||||
position: [1, 2, 3],
|
||||
orientation: [0, 0.7071, 0, 0.7071]
|
||||
};
|
||||
|
||||
const POINTER_TRANSFORM_WITH_ROTATION = {
|
||||
position: [2, 0, 1],
|
||||
orientation: [0, 0, 0.7071, 0.7071]
|
||||
};
|
||||
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "right",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: POINTER_TRANSFORM_WITH_ROTATION,
|
||||
gripOrigin: GRIP_TRANSFORM_WITH_ROTATION
|
||||
});
|
||||
|
||||
const RADIANS_90D = Math.PI / 2;
|
||||
|
||||
const EXPECTED_VIEW_MATRIX_1 = [0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, -5, -4, -3, 1];
|
||||
const EXPECTED_GRIP_MATRIX_1 = [0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 2, 3, 1];
|
||||
const EXPECTED_RAY_MATRIX_1 = [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 2, 2, 1, 1];
|
||||
|
||||
const EXPECTED_VIEW_MATRIX_2 = [0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, -8, 1, 7, 1];
|
||||
const EXPECTED_GRIP_MATRIX_2 = [0, -1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, -9, -2, -5, 1];
|
||||
const EXPECTED_RAY_MATRIX_2 = [0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, -8, -4, -5, 1];
|
||||
|
||||
const EXPECTED_VIEW_MATRIX_3 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -8, 3, 12, 1];
|
||||
const EXPECTED_GRIP_MATRIX_3 = [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 5, -4, -14, 1];
|
||||
const EXPECTED_RAY_MATRIX_3 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5, -6, -13, 1];
|
||||
|
||||
// Must have a reference space to get input poses. eye-level doesn't apply
|
||||
// any transforms to the given matrix.
|
||||
session.requestReferenceSpace('local').then( (referenceSpace) => {
|
||||
function OnFrame(time, frame) {
|
||||
let source = session.inputSources[0];
|
||||
|
||||
function CheckState(referenceSpace, expected_view_matrix, expected_grip_matrix, expected_ray_matrix) {
|
||||
t.step(() => {
|
||||
let pose = frame.getViewerPose(referenceSpace);
|
||||
let grip_pose = frame.getPose(source.gripSpace, referenceSpace);
|
||||
let input_pose = frame.getPose(source.targetRaySpace, referenceSpace);
|
||||
|
||||
let view_matrix = pose.views[0].transform.inverse.matrix;
|
||||
let grip_matrix = grip_pose.transform.matrix;
|
||||
let ray_matrix = input_pose.transform.matrix;
|
||||
|
||||
assert_matrix_approx_equals(view_matrix, expected_view_matrix);
|
||||
assert_matrix_approx_equals(grip_matrix, expected_grip_matrix);
|
||||
assert_matrix_approx_equals(ray_matrix, expected_ray_matrix);
|
||||
});
|
||||
}
|
||||
|
||||
CheckState(referenceSpace, EXPECTED_VIEW_MATRIX_1, EXPECTED_GRIP_MATRIX_1, EXPECTED_RAY_MATRIX_1);
|
||||
|
||||
const new_position1 = {
|
||||
x: 10,
|
||||
y: -3,
|
||||
z: 5,
|
||||
};
|
||||
const new_orientation1 = {
|
||||
x: Math.sin(RADIANS_90D / 2),
|
||||
y: 0,
|
||||
z: 0,
|
||||
w: Math.cos(RADIANS_90D / 2),
|
||||
};
|
||||
|
||||
referenceSpace = referenceSpace.getOffsetReferenceSpace(new XRRigidTransform(new_position1, new_orientation1));
|
||||
CheckState(referenceSpace, EXPECTED_VIEW_MATRIX_2, EXPECTED_GRIP_MATRIX_2, EXPECTED_RAY_MATRIX_2);
|
||||
|
||||
const new_position2 = {
|
||||
x: 5,
|
||||
y: 2,
|
||||
z: 0,
|
||||
};
|
||||
const new_orientation2 = {
|
||||
x: 0,
|
||||
y: Math.sin(RADIANS_90D / 2),
|
||||
z: 0,
|
||||
w: Math.cos(RADIANS_90D / 2),
|
||||
};
|
||||
|
||||
referenceSpace = referenceSpace.getOffsetReferenceSpace(new XRRigidTransform(new_position2, new_orientation2));
|
||||
CheckState(referenceSpace, EXPECTED_VIEW_MATRIX_3, EXPECTED_GRIP_MATRIX_3, EXPECTED_RAY_MATRIX_3);
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
// Can only request input poses in an xr frame.
|
||||
session.requestAnimationFrame(OnFrame);
|
||||
});
|
||||
});
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,243 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
const testName = "Updating XRBoundedReferenceSpace origin offset updates view, input matrices, and bounds geometry.";
|
||||
|
||||
const INITIAL_VIEW_OFFSET = {
|
||||
position: [1, 2, 3],
|
||||
orientation: [0,0,0,1]
|
||||
};
|
||||
|
||||
const VIEWS_WITH_OFFSET = [{
|
||||
eye:"left",
|
||||
projectionMatrix: VALID_PROJECTION_MATRIX,
|
||||
viewOffset: INITIAL_VIEW_OFFSET,
|
||||
resolution: VALID_RESOLUTION
|
||||
}, {
|
||||
eye:"right",
|
||||
projectionMatrix: VALID_PROJECTION_MATRIX,
|
||||
viewOffset: INITIAL_VIEW_OFFSET,
|
||||
resolution: VALID_RESOLUTION
|
||||
}];
|
||||
|
||||
const FLOOR_TRANSFORM = {
|
||||
position: [0.1, 0.2, 0.3],
|
||||
orientation: [0, 0, 0, 1]
|
||||
};
|
||||
|
||||
const fakeDeviceInitParams = {
|
||||
supportsImmersive: true,
|
||||
views: VIEWS_WITH_OFFSET,
|
||||
viewerOrigin: IDENTITY_TRANSFORM,
|
||||
floorOrigin: FLOOR_TRANSFORM,
|
||||
boundsCoordinates: [
|
||||
{ x: 1, z: -1.5 },
|
||||
{ x: 1, z: 1.5 },
|
||||
{ x: -1, z: 1.5 },
|
||||
{ x: -1, z: -1.5 }
|
||||
]
|
||||
};
|
||||
|
||||
function testFunction(session, fakeDeviceController, t) {
|
||||
const INITIAL_GRIP_TRANSFORM = {
|
||||
position: [1, 2, 3],
|
||||
orientation: [0, 0, 0, 1]
|
||||
};
|
||||
|
||||
const LOCAL_POINTER_TRANSFORM = {
|
||||
position: [0.01, 0.02, 0.03],
|
||||
orientation: [0, 0, 0, 1]
|
||||
}
|
||||
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "right",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: LOCAL_POINTER_TRANSFORM,
|
||||
gripOrigin: INITIAL_GRIP_TRANSFORM
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
session.requestAnimationFrame((time, frame) => {
|
||||
let input_source = session.inputSources[0];
|
||||
|
||||
session.requestReferenceSpace('bounded-floor').then((referenceSpace) => {
|
||||
|
||||
function CheckState(
|
||||
reference_space,
|
||||
expected_view_matrix,
|
||||
expected_grip_matrix,
|
||||
expected_ray_matrix,
|
||||
expected_bounds_geometry
|
||||
) {
|
||||
t.step(() => {
|
||||
let pose = frame.getViewerPose(reference_space);
|
||||
let grip_pose = frame.getPose(input_source.gripSpace, reference_space);
|
||||
let input_pose = frame.getPose(input_source.targetRaySpace, reference_space);
|
||||
|
||||
let view_matrix = pose.views[0].transform.inverse.matrix;
|
||||
let grip_matrix = grip_pose.transform.matrix;
|
||||
let ray_matrix = input_pose.transform.matrix;
|
||||
|
||||
assert_matrix_approx_equals(expected_view_matrix, view_matrix);
|
||||
assert_matrix_approx_equals(expected_grip_matrix, grip_matrix);
|
||||
assert_matrix_approx_equals(expected_ray_matrix, ray_matrix);
|
||||
|
||||
assert_equals(reference_space.boundsGeometry.length, expected_bounds_geometry.length);
|
||||
for (var i = 0; i < reference_space.boundsGeometry.length; ++i) {
|
||||
assert_point_approx_equals(reference_space.boundsGeometry[i], expected_bounds_geometry[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const EXPECTED_VIEW_MATRIX_1 = [
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
-1.1, -2.2, -3.3, 1,
|
||||
];
|
||||
const EXPECTED_GRIP_MATRIX_1 = [
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
1.1, 2.2, 3.3, 1,
|
||||
];
|
||||
const EXPECTED_RAY_MATRIX_1 = [
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
1.11, 2.22, 3.33, 1,
|
||||
];
|
||||
|
||||
const EXPECTED_BOUNDS_GEOMETRY_1 = [
|
||||
{x: 1, y: 0, z: -1.5, w: 1},
|
||||
{x: 1, y: 0, z: 1.5, w: 1},
|
||||
{x: -1, y: 0, z: 1.5, w: 1},
|
||||
{x: -1, y: 0, z: -1.5, w: 1},
|
||||
];
|
||||
|
||||
// Check state after initialization
|
||||
CheckState(
|
||||
referenceSpace,
|
||||
EXPECTED_VIEW_MATRIX_1,
|
||||
EXPECTED_GRIP_MATRIX_1,
|
||||
EXPECTED_RAY_MATRIX_1,
|
||||
EXPECTED_BOUNDS_GEOMETRY_1
|
||||
);
|
||||
|
||||
const RADIANS_90D = Math.PI / 2;
|
||||
|
||||
// Perform arbitrary transformation to reference space originOffset
|
||||
const new_position1 = {
|
||||
x: 10, // Translate 10 units along the x-axis
|
||||
y: -3, // Translate -3 units along the y-axis
|
||||
z: 5, // Translate 5 units along the z-axis
|
||||
};
|
||||
const new_orientation1 = {
|
||||
x: Math.sin(RADIANS_90D / 2), // Rotate 90 degrees around the x-axis
|
||||
y: 0,
|
||||
z: 0,
|
||||
w: Math.cos(RADIANS_90D / 2),
|
||||
};
|
||||
referenceSpace = referenceSpace.getOffsetReferenceSpace(new XRRigidTransform(new_position1, new_orientation1));
|
||||
|
||||
const EXPECTED_VIEW_MATRIX_2 = [
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, -1, 0, 0,
|
||||
8.9, -5.2, 1.7, 1,
|
||||
];
|
||||
const EXPECTED_GRIP_MATRIX_2 = [
|
||||
1, 0, 0, 0,
|
||||
0, 0, -1, 0,
|
||||
0, 1, 0, 0,
|
||||
-8.9, -1.7, -5.2, 1,
|
||||
];
|
||||
const EXPECTED_RAY_MATRIX_2 = [
|
||||
1, 0, 0, 0,
|
||||
0, 0, -1, 0,
|
||||
0, 1, 0, 0,
|
||||
-8.89, -1.67, -5.22, 1,
|
||||
];
|
||||
|
||||
const EXPECTED_BOUNDS_GEOMETRY_2 = [
|
||||
{x: -9, y: -6.5, z: -3, w: 1},
|
||||
{x: -9, y: -3.5, z: -3, w: 1},
|
||||
{x: -11, y: -3.5, z: -3, w: 1},
|
||||
{x: -11, y: -6.5, z: -3, w: 1},
|
||||
];
|
||||
|
||||
// Check state after transformation
|
||||
CheckState(
|
||||
referenceSpace,
|
||||
EXPECTED_VIEW_MATRIX_2,
|
||||
EXPECTED_GRIP_MATRIX_2,
|
||||
EXPECTED_RAY_MATRIX_2,
|
||||
EXPECTED_BOUNDS_GEOMETRY_2
|
||||
);
|
||||
|
||||
// Perform arbitrary transformation to reference space originOffset
|
||||
const new_position2 = {
|
||||
x: 5, // Translate 5 units along the x-axis
|
||||
y: 2, // Translate 2 units along the y-axis
|
||||
z: 0,
|
||||
};
|
||||
const new_orientation2 = {
|
||||
x: 0,
|
||||
y: Math.sin(RADIANS_90D / 2), // Rotate 90 degrees about the y-axis
|
||||
z: 0,
|
||||
w: Math.cos(RADIANS_90D / 2),
|
||||
};
|
||||
referenceSpace = referenceSpace.getOffsetReferenceSpace(new XRRigidTransform(new_position2, new_orientation2));
|
||||
|
||||
const EXPECTED_VIEW_MATRIX_3 = [
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
13.9, -5.2, 3.7, 1,
|
||||
];
|
||||
const EXPECTED_GRIP_MATRIX_3 = [
|
||||
0, 0, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
5.2, -3.7, -13.9, 1,
|
||||
];
|
||||
const EXPECTED_RAY_MATRIX_3 = [
|
||||
0, 0, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
5.22, -3.67, -13.89, 1,
|
||||
];
|
||||
|
||||
const EXPECTED_BOUNDS_GEOMETRY_3 = [
|
||||
{x: 3, y: -8.5, z: -14, w: 1},
|
||||
{x: 3, y: -5.5, z: -14, w: 1},
|
||||
{x: 3, y: -5.5, z: -16, w: 1},
|
||||
{x: 3, y: -8.5, z: -16, w: 1},
|
||||
];
|
||||
|
||||
// Check state after transformation
|
||||
CheckState(
|
||||
referenceSpace,
|
||||
EXPECTED_VIEW_MATRIX_3,
|
||||
EXPECTED_GRIP_MATRIX_3,
|
||||
EXPECTED_RAY_MATRIX_3,
|
||||
EXPECTED_BOUNDS_GEOMETRY_3
|
||||
);
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<canvas id="webgl-canvas"></canvas>
|
||||
|
||||
<script>
|
||||
let testName = "Calling end during an input callback stops processing at the right time";
|
||||
|
||||
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
||||
|
||||
function requestImmersiveSession() {
|
||||
return new Promise((resolve, reject) => {
|
||||
navigator.xr.test.simulateUserActivation(() => {
|
||||
navigator.xr.requestSession('immersive-vr').then((session) => {
|
||||
resolve(session);
|
||||
}, (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
|
||||
// helper method to send a click and then request a dummy animation frame to
|
||||
// ensure that the click propagates. We're doing everything in these tests
|
||||
// from event watchers, we just need to trigger the add/click to make the
|
||||
// event listeners callback.
|
||||
function sendClick(session) {
|
||||
let input_source = fakeDeviceController.simulateInputSourceConnection({
|
||||
handedness: "right",
|
||||
targetRayMode: "tracked-pointer",
|
||||
pointerOrigin: VALID_POINTER_TRANSFORM,
|
||||
profiles: [],
|
||||
selectionClicked: true
|
||||
});
|
||||
session.requestAnimationFrame(() => {});
|
||||
}
|
||||
|
||||
function sessionEndTest(endEvent, eventOrder) {
|
||||
return requestImmersiveSession().then((session) => {
|
||||
let eventWatcher = new EventWatcher(t, session,
|
||||
["inputsourceschange", "selectstart", "select", "selectend", "end"]);
|
||||
let eventPromise = eventWatcher.wait_for(eventOrder);
|
||||
|
||||
session.addEventListener(endEvent, ()=> {
|
||||
session.end();
|
||||
}, false);
|
||||
|
||||
sendClick(session);
|
||||
return eventPromise;
|
||||
});
|
||||
}
|
||||
|
||||
// End our first session, just for simplicity, then make end session calls
|
||||
// during each of our input events, and ensure that events stop processing
|
||||
// and no crashes occur from calling end inside the event callbacks.
|
||||
return session.end().then(() => {
|
||||
return sessionEndTest("inputsourceschange", ["inputsourceschange", "end"]);
|
||||
}).then(() => {
|
||||
return sessionEndTest("selectstart", ["inputsourceschange", "selectstart", "selectend", "end"]);
|
||||
}).then(() => {
|
||||
return sessionEndTest("select", ["inputsourceschange", "selectstart", "select", "selectend", "end"]);
|
||||
}).then(() => {
|
||||
return sessionEndTest("selectend", ["inputsourceschange", "selectstart", "select", "selectend", "end"]);
|
||||
});
|
||||
};
|
||||
|
||||
xr_session_promise_test(
|
||||
testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
|
||||
|
||||
</script>
|
|
@ -4,7 +4,7 @@
|
|||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/xr-test-asserts.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas></canvas>
|
||||
|
||||
<script>
|
||||
|
@ -54,7 +54,7 @@
|
|||
|
||||
let poseMatrix = pose.transform.matrix;
|
||||
assert_not_equals(poseMatrix, null);
|
||||
assert_matrix_approx_equals(poseMatrix, expectedPoseMatrix, FLOAT_EPSILON);
|
||||
assert_matrix_approx_equals(poseMatrix, expectedPoseMatrix);
|
||||
});
|
||||
|
||||
// Finished.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/xr-test-asserts.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas></canvas>
|
||||
|
||||
<script>
|
||||
|
@ -49,7 +49,7 @@ let testFunction = function(session, fakeDeviceController, t) {
|
|||
assert_not_equals(pose, null);
|
||||
|
||||
let poseMatrix = pose.transform.matrix;
|
||||
assert_matrix_approx_equals(poseMatrix, VALID_FLOOR_ORIGIN_MATRIX, FLOAT_EPSILON);
|
||||
assert_matrix_approx_equals(poseMatrix, VALID_FLOOR_ORIGIN_MATRIX);
|
||||
});
|
||||
|
||||
// Finished.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/xr-test-asserts.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas></canvas>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/webxr_test_constants.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/xr-test-asserts.js"></script>
|
||||
<script src="resources/webxr_test_asserts.js"></script>
|
||||
<canvas></canvas>
|
||||
|
||||
<script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue