diff --git a/leenkx/Sources/iron/RenderPath.hx b/leenkx/Sources/iron/RenderPath.hx index 17cb5dd..dcfd92e 100644 --- a/leenkx/Sources/iron/RenderPath.hx +++ b/leenkx/Sources/iron/RenderPath.hx @@ -518,12 +518,44 @@ class RenderPath { return Reflect.field(kha.Shaders, handle + "_comp"); } - #if (kha_krom && lnx_vr) - public function drawStereo(drawMeshes: Int->Void) { - for (eye in 0...2) { - Krom.vrBeginRender(eye); - drawMeshes(eye); - Krom.vrEndRender(eye); + #if lnx_vr + public function drawStereo(drawMeshes: Void->Void) { + var vr = kha.vr.VrInterface.instance; + var appw = iron.App.w(); + var apph = iron.App.h(); + var halfw = Std.int(appw / 2); + var g = currentG; + + if (vr != null && vr.IsPresenting()) { + // Left eye + Scene.active.camera.V.setFrom(Scene.active.camera.leftV); + Scene.active.camera.P.self = vr.GetProjectionMatrix(0); + g.viewport(0, 0, halfw, apph); + drawMeshes(); + + // Right eye + begin(g, additionalTargets); + Scene.active.camera.V.setFrom(Scene.active.camera.rightV); + Scene.active.camera.P.self = vr.GetProjectionMatrix(1); + g.viewport(halfw, 0, halfw, apph); + drawMeshes(); + } + else { // Simulate + Scene.active.camera.buildProjection(halfw / apph); + + // Left eye + g.viewport(0, 0, halfw, apph); + drawMeshes(); + + // Right eye + begin(g, additionalTargets); + Scene.active.camera.transform.move(Scene.active.camera.right(), 0.032); + Scene.active.camera.buildMatrix(); + g.viewport(halfw, 0, halfw, apph); + drawMeshes(); + + Scene.active.camera.transform.move(Scene.active.camera.right(), -0.032); + Scene.active.camera.buildMatrix(); } } #end diff --git a/leenkx/Sources/iron/object/CameraObject.hx b/leenkx/Sources/iron/object/CameraObject.hx index 36f8ab9..fb52933 100644 --- a/leenkx/Sources/iron/object/CameraObject.hx +++ b/leenkx/Sources/iron/object/CameraObject.hx @@ -30,12 +30,22 @@ class CameraObject extends Object { static var sphereCenter = new Vec4(); static var vcenter = new Vec4(); static var vup = new Vec4(); - + + #if lnx_vr + var helpMat = Mat4.identity(); + public var leftV = Mat4.identity(); + public var rightV = Mat4.identity(); + #end + public function new(data: CameraData) { super(); this.data = data; + #if lnx_vr + iron.system.VR.initButton(); + #end + buildProjection(); V = Mat4.identity(); @@ -117,6 +127,26 @@ class CameraObject extends Object { V.getInverse(transform.world); VP.multmats(P, V); + + #if lnx_vr + var vr = kha.vr.VrInterface.instance; + if (vr != null && vr.IsPresenting()) { + leftV.setFrom(V); + helpMat.self = vr.GetViewMatrix(0); + leftV.multmat(helpMat); + + rightV.setFrom(V); + helpMat.self = vr.GetViewMatrix(1); + rightV.multmat(helpMat); + } + else { + leftV.setFrom(V); + } + VP.multmats(P, leftV); + #else + VP.multmats(P, V); + #end + if (data.raw.frustum_culling) { buildViewFrustum(VP, frustumPlanes); } diff --git a/leenkx/Sources/iron/object/LightObject.hx b/leenkx/Sources/iron/object/LightObject.hx index ee19ba3..1c1908f 100644 --- a/leenkx/Sources/iron/object/LightObject.hx +++ b/leenkx/Sources/iron/object/LightObject.hx @@ -155,8 +155,13 @@ class LightObject extends Object { } public function setCascade(camera: CameraObject, cascade: Int) { - m.setFrom(camera.V); + #if lnx_vr + m.setFrom(camera.leftV); + #else + m.setFrom(camera.V); + #end + #if lnx_csm if (camSlicedP == null) { camSlicedP = []; diff --git a/leenkx/Sources/iron/system/VR.hx b/leenkx/Sources/iron/system/VR.hx new file mode 100644 index 0000000..3a6943d --- /dev/null +++ b/leenkx/Sources/iron/system/VR.hx @@ -0,0 +1,52 @@ +package iron.system; + +import iron.math.Mat4; + +#if lnx_vr +class VR { + + static var undistortionMatrix: Mat4 = null; + + public function new() {} + + public static function getUndistortionMatrix(): Mat4 { + if (undistortionMatrix == null) { + undistortionMatrix = Mat4.identity(); + } + + return undistortionMatrix; + } + + public static function getMaxRadiusSq(): Float { + return 0.0; + } + + public static function initButton() { + function vrDownListener(index: Int, x: Float, y: Float) { + var vr = kha.vr.VrInterface.instance; + if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return; + var w: Float = iron.App.w(); + var h: Float = iron.App.h(); + if (x < w - 150 || y < h - 150) return; + vr.onVRRequestPresent(); + } + + function vrRender2D(g: kha.graphics2.Graphics) { + var vr = kha.vr.VrInterface.instance; + if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return; + var w: Float = iron.App.w(); + var h: Float = iron.App.h(); + g.color = 0xffff0000; + g.fillRect(w - 150, h - 150, 140, 140); + } + + kha.input.Mouse.get().notify(vrDownListener, null, null, null); + iron.App.notifyOnRender2D(vrRender2D); + + var vr = kha.vr.VrInterface.instance; // Straight to VR (Oculus Carmel) + if (vr != null && vr.IsVrEnabled()) { + vr.onVRRequestPresent(); + } + } +} +#end \ No newline at end of file