forked from LeenkxTeam/LNXSDK
Next patch
This commit is contained in:
@ -227,7 +227,7 @@ class SystemImpl {
|
||||
}
|
||||
|
||||
static inline var maxGamepads: Int = 4;
|
||||
static var frame: Framebuffer;
|
||||
public static var frame: Framebuffer;
|
||||
static var keyboard: Keyboard = null;
|
||||
static var mouse: kha.input.Mouse;
|
||||
static var surface: Surface;
|
||||
@ -388,7 +388,8 @@ class SystemImpl {
|
||||
{
|
||||
alpha: false,
|
||||
antialias: options.framebuffer.samplesPerPixel > 1,
|
||||
stencil: true
|
||||
stencil: true,
|
||||
xrCompatible: true
|
||||
}); // preserveDrawingBuffer: true } ); Warning: preserveDrawingBuffer can cause huge performance issues on mobile browsers
|
||||
SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
|
||||
|
||||
@ -417,7 +418,8 @@ class SystemImpl {
|
||||
{
|
||||
alpha: false,
|
||||
antialias: options.framebuffer.samplesPerPixel > 1,
|
||||
stencil: true
|
||||
stencil: true,
|
||||
xrCompatible: true
|
||||
}); // preserveDrawingBuffer: true } ); WARNING: preserveDrawingBuffer causes huge performance issues (on mobile browser)!
|
||||
SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
|
||||
SystemImpl.gl.getExtension("OES_texture_float");
|
||||
@ -547,6 +549,12 @@ class SystemImpl {
|
||||
];
|
||||
|
||||
function animate(timestamp) {
|
||||
if (untyped Browser.window._khaSkipWindowRender == true) {
|
||||
if (requestAnimationFrame != null)
|
||||
requestAnimationFrame(animate);
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestAnimationFrame == null)
|
||||
Browser.window.setTimeout(animate, 1000.0 / 60.0);
|
||||
else
|
||||
|
||||
@ -47,6 +47,7 @@ class Graphics implements kha.graphics4.Graphics {
|
||||
|
||||
static var current: Graphics = null;
|
||||
static var useVertexAttributes: Int = 0;
|
||||
public static var vrFramebufferBound: Bool = false;
|
||||
|
||||
public function new(renderTarget: Canvas = null) {
|
||||
this.renderTarget = renderTarget;
|
||||
@ -89,8 +90,10 @@ class Graphics implements kha.graphics4.Graphics {
|
||||
SystemImpl.gl.enable(GL.BLEND);
|
||||
SystemImpl.gl.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA);
|
||||
if (renderTarget == null) {
|
||||
SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, null);
|
||||
SystemImpl.gl.viewport(0, 0, System.windowWidth(), System.windowHeight());
|
||||
if (!vrFramebufferBound) {
|
||||
SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, null);
|
||||
SystemImpl.gl.viewport(0, 0, System.windowWidth(), System.windowHeight());
|
||||
}
|
||||
}
|
||||
else {
|
||||
SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, renderTargetFrameBuffer);
|
||||
|
||||
@ -13,10 +13,29 @@ import kha.SystemImpl;
|
||||
|
||||
class VrInterface extends kha.vr.VrInterface {
|
||||
var vrEnabled: Bool = false;
|
||||
var isWebXR: Bool = false;
|
||||
|
||||
var vrDisplay: Dynamic;
|
||||
var frameData: Dynamic;
|
||||
|
||||
var xrSession: Dynamic;
|
||||
var xrRefSpace: Dynamic;
|
||||
public var xrGLLayer: Dynamic;
|
||||
public var currentFrame: Dynamic;
|
||||
public var currentViews: Dynamic;
|
||||
public var currentViewerPose: Dynamic;
|
||||
public var currentInputSources: Dynamic;
|
||||
var xrAnimationFrameHandle: Int = -1;
|
||||
|
||||
public var _glContext: Dynamic;
|
||||
public var _leftViewport: Dynamic;
|
||||
public var _rightViewport: Dynamic;
|
||||
public var _cachedViewsLength: Int = 0;
|
||||
|
||||
var savedCanvasWidth: Int = 0;
|
||||
var savedCanvasHeight: Int = 0;
|
||||
var browserRAFId: Int = -1;
|
||||
|
||||
var leftProjectionMatrix: FastMatrix4 = FastMatrix4.identity();
|
||||
var rightProjectionMatrix: FastMatrix4 = FastMatrix4.identity();
|
||||
var leftViewMatrix: FastMatrix4 = FastMatrix4.identity();
|
||||
@ -30,7 +49,20 @@ class VrInterface extends kha.vr.VrInterface {
|
||||
public function new() {
|
||||
super();
|
||||
#if kha_webvr
|
||||
var displayEnabled: Bool = Syntax.code("navigator.getVRDisplays");
|
||||
var webXREnabled: Bool = Syntax.code("navigator.xr");
|
||||
if (webXREnabled) {
|
||||
isWebXR = true;
|
||||
vrEnabled = true;
|
||||
}
|
||||
else {
|
||||
var displayEnabled: Bool = Syntax.code("navigator.getVRDisplays");
|
||||
if (displayEnabled) {
|
||||
isWebXR = false;
|
||||
vrEnabled = true;
|
||||
getVRDisplays();
|
||||
trace("WebVR 1.1 API detected");
|
||||
}
|
||||
}
|
||||
#else
|
||||
var displayEnabled = false;
|
||||
#end
|
||||
@ -64,27 +96,475 @@ class VrInterface extends kha.vr.VrInterface {
|
||||
}
|
||||
|
||||
public override function onVRRequestPresent() {
|
||||
if (isWebXR) {
|
||||
requestWebXRSession();
|
||||
} else {
|
||||
// WebVR 1.1
|
||||
try {
|
||||
vrDisplay.requestPresent([{source: SystemImpl.khanvas}]).then(function() {
|
||||
onResize();
|
||||
vrDisplay.requestAnimationFrame(onAnimationFrame);
|
||||
});
|
||||
}
|
||||
catch (err:Dynamic) {
|
||||
trace("Failed to requestPresent WebVR: " + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function requestWebXRSession() {
|
||||
var vrScaleFactor = 1.0;
|
||||
#if lnx_vr
|
||||
vrScaleFactor = leenkx.renderpath.Inc.getSuperSampling();
|
||||
trace("[VR] Using renderpath superSample as framebufferScaleFactor: " + vrScaleFactor);
|
||||
#end
|
||||
|
||||
try {
|
||||
vrDisplay.requestPresent([{source: SystemImpl.khanvas}]).then(function() {
|
||||
onResize();
|
||||
vrDisplay.requestAnimationFrame(onAnimationFrame);
|
||||
});
|
||||
Syntax.code("
|
||||
|
||||
|
||||
let gl = null;
|
||||
let canvas = null;
|
||||
|
||||
try {
|
||||
if (typeof kha_SystemImpl !== 'undefined') {
|
||||
gl = kha_SystemImpl.gl;
|
||||
canvas = kha_SystemImpl.khanvas;
|
||||
}
|
||||
} catch (e) {
|
||||
trace('kha_SystemImpl access failed: ' + e.message;
|
||||
}
|
||||
|
||||
if (!canvas) {
|
||||
canvas = document.querySelector('canvas');
|
||||
}
|
||||
|
||||
if (canvas && !gl) {
|
||||
const contextAttributes = { xrCompatible: true, antialias: true, alpha: false };
|
||||
gl = canvas.getContext('webgl2', contextAttributes) ||
|
||||
canvas.getContext('webgl', contextAttributes) ||
|
||||
canvas.getContext('experimental-webgl', contextAttributes);
|
||||
}
|
||||
|
||||
if (!canvas) {
|
||||
canvas = document.getElementById('khanvas');
|
||||
if (canvas && !gl) {
|
||||
gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
||||
}
|
||||
}
|
||||
|
||||
if (!gl) {
|
||||
return;
|
||||
}
|
||||
const self = this;
|
||||
const glContext = gl;
|
||||
|
||||
self._glContext = glContext;
|
||||
");
|
||||
|
||||
Syntax.code("
|
||||
self._vrRenderCallback = function() {
|
||||
self.vrRenderCallback();
|
||||
};
|
||||
|
||||
const checkAndRequestSession = async () => {
|
||||
try {
|
||||
const supported = await navigator.xr.isSessionSupported('immersive-vr');
|
||||
if (!supported) {
|
||||
trace('immersive-vr session not supported');
|
||||
}
|
||||
} catch (e) {
|
||||
trace('WARN: isSessionSupported failed: ' + e.message);
|
||||
// Continue anyway as some browsers do not support the check itself
|
||||
}
|
||||
|
||||
return await navigator.xr.requestSession('immersive-vr', {
|
||||
optionalFeatures: ['local-floor', 'hand-tracking', 'bounded-floor']
|
||||
});
|
||||
};
|
||||
|
||||
checkAndRequestSession().then(async (session) => {
|
||||
self.xrSession = session;
|
||||
if (typeof window !== 'undefined') {
|
||||
window._khaSkipWindowRender = true;
|
||||
}
|
||||
|
||||
const contextAttributes = glContext.getContextAttributes();
|
||||
if (!contextAttributes || !contextAttributes.xrCompatible) {
|
||||
await glContext.makeXRCompatible();
|
||||
}
|
||||
self.xrGLLayer = new XRWebGLLayer(session, glContext, {
|
||||
depth: true, // Essential for depth testing
|
||||
stencil: false, // Not needed, wastes memory
|
||||
alpha: false, // Not needed in VR wastes
|
||||
antialias: true, // Smooth rendering
|
||||
framebufferScaleFactor: {0} // VR resolution quality from renderpath
|
||||
});
|
||||
|
||||
if (self.xrGLLayer.framebufferWidth === 0 || self.xrGLLayer.framebufferHeight === 0) {
|
||||
trace('XRWebGLLayer framebuffer has invalid dimensions');
|
||||
}
|
||||
|
||||
|
||||
session.updateRenderState({
|
||||
baseLayer: self.xrGLLayer
|
||||
});
|
||||
const handlers = {};
|
||||
|
||||
handlers.end = () => {
|
||||
self.onSessionEnd();
|
||||
};
|
||||
session.addEventListener('end', handlers.end);
|
||||
|
||||
handlers.select = (event) => {
|
||||
if (self.onSelect) self.onSelect(event);
|
||||
};
|
||||
session.addEventListener('select', handlers.select);
|
||||
|
||||
handlers.selectstart = (event) => {
|
||||
if (self.onSelectStart) self.onSelectStart(event);
|
||||
};
|
||||
session.addEventListener('selectstart', handlers.selectstart);
|
||||
|
||||
handlers.selectend = (event) => {
|
||||
if (self.onSelectEnd) self.onSelectEnd(event);
|
||||
};
|
||||
session.addEventListener('selectend', handlers.selectend);
|
||||
|
||||
handlers.squeeze = (event) => {
|
||||
if (self.onSqueeze) self.onSqueeze(event);
|
||||
};
|
||||
session.addEventListener('squeeze', handlers.squeeze);
|
||||
|
||||
handlers.squeezestart = (event) => {
|
||||
if (self.onSqueezeStart) self.onSqueezeStart(event);
|
||||
};
|
||||
session.addEventListener('squeezestart', handlers.squeezestart);
|
||||
|
||||
handlers.squeezeend = (event) => {
|
||||
if (self.onSqueezeEnd) self.onSqueezeEnd(event);
|
||||
};
|
||||
session.addEventListener('squeezeend', handlers.squeezeend);
|
||||
|
||||
session.addEventListener('inputsourceschange', handlers.inputsourceschange);
|
||||
|
||||
handlers.visibilitychange = (event) => {
|
||||
const state = event.session.visibilityState;
|
||||
|
||||
};
|
||||
session.addEventListener('visibilitychange', handlers.visibilitychange);
|
||||
|
||||
self._eventHandlers = handlers;
|
||||
|
||||
const requestRefSpace = async () => {
|
||||
const spaces = ['local-floor', 'local'];
|
||||
for (const space of spaces) {
|
||||
try {
|
||||
const refSpace = await session.requestReferenceSpace(space);
|
||||
return refSpace;
|
||||
} catch (e) {
|
||||
trace(space + ' not supported');
|
||||
}
|
||||
}
|
||||
trace('No reference space supported');
|
||||
};
|
||||
|
||||
requestRefSpace().then((refSpace) => {
|
||||
self.xrRefSpace = refSpace;
|
||||
|
||||
if (canvas && canvas.width) {
|
||||
self.savedCanvasWidth = canvas.width;
|
||||
self.savedCanvasHeight = canvas.height;
|
||||
} else {
|
||||
const canvasFallback = document.querySelector('canvas');
|
||||
if (canvasFallback) {
|
||||
self.savedCanvasWidth = canvasFallback.width;
|
||||
self.savedCanvasHeight = canvasFallback.height;
|
||||
}
|
||||
}
|
||||
|
||||
const onFrame = (time, frame) => {
|
||||
try {
|
||||
if (self.xrSession) {
|
||||
self.xrAnimationFrameHandle = self.xrSession.requestAnimationFrame(onFrame);
|
||||
}
|
||||
|
||||
if (!self._lastFrameTime) self._lastFrameTime = time;
|
||||
const deltaTime = time - self._lastFrameTime;
|
||||
self._lastFrameTime = time;
|
||||
|
||||
if (!window._xrFrameCount) window._xrFrameCount = 0;
|
||||
window._xrFrameCount++;
|
||||
|
||||
if (glContext && self.xrSession && self.xrSession.renderState && self.xrSession.renderState.baseLayer) {
|
||||
const layer = self.xrSession.renderState.baseLayer;
|
||||
if (layer.framebuffer) {
|
||||
const pose = frame.getViewerPose(self.xrRefSpace);
|
||||
if (pose && pose.views && pose.views.length > 0) {
|
||||
glContext.bindFramebuffer(glContext.FRAMEBUFFER, layer.framebuffer);
|
||||
|
||||
let bgR = 0, bgG = 0, bgB = 0;
|
||||
if (typeof iron !== 'undefined' && iron.Scene && iron.Scene.active && iron.Scene.active.world && iron.Scene.active.world.raw) {
|
||||
const bgColor = iron.Scene.active.world.raw.background_color;
|
||||
if (bgColor !== undefined) {
|
||||
bgR = ((bgColor >> 16) & 255) / 255;
|
||||
bgG = ((bgColor >> 8) & 255) / 255;
|
||||
bgB = (bgColor & 255) / 255;
|
||||
}
|
||||
}
|
||||
|
||||
for (const view of pose.views) {
|
||||
const vp = layer.getViewport(view);
|
||||
glContext.viewport(vp.x, vp.y, vp.width, vp.height);
|
||||
glContext.scissor(vp.x, vp.y, vp.width, vp.height);
|
||||
glContext.enable(glContext.SCISSOR_TEST);
|
||||
|
||||
glContext.clearColor(bgR, bgG, bgB, 1.0);
|
||||
glContext.clear(glContext.COLOR_BUFFER_BIT | glContext.DEPTH_BUFFER_BIT);
|
||||
|
||||
}
|
||||
glContext.disable(glContext.SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!self.xrSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pose = frame.getViewerPose(self.xrRefSpace);
|
||||
if (!pose) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pose.emulatedPosition && !self._emulatedPosLogged) {
|
||||
self._emulatedPosLogged = true;
|
||||
}
|
||||
|
||||
const views = pose.views;
|
||||
|
||||
if (!self.xrSession.renderState || !self.xrSession.renderState.baseLayer) {
|
||||
if (!self._noRenderStateLogged) {
|
||||
self._noRenderStateLogged = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const glLayer = self.xrSession.renderState.baseLayer;
|
||||
|
||||
if (!views || views.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.xrSession.visibilityState === 'hidden') {
|
||||
return;
|
||||
}
|
||||
|
||||
self.currentFrame = frame;
|
||||
self.currentViews = views;
|
||||
self.currentViewerPose = pose; /
|
||||
if (self.xrSession && self.xrSession.inputSources) {
|
||||
self.currentInputSources = self.xrSession.inputSources;
|
||||
}
|
||||
|
||||
if (glContext.isContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!glContext || !glLayer || !glLayer.framebuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (glContext.bindVertexArray) {
|
||||
glContext.bindVertexArray(null);
|
||||
}
|
||||
|
||||
while (glContext.getError() !== glContext.NO_ERROR) {
|
||||
// Drain error queue
|
||||
}
|
||||
|
||||
glContext.bindFramebuffer(glContext.FRAMEBUFFER, glLayer.framebuffer);
|
||||
|
||||
|
||||
const bindError = glContext.getError();
|
||||
if (bindError !== glContext.NO_ERROR && !self._bindErrorLogged) {
|
||||
self._bindErrorLogged = true;
|
||||
}
|
||||
|
||||
const fbStatus = glContext.checkFramebufferStatus(glContext.FRAMEBUFFER);
|
||||
if (fbStatus !== glContext.FRAMEBUFFER_COMPLETE) {
|
||||
return;
|
||||
}
|
||||
|
||||
glContext.enable(glContext.DEPTH_TEST);
|
||||
glContext.depthFunc(glContext.LEQUAL);
|
||||
glContext.depthMask(true);
|
||||
glContext.colorMask(true, true, true, true);
|
||||
glContext.disable(glContext.BLEND);
|
||||
glContext.enable(glContext.CULL_FACE);
|
||||
glContext.cullFace(glContext.BACK);
|
||||
glContext.frontFace(glContext.CCW);
|
||||
glContext.disable(glContext.STENCIL_TEST);
|
||||
glContext.disable(glContext.POLYGON_OFFSET_FILL);
|
||||
|
||||
|
||||
if (!self._fbLogged && p) {
|
||||
const depthTest = glContext.isEnabled(glContext.DEPTH_TEST);
|
||||
const cullFace = glContext.isEnabled(glContext.CULL_FACE);
|
||||
const blend = glContext.isEnabled(glContext.BLEND);
|
||||
self._fbLogged = true;
|
||||
}
|
||||
|
||||
if (views.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (views.length >= 1) {
|
||||
try {
|
||||
self._leftViewport = glLayer.getViewport(views[0]);
|
||||
self._rightViewport = views.length >= 2 ? glLayer.getViewport(views[1]) : null;
|
||||
self._cachedViewsLength = views.length;
|
||||
|
||||
if (!self._leftViewport) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (views.length >= 1) {
|
||||
self.leftProjectionMatrix = self.createMatrixFromArray(views[0].projectionMatrix);
|
||||
self.leftViewMatrix = self.createMatrixFromArray(views[0].transform.inverse.matrix);
|
||||
}
|
||||
if (views.length >= 2) {
|
||||
self.rightProjectionMatrix = self.createMatrixFromArray(views[1].projectionMatrix);
|
||||
self.rightViewMatrix = self.createMatrixFromArray(views[1].transform.inverse.matrix);
|
||||
} else if (views.length === 1) {
|
||||
self.rightProjectionMatrix = self.leftProjectionMatrix;
|
||||
self.rightViewMatrix = self.leftViewMatrix;
|
||||
}
|
||||
|
||||
if (self._vrRenderCallback) {
|
||||
self._vrRenderCallback();
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('XR Frame Error:', err);
|
||||
} finally {
|
||||
self.currentFrame = null;
|
||||
self.currentViews = null;
|
||||
self.currentInputSources = null;
|
||||
}
|
||||
};
|
||||
|
||||
self.xrAnimationFrameHandle = session.requestAnimationFrame(onFrame);
|
||||
}).catch((err) => {
|
||||
trace('REF SPACE FAILED: ' + err.message );
|
||||
});
|
||||
}).catch((err) => {
|
||||
trace('SESSION FAILED: ' + err);
|
||||
});
|
||||
", vrScaleFactor);
|
||||
}
|
||||
catch (err:Dynamic) {
|
||||
trace("Failed to requestPresent.");
|
||||
trace("Failed to requestSession (WebXR).");
|
||||
trace(err);
|
||||
}
|
||||
}
|
||||
|
||||
public override function onVRExitPresent() {
|
||||
try {
|
||||
vrDisplay.exitPresent([{source: SystemImpl.khanvas}]).then(function() {
|
||||
onResize();
|
||||
});
|
||||
function onSessionEnd() {
|
||||
var canvas = SystemImpl.khanvas;
|
||||
if (canvas == null) {
|
||||
canvas = Syntax.code("document.querySelector('canvas')");
|
||||
}
|
||||
catch (err:Dynamic) {
|
||||
trace("Failed to exitPresent.");
|
||||
trace(err);
|
||||
|
||||
if (canvas != null && savedCanvasWidth > 0 && savedCanvasHeight > 0) {
|
||||
canvas.width = savedCanvasWidth;
|
||||
canvas.height = savedCanvasHeight;
|
||||
}
|
||||
|
||||
if (xrSession != null) {
|
||||
Syntax.code("
|
||||
if (this.xrAnimationFrameHandle !== -1 && this.xrSession) {
|
||||
this.xrSession.cancelAnimationFrame(this.xrAnimationFrameHandle);
|
||||
this.xrAnimationFrameHandle = -1;
|
||||
}
|
||||
|
||||
if (this._eventHandlers && this.xrSession) {
|
||||
const handlers = this._eventHandlers;
|
||||
const events = ['end', 'select', 'selectstart', 'selectend', 'squeeze', 'squeezestart', 'squeezeend', 'inputsourceschange', 'visibilitychange'];
|
||||
for (const event of events) {
|
||||
if (handlers[event]) {
|
||||
this.xrSession.removeEventListener(event, handlers[event]);
|
||||
}
|
||||
}
|
||||
this._eventHandlers = null;
|
||||
}
|
||||
");
|
||||
}
|
||||
|
||||
Syntax.code("
|
||||
const gl = this._glContext;
|
||||
if (gl) {
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null); // Restore default framebuffer
|
||||
gl.disable(gl.SCISSOR_TEST);
|
||||
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window._khaSkipWindowRender = false;
|
||||
}
|
||||
|
||||
this.xrSession = null;
|
||||
this.xrRefSpace = null;
|
||||
this.xrGLLayer = null;
|
||||
this.currentFrame = null;
|
||||
this.currentViews = null;
|
||||
this.currentInputSources = null;
|
||||
this._lastFrameTime = null;
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
delete window._xrFrameCount;
|
||||
delete window._ironRenderCount;
|
||||
delete window._slowFrameCount;
|
||||
}
|
||||
");
|
||||
}
|
||||
|
||||
public override function onVRExitPresent() {
|
||||
if (isWebXR) {
|
||||
try {
|
||||
if (xrSession != null) {
|
||||
Syntax.code("
|
||||
if (this.xrSession) {
|
||||
this.xrSession.end().then(() => {
|
||||
trace('Session ended');
|
||||
}).catch((err) => {
|
||||
trace('Session.end() failed:', err);
|
||||
});
|
||||
}
|
||||
");
|
||||
xrSession = null;
|
||||
xrRefSpace = null;
|
||||
xrGLLayer = null;
|
||||
}
|
||||
}
|
||||
catch (err:Dynamic) {
|
||||
trace("Failed to exitPresent in WebXR");
|
||||
trace(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// WebVR 1.1
|
||||
try {
|
||||
vrDisplay.exitPresent([{source: SystemImpl.khanvas}]).then(function() {
|
||||
onResize();
|
||||
});
|
||||
}
|
||||
catch (err:Dynamic) {
|
||||
trace("Failed to exitPresent");
|
||||
trace(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,13 +596,25 @@ class VrInterface extends kha.vr.VrInterface {
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
if (vrDisplay != null && vrDisplay.isPresenting) {
|
||||
SystemImpl.khanvas.width = vrWidth;
|
||||
SystemImpl.khanvas.height = vrHeight;
|
||||
if (isWebXR) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
SystemImpl.khanvas.width = width;
|
||||
SystemImpl.khanvas.height = height;
|
||||
// WebVR 1.1
|
||||
if (vrDisplay != null && vrDisplay.isPresenting) {
|
||||
var canvas = SystemImpl.khanvas;
|
||||
if (canvas != null) {
|
||||
canvas.width = vrWidth;
|
||||
canvas.height = vrHeight;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var canvas = SystemImpl.khanvas;
|
||||
if (canvas != null) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,9 +666,11 @@ class VrInterface extends kha.vr.VrInterface {
|
||||
}
|
||||
|
||||
public override function IsPresenting(): Bool {
|
||||
var presenting = false;
|
||||
if (vrDisplay != null)
|
||||
return vrDisplay.isPresenting;
|
||||
return false;
|
||||
presenting = vrDisplay.isPresenting;
|
||||
}
|
||||
return presenting;
|
||||
}
|
||||
|
||||
public override function IsVrEnabled(): Bool {
|
||||
@ -207,6 +701,10 @@ class VrInterface extends kha.vr.VrInterface {
|
||||
|
||||
function createMatrixFromArray(array: Float32Array): FastMatrix4 {
|
||||
var matrix: FastMatrix4 = FastMatrix4.identity();
|
||||
if (array == null || array.length < 16) {
|
||||
trace("Warning: Invalid matrix array, using identity");
|
||||
return matrix;
|
||||
}
|
||||
matrix._00 = array[0];
|
||||
matrix._01 = array[1];
|
||||
matrix._02 = array[2];
|
||||
@ -246,4 +744,63 @@ class VrInterface extends kha.vr.VrInterface {
|
||||
}
|
||||
return quaternion;
|
||||
}
|
||||
|
||||
public function vrRenderCallback(): Void {
|
||||
var g4 = kha.SystemImpl.frame != null ? kha.SystemImpl.frame.g4 : null;
|
||||
|
||||
|
||||
if (g4 != null && iron.Scene.active != null && iron.RenderPath.active != null) {
|
||||
|
||||
if (untyped window._vrUpdateStarted == null) {
|
||||
untyped window._vrUpdateStarted = true;
|
||||
}
|
||||
|
||||
iron.system.Time.update();
|
||||
|
||||
iron.Scene.active.updateFrame();
|
||||
|
||||
|
||||
js.Syntax.code("
|
||||
const App = iron.App;
|
||||
if (App) {
|
||||
const frame = window._vrCallbackCount;
|
||||
const inits = App.traitInits;
|
||||
if (inits && inits.length > 0) {
|
||||
for (let i = 0; i < inits.length; i++) {
|
||||
inits[i]();
|
||||
}
|
||||
inits.length = 0;
|
||||
}
|
||||
|
||||
const fixedUpdates = App.traitFixedUpdates;
|
||||
if (fixedUpdates) {
|
||||
for (let i = 0; i < fixedUpdates.length; i++) {
|
||||
fixedUpdates[i]();
|
||||
}
|
||||
}
|
||||
|
||||
const updates = App.traitUpdates;
|
||||
if (updates) {
|
||||
for (let i = 0; i < updates.length; i++) {
|
||||
updates[i]();
|
||||
}
|
||||
}
|
||||
|
||||
const lateUpdates = App.traitLateUpdates;
|
||||
if (lateUpdates) {
|
||||
for (let i = 0; i < lateUpdates.length; i++) {
|
||||
lateUpdates[i]();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
");
|
||||
iron.Scene.active.renderFrame(g4);
|
||||
}
|
||||
else {
|
||||
if (untyped window._vrSkipLogged == null) {
|
||||
untyped window._vrSkipLogged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,4 +157,5 @@ extern class Krom {
|
||||
static function getConstantLocationCompute(shader: Dynamic, name: String): Dynamic;
|
||||
static function getTextureUnitCompute(shader: Dynamic, name: String): Dynamic;
|
||||
static function compute(x: Int, y: Int, z: Int): Void;
|
||||
static function viewportSetCamera(posX: Float, posY: Float, posZ: Float, rotX: Float, rotY: Float, rotZ: Float, rotW: Float): Void;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user