shaderpad 1.0.0-beta.64 → 1.0.0-beta.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,35 +1,35 @@
1
- "use strict";var he=Object.create;var Y=Object.defineProperty;var xe=Object.getOwnPropertyDescriptor;var Me=Object.getOwnPropertyNames;var Ne=Object.getPrototypeOf,Ce=Object.prototype.hasOwnProperty;var Ie=(t,e)=>{for(var n in e)Y(t,n,{get:e[n],enumerable:!0})},ce=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Me(e))!Ce.call(t,r)&&r!==n&&Y(t,r,{get:()=>e[r],enumerable:!(i=xe(e,r))||i.enumerable});return t};var ue=(t,e,n)=>(n=t!=null?he(Ne(t)):{},ce(e||!t||!t.__esModule?Y(n,"default",{value:t,enumerable:!0}):n,t)),Oe=t=>ce(Y({},"__esModule",{value:!0}),t);var je={};Ie(je,{default:()=>ze});module.exports=Oe(je);var Je={data:new Uint8Array(4),width:1,height:1};function z(t){return t instanceof HTMLVideoElement||t instanceof HTMLImageElement||t instanceof HTMLCanvasElement||t instanceof OffscreenCanvas}function Ee(t){return JSON.stringify(t,Object.keys(t).sort())}function j(t,e,n,i,r=0){let s=1/0,d=-1/0,o=1/0,u=-1/0,E=0,l=0;for(let m of n){let F=(r+e*i+m)*4,A=t[F],R=t[F+1];s=Math.min(s,A),d=Math.max(d,A),o=Math.min(o,R),u=Math.max(u,R),E+=t[F+2],l+=t[F+3]}return[(s+d)/2,(o+u)/2,E/n.length,l/n.length]}var K=null;function me(){return K||(K=import("@mediapipe/tasks-vision").then(({FilesetResolver:t})=>t.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.22-rc.20250304/wasm"))),K}function fe(t){return{historyParams:t?", framesAgo":"",fn:t?(i,r,s,d)=>{let o=s.replace(/\w+ /g,""),u=s?`${s}, int framesAgo`:"int framesAgo",E=o?`${o}, 0`:"0";return`${i} ${r}(${u}) {
2
- ${d}
1
+ "use strict";var he=Object.create;var j=Object.defineProperty;var xe=Object.getOwnPropertyDescriptor;var Me=Object.getOwnPropertyNames;var Ce=Object.getPrototypeOf,Ne=Object.prototype.hasOwnProperty;var Oe=(t,e)=>{for(var n in e)j(t,n,{get:e[n],enumerable:!0})},fe=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Me(e))!Ne.call(t,r)&&r!==n&&j(t,r,{get:()=>e[r],enumerable:!(i=xe(e,r))||i.enumerable});return t};var me=(t,e,n)=>(n=t!=null?he(Ce(t)):{},fe(e||!t||!t.__esModule?j(n,"default",{value:t,enumerable:!0}):n,t)),ye=t=>fe(j({},"__esModule",{value:!0}),t);var qe={};Oe(qe,{default:()=>je});module.exports=ye(qe);var Ze={data:new Uint8Array(4),width:1,height:1};function Q(t){return t instanceof HTMLVideoElement||t instanceof HTMLImageElement||t instanceof HTMLCanvasElement||t instanceof OffscreenCanvas}function Ee(t){return JSON.stringify(t,Object.keys(t).sort())}function ee(t,e,n,i,r=0){let s=1/0,E=-1/0,o=1/0,u=-1/0,l=0,d=0;for(let f of n){let g=(r+e*i+f)*4,T=t[g],F=t[g+1];s=Math.min(s,T),E=Math.max(E,T),o=Math.min(o,F),u=Math.max(u,F),l+=t[g+2],d+=t[g+3]}return[(s+E)/2,(o+u)/2,l/n.length,d/n.length]}var Z=null;function de(){return Z||(Z=import("@mediapipe/tasks-vision").then(({FilesetResolver:t})=>t.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.22-rc.20250304/wasm"))),Z}function _e(t){return{historyParams:t?", framesAgo":"",fn:t?(i,r,s,E)=>{let o=s.replace(/\w+ /g,""),u=s?`${s}, int framesAgo`:"int framesAgo",l=o?`${o}, 0`:"0";return`${i} ${r}(${u}) {
2
+ ${E}
3
3
  }
4
- ${i} ${r}(${s}) { return ${r}(${E}); }`}:(i,r,s,d)=>`${i} ${r}(${s}) {
5
- ${d}
6
- }`}}var le=`#version 300 es
4
+ ${i} ${r}(${s}) { return ${r}(${l}); }`}:(i,r,s,E)=>`${i} ${r}(${s}) {
5
+ ${E}
6
+ }`}}var Ae=`#version 300 es
7
7
  in vec2 a_pos;
8
8
  out vec2 v_uv;
9
9
  void main() {
10
10
  v_uv = a_pos;
11
11
  gl_Position = vec4(a_pos * 2.0 - 1.0, 0.0, 1.0);
12
- }`,ke=`#version 300 es
12
+ }`,Ie=`#version 300 es
13
13
  precision mediump float;
14
14
  uniform vec4 u_color;
15
15
  out vec4 outColor;
16
- void main() { outColor = u_color; }`,Se=`#version 300 es
16
+ void main() { outColor = u_color; }`,ke=`#version 300 es
17
17
  precision mediump float;
18
18
  in vec2 v_uv;
19
19
  uniform sampler2D u_texture;
20
20
  out vec4 outColor;
21
- void main() { outColor = texture(u_texture, v_uv); }`,ve=new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),$=478,Be=2,g=$+Be,I=512,M=1,_e=[336,296,334,293,300,276,283,282,295,285],Te=[362,398,384,385,386,387,388,466,263,249,390,373,374,380,381,382],Fe=[70,63,105,66,107,55,65,52,53,46],Ae=[33,246,161,160,159,158,157,173,133,155,154,153,145,144,163,7],Re=[61,185,40,39,37,0,267,269,270,409,291,375,321,405,314,17,84,181,91,146],J=[78,191,80,81,82,13,312,311,310,415,308,324,318,402,317,14,87,178,88,95],De=Array.from({length:$},(t,e)=>e),S={LEFT_EYEBROW:_e,LEFT_EYE:Te,LEFT_EYE_CENTER:473,RIGHT_EYEBROW:Fe,RIGHT_EYE:Ae,RIGHT_EYE_CENTER:468,NOSE_TIP:4,MOUTH:Re,INNER_MOUTH:J,FACE_CENTER:$,MOUTH_CENTER:$+1},ye=["OVAL","LEFT_EYEBROW","RIGHT_EYEBROW","LEFT_EYE","RIGHT_EYE","MOUTH","INNER_MOUTH"],D=["FACE_0","FACE_1","FACE_2","FACE_3","FACE_4","FACE_5","FACE_6","FACE_7"],Z=["FACE_8","FACE_9","FACE_10","FACE_11","FACE_12","FACE_13","FACE_14","FACE_15"],y=255,q=D.length+Z.length;function Q(t){return Object.fromEntries(t.map((e,n)=>[e,1<<n]))}function ee(t){return Object.fromEntries(Object.entries(t).map(([e,n])=>[e,n/y]))}var ge=Q(ye),Ue=Q(D),Pe=Q(Z),O=ee(ge),$e=ee(Ue),He=ee(Pe),Ge={modelPath:"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task",maxFaces:1,minFaceDetectionConfidence:.5,minFacePresenceConfidence:.5,minTrackingConfidence:.5,outputFaceBlendshapes:!1,outputFacialTransformationMatrixes:!1};function k(t){let e=[];for(let n=1;n<t.length-1;++n)e.push(t[0],t[n],t[n+1]);return e}var T=null;function Ye(t){if(!T){let e=t.FACE_LANDMARKS_TESSELATION,n=[];for(let r=0;r<e.length-2;r+=3)n.push(e[r].start,e[r+1].start,e[r+2].start);let i=t.FACE_LANDMARKS_FACE_OVAL.map(({start:r})=>r);T=Object.fromEntries(Object.entries({LEFT_EYEBROW:k(_e),RIGHT_EYEBROW:k(Fe),LEFT_EYE:k(Te),RIGHT_EYE:k(Ae),MOUTH:k(Re),INNER_MOUTH:k(J),TESSELATION:n,OVAL:k(i)}).map(([r,s])=>[r,{indices:s,vertices:new Float32Array(s.length*2)}]))}}var P=new Map;function de(t,e,n){let i=t.createShader(t.VERTEX_SHADER);t.shaderSource(i,e),t.compileShader(i);let r=t.createShader(t.FRAGMENT_SHADER);t.shaderSource(r,n),t.compileShader(r);let s=t.createProgram();return t.attachShader(s,i),t.attachShader(s,r),t.linkProgram(s),t.deleteShader(i),t.deleteShader(r),s}function we(t){let e=t.getContext("webgl2",{antialias:!1,preserveDrawingBuffer:!0}),n=de(e,le,ke),i=de(e,le,Se),r=e.createBuffer(),s=e.getAttribLocation(n,"a_pos"),d=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,d),e.bufferData(e.ARRAY_BUFFER,ve,e.STATIC_DRAW);let o=e.getAttribLocation(i,"a_pos"),u=e.getUniformLocation(n,"u_color"),E=e.getUniformLocation(i,"u_texture"),l=e.createTexture();e.bindTexture(e.TEXTURE_2D,l),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,1,1,0,e.RGBA,e.UNSIGNED_BYTE,null);let m=e.createFramebuffer();return e.bindFramebuffer(e.FRAMEBUFFER,m),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,l,0),e.bindFramebuffer(e.FRAMEBUFFER,null),e.useProgram(i),e.uniform1i(E,0),e.colorMask(!0,!0,!0,!1),{canvas:t,gl:e,regionProgram:n,blitProgram:i,regionPositionBuffer:r,quadBuffer:d,regionPositionLocation:s,blitPositionLocation:o,colorLocation:u,textureLocation:E,scratchTexture:l,scratchFramebuffer:m}}function We(t,e,n){let{gl:i,canvas:r,scratchTexture:s}=t;r.width===e&&r.height===n||(r.width=e,r.height=n,i.bindTexture(i.TEXTURE_2D,s),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,e,n,0,i.RGBA,i.UNSIGNED_BYTE,null))}function h(t,e,n,i,r,s,d){let{gl:o,regionProgram:u,regionPositionBuffer:E,regionPositionLocation:l,colorLocation:m,scratchFramebuffer:F}=t,A=M+i*g,{indices:R,vertices:v}=n;o.bindFramebuffer(o.FRAMEBUFFER,F),o.viewport(0,0,t.canvas.width,t.canvas.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),o.useProgram(u),o.bindBuffer(o.ARRAY_BUFFER,E),o.enableVertexAttribArray(l),o.vertexAttribPointer(l,2,o.FLOAT,!1,0,0),o.enable(o.BLEND),o.blendEquation(o.MAX),o.blendFunc(o.ONE,o.ONE);for(let a=0;a<R.length;++a){let N=(A+R[a])*4;v[a*2]=e[N],v[a*2+1]=e[N+1]}o.bufferData(o.ARRAY_BUFFER,v,o.DYNAMIC_DRAW),o.uniform4f(m,r,s,d,1),o.drawArrays(o.TRIANGLES,0,R.length)}function x(t){let{gl:e,blitProgram:n,quadBuffer:i,blitPositionLocation:r,scratchTexture:s}=t;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,t.canvas.width,t.canvas.height),e.useProgram(n),e.bindBuffer(e.ARRAY_BUFFER,i),e.enableVertexAttribArray(r),e.vertexAttribPointer(r,2,e.FLOAT,!1,0,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,s),e.enable(e.BLEND),e.blendEquation(e.FUNC_ADD),e.blendFunc(e.ONE,e.ONE),e.drawArrays(e.TRIANGLES,0,6)}function Ve(t,e){let n=t.landmarks.data,i=e.length;n[0]=i;for(let r=0;r<i;++r){let s=e[r];for(let u=0;u<$;++u){let E=s[u],l=(M+r*g+u)*4;n[l]=E.x,n[l+1]=1-E.y,n[l+2]=E.z??0,n[l+3]=E.visibility??1}let d=j(n,r,De,g,M);n.set(d,(M+r*g+S.FACE_CENTER)*4);let o=j(n,r,J,g,1);n.set(o,(M+r*g+S.MOUTH_CENTER)*4)}t.state.nFaces=i}function Xe(t,e,n){let{mask:i,maxFaces:r,landmarks:s,state:{nFaces:d}}=t,{gl:o,canvas:u}=i,{data:E}=s;if(We(i,e,n),o.bindFramebuffer(o.FRAMEBUFFER,null),o.viewport(0,0,u.width,u.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),!T)return;let l=r<=q;for(let m=0;m<d;++m){let F=l&&m<D.length?$e[D[m]]:0,A=l?m<D.length?0:He[Z[m-D.length]]:(m+1)/y;h(i,E,T.TESSELATION,m,0,F,A),x(i),h(i,E,T.OVAL,m,O.OVAL,0,0),x(i),h(i,E,T.LEFT_EYEBROW,m,O.LEFT_EYEBROW,0,0),x(i),h(i,E,T.RIGHT_EYEBROW,m,O.RIGHT_EYEBROW,0,0),x(i),h(i,E,T.LEFT_EYE,m,O.LEFT_EYE,0,0),x(i),h(i,E,T.RIGHT_EYE,m,O.RIGHT_EYE,0,0),x(i),h(i,E,T.MOUTH,m,O.MOUTH,0,0),x(i),h(i,E,T.INNER_MOUTH,m,O.INNER_MOUTH,0,0),x(i)}}function Ke(t){let{textureName:e,options:{history:n,...i}={}}=t,r={...Ge,...i},s=Ee({...r,textureName:e}),d=r.maxFaces*g+M,o=Math.ceil(d/I);return function(u,E){let{injectGLSL:l,emitHook:m,updateTexturesInternal:F}=E,A=P.get(s),R=A?.landmarks.data??new Float32Array(I*o*4),v=A?.mask.canvas??new OffscreenCanvas(1,1),a=null,N=!1,w=!1;function W(c){if(!a)return;let f=a.state.nFaces,_=f*g+M,C=Math.ceil(_/I),L=c;typeof L>"u"&&G.length>0&&(L=G,G=[]),F({u_faceLandmarksTex:{data:a.landmarks.data,width:I,height:C,isPartial:!0},u_faceMask:a.mask.canvas},n?{skipHistoryWrite:w,historyWriteIndex:L}:void 0),u.updateUniforms({u_nFaces:f}),m("face:result",a.state.result)}async function be(){if(P.has(s))a=P.get(s);else{let[c,{FaceLandmarker:f}]=await Promise.all([me(),import("@mediapipe/tasks-vision")]);if(N)return;let _=await f.createFromOptions(c,{baseOptions:{modelAssetPath:r.modelPath,delegate:"GPU"},runningMode:"VIDEO",numFaces:r.maxFaces,minFaceDetectionConfidence:r.minFaceDetectionConfidence,minFacePresenceConfidence:r.minFacePresenceConfidence,minTrackingConfidence:r.minTrackingConfidence,outputFaceBlendshapes:r.outputFaceBlendshapes,outputFacialTransformationMatrixes:r.outputFacialTransformationMatrixes});if(N){_.close();return}a={landmarker:_,mask:we(v),subscribers:new Map,maxFaces:r.maxFaces,state:{nCalls:0,runningMode:"VIDEO",source:null,videoTime:-1,resultTimestamp:0,result:null,pending:Promise.resolve(),nFaces:0},landmarks:{data:R,textureHeight:o}},Ye(f),P.set(s,a)}a.subscribers.set(W,!1)}let te=be();async function ne(c){let f=performance.now();if(await te,!a)return;let _=++a.state.nCalls;a.state.pending=a.state.pending.then(async()=>{if(!a||_!==a.state.nCalls)return;let C=c instanceof HTMLVideoElement?"VIDEO":"IMAGE";a.state.runningMode!==C&&(a.state.runningMode=C,await a.landmarker.setOptions({runningMode:C}));let L=!1;if(c!==a.state.source?(a.state.source=c,a.state.videoTime=-1,L=!0):c instanceof HTMLVideoElement?c.currentTime!==a.state.videoTime&&(a.state.videoTime=c.currentTime,L=!0):c instanceof HTMLImageElement||f-a.state.resultTimestamp>2&&(L=!0),L){let p,U,X;if(c instanceof HTMLVideoElement){if(c.videoWidth===0||c.videoHeight===0||c.readyState<2)return;U=c.videoWidth,X=c.videoHeight,p=a.landmarker.detectForVideo(c,f)}else{if(c.width===0||c.height===0)return;U=c.width,X=c.height,p=a.landmarker.detect(c)}if(p){a.state.resultTimestamp=f,a.state.result=p,Ve(a,p.faceLandmarks),Xe(a,U,X);for(let se of a.subscribers.keys())se(),a.subscribers.set(se,!0)}}else if(a.state.result)for(let[p,U]of a.subscribers.entries())U||(p(),a.subscribers.set(p,!0))}),await a.state.pending}u.on("_init",()=>{u.initializeUniform("u_maxFaces","int",r.maxFaces),u.initializeUniform("u_nFaces","int",0),u.initializeTexture("u_faceLandmarksTex",{data:R,width:I,height:o},{internalFormat:"RGBA32F",type:"FLOAT",minFilter:"NEAREST",magFilter:"NEAREST",history:n}),u.initializeTexture("u_faceMask",v,{minFilter:"NEAREST",magFilter:"NEAREST",history:n}),te.then(()=>{N||!a||m("face:ready")})});let H=0,G=[],re=()=>{n&&(W(H),G.push(H),H=(H+1)%(n+1))};u.on("initializeTexture",(c,f)=>{c===e&&z(f)&&(re(),ne(f))}),u.on("updateTextures",(c,f)=>{let _=c[e];z(_)&&(w=f?.skipHistoryWrite??!1,w||re(),ne(_))}),u.on("destroy",()=>{N=!0,a&&(a.subscribers.delete(W),a.subscribers.size===0&&(a.landmarker.close(),a.mask.gl.deleteProgram(a.mask.regionProgram),a.mask.gl.deleteProgram(a.mask.blitProgram),a.mask.gl.deleteBuffer(a.mask.regionPositionBuffer),a.mask.gl.deleteBuffer(a.mask.quadBuffer),a.mask.gl.deleteTexture(a.mask.scratchTexture),a.mask.gl.deleteFramebuffer(a.mask.scratchFramebuffer),P.delete(s))),a=null});let{fn:B,historyParams:V}=fe(n),ae=n?"_sampleFaceMask(pos, framesAgo)":"texture(u_faceMask, pos)",Le=Array.from({length:q-1},(c,f)=>`step(${2**(f+1)}.0, faceBitF)`).join(" + "),ie=r.maxFaces<=q?`uint faceBits = (uint(mask.b * ${y}.0 + 0.5) << 8) | uint(mask.g * ${y}.0 + 0.5);
21
+ void main() { outColor = texture(u_texture, v_uv); }`,Se=new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),K=478,ve=2,h=K+ve,D=512,I=1,De=Array.from({length:K},(t,e)=>e),Fe=473,Re=468,Be=4,ge=K,ae=K+1,ne=null,Ue=["OVAL","LEFT_EYEBROW","RIGHT_EYEBROW","LEFT_EYE","RIGHT_EYE","MOUTH","INNER_MOUTH"],G=["FACE_0","FACE_1","FACE_2","FACE_3","FACE_4","FACE_5","FACE_6","FACE_7"],ie=["FACE_8","FACE_9","FACE_10","FACE_11","FACE_12","FACE_13","FACE_14","FACE_15"],w=255,re=G.length+ie.length;function oe(t){return Object.fromEntries(t.map((e,n)=>[e,1<<n]))}function se(t){return Object.fromEntries(Object.entries(t).map(([e,n])=>[e,n/w]))}var be=oe(Ue),Pe=oe(G),$e=oe(ie),B=se(be),He=se(Pe),Ge=se($e),we={modelPath:"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task",maxFaces:1,minFaceDetectionConfidence:.5,minFacePresenceConfidence:.5,minTrackingConfidence:.5,outputFaceBlendshapes:!1,outputFacialTransformationMatrixes:!1};function te(t){let e=[];for(let n=1;n<t.length-1;++n)e.push(t[0],t[n],t[n+1]);return e}function p(t){let e=new Array(t.length+1);e[0]=t[0].start;for(let n=0;n<t.length;++n)e[n+1]=t[n].end;return e}function W(t,e){let n=[],i=Math.min(t.length,e.length);for(let r=0;r<i-1;++r)n.push(t[r],e[r],e[r+1],t[r],e[r+1],t[r+1]);return n}var L=null;function Ye(t){if(!L){let e=t.FACE_LANDMARKS_TESSELATION,n=p(t.FACE_LANDMARKS_LEFT_EYEBROW),i=p(t.FACE_LANDMARKS_RIGHT_EYEBROW),r=t.FACE_LANDMARKS_LEFT_EYE,s=t.FACE_LANDMARKS_RIGHT_EYE,E=t.FACE_LANDMARKS_LIPS,o=p(r.slice(0,8)),u=p(r.slice(8,16)),l=p(s.slice(0,8)),d=p(s.slice(8,16)),f=p(E.slice(0,10)),g=p(E.slice(10,20)),T=p(E.slice(20,30)),F=p(E.slice(30,40)),x=[...o,...u.slice(1,-1)],a=[...l,...d.slice(1,-1)];ne=[...T,...F.slice(1,-1)];let b=new Int16Array(h).fill(-1);for(let _ of x)b[_]=Fe;for(let _ of a)b[_]=Re;for(let _ of ne)b[_]=ae;let k=_=>{let A=b[_];return A>=0?A:_},U=[];for(let _=0;_<e.length-2;_+=3){let A=k(e[_].start),S=k(e[_+1].start),H=k(e[_+2].start);A!==S&&A!==H&&S!==H&&U.push(A,S,H)}let q=W(o,u),X=W(l,d),z=[...W(f,T),...W(g,F)],P=W(T,F),$=p(t.FACE_LANDMARKS_FACE_OVAL).slice(0,-1);L=Object.fromEntries(Object.entries({LEFT_EYEBROW:te(n),RIGHT_EYEBROW:te(i),LEFT_EYE:q,RIGHT_EYE:X,MOUTH:z,INNER_MOUTH:P,TESSELATION:U,OVAL:te($)}).map(([_,A])=>[_,{indices:A,vertices:new Float32Array(A.length*2)}]))}}var V=new Map;function Te(t,e,n){let i=t.createShader(t.VERTEX_SHADER);t.shaderSource(i,e),t.compileShader(i);let r=t.createShader(t.FRAGMENT_SHADER);t.shaderSource(r,n),t.compileShader(r);let s=t.createProgram();return t.attachShader(s,i),t.attachShader(s,r),t.linkProgram(s),t.deleteShader(i),t.deleteShader(r),s}function We(t){let e=t.getContext("webgl2",{antialias:!1,preserveDrawingBuffer:!0}),n=Te(e,Ae,Ie),i=Te(e,Ae,ke),r=e.createBuffer(),s=e.getAttribLocation(n,"a_pos"),E=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,E),e.bufferData(e.ARRAY_BUFFER,Se,e.STATIC_DRAW);let o=e.getAttribLocation(i,"a_pos"),u=e.getUniformLocation(n,"u_color"),l=e.getUniformLocation(i,"u_texture"),d=e.createTexture();e.bindTexture(e.TEXTURE_2D,d),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,1,1,0,e.RGBA,e.UNSIGNED_BYTE,null);let f=e.createFramebuffer();return e.bindFramebuffer(e.FRAMEBUFFER,f),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,d,0),e.bindFramebuffer(e.FRAMEBUFFER,null),e.useProgram(i),e.uniform1i(l,0),e.colorMask(!0,!0,!0,!1),{canvas:t,gl:e,regionProgram:n,blitProgram:i,regionPositionBuffer:r,quadBuffer:E,regionPositionLocation:s,blitPositionLocation:o,colorLocation:u,textureLocation:l,scratchTexture:d,scratchFramebuffer:f}}function Ve(t,e,n){let{gl:i,canvas:r,scratchTexture:s}=t;r.width===e&&r.height===n||(r.width=e,r.height=n,i.bindTexture(i.TEXTURE_2D,s),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,e,n,0,i.RGBA,i.UNSIGNED_BYTE,null))}function O(t,e,n,i,r,s,E){let{gl:o,regionProgram:u,regionPositionBuffer:l,regionPositionLocation:d,colorLocation:f,scratchFramebuffer:g}=t,T=I+i*h,{indices:F,vertices:x}=n;o.bindFramebuffer(o.FRAMEBUFFER,g),o.viewport(0,0,t.canvas.width,t.canvas.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),o.useProgram(u),o.bindBuffer(o.ARRAY_BUFFER,l),o.enableVertexAttribArray(d),o.vertexAttribPointer(d,2,o.FLOAT,!1,0,0),o.enable(o.BLEND),o.blendEquation(o.MAX),o.blendFunc(o.ONE,o.ONE);for(let a=0;a<F.length;++a){let b=(T+F[a])*4;x[a*2]=e[b],x[a*2+1]=e[b+1]}o.bufferData(o.ARRAY_BUFFER,x,o.DYNAMIC_DRAW),o.uniform4f(f,r,s,E,1),o.drawArrays(o.TRIANGLES,0,F.length)}function y(t){let{gl:e,blitProgram:n,quadBuffer:i,blitPositionLocation:r,scratchTexture:s}=t;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,t.canvas.width,t.canvas.height),e.useProgram(n),e.bindBuffer(e.ARRAY_BUFFER,i),e.enableVertexAttribArray(r),e.vertexAttribPointer(r,2,e.FLOAT,!1,0,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,s),e.enable(e.BLEND),e.blendEquation(e.FUNC_ADD),e.blendFunc(e.ONE,e.ONE),e.drawArrays(e.TRIANGLES,0,6)}function Ke(t,e){let n=t.landmarks.data,i=e.length;n[0]=i;for(let r=0;r<i;++r){let s=e[r];for(let u=0;u<K;++u){let l=s[u],d=(I+r*h+u)*4;n[d]=l.x,n[d+1]=1-l.y,n[d+2]=l.z??0,n[d+3]=l.visibility??1}let E=ee(n,r,De,h,I);n.set(E,(I+r*h+ge)*4);let o=ee(n,r,ne,h,1);n.set(o,(I+r*h+ae)*4)}t.state.nFaces=i}function Xe(t,e,n){let{mask:i,maxFaces:r,landmarks:s,state:{nFaces:E}}=t,{gl:o,canvas:u}=i,{data:l}=s;if(Ve(i,e,n),o.bindFramebuffer(o.FRAMEBUFFER,null),o.viewport(0,0,u.width,u.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),!L)return;let d=r<=re;for(let f=0;f<E;++f){let g=d&&f<G.length?He[G[f]]:0,T=d?f<G.length?0:Ge[ie[f-G.length]]:(f+1)/w;O(i,l,L.TESSELATION,f,0,g,T),y(i),O(i,l,L.OVAL,f,B.OVAL,0,0),y(i),O(i,l,L.LEFT_EYEBROW,f,B.LEFT_EYEBROW,0,0),y(i),O(i,l,L.RIGHT_EYEBROW,f,B.RIGHT_EYEBROW,0,0),y(i),O(i,l,L.LEFT_EYE,f,B.LEFT_EYE,0,0),y(i),O(i,l,L.RIGHT_EYE,f,B.RIGHT_EYE,0,0),y(i),O(i,l,L.MOUTH,f,B.MOUTH,0,0),y(i),O(i,l,L.INNER_MOUTH,f,B.INNER_MOUTH,0,0),y(i)}}function ze(t){let{textureName:e,options:{history:n,...i}={}}=t,r={...we,...i},s=Ee({...r,textureName:e}),E=r.maxFaces*h+I,o=Math.ceil(E/D);return function(u,l){let{injectGLSL:d,emitHook:f,updateTexturesInternal:g}=l,T=V.get(s),F=T?.landmarks.data??new Float32Array(D*o*4),x=T?.mask.canvas??new OffscreenCanvas(1,1),a=null,b=!1,k=!1;function U(c){if(!a)return;let m=a.state.nFaces,R=m*h+I,v=Math.ceil(R/D),C=c;typeof C>"u"&&$.length>0&&(C=$,$=[]),g({u_faceLandmarksTex:{data:a.landmarks.data,width:D,height:v,isPartial:!0},u_faceMask:a.mask.canvas},n?{skipHistoryWrite:k,historyWriteIndex:C}:void 0),u.updateUniforms({u_nFaces:m}),f("face:result",a.state.result)}async function q(){if(V.has(s))a=V.get(s);else{let[c,{FaceLandmarker:m}]=await Promise.all([de(),import("@mediapipe/tasks-vision")]);if(b)return;let R=await m.createFromOptions(c,{baseOptions:{modelAssetPath:r.modelPath,delegate:"GPU"},runningMode:"VIDEO",numFaces:r.maxFaces,minFaceDetectionConfidence:r.minFaceDetectionConfidence,minFacePresenceConfidence:r.minFacePresenceConfidence,minTrackingConfidence:r.minTrackingConfidence,outputFaceBlendshapes:r.outputFaceBlendshapes,outputFacialTransformationMatrixes:r.outputFacialTransformationMatrixes});if(b){R.close();return}a={landmarker:R,mask:We(x),subscribers:new Map,maxFaces:r.maxFaces,state:{nCalls:0,runningMode:"VIDEO",source:null,videoTime:-1,resultTimestamp:0,result:null,pending:Promise.resolve(),nFaces:0},landmarks:{data:F,textureHeight:o}},Ye(m),V.set(s,a)}a.subscribers.set(U,!1)}let X=q();async function z(c){let m=performance.now();if(await X,!a)return;let R=++a.state.nCalls;a.state.pending=a.state.pending.then(async()=>{if(!a||R!==a.state.nCalls)return;let v=c instanceof HTMLVideoElement?"VIDEO":"IMAGE";a.state.runningMode!==v&&(a.state.runningMode=v,await a.landmarker.setOptions({runningMode:v}));let C=!1;if(c!==a.state.source?(a.state.source=c,a.state.videoTime=-1,C=!0):c instanceof HTMLVideoElement?c.currentTime!==a.state.videoTime&&(a.state.videoTime=c.currentTime,C=!0):c instanceof HTMLImageElement||m-a.state.resultTimestamp>2&&(C=!0),C){let N,Y,J;if(c instanceof HTMLVideoElement){if(c.videoWidth===0||c.videoHeight===0||c.readyState<2)return;Y=c.videoWidth,J=c.videoHeight,N=a.landmarker.detectForVideo(c,m)}else{if(c.width===0||c.height===0)return;Y=c.width,J=c.height,N=a.landmarker.detect(c)}if(N){a.state.resultTimestamp=m,a.state.result=N,Ke(a,N.faceLandmarks),Xe(a,Y,J);for(let le of a.subscribers.keys())le(),a.subscribers.set(le,!0)}}else if(a.state.result)for(let[N,Y]of a.subscribers.entries())Y||(N(),a.subscribers.set(N,!0))}),await a.state.pending}u.on("_init",()=>{u.initializeUniform("u_maxFaces","int",r.maxFaces),u.initializeUniform("u_nFaces","int",0),u.initializeTexture("u_faceLandmarksTex",{data:F,width:D,height:o},{internalFormat:"RGBA32F",type:"FLOAT",minFilter:"NEAREST",magFilter:"NEAREST",history:n}),u.initializeTexture("u_faceMask",x,{minFilter:"NEAREST",magFilter:"NEAREST",history:n}),X.then(()=>{b||!a||f("face:ready")})});let P=0,$=[],_=()=>{n&&(U(P),$.push(P),P=(P+1)%(n+1))};u.on("initializeTexture",(c,m)=>{c===e&&Q(m)&&(_(),z(m))}),u.on("updateTextures",(c,m)=>{let R=c[e];Q(R)&&(k=m?.skipHistoryWrite??!1,k||_(),z(R))}),u.on("destroy",()=>{b=!0,a&&(a.subscribers.delete(U),a.subscribers.size===0&&(a.landmarker.close(),a.mask.gl.deleteProgram(a.mask.regionProgram),a.mask.gl.deleteProgram(a.mask.blitProgram),a.mask.gl.deleteBuffer(a.mask.regionPositionBuffer),a.mask.gl.deleteBuffer(a.mask.quadBuffer),a.mask.gl.deleteTexture(a.mask.scratchTexture),a.mask.gl.deleteFramebuffer(a.mask.scratchFramebuffer),V.delete(s))),a=null});let{fn:A,historyParams:S}=_e(n),H=n?"_sampleFaceMask(pos, framesAgo)":"texture(u_faceMask, pos)",pe=Array.from({length:re-1},(c,m)=>`step(${2**(m+1)}.0, faceBitF)`).join(" + "),ce=r.maxFaces<=re?`uint faceBits = (uint(mask.b * ${w}.0 + 0.5) << 8) | uint(mask.g * ${w}.0 + 0.5);
22
22
  uint faceBit = faceBits & (~faceBits + 1u);
23
23
  float faceBitF = float(faceBit);
24
24
  float hasFace = sign(faceBitF);
25
- float faceIndex = ${Le} - (1.0 - hasFace);`:`float faceIndex = float(int(uint(mask.b * ${y}.0 + 0.5)) - 1);`,b=(c,...f)=>B("vec2",`${c}At`,"vec2 pos",`vec4 mask = ${ae};
26
- ${ie}
27
- uint bits = uint(mask.r * ${y}.0 + 0.5);
28
- float hit = sign(float(bits & ${f.reduce((_,C)=>_|ge[C],0)}u));
29
- return vec2(hit, mix(-1.0, faceIndex, hit));`),oe=(c,f,_)=>B("vec2",`${c}At`,"vec2 pos",`vec2 left = ${f}(pos${V});
30
- vec2 right = ${_}(pos${V});
31
- return mix(right, left, left.x);`),pe=c=>c.map(f=>B("float",`in${f[0].toUpperCase()+f.slice(1)}`,"vec2 pos",`vec2 a = ${f}At(pos${V}); return step(0.0, a.y) * a.x;`)).join(`
32
- `);l(`
25
+ float faceIndex = ${pe} - (1.0 - hasFace);`:`float faceIndex = float(int(uint(mask.b * ${w}.0 + 0.5)) - 1);`,M=(c,...m)=>A("vec2",`${c}At`,"vec2 pos",`vec4 mask = ${H};
26
+ ${ce}
27
+ uint bits = uint(mask.r * ${w}.0 + 0.5);
28
+ float hit = sign(float(bits & ${m.reduce((R,v)=>R|be[v],0)}u));
29
+ return vec2(hit, mix(-1.0, faceIndex, hit));`),ue=(c,m,R)=>A("vec2",`${c}At`,"vec2 pos",`vec2 left = ${m}(pos${S});
30
+ vec2 right = ${R}(pos${S});
31
+ return mix(right, left, left.x);`),Le=c=>c.map(m=>A("float",`in${m[0].toUpperCase()+m.slice(1)}`,"vec2 pos",`vec2 a = ${m}At(pos${S}); return step(0.0, a.y) * a.x;`)).join(`
32
+ `);d(`
33
33
  uniform int u_maxFaces;
34
34
  uniform int u_nFaces;
35
35
  uniform highp sampler2D${n?"Array":""} u_faceLandmarksTex;${n?`
@@ -37,19 +37,19 @@ uniform int u_faceLandmarksTexFrameOffset;`:""}
37
37
  uniform mediump sampler2D${n?"Array":""} u_faceMask;${n?`
38
38
  uniform int u_faceMaskFrameOffset;`:""}
39
39
 
40
- #define FACE_LANDMARK_L_EYE_CENTER ${S.LEFT_EYE_CENTER}
41
- #define FACE_LANDMARK_R_EYE_CENTER ${S.RIGHT_EYE_CENTER}
42
- #define FACE_LANDMARK_NOSE_TIP ${S.NOSE_TIP}
43
- #define FACE_LANDMARK_FACE_CENTER ${S.FACE_CENTER}
44
- #define FACE_LANDMARK_MOUTH_CENTER ${S.MOUTH_CENTER}
40
+ #define FACE_LANDMARK_L_EYE_CENTER ${Fe}
41
+ #define FACE_LANDMARK_R_EYE_CENTER ${Re}
42
+ #define FACE_LANDMARK_NOSE_TIP ${Be}
43
+ #define FACE_LANDMARK_FACE_CENTER ${ge}
44
+ #define FACE_LANDMARK_MOUTH_CENTER ${ae}
45
45
 
46
- ${B("int","nFacesAt","",n?`
46
+ ${A("int","nFacesAt","",n?`
47
47
  int layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${n+1}) % ${n+1};
48
48
  return int(texelFetch(u_faceLandmarksTex, ivec3(0, 0, layer), 0).r + 0.5);`:`
49
49
  return int(texelFetch(u_faceLandmarksTex, ivec2(0, 0), 0).r + 0.5);`)}
50
- ${B("vec4","faceLandmark","int faceIndex, int landmarkIndex",`int i = ${M} + faceIndex * ${g} + landmarkIndex;
51
- int x = i % ${I};
52
- int y = i / ${I};${n?`
50
+ ${A("vec4","faceLandmark","int faceIndex, int landmarkIndex",`int i = ${I} + faceIndex * ${h} + landmarkIndex;
51
+ int x = i % ${D};
52
+ int y = i / ${D};${n?`
53
53
  int layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${n+1}) % ${n+1};
54
54
  return texelFetch(u_faceLandmarksTex, ivec3(x, y, layer), 0);`:`
55
55
  return texelFetch(u_faceLandmarksTex, ivec2(x, y), 0);`}`)}
@@ -59,18 +59,18 @@ vec4 _sampleFaceMask(vec2 pos, int framesAgo) {
59
59
  return texture(u_faceMask, vec3(pos, float(layer)));
60
60
  }
61
61
  `:""}
62
- ${b("leftEyebrow","LEFT_EYEBROW")}
63
- ${b("rightEyebrow","RIGHT_EYEBROW")}
64
- ${b("leftEye","LEFT_EYE")}
65
- ${b("rightEye","RIGHT_EYE")}
66
- ${b("lips","MOUTH")}
67
- ${b("mouth","MOUTH","INNER_MOUTH")}
68
- ${b("innerMouth","INNER_MOUTH")}
69
- ${b("faceOval","OVAL")}
70
- ${B("vec2","faceAt","vec2 pos",`vec4 mask = ${ae};
71
- ${ie}
62
+ ${M("leftEyebrow","LEFT_EYEBROW")}
63
+ ${M("rightEyebrow","RIGHT_EYEBROW")}
64
+ ${M("leftEye","LEFT_EYE")}
65
+ ${M("rightEye","RIGHT_EYE")}
66
+ ${M("lips","MOUTH")}
67
+ ${M("mouth","MOUTH","INNER_MOUTH")}
68
+ ${M("innerMouth","INNER_MOUTH")}
69
+ ${M("faceOval","OVAL")}
70
+ ${A("vec2","faceAt","vec2 pos",`vec4 mask = ${H};
71
+ ${ce}
72
72
  return vec2(step(0.0, faceIndex), faceIndex);`)}
73
- ${oe("eye","leftEyeAt","rightEyeAt")}
74
- ${oe("eyebrow","leftEyebrowAt","rightEyebrowAt")}
75
- ${pe(["eyebrow","eye","mouth","innerMouth","lips","face"])}`)}}var ze=Ke;
73
+ ${ue("eye","leftEyeAt","rightEyeAt")}
74
+ ${ue("eyebrow","leftEyebrowAt","rightEyebrowAt")}
75
+ ${Le(["eyebrow","eye","mouth","innerMouth","lips","face"])}`)}}var je=ze;
76
76
  //# sourceMappingURL=face.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/plugins/face.ts","../../src/plugins/mediapipe-common.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '..';\nimport {\n\tcalculateBoundingBoxCenter,\n\tgenerateGLSLFn,\n\tgetSharedFileset,\n\thashOptions,\n\tisMediaPipeSource,\n\tMediaPipeSource,\n} from './mediapipe-common';\nimport type { FaceLandmarker, FaceLandmarkerResult, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface FacePluginOptions {\n\tmodelPath?: string;\n\tmaxFaces?: number;\n\tminFaceDetectionConfidence?: number;\n\tminFacePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputFaceBlendshapes?: boolean;\n\toutputFacialTransformationMatrixes?: boolean;\n\thistory?: number;\n}\n\nconst MASK_VERTEX_SHADER = `#version 300 es\nin vec2 a_pos;\nout vec2 v_uv;\nvoid main() {\n\tv_uv = a_pos;\n\tgl_Position = vec4(a_pos * 2.0 - 1.0, 0.0, 1.0);\n}`;\nconst MASK_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nuniform vec4 u_color;\nout vec4 outColor;\nvoid main() { outColor = u_color; }`;\nconst BLIT_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nuniform sampler2D u_texture;\nout vec4 outColor;\nvoid main() { outColor = texture(u_texture, v_uv); }`;\nconst FULLSCREEN_TRIANGLES = new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]);\n\nconst STANDARD_LANDMARK_COUNT = 478;\nconst CUSTOM_LANDMARK_COUNT = 2;\nconst LANDMARK_COUNT = STANDARD_LANDMARK_COUNT + CUSTOM_LANDMARK_COUNT;\nconst LANDMARKS_TEXTURE_WIDTH = 512;\nconst N_LANDMARK_METADATA_SLOTS = 1;\n\nconst LEFT_EYEBROW_INDICES = [336, 296, 334, 293, 300, 276, 283, 282, 295, 285] as const;\nconst LEFT_EYE_INDICES = [362, 398, 384, 385, 386, 387, 388, 466, 263, 249, 390, 373, 374, 380, 381, 382] as const;\nconst RIGHT_EYEBROW_INDICES = [70, 63, 105, 66, 107, 55, 65, 52, 53, 46] as const;\nconst RIGHT_EYE_INDICES = [33, 246, 161, 160, 159, 158, 157, 173, 133, 155, 154, 153, 145, 144, 163, 7] as const;\nconst MOUTH_INDICES = [\n\t61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291, 375, 321, 405, 314, 17, 84, 181, 91, 146,\n] as const;\nconst INNER_MOUTH_INDICES = [\n\t78, 191, 80, 81, 82, 13, 312, 311, 310, 415, 308, 324, 318, 402, 317, 14, 87, 178, 88, 95,\n] as const;\nconst ALL_STANDARD_INDICES = Array.from({ length: STANDARD_LANDMARK_COUNT }, (_, i) => i);\nconst LANDMARK_INDICES = {\n\tLEFT_EYEBROW: LEFT_EYEBROW_INDICES,\n\tLEFT_EYE: LEFT_EYE_INDICES,\n\tLEFT_EYE_CENTER: 473,\n\tRIGHT_EYEBROW: RIGHT_EYEBROW_INDICES,\n\tRIGHT_EYE: RIGHT_EYE_INDICES,\n\tRIGHT_EYE_CENTER: 468,\n\tNOSE_TIP: 4,\n\tMOUTH: MOUTH_INDICES,\n\tINNER_MOUTH: INNER_MOUTH_INDICES,\n\t// Custom landmarks.\n\tFACE_CENTER: STANDARD_LANDMARK_COUNT,\n\tMOUTH_CENTER: STANDARD_LANDMARK_COUNT + 1,\n};\n\n/* Face mask channel layout:\n- R: additive bitfield for face regions. Since it’s additive, it handles overlapping regions.\n- G/B: tessellation ownership. When maxFaces is <= 16, G stores one-hot bits for\n faces 0-7 and B stores one-hot bits for faces 8-15 so overlapping faces\n remain decodable. Above 16 maxFaces, B falls back to storing faceIndex + 1 as\n an additive byte value, which will overcount on overlaps. */\nconst RED_REGION_NAMES = [\n\t'OVAL',\n\t'LEFT_EYEBROW',\n\t'RIGHT_EYEBROW',\n\t'LEFT_EYE',\n\t'RIGHT_EYE',\n\t'MOUTH',\n\t'INNER_MOUTH',\n] as const;\nconst GREEN_REGION_NAMES = ['FACE_0', 'FACE_1', 'FACE_2', 'FACE_3', 'FACE_4', 'FACE_5', 'FACE_6', 'FACE_7'] as const;\nconst BLUE_REGION_NAMES = [\n\t'FACE_8',\n\t'FACE_9',\n\t'FACE_10',\n\t'FACE_11',\n\t'FACE_12',\n\t'FACE_13',\n\t'FACE_14',\n\t'FACE_15',\n] as const;\nconst CHANNEL_BIT_SCALE = 255;\nconst GB_BITMASK_MAX_FACES = GREEN_REGION_NAMES.length + BLUE_REGION_NAMES.length;\n\nfunction createChannelBitValues<const T extends readonly string[]>(names: T): Record<T[number], number> {\n\treturn Object.fromEntries(names.map((name, i) => [name, 1 << i])) as Record<T[number], number>;\n}\n\nfunction normalizeChannelBitValues<T extends Record<string, number>>(bitValues: T): T {\n\treturn Object.fromEntries(\n\t\tObject.entries(bitValues).map(([name, bitValue]) => [name, bitValue / CHANNEL_BIT_SCALE]),\n\t) as T;\n}\n\nconst RED_REGION_BIT_VALUES = createChannelBitValues(RED_REGION_NAMES);\nconst GREEN_REGION_BIT_VALUES = createChannelBitValues(GREEN_REGION_NAMES);\nconst BLUE_REGION_BIT_VALUES = createChannelBitValues(BLUE_REGION_NAMES);\nconst RED_CHANNEL_VALUES = normalizeChannelBitValues(RED_REGION_BIT_VALUES);\nconst GREEN_CHANNEL_VALUES = normalizeChannelBitValues(GREEN_REGION_BIT_VALUES);\nconst BLUE_CHANNEL_VALUES = normalizeChannelBitValues(BLUE_REGION_BIT_VALUES);\n\nconst DEFAULT_FACE_OPTIONS: Required<Omit<FacePluginOptions, 'history'>> = {\n\tmodelPath:\n\t\t'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task',\n\tmaxFaces: 1,\n\tminFaceDetectionConfidence: 0.5,\n\tminFacePresenceConfidence: 0.5,\n\tminTrackingConfidence: 0.5,\n\toutputFaceBlendshapes: false,\n\toutputFacialTransformationMatrixes: false,\n};\n\nfunction fanTriangulate(indices: readonly number[]): number[] {\n\tconst tris: number[] = [];\n\tfor (let i = 1; i < indices.length - 1; ++i) {\n\t\ttris.push(indices[0], indices[i], indices[i + 1]);\n\t}\n\treturn tris;\n}\n\ntype FaceRegion = { indices: number[]; vertices: Float32Array };\nlet faceRegions: Record<string, FaceRegion> | null = null;\nfunction initFaceRegions(LandmarkerClass: typeof FaceLandmarker): void {\n\tif (!faceRegions) {\n\t\tconst tesselationConnections = LandmarkerClass.FACE_LANDMARKS_TESSELATION;\n\t\tconst tesselation: number[] = [];\n\t\tfor (let i = 0; i < tesselationConnections.length - 2; i += 3) {\n\t\t\ttesselation.push(\n\t\t\t\ttesselationConnections[i].start,\n\t\t\t\ttesselationConnections[i + 1].start,\n\t\t\t\ttesselationConnections[i + 2].start,\n\t\t\t);\n\t\t}\n\t\tconst ovalIndices = LandmarkerClass.FACE_LANDMARKS_FACE_OVAL.map(({ start }) => start);\n\t\tfaceRegions = Object.fromEntries(\n\t\t\tObject.entries({\n\t\t\t\tLEFT_EYEBROW: fanTriangulate(LEFT_EYEBROW_INDICES),\n\t\t\t\tRIGHT_EYEBROW: fanTriangulate(RIGHT_EYEBROW_INDICES),\n\t\t\t\tLEFT_EYE: fanTriangulate(LEFT_EYE_INDICES),\n\t\t\t\tRIGHT_EYE: fanTriangulate(RIGHT_EYE_INDICES),\n\t\t\t\tMOUTH: fanTriangulate(MOUTH_INDICES),\n\t\t\t\tINNER_MOUTH: fanTriangulate(INNER_MOUTH_INDICES),\n\t\t\t\tTESSELATION: tesselation,\n\t\t\t\tOVAL: fanTriangulate(ovalIndices),\n\t\t\t}).map(([key, indices]) => [key, { indices, vertices: new Float32Array(indices.length * 2) }]),\n\t\t);\n\t}\n}\n\ninterface MaskRenderer {\n\tcanvas: OffscreenCanvas;\n\tgl: WebGL2RenderingContext;\n\tregionProgram: WebGLProgram;\n\tblitProgram: WebGLProgram;\n\tregionPositionBuffer: WebGLBuffer;\n\tquadBuffer: WebGLBuffer;\n\tregionPositionLocation: number;\n\tblitPositionLocation: number;\n\tcolorLocation: WebGLUniformLocation;\n\ttextureLocation: WebGLUniformLocation;\n\tscratchTexture: WebGLTexture;\n\tscratchFramebuffer: WebGLFramebuffer;\n}\n\ninterface Detector {\n\tlandmarker: FaceLandmarker;\n\tmask: MaskRenderer;\n\tsubscribers: Map<Function, boolean>;\n\tmaxFaces: number;\n\tstate: {\n\t\tnCalls: number;\n\t\trunningMode: 'IMAGE' | 'VIDEO';\n\t\tsource: MediaPipeSource | null;\n\t\tvideoTime: number;\n\t\tresultTimestamp: number;\n\t\tresult: FaceLandmarkerResult | null;\n\t\tpending: Promise<void>;\n\t\tnFaces: number;\n\t};\n\tlandmarks: {\n\t\tdata: Float32Array;\n\t\ttextureHeight: number;\n\t};\n}\nconst sharedDetectors = new Map<string, Detector>();\n\nfunction createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n\tconst vertexShader = gl.createShader(gl.VERTEX_SHADER)!;\n\tgl.shaderSource(vertexShader, vertexSource);\n\tgl.compileShader(vertexShader);\n\n\tconst fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;\n\tgl.shaderSource(fragmentShader, fragmentSource);\n\tgl.compileShader(fragmentShader);\n\n\tconst program = gl.createProgram()!;\n\tgl.attachShader(program, vertexShader);\n\tgl.attachShader(program, fragmentShader);\n\tgl.linkProgram(program);\n\tgl.deleteShader(vertexShader);\n\tgl.deleteShader(fragmentShader);\n\treturn program;\n}\n\nfunction initMaskRenderer(canvas: OffscreenCanvas): MaskRenderer {\n\tconst gl = canvas.getContext('webgl2', {\n\t\tantialias: false,\n\t\tpreserveDrawingBuffer: true,\n\t})!;\n\tconst regionProgram = createProgram(gl, MASK_VERTEX_SHADER, MASK_FRAGMENT_SHADER);\n\tconst blitProgram = createProgram(gl, MASK_VERTEX_SHADER, BLIT_FRAGMENT_SHADER);\n\n\tconst regionPositionBuffer = gl.createBuffer()!;\n\tconst regionPositionLocation = gl.getAttribLocation(regionProgram, 'a_pos');\n\n\tconst quadBuffer = gl.createBuffer()!;\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_TRIANGLES, gl.STATIC_DRAW);\n\tconst blitPositionLocation = gl.getAttribLocation(blitProgram, 'a_pos');\n\n\tconst colorLocation = gl.getUniformLocation(regionProgram, 'u_color')!;\n\tconst textureLocation = gl.getUniformLocation(blitProgram, 'u_texture')!;\n\n\tconst scratchTexture = gl.createTexture()!;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n\n\tconst scratchFramebuffer = gl.createFramebuffer()!;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, scratchTexture, 0);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n\tgl.useProgram(blitProgram);\n\tgl.uniform1i(textureLocation, 0);\n\tgl.colorMask(true, true, true, false);\n\n\treturn {\n\t\tcanvas,\n\t\tgl,\n\t\tregionProgram,\n\t\tblitProgram,\n\t\tregionPositionBuffer,\n\t\tquadBuffer,\n\t\tregionPositionLocation,\n\t\tblitPositionLocation,\n\t\tcolorLocation,\n\t\ttextureLocation,\n\t\tscratchTexture,\n\t\tscratchFramebuffer,\n\t};\n}\n\nfunction resizeMaskRenderer(mask: MaskRenderer, width: number, height: number) {\n\tconst { gl, canvas, scratchTexture } = mask;\n\tif (canvas.width === width && canvas.height === height) return;\n\tcanvas.width = width;\n\tcanvas.height = height;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n}\n\nfunction drawRegionToScratch(\n\tmask: MaskRenderer,\n\tlandmarksData: Float32Array,\n\tfaceRegion: FaceRegion,\n\tfaceIdx: number,\n\tr: number,\n\tg: number,\n\tb: number,\n) {\n\tconst { gl, regionProgram, regionPositionBuffer, regionPositionLocation, colorLocation, scratchFramebuffer } = mask;\n\tconst baseIdx = N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT;\n\tconst { indices, vertices } = faceRegion;\n\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\tgl.useProgram(regionProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, regionPositionBuffer);\n\tgl.enableVertexAttribArray(regionPositionLocation);\n\tgl.vertexAttribPointer(regionPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.MAX);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\n\tfor (let i = 0; i < indices.length; ++i) {\n\t\tconst landmarkIdx = (baseIdx + indices[i]) * 4;\n\t\tvertices[i * 2] = landmarksData[landmarkIdx];\n\t\tvertices[i * 2 + 1] = landmarksData[landmarkIdx + 1];\n\t}\n\tgl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);\n\tgl.uniform4f(colorLocation, r, g, b, 1.0);\n\tgl.drawArrays(gl.TRIANGLES, 0, indices.length);\n}\n\nfunction accumulateScratch(mask: MaskRenderer) {\n\tconst { gl, blitProgram, quadBuffer, blitPositionLocation, scratchTexture } = mask;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.useProgram(blitProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.enableVertexAttribArray(blitPositionLocation);\n\tgl.vertexAttribPointer(blitPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.activeTexture(gl.TEXTURE0);\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.FUNC_ADD);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n}\n\nfunction updateLandmarksData(detector: Detector, faces: NormalizedLandmark[][]) {\n\tconst data = detector.landmarks.data;\n\tconst nFaces = faces.length;\n\tdata[0] = nFaces;\n\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst landmarks = faces[faceIdx];\n\t\tfor (let landmarkIdx = 0; landmarkIdx < STANDARD_LANDMARK_COUNT; ++landmarkIdx) {\n\t\t\tconst landmark = landmarks[landmarkIdx];\n\t\t\tconst dataIdx = (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + landmarkIdx) * 4;\n\t\t\tdata[dataIdx] = landmark.x;\n\t\t\tdata[dataIdx + 1] = 1 - landmark.y;\n\t\t\tdata[dataIdx + 2] = landmark.z ?? 0;\n\t\t\tdata[dataIdx + 3] = landmark.visibility ?? 1;\n\t\t}\n\n\t\tconst faceCenter = calculateBoundingBoxCenter(\n\t\t\tdata,\n\t\t\tfaceIdx,\n\t\t\tALL_STANDARD_INDICES,\n\t\t\tLANDMARK_COUNT,\n\t\t\tN_LANDMARK_METADATA_SLOTS,\n\t\t);\n\t\tdata.set(faceCenter, (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + LANDMARK_INDICES.FACE_CENTER) * 4);\n\n\t\tconst mouthCenter = calculateBoundingBoxCenter(data, faceIdx, INNER_MOUTH_INDICES, LANDMARK_COUNT, 1);\n\t\tdata.set(\n\t\t\tmouthCenter,\n\t\t\t(N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + LANDMARK_INDICES.MOUTH_CENTER) * 4,\n\t\t);\n\t}\n\n\tdetector.state.nFaces = nFaces;\n}\n\nfunction updateMask(detector: Detector, width: number, height: number) {\n\tconst {\n\t\tmask,\n\t\tmaxFaces,\n\t\tlandmarks,\n\t\tstate: { nFaces },\n\t} = detector;\n\tconst { gl, canvas: maskCanvas } = mask;\n\tconst { data: landmarksData } = landmarks;\n\n\tresizeMaskRenderer(mask, width, height);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, maskCanvas.width, maskCanvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\tif (!faceRegions) return;\n\n\tconst useTesselationBitmask = maxFaces <= GB_BITMASK_MAX_FACES;\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst g =\n\t\t\tuseTesselationBitmask && faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? GREEN_CHANNEL_VALUES[GREEN_REGION_NAMES[faceIdx]]\n\t\t\t\t: 0;\n\t\tconst b = useTesselationBitmask\n\t\t\t? faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? 0\n\t\t\t\t: BLUE_CHANNEL_VALUES[BLUE_REGION_NAMES[faceIdx - GREEN_REGION_NAMES.length]]\n\t\t\t: (faceIdx + 1) / CHANNEL_BIT_SCALE;\n\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.TESSELATION, faceIdx, 0, g, b);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.OVAL, faceIdx, RED_CHANNEL_VALUES.OVAL, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.LEFT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.LEFT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.RIGHT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.RIGHT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.LEFT_EYE, faceIdx, RED_CHANNEL_VALUES.LEFT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.RIGHT_EYE, faceIdx, RED_CHANNEL_VALUES.RIGHT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.MOUTH, faceIdx, RED_CHANNEL_VALUES.MOUTH, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.INNER_MOUTH,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.INNER_MOUTH,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t}\n}\n\nfunction face(config: { textureName: string; options?: FacePluginOptions }) {\n\tconst { textureName, options: { history, ...mediapipeOptions } = {} } = config;\n\tconst options = { ...DEFAULT_FACE_OPTIONS, ...mediapipeOptions };\n\tconst optionsKey = hashOptions({ ...options, textureName });\n\n\tconst nLandmarksMax = options.maxFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\tconst textureHeight = Math.ceil(nLandmarksMax / LANDMARKS_TEXTURE_WIDTH);\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, emitHook, updateTexturesInternal } = context;\n\n\t\tconst existingDetector = sharedDetectors.get(optionsKey);\n\t\tconst landmarksData =\n\t\t\texistingDetector?.landmarks.data ?? new Float32Array(LANDMARKS_TEXTURE_WIDTH * textureHeight * 4);\n\t\tconst maskCanvas = existingDetector?.mask.canvas ?? new OffscreenCanvas(1, 1);\n\t\tlet detector: Detector | null = null;\n\t\tlet destroyed = false;\n\t\tlet skipHistoryWrite = false;\n\n\t\tfunction onResult(singleHistoryWriteIndex?: number) {\n\t\t\tif (!detector) return;\n\t\t\tconst nFaces = detector.state.nFaces;\n\t\t\tconst nSlots = nFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\t\t\tconst rowsToUpdate = Math.ceil(nSlots / LANDMARKS_TEXTURE_WIDTH);\n\t\t\tlet historyWriteIndex: number | number[] | undefined = singleHistoryWriteIndex;\n\t\t\tif (typeof historyWriteIndex === 'undefined' && pendingBackfillSlots.length > 0) {\n\t\t\t\thistoryWriteIndex = pendingBackfillSlots;\n\t\t\t\tpendingBackfillSlots = [];\n\t\t\t}\n\t\t\tupdateTexturesInternal(\n\t\t\t\t{\n\t\t\t\t\tu_faceLandmarksTex: {\n\t\t\t\t\t\tdata: detector.landmarks.data,\n\t\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\t\theight: rowsToUpdate,\n\t\t\t\t\t\tisPartial: true,\n\t\t\t\t\t},\n\t\t\t\t\tu_faceMask: detector.mask.canvas,\n\t\t\t\t},\n\t\t\t\thistory ? { skipHistoryWrite, historyWriteIndex } : undefined,\n\t\t\t);\n\t\t\tshaderPad.updateUniforms({ u_nFaces: nFaces });\n\t\t\temitHook('face:result', detector.state.result);\n\t\t}\n\n\t\tasync function initializeDetector() {\n\t\t\tif (sharedDetectors.has(optionsKey)) {\n\t\t\t\tdetector = sharedDetectors.get(optionsKey)!;\n\t\t\t} else {\n\t\t\t\tconst [mediaPipe, { FaceLandmarker }] = await Promise.all([\n\t\t\t\t\tgetSharedFileset(),\n\t\t\t\t\timport('@mediapipe/tasks-vision'),\n\t\t\t\t]);\n\t\t\t\tif (destroyed) return;\n\n\t\t\t\tconst faceLandmarker = await FaceLandmarker.createFromOptions(mediaPipe, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options.modelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumFaces: options.maxFaces,\n\t\t\t\t\tminFaceDetectionConfidence: options.minFaceDetectionConfidence,\n\t\t\t\t\tminFacePresenceConfidence: options.minFacePresenceConfidence,\n\t\t\t\t\tminTrackingConfidence: options.minTrackingConfidence,\n\t\t\t\t\toutputFaceBlendshapes: options.outputFaceBlendshapes,\n\t\t\t\t\toutputFacialTransformationMatrixes: options.outputFacialTransformationMatrixes,\n\t\t\t\t});\n\t\t\t\tif (destroyed) {\n\t\t\t\t\tfaceLandmarker.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdetector = {\n\t\t\t\t\tlandmarker: faceLandmarker,\n\t\t\t\t\tmask: initMaskRenderer(maskCanvas),\n\t\t\t\t\tsubscribers: new Map(),\n\t\t\t\t\tmaxFaces: options.maxFaces,\n\t\t\t\t\tstate: {\n\t\t\t\t\t\tnCalls: 0,\n\t\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\t\tsource: null,\n\t\t\t\t\t\tvideoTime: -1,\n\t\t\t\t\t\tresultTimestamp: 0,\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\tpending: Promise.resolve(),\n\t\t\t\t\t\tnFaces: 0,\n\t\t\t\t\t},\n\t\t\t\t\tlandmarks: {\n\t\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\t\ttextureHeight,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tinitFaceRegions(FaceLandmarker);\n\t\t\t\tsharedDetectors.set(optionsKey, detector);\n\t\t\t}\n\n\t\t\tdetector.subscribers.set(onResult, false);\n\t\t}\n\t\tconst initPromise = initializeDetector();\n\n\t\tasync function detectFaces(source: MediaPipeSource) {\n\t\t\tconst now = performance.now();\n\t\t\tawait initPromise;\n\t\t\tif (!detector) return;\n\t\t\tconst callOrder = ++detector.state.nCalls;\n\n\t\t\tdetector.state.pending = detector.state.pending.then(async () => {\n\t\t\t\tif (!detector || callOrder !== detector.state.nCalls) return;\n\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (detector.state.runningMode !== requiredMode) {\n\t\t\t\t\tdetector.state.runningMode = requiredMode;\n\t\t\t\t\tawait detector.landmarker.setOptions({\n\t\t\t\t\t\trunningMode: requiredMode,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tlet shouldDetect = false;\n\n\t\t\t\tif (source !== detector.state.source) {\n\t\t\t\t\tdetector.state.source = source;\n\t\t\t\t\tdetector.state.videoTime = -1;\n\t\t\t\t\tshouldDetect = true;\n\t\t\t\t} else if (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.currentTime !== detector.state.videoTime) {\n\t\t\t\t\t\tdetector.state.videoTime = source.currentTime;\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (!(source instanceof HTMLImageElement)) {\n\t\t\t\t\tif (now - detector.state.resultTimestamp > 2) {\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shouldDetect) {\n\t\t\t\t\tlet result: FaceLandmarkerResult | undefined;\n\t\t\t\t\tlet width: number, height: number;\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) return;\n\t\t\t\t\t\twidth = source.videoWidth;\n\t\t\t\t\t\theight = source.videoHeight;\n\t\t\t\t\t\tresult = detector.landmarker.detectForVideo(source, now);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (source.width === 0 || source.height === 0) return;\n\t\t\t\t\t\twidth = source.width;\n\t\t\t\t\t\theight = source.height;\n\t\t\t\t\t\tresult = detector.landmarker.detect(source);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tdetector.state.resultTimestamp = now;\n\t\t\t\t\t\tdetector.state.result = result;\n\t\t\t\t\t\tupdateLandmarksData(detector, result.faceLandmarks);\n\t\t\t\t\t\tupdateMask(detector, width, height);\n\t\t\t\t\t\tfor (const cb of detector.subscribers.keys()) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (detector.state.result) {\n\t\t\t\t\tfor (const [cb, hasCalled] of detector.subscribers.entries()) {\n\t\t\t\t\t\tif (!hasCalled) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait detector.state.pending;\n\t\t}\n\n\t\tshaderPad.on('_init', () => {\n\t\t\tshaderPad.initializeUniform('u_maxFaces', 'int', options.maxFaces);\n\t\t\tshaderPad.initializeUniform('u_nFaces', 'int', 0);\n\t\t\tshaderPad.initializeTexture(\n\t\t\t\t'u_faceLandmarksTex',\n\t\t\t\t{\n\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\theight: textureHeight,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinternalFormat: 'RGBA32F',\n\t\t\t\t\ttype: 'FLOAT',\n\t\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\t\thistory,\n\t\t\t\t},\n\t\t\t);\n\t\t\tshaderPad.initializeTexture('u_faceMask', maskCanvas, {\n\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\thistory,\n\t\t\t});\n\t\t\tinitPromise.then(() => {\n\t\t\t\tif (destroyed || !detector) return;\n\t\t\t\temitHook('face:ready');\n\t\t\t});\n\t\t});\n\n\t\tlet historyWriteCounter = 0;\n\t\tlet pendingBackfillSlots: number[] = [];\n\t\tconst writeToHistory = () => {\n\t\t\tif (!history) return;\n\t\t\tonResult(historyWriteCounter); // Write stale data immediately.\n\t\t\tpendingBackfillSlots.push(historyWriteCounter); // Queue up backfill with more recent data.\n\t\t\thistoryWriteCounter = (historyWriteCounter + 1) % (history + 1);\n\t\t};\n\n\t\tshaderPad.on('initializeTexture', (name: string, source: TextureSource) => {\n\t\t\tif (name === textureName && isMediaPipeSource(source)) {\n\t\t\t\twriteToHistory();\n\t\t\t\tdetectFaces(source);\n\t\t\t}\n\t\t});\n\n\t\tshaderPad.on(\n\t\t\t'updateTextures',\n\t\t\t(updates: Record<string, TextureSource>, options?: { skipHistoryWrite?: boolean }) => {\n\t\t\t\tconst source = updates[textureName];\n\t\t\t\tif (isMediaPipeSource(source)) {\n\t\t\t\t\tskipHistoryWrite = options?.skipHistoryWrite ?? false;\n\t\t\t\t\tif (!skipHistoryWrite) writeToHistory();\n\t\t\t\t\tdetectFaces(source);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tshaderPad.on('destroy', () => {\n\t\t\tdestroyed = true;\n\t\t\tif (detector) {\n\t\t\t\tdetector.subscribers.delete(onResult);\n\t\t\t\tif (detector.subscribers.size === 0) {\n\t\t\t\t\tdetector.landmarker.close();\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.regionProgram);\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.blitProgram);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.regionPositionBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.quadBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteTexture(detector.mask.scratchTexture);\n\t\t\t\t\tdetector.mask.gl.deleteFramebuffer(detector.mask.scratchFramebuffer);\n\t\t\t\t\tsharedDetectors.delete(optionsKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdetector = null;\n\t\t});\n\n\t\tconst { fn, historyParams } = generateGLSLFn(history);\n\t\tconst sampleMask = history ? `_sampleFaceMask(pos, framesAgo)` : `texture(u_faceMask, pos)`;\n\t\tconst decodeFaceBitIndex = Array.from(\n\t\t\t{ length: GB_BITMASK_MAX_FACES - 1 },\n\t\t\t(_, i) => `step(${2 ** (i + 1)}.0, faceBitF)`,\n\t\t).join(' + ');\n\t\tconst decodeFaceIndex =\n\t\t\toptions.maxFaces <= GB_BITMASK_MAX_FACES\n\t\t\t\t? `uint faceBits = (uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5) << 8) | uint(mask.g * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tuint faceBit = faceBits & (~faceBits + 1u);\n\tfloat faceBitF = float(faceBit);\n\tfloat hasFace = sign(faceBitF);\n\tfloat faceIndex = ${decodeFaceBitIndex} - (1.0 - hasFace);`\n\t\t\t\t: `float faceIndex = float(int(uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5)) - 1);`;\n\n\t\tconst checkAt = (fnName: string, ...regionNames: (keyof typeof RED_REGION_BIT_VALUES)[]) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\tuint bits = uint(mask.r * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tfloat hit = sign(float(bits & ${regionNames.reduce(\n\t\t(mask, regionName) => mask | RED_REGION_BIT_VALUES[regionName],\n\t\t0,\n\t)}u));\n\treturn vec2(hit, mix(-1.0, faceIndex, hit));`,\n\t\t\t);\n\n\t\tconst combineLeftRight = (fnName: string, leftFn: string, rightFn: string) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec2 left = ${leftFn}(pos${historyParams});\n\tvec2 right = ${rightFn}(pos${historyParams});\n\treturn mix(right, left, left.x);`,\n\t\t\t);\n\n\t\tconst checkIn = (fnNames: string[]) =>\n\t\t\tfnNames\n\t\t\t\t.map(fnName =>\n\t\t\t\t\tfn(\n\t\t\t\t\t\t'float',\n\t\t\t\t\t\t`in${fnName[0].toUpperCase() + fnName.slice(1)}`,\n\t\t\t\t\t\t'vec2 pos',\n\t\t\t\t\t\t`vec2 a = ${fnName}At(pos${historyParams}); return step(0.0, a.y) * a.x;`,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.join('\\n');\n\n\t\tinjectGLSL(`\nuniform int u_maxFaces;\nuniform int u_nFaces;\nuniform highp sampler2D${history ? 'Array' : ''} u_faceLandmarksTex;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceLandmarksTexFrameOffset;`\n\t\t\t\t: ''\n\t\t}\nuniform mediump sampler2D${history ? 'Array' : ''} u_faceMask;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceMaskFrameOffset;`\n\t\t\t\t: ''\n\t\t}\n\n#define FACE_LANDMARK_L_EYE_CENTER ${LANDMARK_INDICES.LEFT_EYE_CENTER}\n#define FACE_LANDMARK_R_EYE_CENTER ${LANDMARK_INDICES.RIGHT_EYE_CENTER}\n#define FACE_LANDMARK_NOSE_TIP ${LANDMARK_INDICES.NOSE_TIP}\n#define FACE_LANDMARK_FACE_CENTER ${LANDMARK_INDICES.FACE_CENTER}\n#define FACE_LANDMARK_MOUTH_CENTER ${LANDMARK_INDICES.MOUTH_CENTER}\n\n${fn(\n\t'int',\n\t'nFacesAt',\n\t'',\n\thistory\n\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn int(texelFetch(u_faceLandmarksTex, ivec3(0, 0, layer), 0).r + 0.5);`\n\t\t: `\n\treturn int(texelFetch(u_faceLandmarksTex, ivec2(0, 0), 0).r + 0.5);`,\n)}\n${fn(\n\t'vec4',\n\t'faceLandmark',\n\t'int faceIndex, int landmarkIndex',\n\t`int i = ${N_LANDMARK_METADATA_SLOTS} + faceIndex * ${LANDMARK_COUNT} + landmarkIndex;\n\tint x = i % ${LANDMARKS_TEXTURE_WIDTH};\n\tint y = i / ${LANDMARKS_TEXTURE_WIDTH};${\n\t\thistory\n\t\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texelFetch(u_faceLandmarksTex, ivec3(x, y, layer), 0);`\n\t\t\t: `\n\treturn texelFetch(u_faceLandmarksTex, ivec2(x, y), 0);`\n\t}`,\n)}\n${\n\thistory\n\t\t? `\nvec4 _sampleFaceMask(vec2 pos, int framesAgo) {\n\tint layer = (u_faceMaskFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texture(u_faceMask, vec3(pos, float(layer)));\n}\n`\n\t\t: ''\n}\n${checkAt('leftEyebrow', 'LEFT_EYEBROW')}\n${checkAt('rightEyebrow', 'RIGHT_EYEBROW')}\n${checkAt('leftEye', 'LEFT_EYE')}\n${checkAt('rightEye', 'RIGHT_EYE')}\n${checkAt('lips', 'MOUTH')}\n${checkAt('mouth', 'MOUTH', 'INNER_MOUTH')}\n${checkAt('innerMouth', 'INNER_MOUTH')}\n${checkAt('faceOval', 'OVAL')}\n${fn(\n\t'vec2',\n\t'faceAt',\n\t'vec2 pos',\n\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\treturn vec2(step(0.0, faceIndex), faceIndex);`,\n)}\n${combineLeftRight('eye', 'leftEyeAt', 'rightEyeAt')}\n${combineLeftRight('eyebrow', 'leftEyebrowAt', 'rightEyebrowAt')}\n${checkIn(['eyebrow', 'eye', 'mouth', 'innerMouth', 'lips', 'face'])}`);\n\t};\n}\n\nexport default face;\n","import { TextureSource } from '..';\n\nexport const dummyTexture = { data: new Uint8Array(4), width: 1, height: 1 };\n\nexport type MediaPipeSource = HTMLVideoElement | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas;\n\nexport function isMediaPipeSource(source: TextureSource): source is MediaPipeSource {\n\treturn (\n\t\tsource instanceof HTMLVideoElement ||\n\t\tsource instanceof HTMLImageElement ||\n\t\tsource instanceof HTMLCanvasElement ||\n\t\tsource instanceof OffscreenCanvas\n\t);\n}\n\nexport function hashOptions(options: object): string {\n\treturn JSON.stringify(options, Object.keys(options).sort());\n}\n\nexport function calculateBoundingBoxCenter(\n\tdata: Float32Array,\n\tentityIdx: number,\n\tlandmarkIndices: readonly number[] | number[],\n\tlandmarkCount: number,\n\toffset: number = 0,\n): [number, number, number, number] {\n\tlet minX = Infinity,\n\t\tmaxX = -Infinity,\n\t\tminY = Infinity,\n\t\tmaxY = -Infinity,\n\t\tavgZ = 0,\n\t\tavgVisibility = 0;\n\n\tfor (const idx of landmarkIndices) {\n\t\tconst dataIdx = (offset + entityIdx * landmarkCount + idx) * 4;\n\t\tconst x = data[dataIdx];\n\t\tconst y = data[dataIdx + 1];\n\t\tminX = Math.min(minX, x);\n\t\tmaxX = Math.max(maxX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxY = Math.max(maxY, y);\n\t\tavgZ += data[dataIdx + 2];\n\t\tavgVisibility += data[dataIdx + 3];\n\t}\n\n\treturn [\n\t\t(minX + maxX) / 2,\n\t\t(minY + maxY) / 2,\n\t\tavgZ / landmarkIndices.length,\n\t\tavgVisibility / landmarkIndices.length,\n\t];\n}\n\nlet filesetPromise: Promise<any> | null = null;\nexport function getSharedFileset(): Promise<any> {\n\tif (!filesetPromise) {\n\t\tfilesetPromise = import('@mediapipe/tasks-vision').then(({ FilesetResolver }) =>\n\t\t\tFilesetResolver.forVisionTasks(\n\t\t\t\t`https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${__MEDIAPIPE_TASKS_VISION_VERSION__}/wasm`,\n\t\t\t),\n\t\t);\n\t}\n\treturn filesetPromise;\n}\n\nexport function generateGLSLFn(history: number | undefined) {\n\tconst historyParams = history ? ', framesAgo' : '';\n\tconst fn = history\n\t\t? (returnType: string, name: string, args: string, body: string) => {\n\t\t\t\tconst argsOnly = args.replace(/\\w+ /g, '');\n\t\t\t\tconst historyArgs = args ? `${args}, int framesAgo` : 'int framesAgo';\n\t\t\t\tconst callArgs = argsOnly ? `${argsOnly}, 0` : '0';\n\t\t\t\treturn `${returnType} ${name}(${historyArgs}) {\\n${body}\\n}\n${returnType} ${name}(${args}) { return ${name}(${callArgs}); }`;\n\t\t\t}\n\t\t: (returnType: string, name: string, args: string, body: string) =>\n\t\t\t\t`${returnType} ${name}(${args}) {\\n${body}\\n}`;\n\treturn { historyParams, fn };\n}\n"],"mappings":"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","names":["face_exports","__export","face_default","__toCommonJS","dummyTexture","isMediaPipeSource","source","hashOptions","options","calculateBoundingBoxCenter","data","entityIdx","landmarkIndices","landmarkCount","offset","minX","maxX","minY","maxY","avgZ","avgVisibility","idx","dataIdx","x","y","filesetPromise","getSharedFileset","FilesetResolver","generateGLSLFn","history","returnType","name","args","body","argsOnly","historyArgs","callArgs","MASK_VERTEX_SHADER","MASK_FRAGMENT_SHADER","BLIT_FRAGMENT_SHADER","FULLSCREEN_TRIANGLES","STANDARD_LANDMARK_COUNT","CUSTOM_LANDMARK_COUNT","LANDMARK_COUNT","LANDMARKS_TEXTURE_WIDTH","N_LANDMARK_METADATA_SLOTS","LEFT_EYEBROW_INDICES","LEFT_EYE_INDICES","RIGHT_EYEBROW_INDICES","RIGHT_EYE_INDICES","MOUTH_INDICES","INNER_MOUTH_INDICES","ALL_STANDARD_INDICES","_","i","LANDMARK_INDICES","RED_REGION_NAMES","GREEN_REGION_NAMES","BLUE_REGION_NAMES","CHANNEL_BIT_SCALE","GB_BITMASK_MAX_FACES","createChannelBitValues","names","name","normalizeChannelBitValues","bitValues","bitValue","RED_REGION_BIT_VALUES","GREEN_REGION_BIT_VALUES","BLUE_REGION_BIT_VALUES","RED_CHANNEL_VALUES","GREEN_CHANNEL_VALUES","BLUE_CHANNEL_VALUES","DEFAULT_FACE_OPTIONS","fanTriangulate","indices","tris","faceRegions","initFaceRegions","LandmarkerClass","tesselationConnections","tesselation","ovalIndices","start","key","sharedDetectors","createProgram","gl","vertexSource","fragmentSource","vertexShader","fragmentShader","program","initMaskRenderer","canvas","regionProgram","blitProgram","regionPositionBuffer","regionPositionLocation","quadBuffer","blitPositionLocation","colorLocation","textureLocation","scratchTexture","scratchFramebuffer","resizeMaskRenderer","mask","width","height","drawRegionToScratch","landmarksData","faceRegion","faceIdx","g","b","baseIdx","vertices","landmarkIdx","accumulateScratch","updateLandmarksData","detector","faces","data","nFaces","landmarks","landmark","dataIdx","faceCenter","calculateBoundingBoxCenter","mouthCenter","updateMask","maxFaces","maskCanvas","useTesselationBitmask","face","config","textureName","history","mediapipeOptions","options","optionsKey","hashOptions","nLandmarksMax","textureHeight","shaderPad","context","injectGLSL","emitHook","updateTexturesInternal","existingDetector","destroyed","skipHistoryWrite","onResult","singleHistoryWriteIndex","nSlots","rowsToUpdate","historyWriteIndex","pendingBackfillSlots","initializeDetector","mediaPipe","FaceLandmarker","getSharedFileset","faceLandmarker","initPromise","detectFaces","source","now","callOrder","requiredMode","shouldDetect","result","cb","hasCalled","historyWriteCounter","writeToHistory","isMediaPipeSource","updates","fn","historyParams","generateGLSLFn","sampleMask","decodeFaceBitIndex","decodeFaceIndex","checkAt","fnName","regionNames","regionName","combineLeftRight","leftFn","rightFn","checkIn","fnNames","face_default"]}
1
+ {"version":3,"sources":["../../src/plugins/face.ts","../../src/plugins/mediapipe-common.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '..';\nimport {\n\tcalculateBoundingBoxCenter,\n\tgenerateGLSLFn,\n\tgetSharedFileset,\n\thashOptions,\n\tisMediaPipeSource,\n\tMediaPipeSource,\n} from './mediapipe-common';\nimport type { FaceLandmarker, FaceLandmarkerResult, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface FacePluginOptions {\n\tmodelPath?: string;\n\tmaxFaces?: number;\n\tminFaceDetectionConfidence?: number;\n\tminFacePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputFaceBlendshapes?: boolean;\n\toutputFacialTransformationMatrixes?: boolean;\n\thistory?: number;\n}\n\nconst MASK_VERTEX_SHADER = `#version 300 es\nin vec2 a_pos;\nout vec2 v_uv;\nvoid main() {\n\tv_uv = a_pos;\n\tgl_Position = vec4(a_pos * 2.0 - 1.0, 0.0, 1.0);\n}`;\nconst MASK_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nuniform vec4 u_color;\nout vec4 outColor;\nvoid main() { outColor = u_color; }`;\nconst BLIT_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nuniform sampler2D u_texture;\nout vec4 outColor;\nvoid main() { outColor = texture(u_texture, v_uv); }`;\nconst FULLSCREEN_TRIANGLES = new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]);\n\nconst STANDARD_LANDMARK_COUNT = 478;\nconst CUSTOM_LANDMARK_COUNT = 2;\nconst LANDMARK_COUNT = STANDARD_LANDMARK_COUNT + CUSTOM_LANDMARK_COUNT;\nconst LANDMARKS_TEXTURE_WIDTH = 512;\nconst N_LANDMARK_METADATA_SLOTS = 1;\n\nconst ALL_STANDARD_INDICES = Array.from({ length: STANDARD_LANDMARK_COUNT }, (_, i) => i);\nconst FACE_LANDMARK_L_EYE_CENTER = 473;\nconst FACE_LANDMARK_R_EYE_CENTER = 468;\nconst FACE_LANDMARK_NOSE_TIP = 4;\nconst FACE_LANDMARK_FACE_CENTER = STANDARD_LANDMARK_COUNT;\nconst FACE_LANDMARK_MOUTH_CENTER = STANDARD_LANDMARK_COUNT + 1;\nlet innerMouthIndices: number[] | null = null;\n\n/* Face mask channel layout:\n- R: additive bitfield for face regions. Since it’s additive, it handles overlapping regions.\n- G/B: tessellation ownership. When maxFaces is <= 16, G stores one-hot bits for\n faces 0-7 and B stores one-hot bits for faces 8-15 so overlapping faces\n remain decodable. Above 16 maxFaces, B falls back to storing faceIndex + 1 as\n an additive byte value, which will overcount on overlaps. */\nconst RED_REGION_NAMES = [\n\t'OVAL',\n\t'LEFT_EYEBROW',\n\t'RIGHT_EYEBROW',\n\t'LEFT_EYE',\n\t'RIGHT_EYE',\n\t'MOUTH',\n\t'INNER_MOUTH',\n] as const;\nconst GREEN_REGION_NAMES = ['FACE_0', 'FACE_1', 'FACE_2', 'FACE_3', 'FACE_4', 'FACE_5', 'FACE_6', 'FACE_7'] as const;\nconst BLUE_REGION_NAMES = [\n\t'FACE_8',\n\t'FACE_9',\n\t'FACE_10',\n\t'FACE_11',\n\t'FACE_12',\n\t'FACE_13',\n\t'FACE_14',\n\t'FACE_15',\n] as const;\nconst CHANNEL_BIT_SCALE = 255;\nconst GB_BITMASK_MAX_FACES = GREEN_REGION_NAMES.length + BLUE_REGION_NAMES.length;\n\nfunction createChannelBitValues<const T extends readonly string[]>(names: T): Record<T[number], number> {\n\treturn Object.fromEntries(names.map((name, i) => [name, 1 << i])) as Record<T[number], number>;\n}\n\nfunction normalizeChannelBitValues<T extends Record<string, number>>(bitValues: T): T {\n\treturn Object.fromEntries(\n\t\tObject.entries(bitValues).map(([name, bitValue]) => [name, bitValue / CHANNEL_BIT_SCALE]),\n\t) as T;\n}\n\nconst RED_REGION_BIT_VALUES = createChannelBitValues(RED_REGION_NAMES);\nconst GREEN_REGION_BIT_VALUES = createChannelBitValues(GREEN_REGION_NAMES);\nconst BLUE_REGION_BIT_VALUES = createChannelBitValues(BLUE_REGION_NAMES);\nconst RED_CHANNEL_VALUES = normalizeChannelBitValues(RED_REGION_BIT_VALUES);\nconst GREEN_CHANNEL_VALUES = normalizeChannelBitValues(GREEN_REGION_BIT_VALUES);\nconst BLUE_CHANNEL_VALUES = normalizeChannelBitValues(BLUE_REGION_BIT_VALUES);\n\nconst DEFAULT_FACE_OPTIONS: Required<Omit<FacePluginOptions, 'history'>> = {\n\tmodelPath:\n\t\t'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task',\n\tmaxFaces: 1,\n\tminFaceDetectionConfidence: 0.5,\n\tminFacePresenceConfidence: 0.5,\n\tminTrackingConfidence: 0.5,\n\toutputFaceBlendshapes: false,\n\toutputFacialTransformationMatrixes: false,\n};\n\nfunction fanTriangulate(indices: readonly number[]): number[] {\n\tconst tris: number[] = [];\n\tfor (let i = 1; i < indices.length - 1; ++i) {\n\t\ttris.push(indices[0], indices[i], indices[i + 1]);\n\t}\n\treturn tris;\n}\n\nfunction contourPath(connections: readonly { start: number; end: number }[]): number[] {\n\tconst indices = new Array<number>(connections.length + 1);\n\tindices[0] = connections[0].start;\n\tfor (let i = 0; i < connections.length; ++i) indices[i + 1] = connections[i].end;\n\treturn indices;\n}\n\nfunction stripTriangulate(a: readonly number[], b: readonly number[]): number[] {\n\tconst tris: number[] = [];\n\tconst n = Math.min(a.length, b.length);\n\tfor (let i = 0; i < n - 1; ++i) {\n\t\ttris.push(a[i], b[i], b[i + 1], a[i], b[i + 1], a[i + 1]);\n\t}\n\treturn tris;\n}\n\ntype FaceRegion = { indices: number[]; vertices: Float32Array };\nlet faceRegions: Record<string, FaceRegion> | null = null;\nfunction initFaceRegions(LandmarkerClass: typeof FaceLandmarker): void {\n\tif (!faceRegions) {\n\t\tconst tesselationConnections = LandmarkerClass.FACE_LANDMARKS_TESSELATION;\n\t\tconst leftEyebrowIndices = contourPath(LandmarkerClass.FACE_LANDMARKS_LEFT_EYEBROW);\n\t\tconst rightEyebrowIndices = contourPath(LandmarkerClass.FACE_LANDMARKS_RIGHT_EYEBROW);\n\t\tconst leftEyeConnections = LandmarkerClass.FACE_LANDMARKS_LEFT_EYE;\n\t\tconst rightEyeConnections = LandmarkerClass.FACE_LANDMARKS_RIGHT_EYE;\n\t\tconst lipConnections = LandmarkerClass.FACE_LANDMARKS_LIPS;\n\t\t// MediaPipe ships eyes as 2 open chains of 8 connections and lips as 4 open chains of 10.\n\t\tconst leftEyeUpper = contourPath(leftEyeConnections.slice(0, 8));\n\t\tconst leftEyeLower = contourPath(leftEyeConnections.slice(8, 16));\n\t\tconst rightEyeUpper = contourPath(rightEyeConnections.slice(0, 8));\n\t\tconst rightEyeLower = contourPath(rightEyeConnections.slice(8, 16));\n\t\tconst outerUpperLip = contourPath(lipConnections.slice(0, 10));\n\t\tconst outerLowerLip = contourPath(lipConnections.slice(10, 20));\n\t\tconst innerUpperLip = contourPath(lipConnections.slice(20, 30));\n\t\tconst innerLowerLip = contourPath(lipConnections.slice(30, 40));\n\t\tconst leftEyeIndices = [...leftEyeUpper, ...leftEyeLower.slice(1, -1)];\n\t\tconst rightEyeIndices = [...rightEyeUpper, ...rightEyeLower.slice(1, -1)];\n\t\tinnerMouthIndices = [...innerUpperLip, ...innerLowerLip.slice(1, -1)];\n\t\tconst tessellationHoleRemap = new Int16Array(LANDMARK_COUNT).fill(-1);\n\t\tfor (const index of leftEyeIndices) tessellationHoleRemap[index] = FACE_LANDMARK_L_EYE_CENTER;\n\t\tfor (const index of rightEyeIndices) tessellationHoleRemap[index] = FACE_LANDMARK_R_EYE_CENTER;\n\t\tfor (const index of innerMouthIndices) tessellationHoleRemap[index] = FACE_LANDMARK_MOUTH_CENTER;\n\t\tconst remapTessellationHole = (index: number) => {\n\t\t\tconst remapped = tessellationHoleRemap[index];\n\t\t\treturn remapped >= 0 ? remapped : index;\n\t\t};\n\t\tconst tesselation: number[] = [];\n\t\tfor (let i = 0; i < tesselationConnections.length - 2; i += 3) {\n\t\t\tconst a = remapTessellationHole(tesselationConnections[i].start);\n\t\t\tconst b = remapTessellationHole(tesselationConnections[i + 1].start);\n\t\t\tconst c = remapTessellationHole(tesselationConnections[i + 2].start);\n\t\t\tif (a !== b && a !== c && b !== c) tesselation.push(a, b, c);\n\t\t}\n\t\tconst leftEyeFill = stripTriangulate(leftEyeUpper, leftEyeLower);\n\t\tconst rightEyeFill = stripTriangulate(rightEyeUpper, rightEyeLower);\n\t\tconst mouthFill = [...stripTriangulate(outerUpperLip, innerUpperLip), ...stripTriangulate(outerLowerLip, innerLowerLip)];\n\t\tconst innerMouthFill = stripTriangulate(innerUpperLip, innerLowerLip);\n\t\tconst ovalIndices = contourPath(LandmarkerClass.FACE_LANDMARKS_FACE_OVAL).slice(0, -1);\n\t\tfaceRegions = Object.fromEntries(\n\t\t\tObject.entries({\n\t\t\t\tLEFT_EYEBROW: fanTriangulate(leftEyebrowIndices),\n\t\t\t\tRIGHT_EYEBROW: fanTriangulate(rightEyebrowIndices),\n\t\t\t\tLEFT_EYE: leftEyeFill,\n\t\t\t\tRIGHT_EYE: rightEyeFill,\n\t\t\t\tMOUTH: mouthFill,\n\t\t\t\tINNER_MOUTH: innerMouthFill,\n\t\t\t\tTESSELATION: tesselation,\n\t\t\t\tOVAL: fanTriangulate(ovalIndices),\n\t\t\t}).map(([key, indices]) => [key, { indices, vertices: new Float32Array(indices.length * 2) }]),\n\t\t);\n\t}\n}\n\ninterface MaskRenderer {\n\tcanvas: OffscreenCanvas;\n\tgl: WebGL2RenderingContext;\n\tregionProgram: WebGLProgram;\n\tblitProgram: WebGLProgram;\n\tregionPositionBuffer: WebGLBuffer;\n\tquadBuffer: WebGLBuffer;\n\tregionPositionLocation: number;\n\tblitPositionLocation: number;\n\tcolorLocation: WebGLUniformLocation;\n\ttextureLocation: WebGLUniformLocation;\n\tscratchTexture: WebGLTexture;\n\tscratchFramebuffer: WebGLFramebuffer;\n}\n\ninterface Detector {\n\tlandmarker: FaceLandmarker;\n\tmask: MaskRenderer;\n\tsubscribers: Map<Function, boolean>;\n\tmaxFaces: number;\n\tstate: {\n\t\tnCalls: number;\n\t\trunningMode: 'IMAGE' | 'VIDEO';\n\t\tsource: MediaPipeSource | null;\n\t\tvideoTime: number;\n\t\tresultTimestamp: number;\n\t\tresult: FaceLandmarkerResult | null;\n\t\tpending: Promise<void>;\n\t\tnFaces: number;\n\t};\n\tlandmarks: {\n\t\tdata: Float32Array;\n\t\ttextureHeight: number;\n\t};\n}\nconst sharedDetectors = new Map<string, Detector>();\n\nfunction createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n\tconst vertexShader = gl.createShader(gl.VERTEX_SHADER)!;\n\tgl.shaderSource(vertexShader, vertexSource);\n\tgl.compileShader(vertexShader);\n\n\tconst fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;\n\tgl.shaderSource(fragmentShader, fragmentSource);\n\tgl.compileShader(fragmentShader);\n\n\tconst program = gl.createProgram()!;\n\tgl.attachShader(program, vertexShader);\n\tgl.attachShader(program, fragmentShader);\n\tgl.linkProgram(program);\n\tgl.deleteShader(vertexShader);\n\tgl.deleteShader(fragmentShader);\n\treturn program;\n}\n\nfunction initMaskRenderer(canvas: OffscreenCanvas): MaskRenderer {\n\tconst gl = canvas.getContext('webgl2', {\n\t\tantialias: false,\n\t\tpreserveDrawingBuffer: true,\n\t})!;\n\tconst regionProgram = createProgram(gl, MASK_VERTEX_SHADER, MASK_FRAGMENT_SHADER);\n\tconst blitProgram = createProgram(gl, MASK_VERTEX_SHADER, BLIT_FRAGMENT_SHADER);\n\n\tconst regionPositionBuffer = gl.createBuffer()!;\n\tconst regionPositionLocation = gl.getAttribLocation(regionProgram, 'a_pos');\n\n\tconst quadBuffer = gl.createBuffer()!;\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_TRIANGLES, gl.STATIC_DRAW);\n\tconst blitPositionLocation = gl.getAttribLocation(blitProgram, 'a_pos');\n\n\tconst colorLocation = gl.getUniformLocation(regionProgram, 'u_color')!;\n\tconst textureLocation = gl.getUniformLocation(blitProgram, 'u_texture')!;\n\n\tconst scratchTexture = gl.createTexture()!;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n\n\tconst scratchFramebuffer = gl.createFramebuffer()!;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, scratchTexture, 0);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n\tgl.useProgram(blitProgram);\n\tgl.uniform1i(textureLocation, 0);\n\tgl.colorMask(true, true, true, false);\n\n\treturn {\n\t\tcanvas,\n\t\tgl,\n\t\tregionProgram,\n\t\tblitProgram,\n\t\tregionPositionBuffer,\n\t\tquadBuffer,\n\t\tregionPositionLocation,\n\t\tblitPositionLocation,\n\t\tcolorLocation,\n\t\ttextureLocation,\n\t\tscratchTexture,\n\t\tscratchFramebuffer,\n\t};\n}\n\nfunction resizeMaskRenderer(mask: MaskRenderer, width: number, height: number) {\n\tconst { gl, canvas, scratchTexture } = mask;\n\tif (canvas.width === width && canvas.height === height) return;\n\tcanvas.width = width;\n\tcanvas.height = height;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n}\n\nfunction drawRegionToScratch(\n\tmask: MaskRenderer,\n\tlandmarksData: Float32Array,\n\tfaceRegion: FaceRegion,\n\tfaceIdx: number,\n\tr: number,\n\tg: number,\n\tb: number,\n) {\n\tconst { gl, regionProgram, regionPositionBuffer, regionPositionLocation, colorLocation, scratchFramebuffer } = mask;\n\tconst baseIdx = N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT;\n\tconst { indices, vertices } = faceRegion;\n\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\tgl.useProgram(regionProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, regionPositionBuffer);\n\tgl.enableVertexAttribArray(regionPositionLocation);\n\tgl.vertexAttribPointer(regionPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.MAX);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\n\tfor (let i = 0; i < indices.length; ++i) {\n\t\tconst landmarkIdx = (baseIdx + indices[i]) * 4;\n\t\tvertices[i * 2] = landmarksData[landmarkIdx];\n\t\tvertices[i * 2 + 1] = landmarksData[landmarkIdx + 1];\n\t}\n\tgl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);\n\tgl.uniform4f(colorLocation, r, g, b, 1.0);\n\tgl.drawArrays(gl.TRIANGLES, 0, indices.length);\n}\n\nfunction accumulateScratch(mask: MaskRenderer) {\n\tconst { gl, blitProgram, quadBuffer, blitPositionLocation, scratchTexture } = mask;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.useProgram(blitProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.enableVertexAttribArray(blitPositionLocation);\n\tgl.vertexAttribPointer(blitPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.activeTexture(gl.TEXTURE0);\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.FUNC_ADD);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n}\n\nfunction updateLandmarksData(detector: Detector, faces: NormalizedLandmark[][]) {\n\tconst data = detector.landmarks.data;\n\tconst nFaces = faces.length;\n\tdata[0] = nFaces;\n\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst landmarks = faces[faceIdx];\n\t\tfor (let landmarkIdx = 0; landmarkIdx < STANDARD_LANDMARK_COUNT; ++landmarkIdx) {\n\t\t\tconst landmark = landmarks[landmarkIdx];\n\t\t\tconst dataIdx = (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + landmarkIdx) * 4;\n\t\t\tdata[dataIdx] = landmark.x;\n\t\t\tdata[dataIdx + 1] = 1 - landmark.y;\n\t\t\tdata[dataIdx + 2] = landmark.z ?? 0;\n\t\t\tdata[dataIdx + 3] = landmark.visibility ?? 1;\n\t\t}\n\n\t\tconst faceCenter = calculateBoundingBoxCenter(\n\t\t\tdata,\n\t\t\tfaceIdx,\n\t\t\tALL_STANDARD_INDICES,\n\t\t\tLANDMARK_COUNT,\n\t\t\tN_LANDMARK_METADATA_SLOTS,\n\t\t);\n\t\tdata.set(faceCenter, (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + FACE_LANDMARK_FACE_CENTER) * 4);\n\t\tconst mouthCenter = calculateBoundingBoxCenter(data, faceIdx, innerMouthIndices!, LANDMARK_COUNT, 1);\n\t\tdata.set(mouthCenter, (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + FACE_LANDMARK_MOUTH_CENTER) * 4);\n\t}\n\n\tdetector.state.nFaces = nFaces;\n}\n\nfunction updateMask(detector: Detector, width: number, height: number) {\n\tconst {\n\t\tmask,\n\t\tmaxFaces,\n\t\tlandmarks,\n\t\tstate: { nFaces },\n\t} = detector;\n\tconst { gl, canvas: maskCanvas } = mask;\n\tconst { data: landmarksData } = landmarks;\n\n\tresizeMaskRenderer(mask, width, height);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, maskCanvas.width, maskCanvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\tif (!faceRegions) return;\n\n\tconst useTesselationBitmask = maxFaces <= GB_BITMASK_MAX_FACES;\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst g =\n\t\t\tuseTesselationBitmask && faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? GREEN_CHANNEL_VALUES[GREEN_REGION_NAMES[faceIdx]]\n\t\t\t\t: 0;\n\t\tconst b = useTesselationBitmask\n\t\t\t? faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? 0\n\t\t\t\t: BLUE_CHANNEL_VALUES[BLUE_REGION_NAMES[faceIdx - GREEN_REGION_NAMES.length]]\n\t\t\t: (faceIdx + 1) / CHANNEL_BIT_SCALE;\n\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.TESSELATION, faceIdx, 0, g, b);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.OVAL, faceIdx, RED_CHANNEL_VALUES.OVAL, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.LEFT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.LEFT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.RIGHT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.RIGHT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.LEFT_EYE, faceIdx, RED_CHANNEL_VALUES.LEFT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.RIGHT_EYE, faceIdx, RED_CHANNEL_VALUES.RIGHT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.MOUTH, faceIdx, RED_CHANNEL_VALUES.MOUTH, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.INNER_MOUTH,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.INNER_MOUTH,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t}\n}\n\nfunction face(config: { textureName: string; options?: FacePluginOptions }) {\n\tconst { textureName, options: { history, ...mediapipeOptions } = {} } = config;\n\tconst options = { ...DEFAULT_FACE_OPTIONS, ...mediapipeOptions };\n\tconst optionsKey = hashOptions({ ...options, textureName });\n\n\tconst nLandmarksMax = options.maxFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\tconst textureHeight = Math.ceil(nLandmarksMax / LANDMARKS_TEXTURE_WIDTH);\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, emitHook, updateTexturesInternal } = context;\n\n\t\tconst existingDetector = sharedDetectors.get(optionsKey);\n\t\tconst landmarksData =\n\t\t\texistingDetector?.landmarks.data ?? new Float32Array(LANDMARKS_TEXTURE_WIDTH * textureHeight * 4);\n\t\tconst maskCanvas = existingDetector?.mask.canvas ?? new OffscreenCanvas(1, 1);\n\t\tlet detector: Detector | null = null;\n\t\tlet destroyed = false;\n\t\tlet skipHistoryWrite = false;\n\n\t\tfunction onResult(singleHistoryWriteIndex?: number) {\n\t\t\tif (!detector) return;\n\t\t\tconst nFaces = detector.state.nFaces;\n\t\t\tconst nSlots = nFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\t\t\tconst rowsToUpdate = Math.ceil(nSlots / LANDMARKS_TEXTURE_WIDTH);\n\t\t\tlet historyWriteIndex: number | number[] | undefined = singleHistoryWriteIndex;\n\t\t\tif (typeof historyWriteIndex === 'undefined' && pendingBackfillSlots.length > 0) {\n\t\t\t\thistoryWriteIndex = pendingBackfillSlots;\n\t\t\t\tpendingBackfillSlots = [];\n\t\t\t}\n\t\t\tupdateTexturesInternal(\n\t\t\t\t{\n\t\t\t\t\tu_faceLandmarksTex: {\n\t\t\t\t\t\tdata: detector.landmarks.data,\n\t\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\t\theight: rowsToUpdate,\n\t\t\t\t\t\tisPartial: true,\n\t\t\t\t\t},\n\t\t\t\t\tu_faceMask: detector.mask.canvas,\n\t\t\t\t},\n\t\t\t\thistory ? { skipHistoryWrite, historyWriteIndex } : undefined,\n\t\t\t);\n\t\t\tshaderPad.updateUniforms({ u_nFaces: nFaces });\n\t\t\temitHook('face:result', detector.state.result);\n\t\t}\n\n\t\tasync function initializeDetector() {\n\t\t\tif (sharedDetectors.has(optionsKey)) {\n\t\t\t\tdetector = sharedDetectors.get(optionsKey)!;\n\t\t\t} else {\n\t\t\t\tconst [mediaPipe, { FaceLandmarker }] = await Promise.all([\n\t\t\t\t\tgetSharedFileset(),\n\t\t\t\t\timport('@mediapipe/tasks-vision'),\n\t\t\t\t]);\n\t\t\t\tif (destroyed) return;\n\n\t\t\t\tconst faceLandmarker = await FaceLandmarker.createFromOptions(mediaPipe, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options.modelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumFaces: options.maxFaces,\n\t\t\t\t\tminFaceDetectionConfidence: options.minFaceDetectionConfidence,\n\t\t\t\t\tminFacePresenceConfidence: options.minFacePresenceConfidence,\n\t\t\t\t\tminTrackingConfidence: options.minTrackingConfidence,\n\t\t\t\t\toutputFaceBlendshapes: options.outputFaceBlendshapes,\n\t\t\t\t\toutputFacialTransformationMatrixes: options.outputFacialTransformationMatrixes,\n\t\t\t\t});\n\t\t\t\tif (destroyed) {\n\t\t\t\t\tfaceLandmarker.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdetector = {\n\t\t\t\t\tlandmarker: faceLandmarker,\n\t\t\t\t\tmask: initMaskRenderer(maskCanvas),\n\t\t\t\t\tsubscribers: new Map(),\n\t\t\t\t\tmaxFaces: options.maxFaces,\n\t\t\t\t\tstate: {\n\t\t\t\t\t\tnCalls: 0,\n\t\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\t\tsource: null,\n\t\t\t\t\t\tvideoTime: -1,\n\t\t\t\t\t\tresultTimestamp: 0,\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\tpending: Promise.resolve(),\n\t\t\t\t\t\tnFaces: 0,\n\t\t\t\t\t},\n\t\t\t\t\tlandmarks: {\n\t\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\t\ttextureHeight,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tinitFaceRegions(FaceLandmarker);\n\t\t\t\tsharedDetectors.set(optionsKey, detector);\n\t\t\t}\n\n\t\t\tdetector.subscribers.set(onResult, false);\n\t\t}\n\t\tconst initPromise = initializeDetector();\n\n\t\tasync function detectFaces(source: MediaPipeSource) {\n\t\t\tconst now = performance.now();\n\t\t\tawait initPromise;\n\t\t\tif (!detector) return;\n\t\t\tconst callOrder = ++detector.state.nCalls;\n\n\t\t\tdetector.state.pending = detector.state.pending.then(async () => {\n\t\t\t\tif (!detector || callOrder !== detector.state.nCalls) return;\n\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (detector.state.runningMode !== requiredMode) {\n\t\t\t\t\tdetector.state.runningMode = requiredMode;\n\t\t\t\t\tawait detector.landmarker.setOptions({\n\t\t\t\t\t\trunningMode: requiredMode,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tlet shouldDetect = false;\n\n\t\t\t\tif (source !== detector.state.source) {\n\t\t\t\t\tdetector.state.source = source;\n\t\t\t\t\tdetector.state.videoTime = -1;\n\t\t\t\t\tshouldDetect = true;\n\t\t\t\t} else if (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.currentTime !== detector.state.videoTime) {\n\t\t\t\t\t\tdetector.state.videoTime = source.currentTime;\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (!(source instanceof HTMLImageElement)) {\n\t\t\t\t\tif (now - detector.state.resultTimestamp > 2) {\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shouldDetect) {\n\t\t\t\t\tlet result: FaceLandmarkerResult | undefined;\n\t\t\t\t\tlet width: number, height: number;\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) return;\n\t\t\t\t\t\twidth = source.videoWidth;\n\t\t\t\t\t\theight = source.videoHeight;\n\t\t\t\t\t\tresult = detector.landmarker.detectForVideo(source, now);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (source.width === 0 || source.height === 0) return;\n\t\t\t\t\t\twidth = source.width;\n\t\t\t\t\t\theight = source.height;\n\t\t\t\t\t\tresult = detector.landmarker.detect(source);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tdetector.state.resultTimestamp = now;\n\t\t\t\t\t\tdetector.state.result = result;\n\t\t\t\t\t\tupdateLandmarksData(detector, result.faceLandmarks);\n\t\t\t\t\t\tupdateMask(detector, width, height);\n\t\t\t\t\t\tfor (const cb of detector.subscribers.keys()) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (detector.state.result) {\n\t\t\t\t\tfor (const [cb, hasCalled] of detector.subscribers.entries()) {\n\t\t\t\t\t\tif (!hasCalled) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait detector.state.pending;\n\t\t}\n\n\t\tshaderPad.on('_init', () => {\n\t\t\tshaderPad.initializeUniform('u_maxFaces', 'int', options.maxFaces);\n\t\t\tshaderPad.initializeUniform('u_nFaces', 'int', 0);\n\t\t\tshaderPad.initializeTexture(\n\t\t\t\t'u_faceLandmarksTex',\n\t\t\t\t{\n\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\theight: textureHeight,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinternalFormat: 'RGBA32F',\n\t\t\t\t\ttype: 'FLOAT',\n\t\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\t\thistory,\n\t\t\t\t},\n\t\t\t);\n\t\t\tshaderPad.initializeTexture('u_faceMask', maskCanvas, {\n\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\thistory,\n\t\t\t});\n\t\t\tinitPromise.then(() => {\n\t\t\t\tif (destroyed || !detector) return;\n\t\t\t\temitHook('face:ready');\n\t\t\t});\n\t\t});\n\n\t\tlet historyWriteCounter = 0;\n\t\tlet pendingBackfillSlots: number[] = [];\n\t\tconst writeToHistory = () => {\n\t\t\tif (!history) return;\n\t\t\tonResult(historyWriteCounter); // Write stale data immediately.\n\t\t\tpendingBackfillSlots.push(historyWriteCounter); // Queue up backfill with more recent data.\n\t\t\thistoryWriteCounter = (historyWriteCounter + 1) % (history + 1);\n\t\t};\n\n\t\tshaderPad.on('initializeTexture', (name: string, source: TextureSource) => {\n\t\t\tif (name === textureName && isMediaPipeSource(source)) {\n\t\t\t\twriteToHistory();\n\t\t\t\tdetectFaces(source);\n\t\t\t}\n\t\t});\n\n\t\tshaderPad.on(\n\t\t\t'updateTextures',\n\t\t\t(updates: Record<string, TextureSource>, options?: { skipHistoryWrite?: boolean }) => {\n\t\t\t\tconst source = updates[textureName];\n\t\t\t\tif (isMediaPipeSource(source)) {\n\t\t\t\t\tskipHistoryWrite = options?.skipHistoryWrite ?? false;\n\t\t\t\t\tif (!skipHistoryWrite) writeToHistory();\n\t\t\t\t\tdetectFaces(source);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tshaderPad.on('destroy', () => {\n\t\t\tdestroyed = true;\n\t\t\tif (detector) {\n\t\t\t\tdetector.subscribers.delete(onResult);\n\t\t\t\tif (detector.subscribers.size === 0) {\n\t\t\t\t\tdetector.landmarker.close();\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.regionProgram);\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.blitProgram);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.regionPositionBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.quadBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteTexture(detector.mask.scratchTexture);\n\t\t\t\t\tdetector.mask.gl.deleteFramebuffer(detector.mask.scratchFramebuffer);\n\t\t\t\t\tsharedDetectors.delete(optionsKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdetector = null;\n\t\t});\n\n\t\tconst { fn, historyParams } = generateGLSLFn(history);\n\t\tconst sampleMask = history ? `_sampleFaceMask(pos, framesAgo)` : `texture(u_faceMask, pos)`;\n\t\tconst decodeFaceBitIndex = Array.from(\n\t\t\t{ length: GB_BITMASK_MAX_FACES - 1 },\n\t\t\t(_, i) => `step(${2 ** (i + 1)}.0, faceBitF)`,\n\t\t).join(' + ');\n\t\tconst decodeFaceIndex =\n\t\t\toptions.maxFaces <= GB_BITMASK_MAX_FACES\n\t\t\t\t? `uint faceBits = (uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5) << 8) | uint(mask.g * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tuint faceBit = faceBits & (~faceBits + 1u);\n\tfloat faceBitF = float(faceBit);\n\tfloat hasFace = sign(faceBitF);\n\tfloat faceIndex = ${decodeFaceBitIndex} - (1.0 - hasFace);`\n\t\t\t\t: `float faceIndex = float(int(uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5)) - 1);`;\n\n\t\tconst checkAt = (fnName: string, ...regionNames: (keyof typeof RED_REGION_BIT_VALUES)[]) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\tuint bits = uint(mask.r * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tfloat hit = sign(float(bits & ${regionNames.reduce(\n\t\t(mask, regionName) => mask | RED_REGION_BIT_VALUES[regionName],\n\t\t0,\n\t)}u));\n\treturn vec2(hit, mix(-1.0, faceIndex, hit));`,\n\t\t\t);\n\n\t\tconst combineLeftRight = (fnName: string, leftFn: string, rightFn: string) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec2 left = ${leftFn}(pos${historyParams});\n\tvec2 right = ${rightFn}(pos${historyParams});\n\treturn mix(right, left, left.x);`,\n\t\t\t);\n\n\t\tconst checkIn = (fnNames: string[]) =>\n\t\t\tfnNames\n\t\t\t\t.map(fnName =>\n\t\t\t\t\tfn(\n\t\t\t\t\t\t'float',\n\t\t\t\t\t\t`in${fnName[0].toUpperCase() + fnName.slice(1)}`,\n\t\t\t\t\t\t'vec2 pos',\n\t\t\t\t\t\t`vec2 a = ${fnName}At(pos${historyParams}); return step(0.0, a.y) * a.x;`,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.join('\\n');\n\n\t\tinjectGLSL(`\nuniform int u_maxFaces;\nuniform int u_nFaces;\nuniform highp sampler2D${history ? 'Array' : ''} u_faceLandmarksTex;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceLandmarksTexFrameOffset;`\n\t\t\t\t: ''\n\t\t}\nuniform mediump sampler2D${history ? 'Array' : ''} u_faceMask;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceMaskFrameOffset;`\n\t\t\t\t: ''\n\t\t}\n\n#define FACE_LANDMARK_L_EYE_CENTER ${FACE_LANDMARK_L_EYE_CENTER}\n#define FACE_LANDMARK_R_EYE_CENTER ${FACE_LANDMARK_R_EYE_CENTER}\n#define FACE_LANDMARK_NOSE_TIP ${FACE_LANDMARK_NOSE_TIP}\n#define FACE_LANDMARK_FACE_CENTER ${FACE_LANDMARK_FACE_CENTER}\n#define FACE_LANDMARK_MOUTH_CENTER ${FACE_LANDMARK_MOUTH_CENTER}\n\n${fn(\n\t'int',\n\t'nFacesAt',\n\t'',\n\thistory\n\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn int(texelFetch(u_faceLandmarksTex, ivec3(0, 0, layer), 0).r + 0.5);`\n\t\t: `\n\treturn int(texelFetch(u_faceLandmarksTex, ivec2(0, 0), 0).r + 0.5);`,\n)}\n${fn(\n\t'vec4',\n\t'faceLandmark',\n\t'int faceIndex, int landmarkIndex',\n\t`int i = ${N_LANDMARK_METADATA_SLOTS} + faceIndex * ${LANDMARK_COUNT} + landmarkIndex;\n\tint x = i % ${LANDMARKS_TEXTURE_WIDTH};\n\tint y = i / ${LANDMARKS_TEXTURE_WIDTH};${\n\t\thistory\n\t\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texelFetch(u_faceLandmarksTex, ivec3(x, y, layer), 0);`\n\t\t\t: `\n\treturn texelFetch(u_faceLandmarksTex, ivec2(x, y), 0);`\n\t}`,\n)}\n${\n\thistory\n\t\t? `\nvec4 _sampleFaceMask(vec2 pos, int framesAgo) {\n\tint layer = (u_faceMaskFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texture(u_faceMask, vec3(pos, float(layer)));\n}\n`\n\t\t: ''\n}\n${checkAt('leftEyebrow', 'LEFT_EYEBROW')}\n${checkAt('rightEyebrow', 'RIGHT_EYEBROW')}\n${checkAt('leftEye', 'LEFT_EYE')}\n${checkAt('rightEye', 'RIGHT_EYE')}\n${checkAt('lips', 'MOUTH')}\n${checkAt('mouth', 'MOUTH', 'INNER_MOUTH')}\n${checkAt('innerMouth', 'INNER_MOUTH')}\n${checkAt('faceOval', 'OVAL')}\n${fn(\n\t'vec2',\n\t'faceAt',\n\t'vec2 pos',\n\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\treturn vec2(step(0.0, faceIndex), faceIndex);`,\n)}\n${combineLeftRight('eye', 'leftEyeAt', 'rightEyeAt')}\n${combineLeftRight('eyebrow', 'leftEyebrowAt', 'rightEyebrowAt')}\n${checkIn(['eyebrow', 'eye', 'mouth', 'innerMouth', 'lips', 'face'])}`);\n\t};\n}\n\nexport default face;\n","import { TextureSource } from '..';\n\nexport const dummyTexture = { data: new Uint8Array(4), width: 1, height: 1 };\n\nexport type MediaPipeSource = HTMLVideoElement | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas;\n\nexport function isMediaPipeSource(source: TextureSource): source is MediaPipeSource {\n\treturn (\n\t\tsource instanceof HTMLVideoElement ||\n\t\tsource instanceof HTMLImageElement ||\n\t\tsource instanceof HTMLCanvasElement ||\n\t\tsource instanceof OffscreenCanvas\n\t);\n}\n\nexport function hashOptions(options: object): string {\n\treturn JSON.stringify(options, Object.keys(options).sort());\n}\n\nexport function calculateBoundingBoxCenter(\n\tdata: Float32Array,\n\tentityIdx: number,\n\tlandmarkIndices: readonly number[] | number[],\n\tlandmarkCount: number,\n\toffset: number = 0,\n): [number, number, number, number] {\n\tlet minX = Infinity,\n\t\tmaxX = -Infinity,\n\t\tminY = Infinity,\n\t\tmaxY = -Infinity,\n\t\tavgZ = 0,\n\t\tavgVisibility = 0;\n\n\tfor (const idx of landmarkIndices) {\n\t\tconst dataIdx = (offset + entityIdx * landmarkCount + idx) * 4;\n\t\tconst x = data[dataIdx];\n\t\tconst y = data[dataIdx + 1];\n\t\tminX = Math.min(minX, x);\n\t\tmaxX = Math.max(maxX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxY = Math.max(maxY, y);\n\t\tavgZ += data[dataIdx + 2];\n\t\tavgVisibility += data[dataIdx + 3];\n\t}\n\n\treturn [\n\t\t(minX + maxX) / 2,\n\t\t(minY + maxY) / 2,\n\t\tavgZ / landmarkIndices.length,\n\t\tavgVisibility / landmarkIndices.length,\n\t];\n}\n\nlet filesetPromise: Promise<any> | null = null;\nexport function getSharedFileset(): Promise<any> {\n\tif (!filesetPromise) {\n\t\tfilesetPromise = import('@mediapipe/tasks-vision').then(({ FilesetResolver }) =>\n\t\t\tFilesetResolver.forVisionTasks(\n\t\t\t\t`https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${__MEDIAPIPE_TASKS_VISION_VERSION__}/wasm`,\n\t\t\t),\n\t\t);\n\t}\n\treturn filesetPromise;\n}\n\nexport function generateGLSLFn(history: number | undefined) {\n\tconst historyParams = history ? ', framesAgo' : '';\n\tconst fn = history\n\t\t? (returnType: string, name: string, args: string, body: string) => {\n\t\t\t\tconst argsOnly = args.replace(/\\w+ /g, '');\n\t\t\t\tconst historyArgs = args ? `${args}, int framesAgo` : 'int framesAgo';\n\t\t\t\tconst callArgs = argsOnly ? `${argsOnly}, 0` : '0';\n\t\t\t\treturn `${returnType} ${name}(${historyArgs}) {\\n${body}\\n}\n${returnType} ${name}(${args}) { return ${name}(${callArgs}); }`;\n\t\t\t}\n\t\t: (returnType: string, name: string, args: string, body: string) =>\n\t\t\t\t`${returnType} ${name}(${args}) {\\n${body}\\n}`;\n\treturn { historyParams, fn };\n}\n"],"mappings":"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","names":["face_exports","__export","face_default","__toCommonJS","dummyTexture","isMediaPipeSource","source","hashOptions","options","calculateBoundingBoxCenter","data","entityIdx","landmarkIndices","landmarkCount","offset","minX","maxX","minY","maxY","avgZ","avgVisibility","idx","dataIdx","x","y","filesetPromise","getSharedFileset","FilesetResolver","generateGLSLFn","history","returnType","name","args","body","argsOnly","historyArgs","callArgs","MASK_VERTEX_SHADER","MASK_FRAGMENT_SHADER","BLIT_FRAGMENT_SHADER","FULLSCREEN_TRIANGLES","STANDARD_LANDMARK_COUNT","CUSTOM_LANDMARK_COUNT","LANDMARK_COUNT","LANDMARKS_TEXTURE_WIDTH","N_LANDMARK_METADATA_SLOTS","ALL_STANDARD_INDICES","_","i","FACE_LANDMARK_L_EYE_CENTER","FACE_LANDMARK_R_EYE_CENTER","FACE_LANDMARK_NOSE_TIP","FACE_LANDMARK_FACE_CENTER","FACE_LANDMARK_MOUTH_CENTER","innerMouthIndices","RED_REGION_NAMES","GREEN_REGION_NAMES","BLUE_REGION_NAMES","CHANNEL_BIT_SCALE","GB_BITMASK_MAX_FACES","createChannelBitValues","names","name","normalizeChannelBitValues","bitValues","bitValue","RED_REGION_BIT_VALUES","GREEN_REGION_BIT_VALUES","BLUE_REGION_BIT_VALUES","RED_CHANNEL_VALUES","GREEN_CHANNEL_VALUES","BLUE_CHANNEL_VALUES","DEFAULT_FACE_OPTIONS","fanTriangulate","indices","tris","contourPath","connections","stripTriangulate","a","b","n","faceRegions","initFaceRegions","LandmarkerClass","tesselationConnections","leftEyebrowIndices","rightEyebrowIndices","leftEyeConnections","rightEyeConnections","lipConnections","leftEyeUpper","leftEyeLower","rightEyeUpper","rightEyeLower","outerUpperLip","outerLowerLip","innerUpperLip","innerLowerLip","leftEyeIndices","rightEyeIndices","tessellationHoleRemap","index","remapTessellationHole","remapped","tesselation","c","leftEyeFill","rightEyeFill","mouthFill","innerMouthFill","ovalIndices","key","sharedDetectors","createProgram","gl","vertexSource","fragmentSource","vertexShader","fragmentShader","program","initMaskRenderer","canvas","regionProgram","blitProgram","regionPositionBuffer","regionPositionLocation","quadBuffer","blitPositionLocation","colorLocation","textureLocation","scratchTexture","scratchFramebuffer","resizeMaskRenderer","mask","width","height","drawRegionToScratch","landmarksData","faceRegion","faceIdx","g","baseIdx","vertices","landmarkIdx","accumulateScratch","updateLandmarksData","detector","faces","data","nFaces","landmarks","landmark","dataIdx","faceCenter","calculateBoundingBoxCenter","mouthCenter","updateMask","maxFaces","maskCanvas","useTesselationBitmask","face","config","textureName","history","mediapipeOptions","options","optionsKey","hashOptions","nLandmarksMax","textureHeight","shaderPad","context","injectGLSL","emitHook","updateTexturesInternal","existingDetector","destroyed","skipHistoryWrite","onResult","singleHistoryWriteIndex","nSlots","rowsToUpdate","historyWriteIndex","pendingBackfillSlots","initializeDetector","mediaPipe","FaceLandmarker","getSharedFileset","faceLandmarker","initPromise","detectFaces","source","now","callOrder","requiredMode","shouldDetect","result","cb","hasCalled","historyWriteCounter","writeToHistory","isMediaPipeSource","updates","fn","historyParams","generateGLSLFn","sampleMask","decodeFaceBitIndex","decodeFaceIndex","checkAt","fnName","regionNames","regionName","combineLeftRight","leftFn","rightFn","checkIn","fnNames","face_default"]}
@@ -1,4 +1,4 @@
1
- import{b as X,c as oe,d as K,e as se,f as ce}from"../chunk-VMNWRREI.mjs";var Ee=`#version 300 es
1
+ import{b as J,c as ue,d as Q,e as le,f as fe}from"../chunk-VMNWRREI.mjs";var Ee=`#version 300 es
2
2
  in vec2 a_pos;
3
3
  out vec2 v_uv;
4
4
  void main() {
@@ -13,59 +13,59 @@ precision mediump float;
13
13
  in vec2 v_uv;
14
14
  uniform sampler2D u_texture;
15
15
  out vec4 outColor;
16
- void main() { outColor = texture(u_texture, v_uv); }`,Le=new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),H=478,pe=2,F=H+pe,x=512,p=1,fe=[336,296,334,293,300,276,283,282,295,285],le=[362,398,384,385,386,387,388,466,263,249,390,373,374,380,381,382],me=[70,63,105,66,107,55,65,52,53,46],de=[33,246,161,160,159,158,157,173,133,155,154,153,145,144,163,7],_e=[61,185,40,39,37,0,267,269,270,409,291,375,321,405,314,17,84,181,91,146],j=[78,191,80,81,82,13,312,311,310,415,308,324,318,402,317,14,87,178,88,95],he=Array.from({length:H},(i,e)=>e),I={LEFT_EYEBROW:fe,LEFT_EYE:le,LEFT_EYE_CENTER:473,RIGHT_EYEBROW:me,RIGHT_EYE:de,RIGHT_EYE_CENTER:468,NOSE_TIP:4,MOUTH:_e,INNER_MOUTH:j,FACE_CENTER:H,MOUTH_CENTER:H+1},Ne=["OVAL","LEFT_EYEBROW","RIGHT_EYEBROW","LEFT_EYE","RIGHT_EYE","MOUTH","INNER_MOUTH"],D=["FACE_0","FACE_1","FACE_2","FACE_3","FACE_4","FACE_5","FACE_6","FACE_7"],q=["FACE_8","FACE_9","FACE_10","FACE_11","FACE_12","FACE_13","FACE_14","FACE_15"],v=255,z=D.length+q.length;function J(i){return Object.fromEntries(i.map((e,n)=>[e,1<<n]))}function Q(i){return Object.fromEntries(Object.entries(i).map(([e,n])=>[e,n/v]))}var Te=J(Ne),xe=J(D),Ce=J(q),C=Q(Te),Me=Q(xe),Ie=Q(Ce),ke={modelPath:"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task",maxFaces:1,minFaceDetectionConfidence:.5,minFacePresenceConfidence:.5,minTrackingConfidence:.5,outputFaceBlendshapes:!1,outputFacialTransformationMatrixes:!1};function M(i){let e=[];for(let n=1;n<i.length-1;++n)e.push(i[0],i[n],i[n+1]);return e}var _=null;function Oe(i){if(!_){let e=i.FACE_LANDMARKS_TESSELATION,n=[];for(let a=0;a<e.length-2;a+=3)n.push(e[a].start,e[a+1].start,e[a+2].start);let r=i.FACE_LANDMARKS_FACE_OVAL.map(({start:a})=>a);_=Object.fromEntries(Object.entries({LEFT_EYEBROW:M(fe),RIGHT_EYEBROW:M(me),LEFT_EYE:M(le),RIGHT_EYE:M(de),MOUTH:M(_e),INNER_MOUTH:M(j),TESSELATION:n,OVAL:M(r)}).map(([a,c])=>[a,{indices:c,vertices:new Float32Array(c.length*2)}]))}}var P=new Map;function ue(i,e,n){let r=i.createShader(i.VERTEX_SHADER);i.shaderSource(r,e),i.compileShader(r);let a=i.createShader(i.FRAGMENT_SHADER);i.shaderSource(a,n),i.compileShader(a);let c=i.createProgram();return i.attachShader(c,r),i.attachShader(c,a),i.linkProgram(c),i.deleteShader(r),i.deleteShader(a),c}function Se(i){let e=i.getContext("webgl2",{antialias:!1,preserveDrawingBuffer:!0}),n=ue(e,Ee,ge),r=ue(e,Ee,be),a=e.createBuffer(),c=e.getAttribLocation(n,"a_pos"),T=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,T),e.bufferData(e.ARRAY_BUFFER,Le,e.STATIC_DRAW);let o=e.getAttribLocation(r,"a_pos"),f=e.getUniformLocation(n,"u_color"),l=e.getUniformLocation(r,"u_texture"),m=e.createTexture();e.bindTexture(e.TEXTURE_2D,m),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,1,1,0,e.RGBA,e.UNSIGNED_BYTE,null);let u=e.createFramebuffer();return e.bindFramebuffer(e.FRAMEBUFFER,u),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,m,0),e.bindFramebuffer(e.FRAMEBUFFER,null),e.useProgram(r),e.uniform1i(l,0),e.colorMask(!0,!0,!0,!1),{canvas:i,gl:e,regionProgram:n,blitProgram:r,regionPositionBuffer:a,quadBuffer:T,regionPositionLocation:c,blitPositionLocation:o,colorLocation:f,textureLocation:l,scratchTexture:m,scratchFramebuffer:u}}function Be(i,e,n){let{gl:r,canvas:a,scratchTexture:c}=i;a.width===e&&a.height===n||(a.width=e,a.height=n,r.bindTexture(r.TEXTURE_2D,c),r.texImage2D(r.TEXTURE_2D,0,r.RGBA,e,n,0,r.RGBA,r.UNSIGNED_BYTE,null))}function b(i,e,n,r,a,c,T){let{gl:o,regionProgram:f,regionPositionBuffer:l,regionPositionLocation:m,colorLocation:u,scratchFramebuffer:U}=i,k=p+r*F,{indices:O,vertices:S}=n;o.bindFramebuffer(o.FRAMEBUFFER,U),o.viewport(0,0,i.canvas.width,i.canvas.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),o.useProgram(f),o.bindBuffer(o.ARRAY_BUFFER,l),o.enableVertexAttribArray(m),o.vertexAttribPointer(m,2,o.FLOAT,!1,0,0),o.enable(o.BLEND),o.blendEquation(o.MAX),o.blendFunc(o.ONE,o.ONE);for(let t=0;t<O.length;++t){let h=(k+O[t])*4;S[t*2]=e[h],S[t*2+1]=e[h+1]}o.bufferData(o.ARRAY_BUFFER,S,o.DYNAMIC_DRAW),o.uniform4f(u,a,c,T,1),o.drawArrays(o.TRIANGLES,0,O.length)}function L(i){let{gl:e,blitProgram:n,quadBuffer:r,blitPositionLocation:a,scratchTexture:c}=i;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,i.canvas.width,i.canvas.height),e.useProgram(n),e.bindBuffer(e.ARRAY_BUFFER,r),e.enableVertexAttribArray(a),e.vertexAttribPointer(a,2,e.FLOAT,!1,0,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,c),e.enable(e.BLEND),e.blendEquation(e.FUNC_ADD),e.blendFunc(e.ONE,e.ONE),e.drawArrays(e.TRIANGLES,0,6)}function De(i,e){let n=i.landmarks.data,r=e.length;n[0]=r;for(let a=0;a<r;++a){let c=e[a];for(let f=0;f<H;++f){let l=c[f],m=(p+a*F+f)*4;n[m]=l.x,n[m+1]=1-l.y,n[m+2]=l.z??0,n[m+3]=l.visibility??1}let T=K(n,a,he,F,p);n.set(T,(p+a*F+I.FACE_CENTER)*4);let o=K(n,a,j,F,1);n.set(o,(p+a*F+I.MOUTH_CENTER)*4)}i.state.nFaces=r}function ve(i,e,n){let{mask:r,maxFaces:a,landmarks:c,state:{nFaces:T}}=i,{gl:o,canvas:f}=r,{data:l}=c;if(Be(r,e,n),o.bindFramebuffer(o.FRAMEBUFFER,null),o.viewport(0,0,f.width,f.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),!_)return;let m=a<=z;for(let u=0;u<T;++u){let U=m&&u<D.length?Me[D[u]]:0,k=m?u<D.length?0:Ie[q[u-D.length]]:(u+1)/v;b(r,l,_.TESSELATION,u,0,U,k),L(r),b(r,l,_.OVAL,u,C.OVAL,0,0),L(r),b(r,l,_.LEFT_EYEBROW,u,C.LEFT_EYEBROW,0,0),L(r),b(r,l,_.RIGHT_EYEBROW,u,C.RIGHT_EYEBROW,0,0),L(r),b(r,l,_.LEFT_EYE,u,C.LEFT_EYE,0,0),L(r),b(r,l,_.RIGHT_EYE,u,C.RIGHT_EYE,0,0),L(r),b(r,l,_.MOUTH,u,C.MOUTH,0,0),L(r),b(r,l,_.INNER_MOUTH,u,C.INNER_MOUTH,0,0),L(r)}}function Ue(i){let{textureName:e,options:{history:n,...r}={}}=i,a={...ke,...r},c=oe({...a,textureName:e}),T=a.maxFaces*F+p,o=Math.ceil(T/x);return function(f,l){let{injectGLSL:m,emitHook:u,updateTexturesInternal:U}=l,k=P.get(c),O=k?.landmarks.data??new Float32Array(x*o*4),S=k?.mask.canvas??new OffscreenCanvas(1,1),t=null,h=!1,Y=!1;function w(s){if(!t)return;let E=t.state.nFaces,d=E*F+p,N=Math.ceil(d/x),A=s;typeof A>"u"&&$.length>0&&(A=$,$=[]),U({u_faceLandmarksTex:{data:t.landmarks.data,width:x,height:N,isPartial:!0},u_faceMask:t.mask.canvas},n?{skipHistoryWrite:Y,historyWriteIndex:A}:void 0),f.updateUniforms({u_nFaces:E}),u("face:result",t.state.result)}async function Fe(){if(P.has(c))t=P.get(c);else{let[s,{FaceLandmarker:E}]=await Promise.all([se(),import("@mediapipe/tasks-vision")]);if(h)return;let d=await E.createFromOptions(s,{baseOptions:{modelAssetPath:a.modelPath,delegate:"GPU"},runningMode:"VIDEO",numFaces:a.maxFaces,minFaceDetectionConfidence:a.minFaceDetectionConfidence,minFacePresenceConfidence:a.minFacePresenceConfidence,minTrackingConfidence:a.minTrackingConfidence,outputFaceBlendshapes:a.outputFaceBlendshapes,outputFacialTransformationMatrixes:a.outputFacialTransformationMatrixes});if(h){d.close();return}t={landmarker:d,mask:Se(S),subscribers:new Map,maxFaces:a.maxFaces,state:{nCalls:0,runningMode:"VIDEO",source:null,videoTime:-1,resultTimestamp:0,result:null,pending:Promise.resolve(),nFaces:0},landmarks:{data:O,textureHeight:o}},Oe(E),P.set(c,t)}t.subscribers.set(w,!1)}let Z=Fe();async function ee(s){let E=performance.now();if(await Z,!t)return;let d=++t.state.nCalls;t.state.pending=t.state.pending.then(async()=>{if(!t||d!==t.state.nCalls)return;let N=s instanceof HTMLVideoElement?"VIDEO":"IMAGE";t.state.runningMode!==N&&(t.state.runningMode=N,await t.landmarker.setOptions({runningMode:N}));let A=!1;if(s!==t.state.source?(t.state.source=s,t.state.videoTime=-1,A=!0):s instanceof HTMLVideoElement?s.currentTime!==t.state.videoTime&&(t.state.videoTime=s.currentTime,A=!0):s instanceof HTMLImageElement||E-t.state.resultTimestamp>2&&(A=!0),A){let g,y,V;if(s instanceof HTMLVideoElement){if(s.videoWidth===0||s.videoHeight===0||s.readyState<2)return;y=s.videoWidth,V=s.videoHeight,g=t.landmarker.detectForVideo(s,E)}else{if(s.width===0||s.height===0)return;y=s.width,V=s.height,g=t.landmarker.detect(s)}if(g){t.state.resultTimestamp=E,t.state.result=g,De(t,g.faceLandmarks),ve(t,y,V);for(let ie of t.subscribers.keys())ie(),t.subscribers.set(ie,!0)}}else if(t.state.result)for(let[g,y]of t.subscribers.entries())y||(g(),t.subscribers.set(g,!0))}),await t.state.pending}f.on("_init",()=>{f.initializeUniform("u_maxFaces","int",a.maxFaces),f.initializeUniform("u_nFaces","int",0),f.initializeTexture("u_faceLandmarksTex",{data:O,width:x,height:o},{internalFormat:"RGBA32F",type:"FLOAT",minFilter:"NEAREST",magFilter:"NEAREST",history:n}),f.initializeTexture("u_faceMask",S,{minFilter:"NEAREST",magFilter:"NEAREST",history:n}),Z.then(()=>{h||!t||u("face:ready")})});let G=0,$=[],te=()=>{n&&(w(G),$.push(G),G=(G+1)%(n+1))};f.on("initializeTexture",(s,E)=>{s===e&&X(E)&&(te(),ee(E))}),f.on("updateTextures",(s,E)=>{let d=s[e];X(d)&&(Y=E?.skipHistoryWrite??!1,Y||te(),ee(d))}),f.on("destroy",()=>{h=!0,t&&(t.subscribers.delete(w),t.subscribers.size===0&&(t.landmarker.close(),t.mask.gl.deleteProgram(t.mask.regionProgram),t.mask.gl.deleteProgram(t.mask.blitProgram),t.mask.gl.deleteBuffer(t.mask.regionPositionBuffer),t.mask.gl.deleteBuffer(t.mask.quadBuffer),t.mask.gl.deleteTexture(t.mask.scratchTexture),t.mask.gl.deleteFramebuffer(t.mask.scratchFramebuffer),P.delete(c))),t=null});let{fn:B,historyParams:W}=ce(n),ne=n?"_sampleFaceMask(pos, framesAgo)":"texture(u_faceMask, pos)",Re=Array.from({length:z-1},(s,E)=>`step(${2**(E+1)}.0, faceBitF)`).join(" + "),ae=a.maxFaces<=z?`uint faceBits = (uint(mask.b * ${v}.0 + 0.5) << 8) | uint(mask.g * ${v}.0 + 0.5);
16
+ void main() { outColor = texture(u_texture, v_uv); }`,Le=new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),K=478,pe=2,p=K+pe,v=512,O=1,he=Array.from({length:K},(n,e)=>e),de=473,_e=468,xe=4,Ae=K,ne=K+1,ee=null,Me=["OVAL","LEFT_EYEBROW","RIGHT_EYEBROW","LEFT_EYE","RIGHT_EYE","MOUTH","INNER_MOUTH"],H=["FACE_0","FACE_1","FACE_2","FACE_3","FACE_4","FACE_5","FACE_6","FACE_7"],re=["FACE_8","FACE_9","FACE_10","FACE_11","FACE_12","FACE_13","FACE_14","FACE_15"],w=255,te=H.length+re.length;function ae(n){return Object.fromEntries(n.map((e,t)=>[e,1<<t]))}function ie(n){return Object.fromEntries(Object.entries(n).map(([e,t])=>[e,t/w]))}var Te=ae(Me),Ne=ae(H),Ce=ae(re),y=ie(Te),ke=ie(Ne),Oe=ie(Ce),Ie={modelPath:"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task",maxFaces:1,minFaceDetectionConfidence:.5,minFacePresenceConfidence:.5,minTrackingConfidence:.5,outputFaceBlendshapes:!1,outputFacialTransformationMatrixes:!1};function Z(n){let e=[];for(let t=1;t<n.length-1;++t)e.push(n[0],n[t],n[t+1]);return e}function R(n){let e=new Array(n.length+1);e[0]=n[0].start;for(let t=0;t<n.length;++t)e[t+1]=n[t].end;return e}function W(n,e){let t=[],i=Math.min(n.length,e.length);for(let a=0;a<i-1;++a)t.push(n[a],e[a],e[a+1],n[a],e[a+1],n[a+1]);return t}var g=null;function De(n){if(!g){let e=n.FACE_LANDMARKS_TESSELATION,t=R(n.FACE_LANDMARKS_LEFT_EYEBROW),i=R(n.FACE_LANDMARKS_RIGHT_EYEBROW),a=n.FACE_LANDMARKS_LEFT_EYE,c=n.FACE_LANDMARKS_RIGHT_EYE,A=n.FACE_LANDMARKS_LIPS,o=R(a.slice(0,8)),l=R(a.slice(8,16)),E=R(c.slice(0,8)),m=R(c.slice(8,16)),u=R(A.slice(0,10)),I=R(A.slice(10,20)),b=R(A.slice(20,30)),L=R(A.slice(30,40)),h=[...o,...l.slice(1,-1)],r=[...E,...m.slice(1,-1)];ee=[...b,...L.slice(1,-1)];let F=new Int16Array(p).fill(-1);for(let d of h)F[d]=de;for(let d of r)F[d]=_e;for(let d of ee)F[d]=ne;let D=d=>{let _=F[d];return _>=0?_:d},U=[];for(let d=0;d<e.length-2;d+=3){let _=D(e[d].start),S=D(e[d+1].start),$=D(e[d+2].start);_!==S&&_!==$&&S!==$&&U.push(_,S,$)}let j=W(o,l),X=W(E,m),z=[...W(u,b),...W(I,L)],P=W(b,L),G=R(n.FACE_LANDMARKS_FACE_OVAL).slice(0,-1);g=Object.fromEntries(Object.entries({LEFT_EYEBROW:Z(t),RIGHT_EYEBROW:Z(i),LEFT_EYE:j,RIGHT_EYE:X,MOUTH:z,INNER_MOUTH:P,TESSELATION:U,OVAL:Z(G)}).map(([d,_])=>[d,{indices:_,vertices:new Float32Array(_.length*2)}]))}}var V=new Map;function me(n,e,t){let i=n.createShader(n.VERTEX_SHADER);n.shaderSource(i,e),n.compileShader(i);let a=n.createShader(n.FRAGMENT_SHADER);n.shaderSource(a,t),n.compileShader(a);let c=n.createProgram();return n.attachShader(c,i),n.attachShader(c,a),n.linkProgram(c),n.deleteShader(i),n.deleteShader(a),c}function Se(n){let e=n.getContext("webgl2",{antialias:!1,preserveDrawingBuffer:!0}),t=me(e,Ee,ge),i=me(e,Ee,be),a=e.createBuffer(),c=e.getAttribLocation(t,"a_pos"),A=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,A),e.bufferData(e.ARRAY_BUFFER,Le,e.STATIC_DRAW);let o=e.getAttribLocation(i,"a_pos"),l=e.getUniformLocation(t,"u_color"),E=e.getUniformLocation(i,"u_texture"),m=e.createTexture();e.bindTexture(e.TEXTURE_2D,m),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,1,1,0,e.RGBA,e.UNSIGNED_BYTE,null);let u=e.createFramebuffer();return e.bindFramebuffer(e.FRAMEBUFFER,u),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,m,0),e.bindFramebuffer(e.FRAMEBUFFER,null),e.useProgram(i),e.uniform1i(E,0),e.colorMask(!0,!0,!0,!1),{canvas:n,gl:e,regionProgram:t,blitProgram:i,regionPositionBuffer:a,quadBuffer:A,regionPositionLocation:c,blitPositionLocation:o,colorLocation:l,textureLocation:E,scratchTexture:m,scratchFramebuffer:u}}function Be(n,e,t){let{gl:i,canvas:a,scratchTexture:c}=n;a.width===e&&a.height===t||(a.width=e,a.height=t,i.bindTexture(i.TEXTURE_2D,c),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,e,t,0,i.RGBA,i.UNSIGNED_BYTE,null))}function C(n,e,t,i,a,c,A){let{gl:o,regionProgram:l,regionPositionBuffer:E,regionPositionLocation:m,colorLocation:u,scratchFramebuffer:I}=n,b=O+i*p,{indices:L,vertices:h}=t;o.bindFramebuffer(o.FRAMEBUFFER,I),o.viewport(0,0,n.canvas.width,n.canvas.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),o.useProgram(l),o.bindBuffer(o.ARRAY_BUFFER,E),o.enableVertexAttribArray(m),o.vertexAttribPointer(m,2,o.FLOAT,!1,0,0),o.enable(o.BLEND),o.blendEquation(o.MAX),o.blendFunc(o.ONE,o.ONE);for(let r=0;r<L.length;++r){let F=(b+L[r])*4;h[r*2]=e[F],h[r*2+1]=e[F+1]}o.bufferData(o.ARRAY_BUFFER,h,o.DYNAMIC_DRAW),o.uniform4f(u,a,c,A,1),o.drawArrays(o.TRIANGLES,0,L.length)}function k(n){let{gl:e,blitProgram:t,quadBuffer:i,blitPositionLocation:a,scratchTexture:c}=n;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,n.canvas.width,n.canvas.height),e.useProgram(t),e.bindBuffer(e.ARRAY_BUFFER,i),e.enableVertexAttribArray(a),e.vertexAttribPointer(a,2,e.FLOAT,!1,0,0),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,c),e.enable(e.BLEND),e.blendEquation(e.FUNC_ADD),e.blendFunc(e.ONE,e.ONE),e.drawArrays(e.TRIANGLES,0,6)}function ve(n,e){let t=n.landmarks.data,i=e.length;t[0]=i;for(let a=0;a<i;++a){let c=e[a];for(let l=0;l<K;++l){let E=c[l],m=(O+a*p+l)*4;t[m]=E.x,t[m+1]=1-E.y,t[m+2]=E.z??0,t[m+3]=E.visibility??1}let A=Q(t,a,he,p,O);t.set(A,(O+a*p+Ae)*4);let o=Q(t,a,ee,p,1);t.set(o,(O+a*p+ne)*4)}n.state.nFaces=i}function ye(n,e,t){let{mask:i,maxFaces:a,landmarks:c,state:{nFaces:A}}=n,{gl:o,canvas:l}=i,{data:E}=c;if(Be(i,e,t),o.bindFramebuffer(o.FRAMEBUFFER,null),o.viewport(0,0,l.width,l.height),o.clearColor(0,0,0,0),o.clear(o.COLOR_BUFFER_BIT),!g)return;let m=a<=te;for(let u=0;u<A;++u){let I=m&&u<H.length?ke[H[u]]:0,b=m?u<H.length?0:Oe[re[u-H.length]]:(u+1)/w;C(i,E,g.TESSELATION,u,0,I,b),k(i),C(i,E,g.OVAL,u,y.OVAL,0,0),k(i),C(i,E,g.LEFT_EYEBROW,u,y.LEFT_EYEBROW,0,0),k(i),C(i,E,g.RIGHT_EYEBROW,u,y.RIGHT_EYEBROW,0,0),k(i),C(i,E,g.LEFT_EYE,u,y.LEFT_EYE,0,0),k(i),C(i,E,g.RIGHT_EYE,u,y.RIGHT_EYE,0,0),k(i),C(i,E,g.MOUTH,u,y.MOUTH,0,0),k(i),C(i,E,g.INNER_MOUTH,u,y.INNER_MOUTH,0,0),k(i)}}function Ue(n){let{textureName:e,options:{history:t,...i}={}}=n,a={...Ie,...i},c=ue({...a,textureName:e}),A=a.maxFaces*p+O,o=Math.ceil(A/v);return function(l,E){let{injectGLSL:m,emitHook:u,updateTexturesInternal:I}=E,b=V.get(c),L=b?.landmarks.data??new Float32Array(v*o*4),h=b?.mask.canvas??new OffscreenCanvas(1,1),r=null,F=!1,D=!1;function U(s){if(!r)return;let f=r.state.nFaces,T=f*p+O,B=Math.ceil(T/v),M=s;typeof M>"u"&&G.length>0&&(M=G,G=[]),I({u_faceLandmarksTex:{data:r.landmarks.data,width:v,height:B,isPartial:!0},u_faceMask:r.mask.canvas},t?{skipHistoryWrite:D,historyWriteIndex:M}:void 0),l.updateUniforms({u_nFaces:f}),u("face:result",r.state.result)}async function j(){if(V.has(c))r=V.get(c);else{let[s,{FaceLandmarker:f}]=await Promise.all([le(),import("@mediapipe/tasks-vision")]);if(F)return;let T=await f.createFromOptions(s,{baseOptions:{modelAssetPath:a.modelPath,delegate:"GPU"},runningMode:"VIDEO",numFaces:a.maxFaces,minFaceDetectionConfidence:a.minFaceDetectionConfidence,minFacePresenceConfidence:a.minFacePresenceConfidence,minTrackingConfidence:a.minTrackingConfidence,outputFaceBlendshapes:a.outputFaceBlendshapes,outputFacialTransformationMatrixes:a.outputFacialTransformationMatrixes});if(F){T.close();return}r={landmarker:T,mask:Se(h),subscribers:new Map,maxFaces:a.maxFaces,state:{nCalls:0,runningMode:"VIDEO",source:null,videoTime:-1,resultTimestamp:0,result:null,pending:Promise.resolve(),nFaces:0},landmarks:{data:L,textureHeight:o}},De(f),V.set(c,r)}r.subscribers.set(U,!1)}let X=j();async function z(s){let f=performance.now();if(await X,!r)return;let T=++r.state.nCalls;r.state.pending=r.state.pending.then(async()=>{if(!r||T!==r.state.nCalls)return;let B=s instanceof HTMLVideoElement?"VIDEO":"IMAGE";r.state.runningMode!==B&&(r.state.runningMode=B,await r.landmarker.setOptions({runningMode:B}));let M=!1;if(s!==r.state.source?(r.state.source=s,r.state.videoTime=-1,M=!0):s instanceof HTMLVideoElement?s.currentTime!==r.state.videoTime&&(r.state.videoTime=s.currentTime,M=!0):s instanceof HTMLImageElement||f-r.state.resultTimestamp>2&&(M=!0),M){let N,Y,q;if(s instanceof HTMLVideoElement){if(s.videoWidth===0||s.videoHeight===0||s.readyState<2)return;Y=s.videoWidth,q=s.videoHeight,N=r.landmarker.detectForVideo(s,f)}else{if(s.width===0||s.height===0)return;Y=s.width,q=s.height,N=r.landmarker.detect(s)}if(N){r.state.resultTimestamp=f,r.state.result=N,ve(r,N.faceLandmarks),ye(r,Y,q);for(let ce of r.subscribers.keys())ce(),r.subscribers.set(ce,!0)}}else if(r.state.result)for(let[N,Y]of r.subscribers.entries())Y||(N(),r.subscribers.set(N,!0))}),await r.state.pending}l.on("_init",()=>{l.initializeUniform("u_maxFaces","int",a.maxFaces),l.initializeUniform("u_nFaces","int",0),l.initializeTexture("u_faceLandmarksTex",{data:L,width:v,height:o},{internalFormat:"RGBA32F",type:"FLOAT",minFilter:"NEAREST",magFilter:"NEAREST",history:t}),l.initializeTexture("u_faceMask",h,{minFilter:"NEAREST",magFilter:"NEAREST",history:t}),X.then(()=>{F||!r||u("face:ready")})});let P=0,G=[],d=()=>{t&&(U(P),G.push(P),P=(P+1)%(t+1))};l.on("initializeTexture",(s,f)=>{s===e&&J(f)&&(d(),z(f))}),l.on("updateTextures",(s,f)=>{let T=s[e];J(T)&&(D=f?.skipHistoryWrite??!1,D||d(),z(T))}),l.on("destroy",()=>{F=!0,r&&(r.subscribers.delete(U),r.subscribers.size===0&&(r.landmarker.close(),r.mask.gl.deleteProgram(r.mask.regionProgram),r.mask.gl.deleteProgram(r.mask.blitProgram),r.mask.gl.deleteBuffer(r.mask.regionPositionBuffer),r.mask.gl.deleteBuffer(r.mask.quadBuffer),r.mask.gl.deleteTexture(r.mask.scratchTexture),r.mask.gl.deleteFramebuffer(r.mask.scratchFramebuffer),V.delete(c))),r=null});let{fn:_,historyParams:S}=fe(t),$=t?"_sampleFaceMask(pos, framesAgo)":"texture(u_faceMask, pos)",Fe=Array.from({length:te-1},(s,f)=>`step(${2**(f+1)}.0, faceBitF)`).join(" + "),oe=a.maxFaces<=te?`uint faceBits = (uint(mask.b * ${w}.0 + 0.5) << 8) | uint(mask.g * ${w}.0 + 0.5);
17
17
  uint faceBit = faceBits & (~faceBits + 1u);
18
18
  float faceBitF = float(faceBit);
19
19
  float hasFace = sign(faceBitF);
20
- float faceIndex = ${Re} - (1.0 - hasFace);`:`float faceIndex = float(int(uint(mask.b * ${v}.0 + 0.5)) - 1);`,R=(s,...E)=>B("vec2",`${s}At`,"vec2 pos",`vec4 mask = ${ne};
21
- ${ae}
22
- uint bits = uint(mask.r * ${v}.0 + 0.5);
23
- float hit = sign(float(bits & ${E.reduce((d,N)=>d|Te[N],0)}u));
24
- return vec2(hit, mix(-1.0, faceIndex, hit));`),re=(s,E,d)=>B("vec2",`${s}At`,"vec2 pos",`vec2 left = ${E}(pos${W});
25
- vec2 right = ${d}(pos${W});
26
- return mix(right, left, left.x);`),Ae=s=>s.map(E=>B("float",`in${E[0].toUpperCase()+E.slice(1)}`,"vec2 pos",`vec2 a = ${E}At(pos${W}); return step(0.0, a.y) * a.x;`)).join(`
20
+ float faceIndex = ${Fe} - (1.0 - hasFace);`:`float faceIndex = float(int(uint(mask.b * ${w}.0 + 0.5)) - 1);`,x=(s,...f)=>_("vec2",`${s}At`,"vec2 pos",`vec4 mask = ${$};
21
+ ${oe}
22
+ uint bits = uint(mask.r * ${w}.0 + 0.5);
23
+ float hit = sign(float(bits & ${f.reduce((T,B)=>T|Te[B],0)}u));
24
+ return vec2(hit, mix(-1.0, faceIndex, hit));`),se=(s,f,T)=>_("vec2",`${s}At`,"vec2 pos",`vec2 left = ${f}(pos${S});
25
+ vec2 right = ${T}(pos${S});
26
+ return mix(right, left, left.x);`),Re=s=>s.map(f=>_("float",`in${f[0].toUpperCase()+f.slice(1)}`,"vec2 pos",`vec2 a = ${f}At(pos${S}); return step(0.0, a.y) * a.x;`)).join(`
27
27
  `);m(`
28
28
  uniform int u_maxFaces;
29
29
  uniform int u_nFaces;
30
- uniform highp sampler2D${n?"Array":""} u_faceLandmarksTex;${n?`
30
+ uniform highp sampler2D${t?"Array":""} u_faceLandmarksTex;${t?`
31
31
  uniform int u_faceLandmarksTexFrameOffset;`:""}
32
- uniform mediump sampler2D${n?"Array":""} u_faceMask;${n?`
32
+ uniform mediump sampler2D${t?"Array":""} u_faceMask;${t?`
33
33
  uniform int u_faceMaskFrameOffset;`:""}
34
34
 
35
- #define FACE_LANDMARK_L_EYE_CENTER ${I.LEFT_EYE_CENTER}
36
- #define FACE_LANDMARK_R_EYE_CENTER ${I.RIGHT_EYE_CENTER}
37
- #define FACE_LANDMARK_NOSE_TIP ${I.NOSE_TIP}
38
- #define FACE_LANDMARK_FACE_CENTER ${I.FACE_CENTER}
39
- #define FACE_LANDMARK_MOUTH_CENTER ${I.MOUTH_CENTER}
35
+ #define FACE_LANDMARK_L_EYE_CENTER ${de}
36
+ #define FACE_LANDMARK_R_EYE_CENTER ${_e}
37
+ #define FACE_LANDMARK_NOSE_TIP ${xe}
38
+ #define FACE_LANDMARK_FACE_CENTER ${Ae}
39
+ #define FACE_LANDMARK_MOUTH_CENTER ${ne}
40
40
 
41
- ${B("int","nFacesAt","",n?`
42
- int layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${n+1}) % ${n+1};
41
+ ${_("int","nFacesAt","",t?`
42
+ int layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${t+1}) % ${t+1};
43
43
  return int(texelFetch(u_faceLandmarksTex, ivec3(0, 0, layer), 0).r + 0.5);`:`
44
44
  return int(texelFetch(u_faceLandmarksTex, ivec2(0, 0), 0).r + 0.5);`)}
45
- ${B("vec4","faceLandmark","int faceIndex, int landmarkIndex",`int i = ${p} + faceIndex * ${F} + landmarkIndex;
46
- int x = i % ${x};
47
- int y = i / ${x};${n?`
48
- int layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${n+1}) % ${n+1};
45
+ ${_("vec4","faceLandmark","int faceIndex, int landmarkIndex",`int i = ${O} + faceIndex * ${p} + landmarkIndex;
46
+ int x = i % ${v};
47
+ int y = i / ${v};${t?`
48
+ int layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${t+1}) % ${t+1};
49
49
  return texelFetch(u_faceLandmarksTex, ivec3(x, y, layer), 0);`:`
50
50
  return texelFetch(u_faceLandmarksTex, ivec2(x, y), 0);`}`)}
51
- ${n?`
51
+ ${t?`
52
52
  vec4 _sampleFaceMask(vec2 pos, int framesAgo) {
53
- int layer = (u_faceMaskFrameOffset - framesAgo + ${n+1}) % ${n+1};
53
+ int layer = (u_faceMaskFrameOffset - framesAgo + ${t+1}) % ${t+1};
54
54
  return texture(u_faceMask, vec3(pos, float(layer)));
55
55
  }
56
56
  `:""}
57
- ${R("leftEyebrow","LEFT_EYEBROW")}
58
- ${R("rightEyebrow","RIGHT_EYEBROW")}
59
- ${R("leftEye","LEFT_EYE")}
60
- ${R("rightEye","RIGHT_EYE")}
61
- ${R("lips","MOUTH")}
62
- ${R("mouth","MOUTH","INNER_MOUTH")}
63
- ${R("innerMouth","INNER_MOUTH")}
64
- ${R("faceOval","OVAL")}
65
- ${B("vec2","faceAt","vec2 pos",`vec4 mask = ${ne};
66
- ${ae}
57
+ ${x("leftEyebrow","LEFT_EYEBROW")}
58
+ ${x("rightEyebrow","RIGHT_EYEBROW")}
59
+ ${x("leftEye","LEFT_EYE")}
60
+ ${x("rightEye","RIGHT_EYE")}
61
+ ${x("lips","MOUTH")}
62
+ ${x("mouth","MOUTH","INNER_MOUTH")}
63
+ ${x("innerMouth","INNER_MOUTH")}
64
+ ${x("faceOval","OVAL")}
65
+ ${_("vec2","faceAt","vec2 pos",`vec4 mask = ${$};
66
+ ${oe}
67
67
  return vec2(step(0.0, faceIndex), faceIndex);`)}
68
- ${re("eye","leftEyeAt","rightEyeAt")}
69
- ${re("eyebrow","leftEyebrowAt","rightEyebrowAt")}
70
- ${Ae(["eyebrow","eye","mouth","innerMouth","lips","face"])}`)}}var He=Ue;export{He as default};
68
+ ${se("eye","leftEyeAt","rightEyeAt")}
69
+ ${se("eyebrow","leftEyebrowAt","rightEyebrowAt")}
70
+ ${Re(["eyebrow","eye","mouth","innerMouth","lips","face"])}`)}}var $e=Ue;export{$e as default};
71
71
  //# sourceMappingURL=face.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/plugins/face.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '..';\nimport {\n\tcalculateBoundingBoxCenter,\n\tgenerateGLSLFn,\n\tgetSharedFileset,\n\thashOptions,\n\tisMediaPipeSource,\n\tMediaPipeSource,\n} from './mediapipe-common';\nimport type { FaceLandmarker, FaceLandmarkerResult, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface FacePluginOptions {\n\tmodelPath?: string;\n\tmaxFaces?: number;\n\tminFaceDetectionConfidence?: number;\n\tminFacePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputFaceBlendshapes?: boolean;\n\toutputFacialTransformationMatrixes?: boolean;\n\thistory?: number;\n}\n\nconst MASK_VERTEX_SHADER = `#version 300 es\nin vec2 a_pos;\nout vec2 v_uv;\nvoid main() {\n\tv_uv = a_pos;\n\tgl_Position = vec4(a_pos * 2.0 - 1.0, 0.0, 1.0);\n}`;\nconst MASK_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nuniform vec4 u_color;\nout vec4 outColor;\nvoid main() { outColor = u_color; }`;\nconst BLIT_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nuniform sampler2D u_texture;\nout vec4 outColor;\nvoid main() { outColor = texture(u_texture, v_uv); }`;\nconst FULLSCREEN_TRIANGLES = new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]);\n\nconst STANDARD_LANDMARK_COUNT = 478;\nconst CUSTOM_LANDMARK_COUNT = 2;\nconst LANDMARK_COUNT = STANDARD_LANDMARK_COUNT + CUSTOM_LANDMARK_COUNT;\nconst LANDMARKS_TEXTURE_WIDTH = 512;\nconst N_LANDMARK_METADATA_SLOTS = 1;\n\nconst LEFT_EYEBROW_INDICES = [336, 296, 334, 293, 300, 276, 283, 282, 295, 285] as const;\nconst LEFT_EYE_INDICES = [362, 398, 384, 385, 386, 387, 388, 466, 263, 249, 390, 373, 374, 380, 381, 382] as const;\nconst RIGHT_EYEBROW_INDICES = [70, 63, 105, 66, 107, 55, 65, 52, 53, 46] as const;\nconst RIGHT_EYE_INDICES = [33, 246, 161, 160, 159, 158, 157, 173, 133, 155, 154, 153, 145, 144, 163, 7] as const;\nconst MOUTH_INDICES = [\n\t61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291, 375, 321, 405, 314, 17, 84, 181, 91, 146,\n] as const;\nconst INNER_MOUTH_INDICES = [\n\t78, 191, 80, 81, 82, 13, 312, 311, 310, 415, 308, 324, 318, 402, 317, 14, 87, 178, 88, 95,\n] as const;\nconst ALL_STANDARD_INDICES = Array.from({ length: STANDARD_LANDMARK_COUNT }, (_, i) => i);\nconst LANDMARK_INDICES = {\n\tLEFT_EYEBROW: LEFT_EYEBROW_INDICES,\n\tLEFT_EYE: LEFT_EYE_INDICES,\n\tLEFT_EYE_CENTER: 473,\n\tRIGHT_EYEBROW: RIGHT_EYEBROW_INDICES,\n\tRIGHT_EYE: RIGHT_EYE_INDICES,\n\tRIGHT_EYE_CENTER: 468,\n\tNOSE_TIP: 4,\n\tMOUTH: MOUTH_INDICES,\n\tINNER_MOUTH: INNER_MOUTH_INDICES,\n\t// Custom landmarks.\n\tFACE_CENTER: STANDARD_LANDMARK_COUNT,\n\tMOUTH_CENTER: STANDARD_LANDMARK_COUNT + 1,\n};\n\n/* Face mask channel layout:\n- R: additive bitfield for face regions. Since it’s additive, it handles overlapping regions.\n- G/B: tessellation ownership. When maxFaces is <= 16, G stores one-hot bits for\n faces 0-7 and B stores one-hot bits for faces 8-15 so overlapping faces\n remain decodable. Above 16 maxFaces, B falls back to storing faceIndex + 1 as\n an additive byte value, which will overcount on overlaps. */\nconst RED_REGION_NAMES = [\n\t'OVAL',\n\t'LEFT_EYEBROW',\n\t'RIGHT_EYEBROW',\n\t'LEFT_EYE',\n\t'RIGHT_EYE',\n\t'MOUTH',\n\t'INNER_MOUTH',\n] as const;\nconst GREEN_REGION_NAMES = ['FACE_0', 'FACE_1', 'FACE_2', 'FACE_3', 'FACE_4', 'FACE_5', 'FACE_6', 'FACE_7'] as const;\nconst BLUE_REGION_NAMES = [\n\t'FACE_8',\n\t'FACE_9',\n\t'FACE_10',\n\t'FACE_11',\n\t'FACE_12',\n\t'FACE_13',\n\t'FACE_14',\n\t'FACE_15',\n] as const;\nconst CHANNEL_BIT_SCALE = 255;\nconst GB_BITMASK_MAX_FACES = GREEN_REGION_NAMES.length + BLUE_REGION_NAMES.length;\n\nfunction createChannelBitValues<const T extends readonly string[]>(names: T): Record<T[number], number> {\n\treturn Object.fromEntries(names.map((name, i) => [name, 1 << i])) as Record<T[number], number>;\n}\n\nfunction normalizeChannelBitValues<T extends Record<string, number>>(bitValues: T): T {\n\treturn Object.fromEntries(\n\t\tObject.entries(bitValues).map(([name, bitValue]) => [name, bitValue / CHANNEL_BIT_SCALE]),\n\t) as T;\n}\n\nconst RED_REGION_BIT_VALUES = createChannelBitValues(RED_REGION_NAMES);\nconst GREEN_REGION_BIT_VALUES = createChannelBitValues(GREEN_REGION_NAMES);\nconst BLUE_REGION_BIT_VALUES = createChannelBitValues(BLUE_REGION_NAMES);\nconst RED_CHANNEL_VALUES = normalizeChannelBitValues(RED_REGION_BIT_VALUES);\nconst GREEN_CHANNEL_VALUES = normalizeChannelBitValues(GREEN_REGION_BIT_VALUES);\nconst BLUE_CHANNEL_VALUES = normalizeChannelBitValues(BLUE_REGION_BIT_VALUES);\n\nconst DEFAULT_FACE_OPTIONS: Required<Omit<FacePluginOptions, 'history'>> = {\n\tmodelPath:\n\t\t'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task',\n\tmaxFaces: 1,\n\tminFaceDetectionConfidence: 0.5,\n\tminFacePresenceConfidence: 0.5,\n\tminTrackingConfidence: 0.5,\n\toutputFaceBlendshapes: false,\n\toutputFacialTransformationMatrixes: false,\n};\n\nfunction fanTriangulate(indices: readonly number[]): number[] {\n\tconst tris: number[] = [];\n\tfor (let i = 1; i < indices.length - 1; ++i) {\n\t\ttris.push(indices[0], indices[i], indices[i + 1]);\n\t}\n\treturn tris;\n}\n\ntype FaceRegion = { indices: number[]; vertices: Float32Array };\nlet faceRegions: Record<string, FaceRegion> | null = null;\nfunction initFaceRegions(LandmarkerClass: typeof FaceLandmarker): void {\n\tif (!faceRegions) {\n\t\tconst tesselationConnections = LandmarkerClass.FACE_LANDMARKS_TESSELATION;\n\t\tconst tesselation: number[] = [];\n\t\tfor (let i = 0; i < tesselationConnections.length - 2; i += 3) {\n\t\t\ttesselation.push(\n\t\t\t\ttesselationConnections[i].start,\n\t\t\t\ttesselationConnections[i + 1].start,\n\t\t\t\ttesselationConnections[i + 2].start,\n\t\t\t);\n\t\t}\n\t\tconst ovalIndices = LandmarkerClass.FACE_LANDMARKS_FACE_OVAL.map(({ start }) => start);\n\t\tfaceRegions = Object.fromEntries(\n\t\t\tObject.entries({\n\t\t\t\tLEFT_EYEBROW: fanTriangulate(LEFT_EYEBROW_INDICES),\n\t\t\t\tRIGHT_EYEBROW: fanTriangulate(RIGHT_EYEBROW_INDICES),\n\t\t\t\tLEFT_EYE: fanTriangulate(LEFT_EYE_INDICES),\n\t\t\t\tRIGHT_EYE: fanTriangulate(RIGHT_EYE_INDICES),\n\t\t\t\tMOUTH: fanTriangulate(MOUTH_INDICES),\n\t\t\t\tINNER_MOUTH: fanTriangulate(INNER_MOUTH_INDICES),\n\t\t\t\tTESSELATION: tesselation,\n\t\t\t\tOVAL: fanTriangulate(ovalIndices),\n\t\t\t}).map(([key, indices]) => [key, { indices, vertices: new Float32Array(indices.length * 2) }]),\n\t\t);\n\t}\n}\n\ninterface MaskRenderer {\n\tcanvas: OffscreenCanvas;\n\tgl: WebGL2RenderingContext;\n\tregionProgram: WebGLProgram;\n\tblitProgram: WebGLProgram;\n\tregionPositionBuffer: WebGLBuffer;\n\tquadBuffer: WebGLBuffer;\n\tregionPositionLocation: number;\n\tblitPositionLocation: number;\n\tcolorLocation: WebGLUniformLocation;\n\ttextureLocation: WebGLUniformLocation;\n\tscratchTexture: WebGLTexture;\n\tscratchFramebuffer: WebGLFramebuffer;\n}\n\ninterface Detector {\n\tlandmarker: FaceLandmarker;\n\tmask: MaskRenderer;\n\tsubscribers: Map<Function, boolean>;\n\tmaxFaces: number;\n\tstate: {\n\t\tnCalls: number;\n\t\trunningMode: 'IMAGE' | 'VIDEO';\n\t\tsource: MediaPipeSource | null;\n\t\tvideoTime: number;\n\t\tresultTimestamp: number;\n\t\tresult: FaceLandmarkerResult | null;\n\t\tpending: Promise<void>;\n\t\tnFaces: number;\n\t};\n\tlandmarks: {\n\t\tdata: Float32Array;\n\t\ttextureHeight: number;\n\t};\n}\nconst sharedDetectors = new Map<string, Detector>();\n\nfunction createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n\tconst vertexShader = gl.createShader(gl.VERTEX_SHADER)!;\n\tgl.shaderSource(vertexShader, vertexSource);\n\tgl.compileShader(vertexShader);\n\n\tconst fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;\n\tgl.shaderSource(fragmentShader, fragmentSource);\n\tgl.compileShader(fragmentShader);\n\n\tconst program = gl.createProgram()!;\n\tgl.attachShader(program, vertexShader);\n\tgl.attachShader(program, fragmentShader);\n\tgl.linkProgram(program);\n\tgl.deleteShader(vertexShader);\n\tgl.deleteShader(fragmentShader);\n\treturn program;\n}\n\nfunction initMaskRenderer(canvas: OffscreenCanvas): MaskRenderer {\n\tconst gl = canvas.getContext('webgl2', {\n\t\tantialias: false,\n\t\tpreserveDrawingBuffer: true,\n\t})!;\n\tconst regionProgram = createProgram(gl, MASK_VERTEX_SHADER, MASK_FRAGMENT_SHADER);\n\tconst blitProgram = createProgram(gl, MASK_VERTEX_SHADER, BLIT_FRAGMENT_SHADER);\n\n\tconst regionPositionBuffer = gl.createBuffer()!;\n\tconst regionPositionLocation = gl.getAttribLocation(regionProgram, 'a_pos');\n\n\tconst quadBuffer = gl.createBuffer()!;\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_TRIANGLES, gl.STATIC_DRAW);\n\tconst blitPositionLocation = gl.getAttribLocation(blitProgram, 'a_pos');\n\n\tconst colorLocation = gl.getUniformLocation(regionProgram, 'u_color')!;\n\tconst textureLocation = gl.getUniformLocation(blitProgram, 'u_texture')!;\n\n\tconst scratchTexture = gl.createTexture()!;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n\n\tconst scratchFramebuffer = gl.createFramebuffer()!;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, scratchTexture, 0);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n\tgl.useProgram(blitProgram);\n\tgl.uniform1i(textureLocation, 0);\n\tgl.colorMask(true, true, true, false);\n\n\treturn {\n\t\tcanvas,\n\t\tgl,\n\t\tregionProgram,\n\t\tblitProgram,\n\t\tregionPositionBuffer,\n\t\tquadBuffer,\n\t\tregionPositionLocation,\n\t\tblitPositionLocation,\n\t\tcolorLocation,\n\t\ttextureLocation,\n\t\tscratchTexture,\n\t\tscratchFramebuffer,\n\t};\n}\n\nfunction resizeMaskRenderer(mask: MaskRenderer, width: number, height: number) {\n\tconst { gl, canvas, scratchTexture } = mask;\n\tif (canvas.width === width && canvas.height === height) return;\n\tcanvas.width = width;\n\tcanvas.height = height;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n}\n\nfunction drawRegionToScratch(\n\tmask: MaskRenderer,\n\tlandmarksData: Float32Array,\n\tfaceRegion: FaceRegion,\n\tfaceIdx: number,\n\tr: number,\n\tg: number,\n\tb: number,\n) {\n\tconst { gl, regionProgram, regionPositionBuffer, regionPositionLocation, colorLocation, scratchFramebuffer } = mask;\n\tconst baseIdx = N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT;\n\tconst { indices, vertices } = faceRegion;\n\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\tgl.useProgram(regionProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, regionPositionBuffer);\n\tgl.enableVertexAttribArray(regionPositionLocation);\n\tgl.vertexAttribPointer(regionPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.MAX);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\n\tfor (let i = 0; i < indices.length; ++i) {\n\t\tconst landmarkIdx = (baseIdx + indices[i]) * 4;\n\t\tvertices[i * 2] = landmarksData[landmarkIdx];\n\t\tvertices[i * 2 + 1] = landmarksData[landmarkIdx + 1];\n\t}\n\tgl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);\n\tgl.uniform4f(colorLocation, r, g, b, 1.0);\n\tgl.drawArrays(gl.TRIANGLES, 0, indices.length);\n}\n\nfunction accumulateScratch(mask: MaskRenderer) {\n\tconst { gl, blitProgram, quadBuffer, blitPositionLocation, scratchTexture } = mask;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.useProgram(blitProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.enableVertexAttribArray(blitPositionLocation);\n\tgl.vertexAttribPointer(blitPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.activeTexture(gl.TEXTURE0);\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.FUNC_ADD);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n}\n\nfunction updateLandmarksData(detector: Detector, faces: NormalizedLandmark[][]) {\n\tconst data = detector.landmarks.data;\n\tconst nFaces = faces.length;\n\tdata[0] = nFaces;\n\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst landmarks = faces[faceIdx];\n\t\tfor (let landmarkIdx = 0; landmarkIdx < STANDARD_LANDMARK_COUNT; ++landmarkIdx) {\n\t\t\tconst landmark = landmarks[landmarkIdx];\n\t\t\tconst dataIdx = (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + landmarkIdx) * 4;\n\t\t\tdata[dataIdx] = landmark.x;\n\t\t\tdata[dataIdx + 1] = 1 - landmark.y;\n\t\t\tdata[dataIdx + 2] = landmark.z ?? 0;\n\t\t\tdata[dataIdx + 3] = landmark.visibility ?? 1;\n\t\t}\n\n\t\tconst faceCenter = calculateBoundingBoxCenter(\n\t\t\tdata,\n\t\t\tfaceIdx,\n\t\t\tALL_STANDARD_INDICES,\n\t\t\tLANDMARK_COUNT,\n\t\t\tN_LANDMARK_METADATA_SLOTS,\n\t\t);\n\t\tdata.set(faceCenter, (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + LANDMARK_INDICES.FACE_CENTER) * 4);\n\n\t\tconst mouthCenter = calculateBoundingBoxCenter(data, faceIdx, INNER_MOUTH_INDICES, LANDMARK_COUNT, 1);\n\t\tdata.set(\n\t\t\tmouthCenter,\n\t\t\t(N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + LANDMARK_INDICES.MOUTH_CENTER) * 4,\n\t\t);\n\t}\n\n\tdetector.state.nFaces = nFaces;\n}\n\nfunction updateMask(detector: Detector, width: number, height: number) {\n\tconst {\n\t\tmask,\n\t\tmaxFaces,\n\t\tlandmarks,\n\t\tstate: { nFaces },\n\t} = detector;\n\tconst { gl, canvas: maskCanvas } = mask;\n\tconst { data: landmarksData } = landmarks;\n\n\tresizeMaskRenderer(mask, width, height);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, maskCanvas.width, maskCanvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\tif (!faceRegions) return;\n\n\tconst useTesselationBitmask = maxFaces <= GB_BITMASK_MAX_FACES;\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst g =\n\t\t\tuseTesselationBitmask && faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? GREEN_CHANNEL_VALUES[GREEN_REGION_NAMES[faceIdx]]\n\t\t\t\t: 0;\n\t\tconst b = useTesselationBitmask\n\t\t\t? faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? 0\n\t\t\t\t: BLUE_CHANNEL_VALUES[BLUE_REGION_NAMES[faceIdx - GREEN_REGION_NAMES.length]]\n\t\t\t: (faceIdx + 1) / CHANNEL_BIT_SCALE;\n\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.TESSELATION, faceIdx, 0, g, b);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.OVAL, faceIdx, RED_CHANNEL_VALUES.OVAL, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.LEFT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.LEFT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.RIGHT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.RIGHT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.LEFT_EYE, faceIdx, RED_CHANNEL_VALUES.LEFT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.RIGHT_EYE, faceIdx, RED_CHANNEL_VALUES.RIGHT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.MOUTH, faceIdx, RED_CHANNEL_VALUES.MOUTH, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.INNER_MOUTH,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.INNER_MOUTH,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t}\n}\n\nfunction face(config: { textureName: string; options?: FacePluginOptions }) {\n\tconst { textureName, options: { history, ...mediapipeOptions } = {} } = config;\n\tconst options = { ...DEFAULT_FACE_OPTIONS, ...mediapipeOptions };\n\tconst optionsKey = hashOptions({ ...options, textureName });\n\n\tconst nLandmarksMax = options.maxFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\tconst textureHeight = Math.ceil(nLandmarksMax / LANDMARKS_TEXTURE_WIDTH);\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, emitHook, updateTexturesInternal } = context;\n\n\t\tconst existingDetector = sharedDetectors.get(optionsKey);\n\t\tconst landmarksData =\n\t\t\texistingDetector?.landmarks.data ?? new Float32Array(LANDMARKS_TEXTURE_WIDTH * textureHeight * 4);\n\t\tconst maskCanvas = existingDetector?.mask.canvas ?? new OffscreenCanvas(1, 1);\n\t\tlet detector: Detector | null = null;\n\t\tlet destroyed = false;\n\t\tlet skipHistoryWrite = false;\n\n\t\tfunction onResult(singleHistoryWriteIndex?: number) {\n\t\t\tif (!detector) return;\n\t\t\tconst nFaces = detector.state.nFaces;\n\t\t\tconst nSlots = nFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\t\t\tconst rowsToUpdate = Math.ceil(nSlots / LANDMARKS_TEXTURE_WIDTH);\n\t\t\tlet historyWriteIndex: number | number[] | undefined = singleHistoryWriteIndex;\n\t\t\tif (typeof historyWriteIndex === 'undefined' && pendingBackfillSlots.length > 0) {\n\t\t\t\thistoryWriteIndex = pendingBackfillSlots;\n\t\t\t\tpendingBackfillSlots = [];\n\t\t\t}\n\t\t\tupdateTexturesInternal(\n\t\t\t\t{\n\t\t\t\t\tu_faceLandmarksTex: {\n\t\t\t\t\t\tdata: detector.landmarks.data,\n\t\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\t\theight: rowsToUpdate,\n\t\t\t\t\t\tisPartial: true,\n\t\t\t\t\t},\n\t\t\t\t\tu_faceMask: detector.mask.canvas,\n\t\t\t\t},\n\t\t\t\thistory ? { skipHistoryWrite, historyWriteIndex } : undefined,\n\t\t\t);\n\t\t\tshaderPad.updateUniforms({ u_nFaces: nFaces });\n\t\t\temitHook('face:result', detector.state.result);\n\t\t}\n\n\t\tasync function initializeDetector() {\n\t\t\tif (sharedDetectors.has(optionsKey)) {\n\t\t\t\tdetector = sharedDetectors.get(optionsKey)!;\n\t\t\t} else {\n\t\t\t\tconst [mediaPipe, { FaceLandmarker }] = await Promise.all([\n\t\t\t\t\tgetSharedFileset(),\n\t\t\t\t\timport('@mediapipe/tasks-vision'),\n\t\t\t\t]);\n\t\t\t\tif (destroyed) return;\n\n\t\t\t\tconst faceLandmarker = await FaceLandmarker.createFromOptions(mediaPipe, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options.modelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumFaces: options.maxFaces,\n\t\t\t\t\tminFaceDetectionConfidence: options.minFaceDetectionConfidence,\n\t\t\t\t\tminFacePresenceConfidence: options.minFacePresenceConfidence,\n\t\t\t\t\tminTrackingConfidence: options.minTrackingConfidence,\n\t\t\t\t\toutputFaceBlendshapes: options.outputFaceBlendshapes,\n\t\t\t\t\toutputFacialTransformationMatrixes: options.outputFacialTransformationMatrixes,\n\t\t\t\t});\n\t\t\t\tif (destroyed) {\n\t\t\t\t\tfaceLandmarker.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdetector = {\n\t\t\t\t\tlandmarker: faceLandmarker,\n\t\t\t\t\tmask: initMaskRenderer(maskCanvas),\n\t\t\t\t\tsubscribers: new Map(),\n\t\t\t\t\tmaxFaces: options.maxFaces,\n\t\t\t\t\tstate: {\n\t\t\t\t\t\tnCalls: 0,\n\t\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\t\tsource: null,\n\t\t\t\t\t\tvideoTime: -1,\n\t\t\t\t\t\tresultTimestamp: 0,\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\tpending: Promise.resolve(),\n\t\t\t\t\t\tnFaces: 0,\n\t\t\t\t\t},\n\t\t\t\t\tlandmarks: {\n\t\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\t\ttextureHeight,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tinitFaceRegions(FaceLandmarker);\n\t\t\t\tsharedDetectors.set(optionsKey, detector);\n\t\t\t}\n\n\t\t\tdetector.subscribers.set(onResult, false);\n\t\t}\n\t\tconst initPromise = initializeDetector();\n\n\t\tasync function detectFaces(source: MediaPipeSource) {\n\t\t\tconst now = performance.now();\n\t\t\tawait initPromise;\n\t\t\tif (!detector) return;\n\t\t\tconst callOrder = ++detector.state.nCalls;\n\n\t\t\tdetector.state.pending = detector.state.pending.then(async () => {\n\t\t\t\tif (!detector || callOrder !== detector.state.nCalls) return;\n\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (detector.state.runningMode !== requiredMode) {\n\t\t\t\t\tdetector.state.runningMode = requiredMode;\n\t\t\t\t\tawait detector.landmarker.setOptions({\n\t\t\t\t\t\trunningMode: requiredMode,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tlet shouldDetect = false;\n\n\t\t\t\tif (source !== detector.state.source) {\n\t\t\t\t\tdetector.state.source = source;\n\t\t\t\t\tdetector.state.videoTime = -1;\n\t\t\t\t\tshouldDetect = true;\n\t\t\t\t} else if (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.currentTime !== detector.state.videoTime) {\n\t\t\t\t\t\tdetector.state.videoTime = source.currentTime;\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (!(source instanceof HTMLImageElement)) {\n\t\t\t\t\tif (now - detector.state.resultTimestamp > 2) {\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shouldDetect) {\n\t\t\t\t\tlet result: FaceLandmarkerResult | undefined;\n\t\t\t\t\tlet width: number, height: number;\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) return;\n\t\t\t\t\t\twidth = source.videoWidth;\n\t\t\t\t\t\theight = source.videoHeight;\n\t\t\t\t\t\tresult = detector.landmarker.detectForVideo(source, now);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (source.width === 0 || source.height === 0) return;\n\t\t\t\t\t\twidth = source.width;\n\t\t\t\t\t\theight = source.height;\n\t\t\t\t\t\tresult = detector.landmarker.detect(source);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tdetector.state.resultTimestamp = now;\n\t\t\t\t\t\tdetector.state.result = result;\n\t\t\t\t\t\tupdateLandmarksData(detector, result.faceLandmarks);\n\t\t\t\t\t\tupdateMask(detector, width, height);\n\t\t\t\t\t\tfor (const cb of detector.subscribers.keys()) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (detector.state.result) {\n\t\t\t\t\tfor (const [cb, hasCalled] of detector.subscribers.entries()) {\n\t\t\t\t\t\tif (!hasCalled) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait detector.state.pending;\n\t\t}\n\n\t\tshaderPad.on('_init', () => {\n\t\t\tshaderPad.initializeUniform('u_maxFaces', 'int', options.maxFaces);\n\t\t\tshaderPad.initializeUniform('u_nFaces', 'int', 0);\n\t\t\tshaderPad.initializeTexture(\n\t\t\t\t'u_faceLandmarksTex',\n\t\t\t\t{\n\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\theight: textureHeight,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinternalFormat: 'RGBA32F',\n\t\t\t\t\ttype: 'FLOAT',\n\t\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\t\thistory,\n\t\t\t\t},\n\t\t\t);\n\t\t\tshaderPad.initializeTexture('u_faceMask', maskCanvas, {\n\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\thistory,\n\t\t\t});\n\t\t\tinitPromise.then(() => {\n\t\t\t\tif (destroyed || !detector) return;\n\t\t\t\temitHook('face:ready');\n\t\t\t});\n\t\t});\n\n\t\tlet historyWriteCounter = 0;\n\t\tlet pendingBackfillSlots: number[] = [];\n\t\tconst writeToHistory = () => {\n\t\t\tif (!history) return;\n\t\t\tonResult(historyWriteCounter); // Write stale data immediately.\n\t\t\tpendingBackfillSlots.push(historyWriteCounter); // Queue up backfill with more recent data.\n\t\t\thistoryWriteCounter = (historyWriteCounter + 1) % (history + 1);\n\t\t};\n\n\t\tshaderPad.on('initializeTexture', (name: string, source: TextureSource) => {\n\t\t\tif (name === textureName && isMediaPipeSource(source)) {\n\t\t\t\twriteToHistory();\n\t\t\t\tdetectFaces(source);\n\t\t\t}\n\t\t});\n\n\t\tshaderPad.on(\n\t\t\t'updateTextures',\n\t\t\t(updates: Record<string, TextureSource>, options?: { skipHistoryWrite?: boolean }) => {\n\t\t\t\tconst source = updates[textureName];\n\t\t\t\tif (isMediaPipeSource(source)) {\n\t\t\t\t\tskipHistoryWrite = options?.skipHistoryWrite ?? false;\n\t\t\t\t\tif (!skipHistoryWrite) writeToHistory();\n\t\t\t\t\tdetectFaces(source);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tshaderPad.on('destroy', () => {\n\t\t\tdestroyed = true;\n\t\t\tif (detector) {\n\t\t\t\tdetector.subscribers.delete(onResult);\n\t\t\t\tif (detector.subscribers.size === 0) {\n\t\t\t\t\tdetector.landmarker.close();\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.regionProgram);\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.blitProgram);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.regionPositionBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.quadBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteTexture(detector.mask.scratchTexture);\n\t\t\t\t\tdetector.mask.gl.deleteFramebuffer(detector.mask.scratchFramebuffer);\n\t\t\t\t\tsharedDetectors.delete(optionsKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdetector = null;\n\t\t});\n\n\t\tconst { fn, historyParams } = generateGLSLFn(history);\n\t\tconst sampleMask = history ? `_sampleFaceMask(pos, framesAgo)` : `texture(u_faceMask, pos)`;\n\t\tconst decodeFaceBitIndex = Array.from(\n\t\t\t{ length: GB_BITMASK_MAX_FACES - 1 },\n\t\t\t(_, i) => `step(${2 ** (i + 1)}.0, faceBitF)`,\n\t\t).join(' + ');\n\t\tconst decodeFaceIndex =\n\t\t\toptions.maxFaces <= GB_BITMASK_MAX_FACES\n\t\t\t\t? `uint faceBits = (uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5) << 8) | uint(mask.g * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tuint faceBit = faceBits & (~faceBits + 1u);\n\tfloat faceBitF = float(faceBit);\n\tfloat hasFace = sign(faceBitF);\n\tfloat faceIndex = ${decodeFaceBitIndex} - (1.0 - hasFace);`\n\t\t\t\t: `float faceIndex = float(int(uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5)) - 1);`;\n\n\t\tconst checkAt = (fnName: string, ...regionNames: (keyof typeof RED_REGION_BIT_VALUES)[]) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\tuint bits = uint(mask.r * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tfloat hit = sign(float(bits & ${regionNames.reduce(\n\t\t(mask, regionName) => mask | RED_REGION_BIT_VALUES[regionName],\n\t\t0,\n\t)}u));\n\treturn vec2(hit, mix(-1.0, faceIndex, hit));`,\n\t\t\t);\n\n\t\tconst combineLeftRight = (fnName: string, leftFn: string, rightFn: string) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec2 left = ${leftFn}(pos${historyParams});\n\tvec2 right = ${rightFn}(pos${historyParams});\n\treturn mix(right, left, left.x);`,\n\t\t\t);\n\n\t\tconst checkIn = (fnNames: string[]) =>\n\t\t\tfnNames\n\t\t\t\t.map(fnName =>\n\t\t\t\t\tfn(\n\t\t\t\t\t\t'float',\n\t\t\t\t\t\t`in${fnName[0].toUpperCase() + fnName.slice(1)}`,\n\t\t\t\t\t\t'vec2 pos',\n\t\t\t\t\t\t`vec2 a = ${fnName}At(pos${historyParams}); return step(0.0, a.y) * a.x;`,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.join('\\n');\n\n\t\tinjectGLSL(`\nuniform int u_maxFaces;\nuniform int u_nFaces;\nuniform highp sampler2D${history ? 'Array' : ''} u_faceLandmarksTex;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceLandmarksTexFrameOffset;`\n\t\t\t\t: ''\n\t\t}\nuniform mediump sampler2D${history ? 'Array' : ''} u_faceMask;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceMaskFrameOffset;`\n\t\t\t\t: ''\n\t\t}\n\n#define FACE_LANDMARK_L_EYE_CENTER ${LANDMARK_INDICES.LEFT_EYE_CENTER}\n#define FACE_LANDMARK_R_EYE_CENTER ${LANDMARK_INDICES.RIGHT_EYE_CENTER}\n#define FACE_LANDMARK_NOSE_TIP ${LANDMARK_INDICES.NOSE_TIP}\n#define FACE_LANDMARK_FACE_CENTER ${LANDMARK_INDICES.FACE_CENTER}\n#define FACE_LANDMARK_MOUTH_CENTER ${LANDMARK_INDICES.MOUTH_CENTER}\n\n${fn(\n\t'int',\n\t'nFacesAt',\n\t'',\n\thistory\n\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn int(texelFetch(u_faceLandmarksTex, ivec3(0, 0, layer), 0).r + 0.5);`\n\t\t: `\n\treturn int(texelFetch(u_faceLandmarksTex, ivec2(0, 0), 0).r + 0.5);`,\n)}\n${fn(\n\t'vec4',\n\t'faceLandmark',\n\t'int faceIndex, int landmarkIndex',\n\t`int i = ${N_LANDMARK_METADATA_SLOTS} + faceIndex * ${LANDMARK_COUNT} + landmarkIndex;\n\tint x = i % ${LANDMARKS_TEXTURE_WIDTH};\n\tint y = i / ${LANDMARKS_TEXTURE_WIDTH};${\n\t\thistory\n\t\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texelFetch(u_faceLandmarksTex, ivec3(x, y, layer), 0);`\n\t\t\t: `\n\treturn texelFetch(u_faceLandmarksTex, ivec2(x, y), 0);`\n\t}`,\n)}\n${\n\thistory\n\t\t? `\nvec4 _sampleFaceMask(vec2 pos, int framesAgo) {\n\tint layer = (u_faceMaskFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texture(u_faceMask, vec3(pos, float(layer)));\n}\n`\n\t\t: ''\n}\n${checkAt('leftEyebrow', 'LEFT_EYEBROW')}\n${checkAt('rightEyebrow', 'RIGHT_EYEBROW')}\n${checkAt('leftEye', 'LEFT_EYE')}\n${checkAt('rightEye', 'RIGHT_EYE')}\n${checkAt('lips', 'MOUTH')}\n${checkAt('mouth', 'MOUTH', 'INNER_MOUTH')}\n${checkAt('innerMouth', 'INNER_MOUTH')}\n${checkAt('faceOval', 'OVAL')}\n${fn(\n\t'vec2',\n\t'faceAt',\n\t'vec2 pos',\n\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\treturn vec2(step(0.0, faceIndex), faceIndex);`,\n)}\n${combineLeftRight('eye', 'leftEyeAt', 'rightEyeAt')}\n${combineLeftRight('eyebrow', 'leftEyebrowAt', 'rightEyebrowAt')}\n${checkIn(['eyebrow', 'eye', 'mouth', 'innerMouth', 'lips', 'face'])}`);\n\t};\n}\n\nexport default face;\n"],"mappings":"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","names":["MASK_VERTEX_SHADER","MASK_FRAGMENT_SHADER","BLIT_FRAGMENT_SHADER","FULLSCREEN_TRIANGLES","STANDARD_LANDMARK_COUNT","CUSTOM_LANDMARK_COUNT","LANDMARK_COUNT","LANDMARKS_TEXTURE_WIDTH","N_LANDMARK_METADATA_SLOTS","LEFT_EYEBROW_INDICES","LEFT_EYE_INDICES","RIGHT_EYEBROW_INDICES","RIGHT_EYE_INDICES","MOUTH_INDICES","INNER_MOUTH_INDICES","ALL_STANDARD_INDICES","_","i","LANDMARK_INDICES","RED_REGION_NAMES","GREEN_REGION_NAMES","BLUE_REGION_NAMES","CHANNEL_BIT_SCALE","GB_BITMASK_MAX_FACES","createChannelBitValues","names","name","normalizeChannelBitValues","bitValues","bitValue","RED_REGION_BIT_VALUES","GREEN_REGION_BIT_VALUES","BLUE_REGION_BIT_VALUES","RED_CHANNEL_VALUES","GREEN_CHANNEL_VALUES","BLUE_CHANNEL_VALUES","DEFAULT_FACE_OPTIONS","fanTriangulate","indices","tris","faceRegions","initFaceRegions","LandmarkerClass","tesselationConnections","tesselation","ovalIndices","start","key","sharedDetectors","createProgram","gl","vertexSource","fragmentSource","vertexShader","fragmentShader","program","initMaskRenderer","canvas","regionProgram","blitProgram","regionPositionBuffer","regionPositionLocation","quadBuffer","blitPositionLocation","colorLocation","textureLocation","scratchTexture","scratchFramebuffer","resizeMaskRenderer","mask","width","height","drawRegionToScratch","landmarksData","faceRegion","faceIdx","r","g","b","baseIdx","vertices","landmarkIdx","accumulateScratch","updateLandmarksData","detector","faces","data","nFaces","landmarks","landmark","dataIdx","faceCenter","calculateBoundingBoxCenter","mouthCenter","updateMask","maxFaces","maskCanvas","useTesselationBitmask","face","config","textureName","history","mediapipeOptions","options","optionsKey","hashOptions","nLandmarksMax","textureHeight","shaderPad","context","injectGLSL","emitHook","updateTexturesInternal","existingDetector","destroyed","skipHistoryWrite","onResult","singleHistoryWriteIndex","nSlots","rowsToUpdate","historyWriteIndex","pendingBackfillSlots","initializeDetector","mediaPipe","FaceLandmarker","getSharedFileset","faceLandmarker","initPromise","detectFaces","source","now","callOrder","requiredMode","shouldDetect","result","cb","hasCalled","historyWriteCounter","writeToHistory","isMediaPipeSource","updates","fn","historyParams","generateGLSLFn","sampleMask","decodeFaceBitIndex","decodeFaceIndex","checkAt","fnName","regionNames","regionName","combineLeftRight","leftFn","rightFn","checkIn","fnNames","face_default"]}
1
+ {"version":3,"sources":["../../src/plugins/face.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '..';\nimport {\n\tcalculateBoundingBoxCenter,\n\tgenerateGLSLFn,\n\tgetSharedFileset,\n\thashOptions,\n\tisMediaPipeSource,\n\tMediaPipeSource,\n} from './mediapipe-common';\nimport type { FaceLandmarker, FaceLandmarkerResult, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface FacePluginOptions {\n\tmodelPath?: string;\n\tmaxFaces?: number;\n\tminFaceDetectionConfidence?: number;\n\tminFacePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputFaceBlendshapes?: boolean;\n\toutputFacialTransformationMatrixes?: boolean;\n\thistory?: number;\n}\n\nconst MASK_VERTEX_SHADER = `#version 300 es\nin vec2 a_pos;\nout vec2 v_uv;\nvoid main() {\n\tv_uv = a_pos;\n\tgl_Position = vec4(a_pos * 2.0 - 1.0, 0.0, 1.0);\n}`;\nconst MASK_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nuniform vec4 u_color;\nout vec4 outColor;\nvoid main() { outColor = u_color; }`;\nconst BLIT_FRAGMENT_SHADER = `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nuniform sampler2D u_texture;\nout vec4 outColor;\nvoid main() { outColor = texture(u_texture, v_uv); }`;\nconst FULLSCREEN_TRIANGLES = new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]);\n\nconst STANDARD_LANDMARK_COUNT = 478;\nconst CUSTOM_LANDMARK_COUNT = 2;\nconst LANDMARK_COUNT = STANDARD_LANDMARK_COUNT + CUSTOM_LANDMARK_COUNT;\nconst LANDMARKS_TEXTURE_WIDTH = 512;\nconst N_LANDMARK_METADATA_SLOTS = 1;\n\nconst ALL_STANDARD_INDICES = Array.from({ length: STANDARD_LANDMARK_COUNT }, (_, i) => i);\nconst FACE_LANDMARK_L_EYE_CENTER = 473;\nconst FACE_LANDMARK_R_EYE_CENTER = 468;\nconst FACE_LANDMARK_NOSE_TIP = 4;\nconst FACE_LANDMARK_FACE_CENTER = STANDARD_LANDMARK_COUNT;\nconst FACE_LANDMARK_MOUTH_CENTER = STANDARD_LANDMARK_COUNT + 1;\nlet innerMouthIndices: number[] | null = null;\n\n/* Face mask channel layout:\n- R: additive bitfield for face regions. Since it’s additive, it handles overlapping regions.\n- G/B: tessellation ownership. When maxFaces is <= 16, G stores one-hot bits for\n faces 0-7 and B stores one-hot bits for faces 8-15 so overlapping faces\n remain decodable. Above 16 maxFaces, B falls back to storing faceIndex + 1 as\n an additive byte value, which will overcount on overlaps. */\nconst RED_REGION_NAMES = [\n\t'OVAL',\n\t'LEFT_EYEBROW',\n\t'RIGHT_EYEBROW',\n\t'LEFT_EYE',\n\t'RIGHT_EYE',\n\t'MOUTH',\n\t'INNER_MOUTH',\n] as const;\nconst GREEN_REGION_NAMES = ['FACE_0', 'FACE_1', 'FACE_2', 'FACE_3', 'FACE_4', 'FACE_5', 'FACE_6', 'FACE_7'] as const;\nconst BLUE_REGION_NAMES = [\n\t'FACE_8',\n\t'FACE_9',\n\t'FACE_10',\n\t'FACE_11',\n\t'FACE_12',\n\t'FACE_13',\n\t'FACE_14',\n\t'FACE_15',\n] as const;\nconst CHANNEL_BIT_SCALE = 255;\nconst GB_BITMASK_MAX_FACES = GREEN_REGION_NAMES.length + BLUE_REGION_NAMES.length;\n\nfunction createChannelBitValues<const T extends readonly string[]>(names: T): Record<T[number], number> {\n\treturn Object.fromEntries(names.map((name, i) => [name, 1 << i])) as Record<T[number], number>;\n}\n\nfunction normalizeChannelBitValues<T extends Record<string, number>>(bitValues: T): T {\n\treturn Object.fromEntries(\n\t\tObject.entries(bitValues).map(([name, bitValue]) => [name, bitValue / CHANNEL_BIT_SCALE]),\n\t) as T;\n}\n\nconst RED_REGION_BIT_VALUES = createChannelBitValues(RED_REGION_NAMES);\nconst GREEN_REGION_BIT_VALUES = createChannelBitValues(GREEN_REGION_NAMES);\nconst BLUE_REGION_BIT_VALUES = createChannelBitValues(BLUE_REGION_NAMES);\nconst RED_CHANNEL_VALUES = normalizeChannelBitValues(RED_REGION_BIT_VALUES);\nconst GREEN_CHANNEL_VALUES = normalizeChannelBitValues(GREEN_REGION_BIT_VALUES);\nconst BLUE_CHANNEL_VALUES = normalizeChannelBitValues(BLUE_REGION_BIT_VALUES);\n\nconst DEFAULT_FACE_OPTIONS: Required<Omit<FacePluginOptions, 'history'>> = {\n\tmodelPath:\n\t\t'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task',\n\tmaxFaces: 1,\n\tminFaceDetectionConfidence: 0.5,\n\tminFacePresenceConfidence: 0.5,\n\tminTrackingConfidence: 0.5,\n\toutputFaceBlendshapes: false,\n\toutputFacialTransformationMatrixes: false,\n};\n\nfunction fanTriangulate(indices: readonly number[]): number[] {\n\tconst tris: number[] = [];\n\tfor (let i = 1; i < indices.length - 1; ++i) {\n\t\ttris.push(indices[0], indices[i], indices[i + 1]);\n\t}\n\treturn tris;\n}\n\nfunction contourPath(connections: readonly { start: number; end: number }[]): number[] {\n\tconst indices = new Array<number>(connections.length + 1);\n\tindices[0] = connections[0].start;\n\tfor (let i = 0; i < connections.length; ++i) indices[i + 1] = connections[i].end;\n\treturn indices;\n}\n\nfunction stripTriangulate(a: readonly number[], b: readonly number[]): number[] {\n\tconst tris: number[] = [];\n\tconst n = Math.min(a.length, b.length);\n\tfor (let i = 0; i < n - 1; ++i) {\n\t\ttris.push(a[i], b[i], b[i + 1], a[i], b[i + 1], a[i + 1]);\n\t}\n\treturn tris;\n}\n\ntype FaceRegion = { indices: number[]; vertices: Float32Array };\nlet faceRegions: Record<string, FaceRegion> | null = null;\nfunction initFaceRegions(LandmarkerClass: typeof FaceLandmarker): void {\n\tif (!faceRegions) {\n\t\tconst tesselationConnections = LandmarkerClass.FACE_LANDMARKS_TESSELATION;\n\t\tconst leftEyebrowIndices = contourPath(LandmarkerClass.FACE_LANDMARKS_LEFT_EYEBROW);\n\t\tconst rightEyebrowIndices = contourPath(LandmarkerClass.FACE_LANDMARKS_RIGHT_EYEBROW);\n\t\tconst leftEyeConnections = LandmarkerClass.FACE_LANDMARKS_LEFT_EYE;\n\t\tconst rightEyeConnections = LandmarkerClass.FACE_LANDMARKS_RIGHT_EYE;\n\t\tconst lipConnections = LandmarkerClass.FACE_LANDMARKS_LIPS;\n\t\t// MediaPipe ships eyes as 2 open chains of 8 connections and lips as 4 open chains of 10.\n\t\tconst leftEyeUpper = contourPath(leftEyeConnections.slice(0, 8));\n\t\tconst leftEyeLower = contourPath(leftEyeConnections.slice(8, 16));\n\t\tconst rightEyeUpper = contourPath(rightEyeConnections.slice(0, 8));\n\t\tconst rightEyeLower = contourPath(rightEyeConnections.slice(8, 16));\n\t\tconst outerUpperLip = contourPath(lipConnections.slice(0, 10));\n\t\tconst outerLowerLip = contourPath(lipConnections.slice(10, 20));\n\t\tconst innerUpperLip = contourPath(lipConnections.slice(20, 30));\n\t\tconst innerLowerLip = contourPath(lipConnections.slice(30, 40));\n\t\tconst leftEyeIndices = [...leftEyeUpper, ...leftEyeLower.slice(1, -1)];\n\t\tconst rightEyeIndices = [...rightEyeUpper, ...rightEyeLower.slice(1, -1)];\n\t\tinnerMouthIndices = [...innerUpperLip, ...innerLowerLip.slice(1, -1)];\n\t\tconst tessellationHoleRemap = new Int16Array(LANDMARK_COUNT).fill(-1);\n\t\tfor (const index of leftEyeIndices) tessellationHoleRemap[index] = FACE_LANDMARK_L_EYE_CENTER;\n\t\tfor (const index of rightEyeIndices) tessellationHoleRemap[index] = FACE_LANDMARK_R_EYE_CENTER;\n\t\tfor (const index of innerMouthIndices) tessellationHoleRemap[index] = FACE_LANDMARK_MOUTH_CENTER;\n\t\tconst remapTessellationHole = (index: number) => {\n\t\t\tconst remapped = tessellationHoleRemap[index];\n\t\t\treturn remapped >= 0 ? remapped : index;\n\t\t};\n\t\tconst tesselation: number[] = [];\n\t\tfor (let i = 0; i < tesselationConnections.length - 2; i += 3) {\n\t\t\tconst a = remapTessellationHole(tesselationConnections[i].start);\n\t\t\tconst b = remapTessellationHole(tesselationConnections[i + 1].start);\n\t\t\tconst c = remapTessellationHole(tesselationConnections[i + 2].start);\n\t\t\tif (a !== b && a !== c && b !== c) tesselation.push(a, b, c);\n\t\t}\n\t\tconst leftEyeFill = stripTriangulate(leftEyeUpper, leftEyeLower);\n\t\tconst rightEyeFill = stripTriangulate(rightEyeUpper, rightEyeLower);\n\t\tconst mouthFill = [...stripTriangulate(outerUpperLip, innerUpperLip), ...stripTriangulate(outerLowerLip, innerLowerLip)];\n\t\tconst innerMouthFill = stripTriangulate(innerUpperLip, innerLowerLip);\n\t\tconst ovalIndices = contourPath(LandmarkerClass.FACE_LANDMARKS_FACE_OVAL).slice(0, -1);\n\t\tfaceRegions = Object.fromEntries(\n\t\t\tObject.entries({\n\t\t\t\tLEFT_EYEBROW: fanTriangulate(leftEyebrowIndices),\n\t\t\t\tRIGHT_EYEBROW: fanTriangulate(rightEyebrowIndices),\n\t\t\t\tLEFT_EYE: leftEyeFill,\n\t\t\t\tRIGHT_EYE: rightEyeFill,\n\t\t\t\tMOUTH: mouthFill,\n\t\t\t\tINNER_MOUTH: innerMouthFill,\n\t\t\t\tTESSELATION: tesselation,\n\t\t\t\tOVAL: fanTriangulate(ovalIndices),\n\t\t\t}).map(([key, indices]) => [key, { indices, vertices: new Float32Array(indices.length * 2) }]),\n\t\t);\n\t}\n}\n\ninterface MaskRenderer {\n\tcanvas: OffscreenCanvas;\n\tgl: WebGL2RenderingContext;\n\tregionProgram: WebGLProgram;\n\tblitProgram: WebGLProgram;\n\tregionPositionBuffer: WebGLBuffer;\n\tquadBuffer: WebGLBuffer;\n\tregionPositionLocation: number;\n\tblitPositionLocation: number;\n\tcolorLocation: WebGLUniformLocation;\n\ttextureLocation: WebGLUniformLocation;\n\tscratchTexture: WebGLTexture;\n\tscratchFramebuffer: WebGLFramebuffer;\n}\n\ninterface Detector {\n\tlandmarker: FaceLandmarker;\n\tmask: MaskRenderer;\n\tsubscribers: Map<Function, boolean>;\n\tmaxFaces: number;\n\tstate: {\n\t\tnCalls: number;\n\t\trunningMode: 'IMAGE' | 'VIDEO';\n\t\tsource: MediaPipeSource | null;\n\t\tvideoTime: number;\n\t\tresultTimestamp: number;\n\t\tresult: FaceLandmarkerResult | null;\n\t\tpending: Promise<void>;\n\t\tnFaces: number;\n\t};\n\tlandmarks: {\n\t\tdata: Float32Array;\n\t\ttextureHeight: number;\n\t};\n}\nconst sharedDetectors = new Map<string, Detector>();\n\nfunction createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n\tconst vertexShader = gl.createShader(gl.VERTEX_SHADER)!;\n\tgl.shaderSource(vertexShader, vertexSource);\n\tgl.compileShader(vertexShader);\n\n\tconst fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;\n\tgl.shaderSource(fragmentShader, fragmentSource);\n\tgl.compileShader(fragmentShader);\n\n\tconst program = gl.createProgram()!;\n\tgl.attachShader(program, vertexShader);\n\tgl.attachShader(program, fragmentShader);\n\tgl.linkProgram(program);\n\tgl.deleteShader(vertexShader);\n\tgl.deleteShader(fragmentShader);\n\treturn program;\n}\n\nfunction initMaskRenderer(canvas: OffscreenCanvas): MaskRenderer {\n\tconst gl = canvas.getContext('webgl2', {\n\t\tantialias: false,\n\t\tpreserveDrawingBuffer: true,\n\t})!;\n\tconst regionProgram = createProgram(gl, MASK_VERTEX_SHADER, MASK_FRAGMENT_SHADER);\n\tconst blitProgram = createProgram(gl, MASK_VERTEX_SHADER, BLIT_FRAGMENT_SHADER);\n\n\tconst regionPositionBuffer = gl.createBuffer()!;\n\tconst regionPositionLocation = gl.getAttribLocation(regionProgram, 'a_pos');\n\n\tconst quadBuffer = gl.createBuffer()!;\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_TRIANGLES, gl.STATIC_DRAW);\n\tconst blitPositionLocation = gl.getAttribLocation(blitProgram, 'a_pos');\n\n\tconst colorLocation = gl.getUniformLocation(regionProgram, 'u_color')!;\n\tconst textureLocation = gl.getUniformLocation(blitProgram, 'u_texture')!;\n\n\tconst scratchTexture = gl.createTexture()!;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n\n\tconst scratchFramebuffer = gl.createFramebuffer()!;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, scratchTexture, 0);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n\tgl.useProgram(blitProgram);\n\tgl.uniform1i(textureLocation, 0);\n\tgl.colorMask(true, true, true, false);\n\n\treturn {\n\t\tcanvas,\n\t\tgl,\n\t\tregionProgram,\n\t\tblitProgram,\n\t\tregionPositionBuffer,\n\t\tquadBuffer,\n\t\tregionPositionLocation,\n\t\tblitPositionLocation,\n\t\tcolorLocation,\n\t\ttextureLocation,\n\t\tscratchTexture,\n\t\tscratchFramebuffer,\n\t};\n}\n\nfunction resizeMaskRenderer(mask: MaskRenderer, width: number, height: number) {\n\tconst { gl, canvas, scratchTexture } = mask;\n\tif (canvas.width === width && canvas.height === height) return;\n\tcanvas.width = width;\n\tcanvas.height = height;\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n}\n\nfunction drawRegionToScratch(\n\tmask: MaskRenderer,\n\tlandmarksData: Float32Array,\n\tfaceRegion: FaceRegion,\n\tfaceIdx: number,\n\tr: number,\n\tg: number,\n\tb: number,\n) {\n\tconst { gl, regionProgram, regionPositionBuffer, regionPositionLocation, colorLocation, scratchFramebuffer } = mask;\n\tconst baseIdx = N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT;\n\tconst { indices, vertices } = faceRegion;\n\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, scratchFramebuffer);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\tgl.useProgram(regionProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, regionPositionBuffer);\n\tgl.enableVertexAttribArray(regionPositionLocation);\n\tgl.vertexAttribPointer(regionPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.MAX);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\n\tfor (let i = 0; i < indices.length; ++i) {\n\t\tconst landmarkIdx = (baseIdx + indices[i]) * 4;\n\t\tvertices[i * 2] = landmarksData[landmarkIdx];\n\t\tvertices[i * 2 + 1] = landmarksData[landmarkIdx + 1];\n\t}\n\tgl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);\n\tgl.uniform4f(colorLocation, r, g, b, 1.0);\n\tgl.drawArrays(gl.TRIANGLES, 0, indices.length);\n}\n\nfunction accumulateScratch(mask: MaskRenderer) {\n\tconst { gl, blitProgram, quadBuffer, blitPositionLocation, scratchTexture } = mask;\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, mask.canvas.width, mask.canvas.height);\n\tgl.useProgram(blitProgram);\n\tgl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);\n\tgl.enableVertexAttribArray(blitPositionLocation);\n\tgl.vertexAttribPointer(blitPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\tgl.activeTexture(gl.TEXTURE0);\n\tgl.bindTexture(gl.TEXTURE_2D, scratchTexture);\n\tgl.enable(gl.BLEND);\n\tgl.blendEquation(gl.FUNC_ADD);\n\tgl.blendFunc(gl.ONE, gl.ONE);\n\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n}\n\nfunction updateLandmarksData(detector: Detector, faces: NormalizedLandmark[][]) {\n\tconst data = detector.landmarks.data;\n\tconst nFaces = faces.length;\n\tdata[0] = nFaces;\n\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst landmarks = faces[faceIdx];\n\t\tfor (let landmarkIdx = 0; landmarkIdx < STANDARD_LANDMARK_COUNT; ++landmarkIdx) {\n\t\t\tconst landmark = landmarks[landmarkIdx];\n\t\t\tconst dataIdx = (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + landmarkIdx) * 4;\n\t\t\tdata[dataIdx] = landmark.x;\n\t\t\tdata[dataIdx + 1] = 1 - landmark.y;\n\t\t\tdata[dataIdx + 2] = landmark.z ?? 0;\n\t\t\tdata[dataIdx + 3] = landmark.visibility ?? 1;\n\t\t}\n\n\t\tconst faceCenter = calculateBoundingBoxCenter(\n\t\t\tdata,\n\t\t\tfaceIdx,\n\t\t\tALL_STANDARD_INDICES,\n\t\t\tLANDMARK_COUNT,\n\t\t\tN_LANDMARK_METADATA_SLOTS,\n\t\t);\n\t\tdata.set(faceCenter, (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + FACE_LANDMARK_FACE_CENTER) * 4);\n\t\tconst mouthCenter = calculateBoundingBoxCenter(data, faceIdx, innerMouthIndices!, LANDMARK_COUNT, 1);\n\t\tdata.set(mouthCenter, (N_LANDMARK_METADATA_SLOTS + faceIdx * LANDMARK_COUNT + FACE_LANDMARK_MOUTH_CENTER) * 4);\n\t}\n\n\tdetector.state.nFaces = nFaces;\n}\n\nfunction updateMask(detector: Detector, width: number, height: number) {\n\tconst {\n\t\tmask,\n\t\tmaxFaces,\n\t\tlandmarks,\n\t\tstate: { nFaces },\n\t} = detector;\n\tconst { gl, canvas: maskCanvas } = mask;\n\tconst { data: landmarksData } = landmarks;\n\n\tresizeMaskRenderer(mask, width, height);\n\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\tgl.viewport(0, 0, maskCanvas.width, maskCanvas.height);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\tif (!faceRegions) return;\n\n\tconst useTesselationBitmask = maxFaces <= GB_BITMASK_MAX_FACES;\n\tfor (let faceIdx = 0; faceIdx < nFaces; ++faceIdx) {\n\t\tconst g =\n\t\t\tuseTesselationBitmask && faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? GREEN_CHANNEL_VALUES[GREEN_REGION_NAMES[faceIdx]]\n\t\t\t\t: 0;\n\t\tconst b = useTesselationBitmask\n\t\t\t? faceIdx < GREEN_REGION_NAMES.length\n\t\t\t\t? 0\n\t\t\t\t: BLUE_CHANNEL_VALUES[BLUE_REGION_NAMES[faceIdx - GREEN_REGION_NAMES.length]]\n\t\t\t: (faceIdx + 1) / CHANNEL_BIT_SCALE;\n\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.TESSELATION, faceIdx, 0, g, b);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.OVAL, faceIdx, RED_CHANNEL_VALUES.OVAL, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.LEFT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.LEFT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.RIGHT_EYEBROW,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.RIGHT_EYEBROW,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.LEFT_EYE, faceIdx, RED_CHANNEL_VALUES.LEFT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.RIGHT_EYE, faceIdx, RED_CHANNEL_VALUES.RIGHT_EYE, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(mask, landmarksData, faceRegions.MOUTH, faceIdx, RED_CHANNEL_VALUES.MOUTH, 0, 0);\n\t\taccumulateScratch(mask);\n\t\tdrawRegionToScratch(\n\t\t\tmask,\n\t\t\tlandmarksData,\n\t\t\tfaceRegions.INNER_MOUTH,\n\t\t\tfaceIdx,\n\t\t\tRED_CHANNEL_VALUES.INNER_MOUTH,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\taccumulateScratch(mask);\n\t}\n}\n\nfunction face(config: { textureName: string; options?: FacePluginOptions }) {\n\tconst { textureName, options: { history, ...mediapipeOptions } = {} } = config;\n\tconst options = { ...DEFAULT_FACE_OPTIONS, ...mediapipeOptions };\n\tconst optionsKey = hashOptions({ ...options, textureName });\n\n\tconst nLandmarksMax = options.maxFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\tconst textureHeight = Math.ceil(nLandmarksMax / LANDMARKS_TEXTURE_WIDTH);\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, emitHook, updateTexturesInternal } = context;\n\n\t\tconst existingDetector = sharedDetectors.get(optionsKey);\n\t\tconst landmarksData =\n\t\t\texistingDetector?.landmarks.data ?? new Float32Array(LANDMARKS_TEXTURE_WIDTH * textureHeight * 4);\n\t\tconst maskCanvas = existingDetector?.mask.canvas ?? new OffscreenCanvas(1, 1);\n\t\tlet detector: Detector | null = null;\n\t\tlet destroyed = false;\n\t\tlet skipHistoryWrite = false;\n\n\t\tfunction onResult(singleHistoryWriteIndex?: number) {\n\t\t\tif (!detector) return;\n\t\t\tconst nFaces = detector.state.nFaces;\n\t\t\tconst nSlots = nFaces * LANDMARK_COUNT + N_LANDMARK_METADATA_SLOTS;\n\t\t\tconst rowsToUpdate = Math.ceil(nSlots / LANDMARKS_TEXTURE_WIDTH);\n\t\t\tlet historyWriteIndex: number | number[] | undefined = singleHistoryWriteIndex;\n\t\t\tif (typeof historyWriteIndex === 'undefined' && pendingBackfillSlots.length > 0) {\n\t\t\t\thistoryWriteIndex = pendingBackfillSlots;\n\t\t\t\tpendingBackfillSlots = [];\n\t\t\t}\n\t\t\tupdateTexturesInternal(\n\t\t\t\t{\n\t\t\t\t\tu_faceLandmarksTex: {\n\t\t\t\t\t\tdata: detector.landmarks.data,\n\t\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\t\theight: rowsToUpdate,\n\t\t\t\t\t\tisPartial: true,\n\t\t\t\t\t},\n\t\t\t\t\tu_faceMask: detector.mask.canvas,\n\t\t\t\t},\n\t\t\t\thistory ? { skipHistoryWrite, historyWriteIndex } : undefined,\n\t\t\t);\n\t\t\tshaderPad.updateUniforms({ u_nFaces: nFaces });\n\t\t\temitHook('face:result', detector.state.result);\n\t\t}\n\n\t\tasync function initializeDetector() {\n\t\t\tif (sharedDetectors.has(optionsKey)) {\n\t\t\t\tdetector = sharedDetectors.get(optionsKey)!;\n\t\t\t} else {\n\t\t\t\tconst [mediaPipe, { FaceLandmarker }] = await Promise.all([\n\t\t\t\t\tgetSharedFileset(),\n\t\t\t\t\timport('@mediapipe/tasks-vision'),\n\t\t\t\t]);\n\t\t\t\tif (destroyed) return;\n\n\t\t\t\tconst faceLandmarker = await FaceLandmarker.createFromOptions(mediaPipe, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options.modelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumFaces: options.maxFaces,\n\t\t\t\t\tminFaceDetectionConfidence: options.minFaceDetectionConfidence,\n\t\t\t\t\tminFacePresenceConfidence: options.minFacePresenceConfidence,\n\t\t\t\t\tminTrackingConfidence: options.minTrackingConfidence,\n\t\t\t\t\toutputFaceBlendshapes: options.outputFaceBlendshapes,\n\t\t\t\t\toutputFacialTransformationMatrixes: options.outputFacialTransformationMatrixes,\n\t\t\t\t});\n\t\t\t\tif (destroyed) {\n\t\t\t\t\tfaceLandmarker.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdetector = {\n\t\t\t\t\tlandmarker: faceLandmarker,\n\t\t\t\t\tmask: initMaskRenderer(maskCanvas),\n\t\t\t\t\tsubscribers: new Map(),\n\t\t\t\t\tmaxFaces: options.maxFaces,\n\t\t\t\t\tstate: {\n\t\t\t\t\t\tnCalls: 0,\n\t\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\t\tsource: null,\n\t\t\t\t\t\tvideoTime: -1,\n\t\t\t\t\t\tresultTimestamp: 0,\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\tpending: Promise.resolve(),\n\t\t\t\t\t\tnFaces: 0,\n\t\t\t\t\t},\n\t\t\t\t\tlandmarks: {\n\t\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\t\ttextureHeight,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tinitFaceRegions(FaceLandmarker);\n\t\t\t\tsharedDetectors.set(optionsKey, detector);\n\t\t\t}\n\n\t\t\tdetector.subscribers.set(onResult, false);\n\t\t}\n\t\tconst initPromise = initializeDetector();\n\n\t\tasync function detectFaces(source: MediaPipeSource) {\n\t\t\tconst now = performance.now();\n\t\t\tawait initPromise;\n\t\t\tif (!detector) return;\n\t\t\tconst callOrder = ++detector.state.nCalls;\n\n\t\t\tdetector.state.pending = detector.state.pending.then(async () => {\n\t\t\t\tif (!detector || callOrder !== detector.state.nCalls) return;\n\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (detector.state.runningMode !== requiredMode) {\n\t\t\t\t\tdetector.state.runningMode = requiredMode;\n\t\t\t\t\tawait detector.landmarker.setOptions({\n\t\t\t\t\t\trunningMode: requiredMode,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tlet shouldDetect = false;\n\n\t\t\t\tif (source !== detector.state.source) {\n\t\t\t\t\tdetector.state.source = source;\n\t\t\t\t\tdetector.state.videoTime = -1;\n\t\t\t\t\tshouldDetect = true;\n\t\t\t\t} else if (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.currentTime !== detector.state.videoTime) {\n\t\t\t\t\t\tdetector.state.videoTime = source.currentTime;\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (!(source instanceof HTMLImageElement)) {\n\t\t\t\t\tif (now - detector.state.resultTimestamp > 2) {\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shouldDetect) {\n\t\t\t\t\tlet result: FaceLandmarkerResult | undefined;\n\t\t\t\t\tlet width: number, height: number;\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) return;\n\t\t\t\t\t\twidth = source.videoWidth;\n\t\t\t\t\t\theight = source.videoHeight;\n\t\t\t\t\t\tresult = detector.landmarker.detectForVideo(source, now);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (source.width === 0 || source.height === 0) return;\n\t\t\t\t\t\twidth = source.width;\n\t\t\t\t\t\theight = source.height;\n\t\t\t\t\t\tresult = detector.landmarker.detect(source);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tdetector.state.resultTimestamp = now;\n\t\t\t\t\t\tdetector.state.result = result;\n\t\t\t\t\t\tupdateLandmarksData(detector, result.faceLandmarks);\n\t\t\t\t\t\tupdateMask(detector, width, height);\n\t\t\t\t\t\tfor (const cb of detector.subscribers.keys()) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (detector.state.result) {\n\t\t\t\t\tfor (const [cb, hasCalled] of detector.subscribers.entries()) {\n\t\t\t\t\t\tif (!hasCalled) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait detector.state.pending;\n\t\t}\n\n\t\tshaderPad.on('_init', () => {\n\t\t\tshaderPad.initializeUniform('u_maxFaces', 'int', options.maxFaces);\n\t\t\tshaderPad.initializeUniform('u_nFaces', 'int', 0);\n\t\t\tshaderPad.initializeTexture(\n\t\t\t\t'u_faceLandmarksTex',\n\t\t\t\t{\n\t\t\t\t\tdata: landmarksData,\n\t\t\t\t\twidth: LANDMARKS_TEXTURE_WIDTH,\n\t\t\t\t\theight: textureHeight,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tinternalFormat: 'RGBA32F',\n\t\t\t\t\ttype: 'FLOAT',\n\t\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\t\thistory,\n\t\t\t\t},\n\t\t\t);\n\t\t\tshaderPad.initializeTexture('u_faceMask', maskCanvas, {\n\t\t\t\tminFilter: 'NEAREST',\n\t\t\t\tmagFilter: 'NEAREST',\n\t\t\t\thistory,\n\t\t\t});\n\t\t\tinitPromise.then(() => {\n\t\t\t\tif (destroyed || !detector) return;\n\t\t\t\temitHook('face:ready');\n\t\t\t});\n\t\t});\n\n\t\tlet historyWriteCounter = 0;\n\t\tlet pendingBackfillSlots: number[] = [];\n\t\tconst writeToHistory = () => {\n\t\t\tif (!history) return;\n\t\t\tonResult(historyWriteCounter); // Write stale data immediately.\n\t\t\tpendingBackfillSlots.push(historyWriteCounter); // Queue up backfill with more recent data.\n\t\t\thistoryWriteCounter = (historyWriteCounter + 1) % (history + 1);\n\t\t};\n\n\t\tshaderPad.on('initializeTexture', (name: string, source: TextureSource) => {\n\t\t\tif (name === textureName && isMediaPipeSource(source)) {\n\t\t\t\twriteToHistory();\n\t\t\t\tdetectFaces(source);\n\t\t\t}\n\t\t});\n\n\t\tshaderPad.on(\n\t\t\t'updateTextures',\n\t\t\t(updates: Record<string, TextureSource>, options?: { skipHistoryWrite?: boolean }) => {\n\t\t\t\tconst source = updates[textureName];\n\t\t\t\tif (isMediaPipeSource(source)) {\n\t\t\t\t\tskipHistoryWrite = options?.skipHistoryWrite ?? false;\n\t\t\t\t\tif (!skipHistoryWrite) writeToHistory();\n\t\t\t\t\tdetectFaces(source);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tshaderPad.on('destroy', () => {\n\t\t\tdestroyed = true;\n\t\t\tif (detector) {\n\t\t\t\tdetector.subscribers.delete(onResult);\n\t\t\t\tif (detector.subscribers.size === 0) {\n\t\t\t\t\tdetector.landmarker.close();\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.regionProgram);\n\t\t\t\t\tdetector.mask.gl.deleteProgram(detector.mask.blitProgram);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.regionPositionBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteBuffer(detector.mask.quadBuffer);\n\t\t\t\t\tdetector.mask.gl.deleteTexture(detector.mask.scratchTexture);\n\t\t\t\t\tdetector.mask.gl.deleteFramebuffer(detector.mask.scratchFramebuffer);\n\t\t\t\t\tsharedDetectors.delete(optionsKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdetector = null;\n\t\t});\n\n\t\tconst { fn, historyParams } = generateGLSLFn(history);\n\t\tconst sampleMask = history ? `_sampleFaceMask(pos, framesAgo)` : `texture(u_faceMask, pos)`;\n\t\tconst decodeFaceBitIndex = Array.from(\n\t\t\t{ length: GB_BITMASK_MAX_FACES - 1 },\n\t\t\t(_, i) => `step(${2 ** (i + 1)}.0, faceBitF)`,\n\t\t).join(' + ');\n\t\tconst decodeFaceIndex =\n\t\t\toptions.maxFaces <= GB_BITMASK_MAX_FACES\n\t\t\t\t? `uint faceBits = (uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5) << 8) | uint(mask.g * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tuint faceBit = faceBits & (~faceBits + 1u);\n\tfloat faceBitF = float(faceBit);\n\tfloat hasFace = sign(faceBitF);\n\tfloat faceIndex = ${decodeFaceBitIndex} - (1.0 - hasFace);`\n\t\t\t\t: `float faceIndex = float(int(uint(mask.b * ${CHANNEL_BIT_SCALE}.0 + 0.5)) - 1);`;\n\n\t\tconst checkAt = (fnName: string, ...regionNames: (keyof typeof RED_REGION_BIT_VALUES)[]) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\tuint bits = uint(mask.r * ${CHANNEL_BIT_SCALE}.0 + 0.5);\n\tfloat hit = sign(float(bits & ${regionNames.reduce(\n\t\t(mask, regionName) => mask | RED_REGION_BIT_VALUES[regionName],\n\t\t0,\n\t)}u));\n\treturn vec2(hit, mix(-1.0, faceIndex, hit));`,\n\t\t\t);\n\n\t\tconst combineLeftRight = (fnName: string, leftFn: string, rightFn: string) =>\n\t\t\tfn(\n\t\t\t\t'vec2',\n\t\t\t\t`${fnName}At`,\n\t\t\t\t'vec2 pos',\n\t\t\t\t`vec2 left = ${leftFn}(pos${historyParams});\n\tvec2 right = ${rightFn}(pos${historyParams});\n\treturn mix(right, left, left.x);`,\n\t\t\t);\n\n\t\tconst checkIn = (fnNames: string[]) =>\n\t\t\tfnNames\n\t\t\t\t.map(fnName =>\n\t\t\t\t\tfn(\n\t\t\t\t\t\t'float',\n\t\t\t\t\t\t`in${fnName[0].toUpperCase() + fnName.slice(1)}`,\n\t\t\t\t\t\t'vec2 pos',\n\t\t\t\t\t\t`vec2 a = ${fnName}At(pos${historyParams}); return step(0.0, a.y) * a.x;`,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.join('\\n');\n\n\t\tinjectGLSL(`\nuniform int u_maxFaces;\nuniform int u_nFaces;\nuniform highp sampler2D${history ? 'Array' : ''} u_faceLandmarksTex;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceLandmarksTexFrameOffset;`\n\t\t\t\t: ''\n\t\t}\nuniform mediump sampler2D${history ? 'Array' : ''} u_faceMask;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_faceMaskFrameOffset;`\n\t\t\t\t: ''\n\t\t}\n\n#define FACE_LANDMARK_L_EYE_CENTER ${FACE_LANDMARK_L_EYE_CENTER}\n#define FACE_LANDMARK_R_EYE_CENTER ${FACE_LANDMARK_R_EYE_CENTER}\n#define FACE_LANDMARK_NOSE_TIP ${FACE_LANDMARK_NOSE_TIP}\n#define FACE_LANDMARK_FACE_CENTER ${FACE_LANDMARK_FACE_CENTER}\n#define FACE_LANDMARK_MOUTH_CENTER ${FACE_LANDMARK_MOUTH_CENTER}\n\n${fn(\n\t'int',\n\t'nFacesAt',\n\t'',\n\thistory\n\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn int(texelFetch(u_faceLandmarksTex, ivec3(0, 0, layer), 0).r + 0.5);`\n\t\t: `\n\treturn int(texelFetch(u_faceLandmarksTex, ivec2(0, 0), 0).r + 0.5);`,\n)}\n${fn(\n\t'vec4',\n\t'faceLandmark',\n\t'int faceIndex, int landmarkIndex',\n\t`int i = ${N_LANDMARK_METADATA_SLOTS} + faceIndex * ${LANDMARK_COUNT} + landmarkIndex;\n\tint x = i % ${LANDMARKS_TEXTURE_WIDTH};\n\tint y = i / ${LANDMARKS_TEXTURE_WIDTH};${\n\t\thistory\n\t\t\t? `\n\tint layer = (u_faceLandmarksTexFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texelFetch(u_faceLandmarksTex, ivec3(x, y, layer), 0);`\n\t\t\t: `\n\treturn texelFetch(u_faceLandmarksTex, ivec2(x, y), 0);`\n\t}`,\n)}\n${\n\thistory\n\t\t? `\nvec4 _sampleFaceMask(vec2 pos, int framesAgo) {\n\tint layer = (u_faceMaskFrameOffset - framesAgo + ${history + 1}) % ${history + 1};\n\treturn texture(u_faceMask, vec3(pos, float(layer)));\n}\n`\n\t\t: ''\n}\n${checkAt('leftEyebrow', 'LEFT_EYEBROW')}\n${checkAt('rightEyebrow', 'RIGHT_EYEBROW')}\n${checkAt('leftEye', 'LEFT_EYE')}\n${checkAt('rightEye', 'RIGHT_EYE')}\n${checkAt('lips', 'MOUTH')}\n${checkAt('mouth', 'MOUTH', 'INNER_MOUTH')}\n${checkAt('innerMouth', 'INNER_MOUTH')}\n${checkAt('faceOval', 'OVAL')}\n${fn(\n\t'vec2',\n\t'faceAt',\n\t'vec2 pos',\n\t`vec4 mask = ${sampleMask};\n\t${decodeFaceIndex}\n\treturn vec2(step(0.0, faceIndex), faceIndex);`,\n)}\n${combineLeftRight('eye', 'leftEyeAt', 'rightEyeAt')}\n${combineLeftRight('eyebrow', 'leftEyebrowAt', 'rightEyebrowAt')}\n${checkIn(['eyebrow', 'eye', 'mouth', 'innerMouth', 'lips', 'face'])}`);\n\t};\n}\n\nexport default face;\n"],"mappings":"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","names":["MASK_VERTEX_SHADER","MASK_FRAGMENT_SHADER","BLIT_FRAGMENT_SHADER","FULLSCREEN_TRIANGLES","STANDARD_LANDMARK_COUNT","CUSTOM_LANDMARK_COUNT","LANDMARK_COUNT","LANDMARKS_TEXTURE_WIDTH","N_LANDMARK_METADATA_SLOTS","ALL_STANDARD_INDICES","_","i","FACE_LANDMARK_L_EYE_CENTER","FACE_LANDMARK_R_EYE_CENTER","FACE_LANDMARK_NOSE_TIP","FACE_LANDMARK_FACE_CENTER","FACE_LANDMARK_MOUTH_CENTER","innerMouthIndices","RED_REGION_NAMES","GREEN_REGION_NAMES","BLUE_REGION_NAMES","CHANNEL_BIT_SCALE","GB_BITMASK_MAX_FACES","createChannelBitValues","names","name","normalizeChannelBitValues","bitValues","bitValue","RED_REGION_BIT_VALUES","GREEN_REGION_BIT_VALUES","BLUE_REGION_BIT_VALUES","RED_CHANNEL_VALUES","GREEN_CHANNEL_VALUES","BLUE_CHANNEL_VALUES","DEFAULT_FACE_OPTIONS","fanTriangulate","indices","tris","contourPath","connections","stripTriangulate","a","b","n","faceRegions","initFaceRegions","LandmarkerClass","tesselationConnections","leftEyebrowIndices","rightEyebrowIndices","leftEyeConnections","rightEyeConnections","lipConnections","leftEyeUpper","leftEyeLower","rightEyeUpper","rightEyeLower","outerUpperLip","outerLowerLip","innerUpperLip","innerLowerLip","leftEyeIndices","rightEyeIndices","tessellationHoleRemap","index","remapTessellationHole","remapped","tesselation","c","leftEyeFill","rightEyeFill","mouthFill","innerMouthFill","ovalIndices","key","sharedDetectors","createProgram","gl","vertexSource","fragmentSource","vertexShader","fragmentShader","program","initMaskRenderer","canvas","regionProgram","blitProgram","regionPositionBuffer","regionPositionLocation","quadBuffer","blitPositionLocation","colorLocation","textureLocation","scratchTexture","scratchFramebuffer","resizeMaskRenderer","mask","width","height","drawRegionToScratch","landmarksData","faceRegion","faceIdx","r","g","baseIdx","vertices","landmarkIdx","accumulateScratch","updateLandmarksData","detector","faces","data","nFaces","landmarks","landmark","dataIdx","faceCenter","calculateBoundingBoxCenter","mouthCenter","updateMask","maxFaces","maskCanvas","useTesselationBitmask","face","config","textureName","history","mediapipeOptions","options","optionsKey","hashOptions","nLandmarksMax","textureHeight","shaderPad","context","injectGLSL","emitHook","updateTexturesInternal","existingDetector","destroyed","skipHistoryWrite","onResult","singleHistoryWriteIndex","nSlots","rowsToUpdate","historyWriteIndex","pendingBackfillSlots","initializeDetector","mediaPipe","FaceLandmarker","getSharedFileset","faceLandmarker","initPromise","detectFaces","source","now","callOrder","requiredMode","shouldDetect","result","cb","hasCalled","historyWriteCounter","writeToHistory","isMediaPipeSource","updates","fn","historyParams","generateGLSLFn","sampleMask","decodeFaceBitIndex","decodeFaceIndex","checkAt","fnName","regionNames","regionName","combineLeftRight","leftFn","rightFn","checkIn","fnNames","face_default"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shaderpad",
3
- "version": "1.0.0-beta.64",
3
+ "version": "1.0.0-beta.66",
4
4
  "description": "A lightweight, dependency-free library to reduce boilerplate when writing fragment shaders.",
5
5
  "keywords": [
6
6
  "shaders",