250 lines
6.9 KiB
Haxe
Executable File
250 lines
6.9 KiB
Haxe
Executable File
package kha.js.vr;
|
|
|
|
import js.Syntax;
|
|
import js.lib.Float32Array;
|
|
import kha.vr.Pose;
|
|
import kha.vr.PoseState;
|
|
import kha.vr.SensorState;
|
|
import kha.vr.TimeWarpParms;
|
|
import kha.math.FastMatrix4;
|
|
import kha.math.Vector3;
|
|
import kha.math.Quaternion;
|
|
import kha.SystemImpl;
|
|
|
|
class VrInterface extends kha.vr.VrInterface {
|
|
var vrEnabled: Bool = false;
|
|
|
|
var vrDisplay: Dynamic;
|
|
var frameData: Dynamic;
|
|
|
|
var leftProjectionMatrix: FastMatrix4 = FastMatrix4.identity();
|
|
var rightProjectionMatrix: FastMatrix4 = FastMatrix4.identity();
|
|
var leftViewMatrix: FastMatrix4 = FastMatrix4.identity();
|
|
var rightViewMatrix: FastMatrix4 = FastMatrix4.identity();
|
|
|
|
var width: Int = 0;
|
|
var height: Int = 0;
|
|
var vrWidth: Int = 0;
|
|
var vrHeight: Int = 0;
|
|
|
|
public function new() {
|
|
super();
|
|
#if kha_webvr
|
|
var displayEnabled: Bool = Syntax.code("navigator.getVRDisplays");
|
|
#else
|
|
var displayEnabled = false;
|
|
#end
|
|
if (displayEnabled) {
|
|
vrEnabled = true;
|
|
getVRDisplays();
|
|
trace("Display enabled.");
|
|
}
|
|
}
|
|
|
|
function getVRDisplays() {
|
|
var vrDisplayInstance = Syntax.code("navigator.getVRDisplays()");
|
|
vrDisplayInstance.then(function(displays) {
|
|
if (displays.length > 0) {
|
|
frameData = Syntax.code("new VRFrameData()");
|
|
vrDisplay = Syntax.code("displays[0]");
|
|
vrDisplay.depthNear = 0.1;
|
|
vrDisplay.depthFar = 1024.0;
|
|
|
|
var leftEye = vrDisplay.getEyeParameters("left");
|
|
var rightEye = vrDisplay.getEyeParameters("right");
|
|
width = SystemImpl.khanvas.width;
|
|
height = SystemImpl.khanvas.height;
|
|
vrWidth = Std.int(Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2);
|
|
vrHeight = Std.int(Math.max(leftEye.renderHeight, rightEye.renderHeight));
|
|
}
|
|
else {
|
|
trace("There are no VR displays connected.");
|
|
}
|
|
});
|
|
}
|
|
|
|
public override function onVRRequestPresent() {
|
|
try {
|
|
vrDisplay.requestPresent([{source: SystemImpl.khanvas}]).then(function() {
|
|
onResize();
|
|
vrDisplay.requestAnimationFrame(onAnimationFrame);
|
|
});
|
|
}
|
|
catch (err:Dynamic) {
|
|
trace("Failed to requestPresent.");
|
|
trace(err);
|
|
}
|
|
}
|
|
|
|
public override function onVRExitPresent() {
|
|
try {
|
|
vrDisplay.exitPresent([{source: SystemImpl.khanvas}]).then(function() {
|
|
onResize();
|
|
});
|
|
}
|
|
catch (err:Dynamic) {
|
|
trace("Failed to exitPresent.");
|
|
trace(err);
|
|
}
|
|
}
|
|
|
|
public override function onResetPose() {
|
|
try {
|
|
vrDisplay.resetPose();
|
|
}
|
|
catch (err:Dynamic) {
|
|
trace("Failed to resetPose");
|
|
trace(err);
|
|
}
|
|
}
|
|
|
|
function onAnimationFrame(timestamp: Float): Void {
|
|
if (vrDisplay != null && vrDisplay.isPresenting) {
|
|
vrDisplay.requestAnimationFrame(onAnimationFrame);
|
|
|
|
vrDisplay.getFrameData(frameData);
|
|
|
|
leftProjectionMatrix = createMatrixFromArray(untyped frameData.leftProjectionMatrix);
|
|
leftViewMatrix = createMatrixFromArray(untyped frameData.leftViewMatrix);
|
|
|
|
rightProjectionMatrix = createMatrixFromArray(untyped frameData.rightProjectionMatrix);
|
|
rightViewMatrix = createMatrixFromArray(untyped frameData.rightViewMatrix);
|
|
|
|
// Submit the newly rendered layer to be presented by the VRDisplay
|
|
vrDisplay.submitFrame();
|
|
}
|
|
}
|
|
|
|
function onResize() {
|
|
if (vrDisplay != null && vrDisplay.isPresenting) {
|
|
SystemImpl.khanvas.width = vrWidth;
|
|
SystemImpl.khanvas.height = vrHeight;
|
|
}
|
|
else {
|
|
SystemImpl.khanvas.width = width;
|
|
SystemImpl.khanvas.height = height;
|
|
}
|
|
}
|
|
|
|
public override function GetSensorState(): SensorState {
|
|
return GetPredictedSensorState(0.0);
|
|
}
|
|
|
|
public override function GetPredictedSensorState(time: Float): SensorState {
|
|
var result: SensorState = new SensorState();
|
|
|
|
result.Predicted = new PoseState();
|
|
result.Recorded = result.Predicted;
|
|
|
|
result.Predicted.AngularAcceleration = new Vector3();
|
|
result.Predicted.AngularVelocity = new Vector3();
|
|
result.Predicted.LinearAcceleration = new Vector3();
|
|
result.Predicted.LinearVelocity = new Vector3();
|
|
result.Predicted.TimeInSeconds = time;
|
|
result.Predicted.Pose = new Pose();
|
|
result.Predicted.Pose.Orientation = new Quaternion();
|
|
result.Predicted.Pose.Position = new Vector3();
|
|
|
|
var mPose = frameData.pose; // predicted pose of the vrDisplay
|
|
if (mPose != null) {
|
|
result.Predicted.AngularVelocity = createVectorFromArray(untyped mPose.angularVelocity);
|
|
result.Predicted.AngularAcceleration = createVectorFromArray(untyped mPose.angularAcceleration);
|
|
result.Predicted.LinearVelocity = createVectorFromArray(untyped mPose.linearVelocity);
|
|
result.Predicted.LinearAcceleration = createVectorFromArray(untyped mPose.linearAcceleration);
|
|
result.Predicted.Pose.Orientation = createQuaternion(untyped mPose.orientation);
|
|
result.Predicted.Pose.Position = createVectorFromArray(untyped mPose.position);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Sends a black image to the warp swap thread
|
|
public override function WarpSwapBlack(): Void {
|
|
// TODO: Implement
|
|
}
|
|
|
|
// Sends the Oculus loading symbol to the warp swap thread
|
|
public override function WarpSwapLoadingIcon(): Void {
|
|
// TODO: Implement
|
|
}
|
|
|
|
// Sends the set of images to the warp swap thread
|
|
public override function WarpSwap(parms: TimeWarpParms): Void {
|
|
// TODO: Implement
|
|
}
|
|
|
|
public override function IsPresenting(): Bool {
|
|
if (vrDisplay != null)
|
|
return vrDisplay.isPresenting;
|
|
return false;
|
|
}
|
|
|
|
public override function IsVrEnabled(): Bool {
|
|
return vrEnabled;
|
|
}
|
|
|
|
public override function GetTimeInSeconds(): Float {
|
|
return Scheduler.time();
|
|
}
|
|
|
|
public override function GetProjectionMatrix(eye: Int): FastMatrix4 {
|
|
if (eye == 0) {
|
|
return leftProjectionMatrix;
|
|
}
|
|
else {
|
|
return rightProjectionMatrix;
|
|
}
|
|
}
|
|
|
|
public override function GetViewMatrix(eye: Int): FastMatrix4 {
|
|
if (eye == 0) {
|
|
return leftViewMatrix;
|
|
}
|
|
else {
|
|
return rightViewMatrix;
|
|
}
|
|
}
|
|
|
|
function createMatrixFromArray(array: Float32Array): FastMatrix4 {
|
|
var matrix: FastMatrix4 = FastMatrix4.identity();
|
|
matrix._00 = array[0];
|
|
matrix._01 = array[1];
|
|
matrix._02 = array[2];
|
|
matrix._03 = array[3];
|
|
matrix._10 = array[4];
|
|
matrix._11 = array[5];
|
|
matrix._12 = array[6];
|
|
matrix._13 = array[7];
|
|
matrix._20 = array[8];
|
|
matrix._21 = array[9];
|
|
matrix._22 = array[10];
|
|
matrix._23 = array[11];
|
|
matrix._30 = array[12];
|
|
matrix._31 = array[13];
|
|
matrix._32 = array[14];
|
|
matrix._33 = array[15];
|
|
return matrix;
|
|
}
|
|
|
|
function createVectorFromArray(array: Float32Array): Vector3 {
|
|
var vector: Vector3 = new Vector3(0, 0, 0);
|
|
if (array != null) {
|
|
vector.x = array[0];
|
|
vector.y = array[1];
|
|
vector.z = array[2];
|
|
}
|
|
return vector;
|
|
}
|
|
|
|
function createQuaternion(array: Float32Array): Quaternion {
|
|
var quaternion: Quaternion = new Quaternion(0, 0, 0, 0);
|
|
if (array != null) {
|
|
quaternion.x = array[0];
|
|
quaternion.y = array[1];
|
|
quaternion.z = array[2];
|
|
quaternion.w = array[3];
|
|
}
|
|
return quaternion;
|
|
}
|
|
}
|