LNXSDK/Kha/Backends/HTML5/kha/js/vr/VrInterface.hx
2025-01-22 16:18:30 +01:00

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;
}
}