From 06854547d37901dfbe661e85798fbb38b09a5206 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Sun, 31 Dec 2023 01:07:44 +0100 Subject: [PATCH] rewrite of stereo renderer and input --- stereoview.js | 234 +++++++++++++++++++++++++++++++++----------------- view.sh | 2 +- 2 files changed, 157 insertions(+), 79 deletions(-) diff --git a/stereoview.js b/stereoview.js index d2c4ec5..aadb68b 100644 --- a/stereoview.js +++ b/stereoview.js @@ -1,4 +1,4 @@ -/* Copyright 2018 Paul Hänsch +/* Copyright 2018, 2023 Paul Hänsch This file is part of Serve0 @@ -16,81 +16,161 @@ along with Serve0 If not, see . */ -var render, video, controlTimeout = 0; -var pitch = 0, roll = 0, yaw = 0; -var w, h, hdeg, vdeg, scale, fov = 90, dist=0; +var contLeft = document.createElement("div"); +var contRight = document.createElement("div"); var lv = document.createElement("canvas"); var rv = document.createElement("canvas"); var debug = document.createElement("p"); -var gp; - -function draw() { - sw = fov * hdeg |0; - sh = h / 2 |0; - dh = h / 2 * scale |0; - - if ( layout == "180" ) { - sx = (w / 2 - fov * hdeg) / 2 + yaw * hdeg |0; - sy = ( h - fov * vdeg) / 2 + pitch * vdeg |0; - if (sx + sw > w / 2) { sx = w / 2 - sw; } else if (sx < 0) { sx = 0; } - lc.drawImage(video, sx + dist, sy, sw, sh, 0, 0, lv.width, dh); - rc.drawImage(video, w / 2 + sx - dist, sy, sw, sh, 0, 0, rv.width, dh); - } else { - sx = (w - fov * hdeg) / 2 + yaw * hdeg |0; - sy = (h - fov * vdeg) / 4 + pitch * vdeg |0; - lc.drawImage(video, sx + dist, sy, sw, sh, 0, 0, lv.width, dh); - rc.drawImage(video, sx - dist, h/2 + sy, sw, sh, 0, 0, rv.width, dh); - if (sx + dist < 0) { lc.drawImage(video, sx + w + dist, sy, sw, sh, 0, 0, lv.width, dh); } - if (sx - dist < 0) { rc.drawImage(video, sx + w - dist, h/2 + sy, sw, sh, 0, 0, rv.width, dh); } - if (sx + dist + fov * hdeg > w) { lc.drawImage(video, sx - w + dist, sy, sw, sh, 0, 0, lv.width, dh); } - if (sx - dist + fov * hdeg > w) { rc.drawImage(video, sx - w - dist, h/2 + sy, sw, sh, 0, 0, rv.width, dh); } - } - lv.style.transform = "rotate(" + roll + "deg)"; - rv.style.transform = "rotate(" + roll + "deg)"; - - requestAnimationFrame(draw); - - gp = navigator.getGamepads()[0]; - if ( gp && Date.now() > controlTimeout ) { - if ( gp.axes[0] > .3) { video.currentTime += 10; controlTimeout = Date.now() + 500; } - if ( gp.axes[0] < -.3) { video.currentTime -= 10; controlTimeout = Date.now() + 500; } - if ( gp.axes[1] < -.3) { video.currentTime += 60; controlTimeout = Date.now() + 500; } - if ( gp.axes[1] > .3) { video.currentTime -= 60; controlTimeout = Date.now() + 500; } - if ( gp.buttons[0].pressed ) { video.currentTime += 1/30; video.pause(); } - if ( gp.buttons[1].pressed ) { video.play(); } - if ( gp.buttons[2].pressed ) { fov -= 10; controlTimeout = Date.now() + 500; } - if ( gp.buttons[3].pressed ) { fov += 10; controlTimeout = Date.now() + 500; } - if ( gp.axes[2] < -.3) { dist -= 1; controlTimeout = Date.now() + 500; } - if ( gp.axes[2] > .3) { dist += 1; controlTimeout = Date.now() + 500; } - - date = new Date(); - date.setTime(date.getTime() + 3 * 365 * 86400 * 1000) - document.cookie = "StereoDist=" + dist + "; expires=" + date.toUTCString() + "; path=/"; - document.cookie = "StereoFOV=" + fov + "; expires=" + date.toUTCString() + "; path=/"; - } + contLeft.setAttribute("style", "position: fixed; top: 0; left: 0; width: 50%; height: 100%; overflow: hidden; z-index: 100; background-color: #000;"); +contRight.setAttribute("style", "position: fixed; top: 0; right: 0; width: 50%; height: 100%; overflow: hidden; z-index: 100; background-color: #000;"); + lv.setAttribute("style", "position: absolute; top: 50%; left: calc(100% - 32mm); max-width: unset; max-height: unset;"); + rv.setAttribute("style", "position: absolute; top: 50%; left: 32mm; max-width: unset; max-height: unset;"); + debug.setAttribute("style", "display: none; position: fixed; top: 0; left: 0; z-index: 101; background: #000;"); - // debug.textContent = "" + video.currentTime + " " + controlTimeout + " " + tx + " " + ty + " " + tz; - // debug.textContent = "Pitch: " + pitch + " | Yaw: " + yaw + " | Roll: " + roll; -}; function stereoview(layout, video) { this.layout = layout; this.video = video; - document.body.appendChild( lv ); - document.body.appendChild( rv ); + + let w = video.videoWidth; h = video.videoHeight; + let render, controlTimeout = 0; + let pitch = 0, roll = 0, yaw = 0; + let scale, fov = 90, dist = 32; + + document.body.appendChild(contLeft ).appendChild( lv ); + document.body.appendChild(contRight).appendChild( rv ); document.body.appendChild( debug ); + + if ( layout == "180") { + lv.width = rv.width = w / 2; lv.height = rv.height = h; + } else { + lv.width = rv.width = w; lv.height = rv.height = h / 2; + } + + lc = lv.getContext("2d"); rc = rv.getContext("2d"); + + function draw() { + if ( layout == "180" ) { + scale = contLeft.offsetHeight / h * 2 * fov / 90; + lc.drawImage(video, 0, 0); + rc.drawImage(video, -w / 2, 0); + lv.style.transform = rv.style.transform = + "translate(" + (yaw / 180 * -w / 4 * scale - w / 4) + "px, " + + (pitch / 90 * -h / 2 * scale - h / 2) + "px)" + + "rotate(" + roll + "deg) " + "scale(" + (scale / 2) + ", " + scale + ")"; + } else { + scale = contLeft.offsetHeight / h * 4 * fov / 90; + lc.drawImage(video, yaw / 180 * -w / 2, 0); + lc.drawImage(video, yaw / 180 * -w / 2 + ((yaw>0) ? w : -w), 0); + rc.drawImage(video, yaw / 180 * -w / 2, -h/2); + rc.drawImage(video, yaw / 180 * -w / 2 + ((yaw>0) ? w : -w), -h/2); + lv.style.transform = rv.style.transform = + "translate(" + (- w / 2) + "px, " + (pitch / 90 * -h / 2 * (scale / 2) - h / 4) + "px) " + + "rotate(" + roll + "deg) " + "scale(" + (scale / 2) + ", " + scale + ")"; + } + + // debug.textContent = "" + video.currentTime + " " + controlTimeout + " " + tx + " " + ty + " " + tz; + debug.textContent = "Pitch: " + pitch.toFixed(2) + " | Yaw: " + yaw.toFixed(2) + " | Roll: " + roll.toFixed(2) + + " | FOV: " + fov + " | Eye Distance: " + (2 * dist) + "mm"; - lv.setAttribute( "style", "position: fixed; top: 0; left: 0 ; width: 50%; height: 100%; z-index: 100;"); - rv.setAttribute( "style", "position: fixed; top: 0; left: 50%; width: 50%; height: 100%; z-index: 100;"); - debug.setAttribute( "style", "position: fixed; top: 0; left: 0; z-index: 101; background: #000;"); - - lv.setAttribute( "width", "" + lv.offsetWidth); - rv.setAttribute( "width", "" + rv.offsetWidth); - lv.setAttribute("height", "" + lv.offsetHeight); - rv.setAttribute("height", "" + rv.offsetHeight); - - lc = lv.getContext("2d"); - rc = rv.getContext("2d"); + requestAnimationFrame(draw); + + gpinput(); + }; + + function gpinput() { + let gp = navigator.getGamepads()[0]; + let date = new Date(); + + debug.innerHTML += "

GamePad: " + gp.axes[0].toFixed(3) + " | " + gp.axes[1].toFixed(3) + for (cnt = 0; cnt < 16; cnt++) { + gp.buttons[cnt].pressed ? debug.textContent += " | B" + cnt + " 1" : debug.textContent += " | B" + cnt + " 0"; + } + + if ( gp && Date.now() < controlTimeout ) { + true; + } else if (gp.buttons[0].pressed && gp.buttons[5].pressed) { + this.layout = layout = "180"; + document.body.appendChild(contLeft ).appendChild( lv ); + document.body.appendChild(contRight).appendChild( rv ); + lv.width = rv.width = w / 2; lv.height = rv.height = h; + video.play(); + controlTimeout = Date.now() + 600; + } else if (gp.buttons[0].pressed && gp.buttons[4].pressed) { + this.layout = layout = "360"; + document.body.appendChild(contLeft ).appendChild( lv ); + document.body.appendChild(contRight).appendChild( rv ); + lv.width = rv.width = w; lv.height = rv.height = h / 2; + video.play(); + controlTimeout = Date.now() + 600; + } else if (gp.buttons[0].pressed) { + ( contLeft.parentElement)? contLeft.parentElement.removeChild(contLeft ):{}; + (contRight.parentElement)?contRight.parentElement.removeChild(contRight):{}; + video.pause(); + controlTimeout = Date.now() + 300; + } else if (gp.buttons[1].pressed) { + (debug.style.display == "block") ? debug.style.display = "none" : debug.style.display = "block"; + controlTimeout = Date.now() + 300; + } else if (gp.buttons[5].pressed) { + video.paused ? video.play() : video.pause(); + controlTimeout = Date.now() + 300; + } else if (gp.buttons[4].pressed) { + video.currentTime += 1 / 30; + controlTimeout = Date.now() + 300; + } else if (gp.buttons[3].pressed && gp.axes[0] < -.3) { + dist -= .5; + lv.style.left = "calc(100% - " + dist + "mm)"; + rv.style.left = "" + dist + "mm"; + date.setTime(date.getTime() + 3 * 365 * 86400 * 1000) + document.cookie = "StereoDist=" + dist + "; expires=" + date.toUTCString() + "; path=/"; + controlTimeout = Date.now() + 300; + } else if (gp.buttons[3].pressed && gp.axes[0] > .3) { + dist += .5; + lv.style.left = "calc(100% - " + dist + "mm)"; + rv.style.left = "" + dist + "mm"; + date.setTime(date.getTime() + 3 * 365 * 86400 * 1000) + document.cookie = "StereoDist=" + dist + "; expires=" + date.toUTCString() + "; path=/"; + controlTimeout = Date.now() + 300; + } else if (gp.buttons[3].pressed && gp.axes[1] < -.3) { + fov -= 10; + date.setTime(date.getTime() + 3 * 365 * 86400 * 1000) + document.cookie = "StereoFOV=" + fov + "; expires=" + date.toUTCString() + "; path=/"; + controlTimeout = Date.now() + 300; + } else if (gp.buttons[3].pressed && gp.axes[1] > .3) { + fov += 10; + date.setTime(date.getTime() + 3 * 365 * 86400 * 1000) + document.cookie = "StereoFOV=" + fov + "; expires=" + date.toUTCString() + "; path=/"; + controlTimeout = Date.now() + 300; + } else if (gp.buttons[2].pressed && gp.axes[0] < -.3) { + yaw -= pitch ? ( Math.cos(pitch * Math.PI / 180) % 360 ) : 1; + if ( yaw > 180) yaw -= 360; + if ( yaw < -180) yaw += 360; + controlTimeout = Date.now() + 30; + } else if (gp.buttons[2].pressed && gp.axes[0] > .3) { + yaw += pitch ? ( Math.cos(pitch * Math.PI / 180) % 360 ) : 1; + if ( yaw > 180) yaw -= 360; + if ( yaw < -180) yaw += 360; + controlTimeout = Date.now() + 30; + } else if (gp.buttons[2].pressed && gp.axes[1] < -.3) { + video.volume += .05; + controlTimeout = Date.now() + 300; + } else if (gp.buttons[2].pressed && gp.axes[1] > .3) { + video.volume -= .05; + controlTimeout = Date.now() + 300; + } else if ( gp.axes[0] > .3) { + video.currentTime += 10; + controlTimeout = Date.now() + 200; + } else if ( gp.axes[0] < -.3) { + video.currentTime -= 10; + controlTimeout = Date.now() + 200; + } else if ( gp.axes[1] > .3) { + video.currentTime -= 60; + controlTimeout = Date.now() + 300; + } else if ( gp.axes[1] < -.3) { + video.currentTime += 60; + controlTimeout = Date.now() + 300; + } + } // mpuevent = new EventSource("http://localhost:314"); // var x = [], y = [], z = [], cnt = -1, inertia = 6; @@ -117,8 +197,8 @@ function stereoview(layout, video) { // }, false ); window.addEventListener("devicemotion", (function() { - var x = [], y = [], z = [], cnt = -1, inertia = 6; - return function(event) { + let x = [], y = [], z = [], cnt = -1, inertia = 6; + return event => { cnt = (cnt + 1) % inertia; x[cnt] = event.accelerationIncludingGravity.x; @@ -135,6 +215,8 @@ function stereoview(layout, video) { - event.rotationRate.alpha / 1000 * event.interval * Math.cos(pitch * Math.PI / 180) - event.rotationRate.gamma / 1000 * event.interval * Math.sin(pitch * Math.PI / 180) ) % 360 : yaw; + if ( yaw > 180) yaw -= 360; + if ( yaw < -180) yaw += 360; // pitch = (pitch + event.rotationRate.beta / 1000 * event.interval) % 360; // roll = (roll + event.rotationRate.gamma / 1000 * event.interval) % 360; @@ -143,20 +225,16 @@ function stereoview(layout, video) { })()); window.addEventListener("click", function(event) { - (lv.parentElement)?lv.parentElement.removeChild(lv):{}; - (rv.parentElement)?rv.parentElement.removeChild(rv):{}; - video.style.display = "block"; + ( contLeft.parentElement)? contLeft.parentElement.removeChild(contLeft ):{}; + (contRight.parentElement)?contRight.parentElement.removeChild(contRight):{}; + // video.style.display = "block"; video.pause(); }, true); - w = video.videoWidth; h = video.videoHeight; - hdeg = w / 360; vdeg = h / 180; - scale = lv.width / (fov * hdeg |0); + dist = dist ? dist : parseInt(document.getElementById("StereoDist").getAttribute("value")); + fov = fov ? fov : parseInt(document.getElementById("StereoFOV" ).getAttribute("value")); - dist = parseInt(document.getElementById("StereoDist").getAttribute("value")); - fov = parseInt(document.getElementById("StereoFOV").getAttribute("value")); - // scale = lv.width / (w / 4); video.play(); - video.style.display = "none"; + // video.style.display = "none"; draw(); }; diff --git a/view.sh b/view.sh index 0bc524a..5263e2c 100755 --- a/view.sh +++ b/view.sh @@ -27,7 +27,7 @@ printf 'Content-Type: text/html;charset=utf-8\r\n\r\n' w_prefs cat <<-EOF [input type=hidden id=StereoFOV name=StereoFOV value="$(COOKIE StereoFOV |grep -xE '[0-9]+' || printf 90)"] - [input type=hidden id=StereoDist name=StereoDist value="$(COOKIE StereoDist |grep -xE '[0-9]+' || printf 0)"] + [input type=hidden id=StereoDist name=StereoDist value="$(COOKIE StereoDist |grep -xE '[0-9]+' || printf 32)"] [video #mainvideo controls="controls" preload="auto" [source src="?a=download" type="video/mp4"]] [a "?a=download" Download] [a "javascript:stereoview(180, document.getElementById("mainvideo"));" View 180° Stereoscopic] -- 2.39.2