blob: 08afa5627ad5af3c0ed019c023b392e60190a108 [file] [log] [blame]
/*
* Copyright 2015 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <emscripten.h>
#include <emscripten/vr.h>
static int gDisplay = -1;
static int renderLoopCalled = 0;
static bool renderLoopArgCalled = false;
static void* renderLoopArgArg = NULL;
void report_result(int result) {
emscripten_cancel_main_loop();
if (result == 0) {
printf("Test successful!\n");
} else {
printf("Test failed!\n");
}
#ifdef REPORT_RESULT
REPORT_RESULT(result);
#endif
}
static void printMatrix(float* m) {
printf("{%f, %f, %f, %f,\n"
" %f, %f, %f, %f,\n"
" %f, %f, %f, %f,\n"
" %f, %f, %f, %f}\n",
m[0], m[1], m[2], m[3],
m[4], m[5], m[6], m[7],
m[8], m[9], m[10], m[11],
m[12], m[13], m[14], m[15]);
}
/* Render loop with an argument, set in `renderLoop()` */
static void renderLoopArg(void* arg) {
emscripten_vr_cancel_display_render_loop(gDisplay);
renderLoopArgCalled = true;
renderLoopArgArg = arg;
emscripten_vr_exit_present(gDisplay);
printf("Render loop with argument was called.\n");
return;
}
static void requestPresentCallback(void* userData) {
// Will likely never happen as the callback is not called
// from a user-gesture in this test.
printf("Request present callback called.\n");
}
/* Render loop without argument, set in `mainLoop()` */
static void renderLoop() {
renderLoopCalled++;
if(renderLoopCalled == 1) {
/* First iteration */
VRLayerInit init = {
"#canvas",
VR_LAYER_DEFAULT_LEFT_BOUNDS,
VR_LAYER_DEFAULT_RIGHT_BOUNDS
};
if (!emscripten_vr_request_present(gDisplay, &init, 1, requestPresentCallback, NULL)) {
printf("Request present with default canvas failed.\n");
report_result(1);
return;
}
if(emscripten_vr_display_presenting(gDisplay)) {
/* request present needs to be called from a user gesture callback and
* should have failed to make the display present. */
printf("Error: Expected display not to be presenting.\n");
report_result(1);
return;
}
VRFrameData data;
if (!emscripten_vr_get_frame_data(gDisplay, &data)) {
printf("Could not get frame data. (first iteration)\n");
report_result(1);
return;
}
if(!emscripten_vr_submit_frame(gDisplay)) {
printf("Error: Failed to submit frame to VR display %d (first iteration)\n", gDisplay);
report_result(1);
return;
}
return;
} else if (renderLoopCalled > 2) {
printf("Error: Unexpected render loop iteration\n");
report_result(1);
return; // only two iterations should run code
}
/* Second iteration */
emscripten_vr_cancel_display_render_loop(gDisplay);
VRFrameData data;
if (!emscripten_vr_get_frame_data(gDisplay, &data)) {
printf("Could not get frame data.\n");
report_result(1);
}
/* Print list of properties which are reported as valid */
printf("The following properties are valid:\n[");
if(data.pose.poseFlags & VR_POSE_POSITION) {
printf("position, ");
}
if(data.pose.poseFlags & VR_POSE_LINEAR_VELOCITY) {
printf("linear vel, ");
}
if(data.pose.poseFlags & VR_POSE_LINEAR_ACCELERATION) {
printf("linear accel, ");
}
if(data.pose.poseFlags & VR_POSE_ORIENTATION) {
printf("orientation, ");
}
if(data.pose.poseFlags & VR_POSE_ANGULAR_VELOCITY) {
printf("angular vel, ");
}
if(data.pose.poseFlags & VR_POSE_ANGULAR_ACCELERATION) {
printf("angular accel");
}
printf("]\n");
/* Print all values (independent of validity) */
printf("Position: \t\t%f %f %f\n",
data.pose.position.x,
data.pose.position.y,
data.pose.position.z);
printf("Linear Velocity: \t%f %f %f\n",
data.pose.linearVelocity.x,
data.pose.linearVelocity.y,
data.pose.linearVelocity.z);
printf("Linear Acceleration: \t%f %f %f\n",
data.pose.linearAcceleration.x,
data.pose.linearAcceleration.y,
data.pose.linearAcceleration.z);
printf("Orientation: \t\t%f %f %f %f\n",
data.pose.orientation.x,
data.pose.orientation.y,
data.pose.orientation.z,
data.pose.orientation.w);
printf("Angular Velocity: \t%f %f %f\n",
data.pose.angularVelocity.x,
data.pose.angularVelocity.y,
data.pose.angularVelocity.z);
printf("Angular Acceleration: \t%f %f %f\n",
data.pose.angularAcceleration.x,
data.pose.angularAcceleration.y,
data.pose.angularAcceleration.z);
printf("Left Projection Matrix:\n");
printMatrix(data.leftProjectionMatrix);
printf("Right Projection Matrix:\n");
printMatrix(data.rightProjectionMatrix);
printf("Left View Matrix:\n");
printMatrix(data.leftViewMatrix);
printf("Right View Matrix:\n");
printMatrix(data.rightViewMatrix);
if(!emscripten_vr_submit_frame(gDisplay)) {
printf("Error: Failed to submit frame to VR display %d (second iteration)\n", gDisplay);
report_result(1);
}
printf("Submitted frame.\n");
if (!emscripten_vr_set_display_render_loop_arg(gDisplay, renderLoopArg, (void*) 42)) {
printf("Error: Failed to dereference handle while settings display render loop of device %d\n", gDisplay);
report_result(1);
}
printf("Set main loop with argument to be called next.\n");
}
/* emscripten main loop */
static void mainloop() {
static int loopcount = 0;
if (!emscripten_vr_ready()) {
printf("VR not ready\n");
return;
}
if(gDisplay == -1) {
int numDisplays = emscripten_vr_count_displays();
if (numDisplays == 0) {
printf("No VR displays found!\n");
report_result(0);
return;
}
printf("%d VR displays found\n", numDisplays);
int id = -1;
char *devName;
for (int i = 0; i < numDisplays; ++i) {
VRDisplayHandle handle = emscripten_vr_get_display_handle(i);
if (gDisplay == -1) {
/* Save first found display for more testing */
gDisplay = handle;
devName = emscripten_vr_get_display_name(handle);
printf("Using VRDisplay '%s' (displayId '%d')\n", devName, gDisplay);
VRDisplayCapabilities caps;
if(!emscripten_vr_get_display_capabilities(handle, &caps)) {
printf("Error: failed to get display capabilities.\n");
report_result(1);
return;
}
if(!emscripten_vr_display_connected(gDisplay)) {
printf("Error: expected display to be connected.\n");
report_result(1);
return;
}
printf("Display Capabilities:\n"
"{hasPosition: %d, hasExternalDisplay: %d, canPresent: %d, maxLayers: %lu}\n",
caps.hasPosition, caps.hasExternalDisplay, caps.canPresent, caps.maxLayers);
}
}
if (gDisplay == -1) {
printf("Couln't find a VR display even though at least one was found.\n");
report_result(1);
return;
}
VREyeParameters leftParams, rightParams;
emscripten_vr_get_eye_parameters(gDisplay, VREyeLeft, &leftParams);
emscripten_vr_get_eye_parameters(gDisplay, VREyeRight, &rightParams);
VREyeParameters* p = &leftParams;
printf("Left eye params: {offset: [%f, %f, %f], renderWidth: %lu, renderHeight: %lu}\n", p->offset.x, p->offset.y, p->offset.z, p->renderWidth, p->renderHeight);
p = &rightParams;
printf("Right eye params: {offset: [%f, %f, %f], renderWidth: %lu, renderHeight: %lu}\n", p->offset.x, p->offset.y, p->offset.z, p->renderWidth, p->renderHeight);
if (!emscripten_vr_set_display_render_loop(gDisplay, renderLoop)) {
printf("Error: Failed to dereference handle while settings display render loop of device %d\n", gDisplay);
report_result(1);
}
}
if (loopcount++ > 10) {
if (renderLoopCalled != 2) {
printf("Render loop was not called twice (expected 2, was %d)\n", renderLoopCalled);
report_result(1);
}
if (!renderLoopArgCalled) {
printf("Render loop with argument was never called\n");
report_result(1);
}
if ((int)renderLoopArgArg != 42) {
printf("Argument to emscripten_vr_set_display_render_loop_arg was not passed on correctly\n");
report_result(1);
}
report_result(0);
}
}
int main(int argc, char **argv) {
if (!emscripten_vr_init()) {
printf("Skipping: Browser does not support WebVR\n");
return 0;
}
printf("Browser is running WebVR version %d.%d\n",
emscripten_vr_version_major(),
emscripten_vr_version_minor());
/* 2fps -- no rAF */
emscripten_set_main_loop(mainloop, 2, 0);
}