UNPKG

holoplay-core

Version:

A library that works with Looking Glass HoloPlay Service

12 lines 20.5 kB
(function(e,t){typeof exports==="object"&&typeof module!=="undefined"?t(exports):typeof define==="function"&&define.amd?define(["exports"],t):(e=e||self,t(e.HoloPlayCore={}))})(this,(function(e){"use strict";var t=typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:typeof global!=="undefined"?global:typeof self!=="undefined"?self:{};function n(e,t){return t={exports:{}},e(t,t.exports),t.exports}var i=n((function(e){(function(t,n){var i=Math.pow(2,-24),r=Math.pow(2,32),s=Math.pow(2,53);function o(e){var t=new ArrayBuffer(256);var i=new DataView(t);var o;var l=0;function a(e){var n=t.byteLength;var r=l+e;while(n<r)n*=2;if(n!==t.byteLength){var s=i;t=new ArrayBuffer(n);i=new DataView(t);var a=l+3>>2;for(var c=0;c<a;++c)i.setUint32(c*4,s.getUint32(c*4))}o=e;return i}function c(){l+=o}function u(e){c(a(8).setFloat64(l,e))}function f(e){c(a(1).setUint8(l,e))}function h(e){var t=a(e.length);for(var n=0;n<e.length;++n)t.setUint8(l+n,e[n]);c()}function v(e){c(a(2).setUint16(l,e))}function w(e){c(a(4).setUint32(l,e))}function d(e){var t=e%r;var n=(e-t)/r;var i=a(8);i.setUint32(l,n);i.setUint32(l+4,t);c()}function g(e,t){if(t<24){f(e<<5|t)}else if(t<256){f(e<<5|24);f(t)}else if(t<65536){f(e<<5|25);v(t)}else if(t<4294967296){f(e<<5|26);w(t)}else{f(e<<5|27);d(t)}}function p(e){var t;if(e===false)return f(244);if(e===true)return f(245);if(e===null)return f(246);if(e===n)return f(247);switch(typeof e){case"number":if(Math.floor(e)===e){if(0<=e&&e<=s)return g(0,e);if(-s<=e&&e<0)return g(1,-(e+1))}f(251);return u(e);case"string":var i=[];for(t=0;t<e.length;++t){var r=e.charCodeAt(t);if(r<128){i.push(r)}else if(r<2048){i.push(192|r>>6);i.push(128|r&63)}else if(r<55296){i.push(224|r>>12);i.push(128|r>>6&63);i.push(128|r&63)}else{r=(r&1023)<<10;r|=e.charCodeAt(++t)&1023;r+=65536;i.push(240|r>>18);i.push(128|r>>12&63);i.push(128|r>>6&63);i.push(128|r&63)}}g(3,i.length);return h(i);default:var o;if(Array.isArray(e)){o=e.length;g(4,o);for(t=0;t<o;++t)p(e[t])}else if(e instanceof Uint8Array){g(2,e.length);h(e)}else{var l=Object.keys(e);o=l.length;g(5,o);for(t=0;t<o;++t){var a=l[t];p(a);p(e[a])}}}}p(e);if("slice"in t)return t.slice(0,l);var x=new ArrayBuffer(l);var C=new DataView(x);for(var y=0;y<l;++y)C.setUint8(y,i.getUint8(y));return x}function l(e,t,s){var o=new DataView(e);var l=0;if(typeof t!=="function")t=function(e){return e};if(typeof s!=="function")s=function(){return n};function a(e,t){l+=t;return e}function c(t){return a(new Uint8Array(e,l,t),t)}function u(){var e=new ArrayBuffer(4);var t=new DataView(e);var n=w();var r=n&32768;var s=n&31744;var o=n&1023;if(s===31744)s=255<<10;else if(s!==0)s+=127-15<<10;else if(o!==0)return o*i;t.setUint32(0,r<<16|s<<13|o<<13);return t.getFloat32(0)}function f(){return a(o.getFloat32(l),4)}function h(){return a(o.getFloat64(l),8)}function v(){return a(o.getUint8(l),1)}function w(){return a(o.getUint16(l),2)}function d(){return a(o.getUint32(l),4)}function g(){return d()*r+d()}function p(){if(o.getUint8(l)!==255)return false;l+=1;return true}function x(e){if(e<24)return e;if(e===24)return v();if(e===25)return w();if(e===26)return d();if(e===27)return g();if(e===31)return-1;throw"Invalid length encoding"}function C(e){var t=v();if(t===255)return-1;var n=x(t&31);if(n<0||t>>5!==e)throw"Invalid indefinite length element";return n}function y(e,t){for(var n=0;n<t;++n){var i=v();if(i&128){if(i<224){i=(i&31)<<6|v()&63;t-=1}else if(i<240){i=(i&15)<<12|(v()&63)<<6|v()&63;t-=2}else{i=(i&15)<<18|(v()&63)<<12|(v()&63)<<6|v()&63;t-=3}}if(i<65536){e.push(i)}else{i-=65536;e.push(55296|i>>10);e.push(56320|i&1023)}}}function m(){var e=v();var i=e>>5;var r=e&31;var o;var l;if(i===7){switch(r){case 25:return u();case 26:return f();case 27:return h()}}l=x(r);if(l<0&&(i<2||6<i))throw"Invalid length";switch(i){case 0:return l;case 1:return-1-l;case 2:if(l<0){var a=[];var w=0;while((l=C(i))>=0){w+=l;a.push(c(l))}var d=new Uint8Array(w);var g=0;for(o=0;o<a.length;++o){d.set(a[o],g);g+=a[o].length}return d}return c(l);case 3:var b=[];if(l<0){while((l=C(i))>=0)y(b,l)}else y(b,l);return String.fromCharCode.apply(null,b);case 4:var _;if(l<0){_=[];while(!p())_.push(m())}else{_=new Array(l);for(o=0;o<l;++o)_[o]=m()}return _;case 5:var V={};for(o=0;o<l||l<0&&!p();++o){var S=m();V[S]=m()}return V;case 6:return t(m(),l);case 7:switch(l){case 20:return false;case 21:return true;case 22:return null;case 23:return n;default:return s(l)}}}var b=m();if(l!==e.byteLength)throw"Remaining bytes";return b}var a={encode:o,decode:l};if(typeof n==="function"&&n.amd)n("cbor/cbor",a);else if(e.exports)e.exports=a;else if(!t.CBOR)t.CBOR=a})(t)})); /** * This files defines the HoloPlayClient class and Message class. * * Copyright (c) [2024] [Looking Glass Factory] * * @link https://lookingglassfactory.com/ * @file This files defines the HoloPlayClient class and Message class. * @author Looking Glass Factory. * @version 0.0.11 * @license SEE LICENSE IN LICENSE.txt */const r=typeof window==="undefined"?require("ws"):window.WebSocket;class s{constructor(e,t,n,i=false,r,s,o){this.reqs=[];this.reps=[];this.requestId=this.getRequestId();this.debug=i;this.isGreedy=s;this.errCallback=t;this.closeCallback=n;this.alwaysdebug=false;this.isConnected=false;let a=null;if(r||s||o){a=new l(r,s,o,this.debug)}else{if(i)this.alwaysdebug=true;if(typeof e=="function")a=new f}this.openWebsocket(a,e)}sendMessage(e,t=60){if(this.alwaysdebug)e.cmd.debug=true;let n=e.toCbor();return this.sendRequestObj(n,t)}disconnect(){this.ws.close()}openWebsocket(e=null,t=null){this.ws=new r("ws://localhost:11222/driver",["rep.sp.nanomsg.org"]);this.ws.parent=this;this.ws.binaryType="arraybuffer";this.ws.onmessage=this.messageHandler;this.ws.onopen=()=>{this.isConnected=true;if(this.debug){console.log("socket open")}if(e!=null){this.sendMessage(e).then(t)}};this.ws.onerror=this.onSocketError;this.ws.onclose=this.onClose}sendRequestObj(e,t){return new Promise((n,i)=>{let r={id:this.requestId++,parent:this,payload:e,success:n,error:i,send:function(){if(this.debug)console.log("attemtping to send request with ID "+this.id);this.timeout=setTimeout(r.send.bind(this),t*1e3);let n=new Uint8Array(e.byteLength+4);let i=new DataView(n.buffer);i.setUint32(0,this.id);n.set(new Uint8Array(this.payload),4);this.parent.ws.send(n.buffer)}};this.reqs.push(r);r.send()})}messageHandler(e){let t=e.data;if(t.byteLength<4)return;let n=new DataView(t);let r=n.getUint32(0);if(r<2147483648){this.parent.err("bad nng header");return}let s=this.parent.findReqIndex(r);if(s==-1){this.parent.err("got reply that doesn't match known request!");return}let o={id:r,payload:i.decode(t.slice(4))};if(o.payload.error==0){this.parent.reqs[s].success(o.payload)}else{this.parent.reqs[s].error(o.payload)}clearTimeout(this.parent.reqs[s].timeout);this.parent.reqs.splice(s,1);this.parent.reps.push(o);if(this.debug){console.log(o.payload)}}getRequestId(){return Math.floor(this.prng()*2147483647)+2147483648}onClose(e){this.parent.isConnected=false;if(this.parent.debug){console.log("socket closed")}if(typeof this.parent.closeCallback=="function")this.parent.closeCallback(e)}onSocketError(e){if(this.parent.debug){console.log(e)}if(typeof this.parent.errCallback=="function"){this.parent.errCallback(e)}}err(e){if(this.debug){console.log("[DRIVER ERROR]"+e)}}findReqIndex(e){let t=0;for(;t<this.reqs.length;t++){if(this.reqs[t].id==e){return t}}return-1}prng(){if(this.rng==undefined){this.rng=p()}return this.rng()}}class o{constructor(e,t){this.cmd=e;this.bin=t}toCbor(){return i.encode(this)}}class l extends o{constructor(e="",t=false,n="",i=false){let r={init:{}};if(e!="")r["init"].appid=e;if(n!="")r["init"].onclose=n;if(t)r["init"].greedy=true;if(i)r["init"].debug=true;super(r,null)}}class a extends o{constructor(e=""){let t={delete:{name:e}};super(t,null)}}class c extends o{constructor(e=""){let t={check:{name:e}};super(t,null)}}class u extends o{constructor(e=null){let t={wipe:{}};if(e!=null)t["wipe"].targetDisplay=e;super(t,null)}}class f extends o{constructor(){let e={info:{}};super(e,null)}}class h extends o{constructor(){let e={uniforms:{}};super(e,bindata)}}class v extends o{constructor(){let e={shader:{}};super(e,bindata)}}class w extends o{constructor(e={vx:5,vy:9,aspect:1.6},t="",n=null){let i={show:{source:"bindata",quilt:{type:"image",settings:e}}};if(n!=null)i["show"]["targetDisplay"]=n;super(i,t)}}class d extends o{constructor(e,t={vx:5,vy:9,aspect:1.6},n="",i=false){let r={cache:{show:i,quilt:{name:e,type:"image",settings:t}}};super(r,n)}}class g extends o{constructor(e,t=null,n=null){let i={show:{source:"cache",quilt:{name:e}}};if(t!=null)i["show"]["targetDisplay"]=t;if(n!=null)i["show"]["quilt"].settings=n;super(i,null)}}function p(){function e(e){for(var t=0,n=1779033703^e.length;t<e.length;t++)n=Math.imul(n^e.charCodeAt(t),3432918353),n=n<<13|n>>>19;return function(){n=Math.imul(n^n>>>16,2246822507);n=Math.imul(n^n>>>13,3266489909);return(n^=n>>>16)>>>0}}function t(e,t,n,i){return()=>{var r=t<<9,s=e*5;s=(s<<7|s>>>25)*9;n^=e;i^=t;t^=n;e^=i;n^=r;i=i<<11|i>>>21;return(s>>>0)/4294967296}}var n=Date.now();var i=e(n.toString());return t(i(),i(),i(),i())}function x(e,...t){let n=e[0];for(let i=1;i<e.length;++i){const r=t[i-1];n+=typeof r==="number"?r.toPrecision(10):r;n+=e[i]}return n}function C(e){const t=x`${e.pitch}`;const n=x`${e.tilt}`;const i=x`${e.calibration.center.value}`;const r=x`${e.subp}`;const s=x`${e.numViews}`;const o=x`${e.quiltWidth}`;const l=x`${e.quiltHeight}`;const a=`${Math.round(e.calibration.subpixelCells.length)}`;const c=`${Math.round(e.subpixelMode)}`;const u=x`${e.framebufferWidth}`;const f=x`${e.framebufferHeight}`;const h=x`${e.tileHeight}`;const v=x`${e.tileWidth}`;const w=x`${e.quiltWidth}`;const d=x`${e.quiltHeight}`;const g=x`${e.calibration.screenW.value}`;const p=x`${e.calibration.screenH.value}`;const C=`${Math.round(e.filterMode)}`;const y=x`${e.gaussianSigma}`;return`#version 300 es\n precision mediump float;\n\n uniform int u_viewType;\n uniform sampler2D u_texture;\n in vec2 v_texcoord;\n\n const int MAX_SUBPIXELS = 60;\n uniform float subpixelData[MAX_SUBPIXELS];\n\n const int subpixelCellCount = ${a};\n const int cellPatternType = ${c};\n const int filter_mode = ${C};\n const float gaussian_sigma = ${y};\n const float tileCount = ${s};\n const float focus = 0.0;\n\n const vec2 quiltViewPortion = vec2(\n ${w*v/u},\n ${d*h/f});\n\n int GetCellForPixel(vec2 screen_uv)\n {\n int xPos = int(screen_uv.x * ${g});\n int yPos = int(screen_uv.y * ${p});\n int cell;\n \n if(cellPatternType == 0)\n {\n cell = 0;\n }\n else if(cellPatternType == 1)\n {\n // Checkerboard pattern AB\n // BA\n if ((yPos % 2 == 0 && xPos % 2 == 0) || (yPos % 2 != 0 && xPos % 2 != 0)) {\n cell = 0;\n } else {\n cell = 1;\n }\n }\n else if(cellPatternType == 2)\n {\n cell = xPos % 2;\n }\n else if(cellPatternType == 3)\n {\n int offset = (xPos % 2) * 2;\n cell = ((yPos + offset) % 4);\n }\n else if(cellPatternType == 4)\n {\n cell = yPos % 2;\n }\n \n return cell % subpixelCellCount;\n }\n\n vec2 GetQuiltCoordinates(vec2 tile_uv, int viewIndex)\n {\n float totalTiles = tileCount;\n float floaty = float(viewIndex);\n float view = clamp(floaty, 0.0, totalTiles);\n // on some platforms this is required to fix some precision issue???\n float tx = ${o} - 0.00001; // just an incredibly dumb bugfix\n float tileXIndex = mod(view, tx);\n float tileYIndex = floor(view / tx);\n \n float quiltCoordU = ((tileXIndex + tile_uv.x) / tx) * quiltViewPortion.x;\n float quiltCoordV = ((tileYIndex + tile_uv.y) / ${l}) * quiltViewPortion.y;\n \n vec2 quilt_uv = vec2(quiltCoordU, quiltCoordV);\n \n return quilt_uv;\n }\n\n float GetPixelShift(float val, int subPixel, int axis, int cell)\n {\n int index = cell * 6 + subPixel * 2 + axis;\n float offset = subpixelData[index];\n\n return val + offset;\n }\n\n vec3 GetSubpixelViews(vec2 screen_uv) {\n vec3 views = vec3(0.0);\n\n // calculate x contribution for each cell\n if(subpixelCellCount <= 0)\n {\n views[0] = screen_uv.x + ${r} * 0.0;\n views[1] = screen_uv.x + ${r} * 1.0;\n views[2] = screen_uv.x + ${r} * 2.0;\n \n \n // calculate y contribution for each cell\n views[0] += screen_uv.y * ${n};\n views[1] += screen_uv.y * ${n};\n views[2] += screen_uv.y * ${n};\n } else {\n // get the cell type for this screen space pixel\n int cell = GetCellForPixel(screen_uv);\n \n // calculate x contribution for each cell\n views[0] = GetPixelShift(screen_uv.x, 0, 0, cell);\n views[1] = GetPixelShift(screen_uv.x, 1, 0, cell);\n views[2] = GetPixelShift(screen_uv.x, 2, 0, cell);\n \n // calculate y contribution for each cell\n views[0] += GetPixelShift(screen_uv.y, 0, 1, cell) * ${n};\n views[1] += GetPixelShift(screen_uv.y, 1, 1, cell) * ${n};\n views[2] += GetPixelShift(screen_uv.y, 2, 1, cell) * ${n};\n }\n\n views *= vec3(${t});\n views -= vec3(${i});\n views = vec3(1.0) - fract(views);\n\n views = clamp(views, vec3(0.00001), vec3(0.999999));\n \n return views;\n }\n \n // this is the simplest sampling mode where we just cast the viewIndex to int and take the color from that tile.\n vec4 GetViewsColors(vec2 tile_uv, vec3 views)\n {\n vec4 color = vec4(0, 0, 0, 1);\n \n for(int channel = 0; channel < 3; channel++)\n {\n int viewIndex = int(views[channel] * tileCount);\n \n float viewDir = views[channel] * 2.0 - 1.0;\n vec2 focused_uv = tile_uv;\n focused_uv.x += viewDir * focus;\n \n vec2 quilt_uv = GetQuiltCoordinates(focused_uv, viewIndex);\n color[channel] = texture(u_texture, quilt_uv)[channel];\n }\n \n return color;\n }\n\n //view filtering\n\n vec4 OldViewFiltering(vec2 tile_uv, vec3 views)\n {\n vec3 viewIndicies = views * tileCount;\n float viewSpaceTileSize = 1.0 / tileCount;\n \n // the idea here is to sample the closest two views and lerp between them\n vec3 leftViews = views;\n vec3 rightViews = leftViews + viewSpaceTileSize;\n \n vec4 leftColor = GetViewsColors(tile_uv, leftViews);\n vec4 rightColor = GetViewsColors(tile_uv, rightViews);\n \n vec3 leftRightLerp = viewIndicies - floor(viewIndicies);\n \n return vec4(\n mix(leftColor.x, rightColor.x, leftRightLerp.x),\n mix(leftColor.y, rightColor.y, leftRightLerp.y),\n mix(leftColor.z, rightColor.z, leftRightLerp.z),\n 1.0\n );\n }\n\n vec4 GaussianViewFiltering(vec2 tile_uv, vec3 views)\n {\n vec3 viewIndicies = views * tileCount;\n float viewSpaceTileSize = 1.0 / tileCount;\n \n // this is just sampling a center view and the left and right view\n vec3 centerViews = views;\n vec3 leftViews = centerViews - viewSpaceTileSize;\n vec3 rightViews = centerViews + viewSpaceTileSize;\n \n vec4 centerColor = GetViewsColors(tile_uv, centerViews);\n vec4 leftColor = GetViewsColors(tile_uv, leftViews);\n vec4 rightColor = GetViewsColors(tile_uv, rightViews);\n \n // Calculate the effective discrete view directions based on the tileCount\n vec3 centerSnappedViews = floor(centerViews * tileCount) / tileCount;\n vec3 leftSnappedViews = floor(leftViews * tileCount) / tileCount;\n vec3 rightSnappedViews = floor(rightViews * tileCount) / tileCount;\n \n // Gaussian weighting\n float sigma = gaussian_sigma;\n float multiplier = 2.0 * sigma * sigma;\n \n vec3 centerDiff = views - centerSnappedViews;\n vec3 leftDiff = views - leftSnappedViews;\n vec3 rightDiff = views - rightSnappedViews;\n \n vec3 centerWeight = exp(-centerDiff * centerDiff / multiplier);\n vec3 leftWeight = exp(-leftDiff * leftDiff / multiplier);\n vec3 rightWeight = exp(-rightDiff * rightDiff / multiplier);\n \n // Normalize the weights so they sum to 1 for each channel\n vec3 totalWeight = centerWeight + leftWeight + rightWeight;\n centerWeight /= totalWeight;\n leftWeight /= totalWeight;\n rightWeight /= totalWeight;\n \n // Weighted averaging based on Gaussian weighting for each channel\n vec4 outputColor = vec4(\n centerColor.r * centerWeight.x + leftColor.r * leftWeight.x + rightColor.r * rightWeight.x,\n centerColor.g * centerWeight.y + leftColor.g * leftWeight.y + rightColor.g * rightWeight.y,\n centerColor.b * centerWeight.z + leftColor.b * leftWeight.z + rightColor.b * rightWeight.z,\n 1.0\n );\n \n return outputColor;\n }\n\n vec4 NGaussianViewFiltering(vec2 tile_uv, vec3 views, int n)\n {\n vec3 viewIndicies = views * tileCount;\n float viewSpaceTileSize = 1.0 / tileCount;\n \n float sigma = gaussian_sigma; // Adjust as needed\n float multiplier = 2.0 * sigma * sigma;\n \n vec4 outputColor = vec4(0.0);\n \n for(int i = -n; i <= n; i++)\n {\n float offset = float(i) * viewSpaceTileSize;\n vec3 offsetViews = views + offset;\n \n vec4 sampleColor = GetViewsColors(tile_uv, offsetViews);\n \n // Calculate the effective discrete view directions based on the tileCount\n vec3 snappedViews = floor(offsetViews * tileCount) / tileCount;\n \n // Calculate Gaussian weights\n vec3 diff = views - snappedViews;\n vec3 weight = exp(-diff * diff / multiplier);\n \n // Accumulate color\n outputColor.rgb += sampleColor.rgb * weight;\n }\n // Normalize the color\n vec3 totalWeight = vec3(0.0);\n for(int i = -n; i <= n; i++)\n {\n float offset = float(i) * viewSpaceTileSize;\n vec3 offsetViews = views + offset;\n \n // Calculate the effective discrete view directions based on the tileCount\n vec3 snappedViews = floor(offsetViews * tileCount) / tileCount;\n \n // Calculate Gaussian weights\n vec3 diff = views - snappedViews;\n vec3 weight = exp(-diff * diff / multiplier);\n \n totalWeight += weight;\n }\n \n outputColor.rgb /= totalWeight;\n outputColor.a = 1.0;\n \n return outputColor;\n }\n\n float remap(float value, float from1, float to1, float from2, float to2) {\n return (value - from1) / (to1 - from1) * (to2 - from2) + from2;\n }\n\n out vec4 color;\n\n void main() {\n if (u_viewType == 2) { // "quilt" view\n color = texture(u_texture, v_texcoord);\n return;\n }\n if (u_viewType == 1) { // middle view\n color = texture(u_texture, GetQuiltCoordinates(v_texcoord.xy, ${Math.round(s/2)}));\n return;\n }\n\n vec3 views = GetSubpixelViews(v_texcoord);\n\n if(filter_mode == 0)\n {\n color = GetViewsColors(v_texcoord, views);\n }\n else if(filter_mode == 1)\n {\n color = OldViewFiltering(v_texcoord, views);\n }\n else if(filter_mode == 2)\n {\n color = GaussianViewFiltering(v_texcoord, views);\n }\n else if(filter_mode == 3)\n {\n color = NGaussianViewFiltering(v_texcoord, views, 10);\n }\n }\n `}e.CacheMessage=d;e.CheckMessage=c;e.Client=s;e.DeleteMessage=a;e.InfoMessage=f;e.InitMessage=l;e.Message=o;e.Shader=C;e.ShaderMessage=v;e.ShowCachedMessage=g;e.ShowMessage=w;e.UniformsMessage=h;e.WipeMessage=u;Object.defineProperty(e,"__esModule",{value:true})}));