vdo.ninja/thirdparty/jeeliz/helpers/JeelizCanvas2DHelper.js
2021-08-29 03:56:56 -04:00

141 lines
5.0 KiB
JavaScript

/*
Usage: JeelizCanvas2DHelper(spec) where spec is the returned object of the initialization function (callbackReady)
Return an object width these properties:
- canvas: the CANVAS element
- ctx: the canvas drawing context
- update_canvasTexture: function to launch each time the canvas has been updated (somethink has been drawn on it)
- draw: draw the video with the canvas above
- getCoordinates: transform the detectedState relative 2D viewport coords into canvas 2D pixel coordinates
- resize: to call if the HTML canvas size has changed
*/
const JeelizCanvas2DHelper = function(spec){
// some globalz:
let CV = null, CANVAS2D = null, CTX = null, GL = null, CANVASTEXTURE = null, CANVASTEXTURENEEDSUPDATE = null, SHADERCOPY = null, VIDEOTEXTURE = null;
let VIDEOTEXTURETRANSFORMMAT2 = null, UUVTRANSFORM = null;
const COORDINATES = {
x:0, y:0, s:0
};
//BEGIN WEBGL HELPERS
// compile a shader:
function compile_shader(source, glType, typeString) {
const glShader = GL.createShader(glType);
GL.shaderSource(glShader, source);
GL.compileShader(glShader);
if (!GL.getShaderParameter(glShader, GL.COMPILE_STATUS)) {
alert("ERROR IN " + typeString + " SHADER: " + GL.getShaderInfoLog(glShader));
return null;
}
return glShader;
};
// helper function to build the shader program:
function build_shaderProgram(shaderVertexSource, shaderFragmentSource, id) {
// compile both shader separately:
const glShaderVertex = compile_shader(shaderVertexSource, GL.VERTEX_SHADER, "VERTEX " + id);
const glShaderFragment = compile_shader(shaderFragmentSource, GL.FRAGMENT_SHADER, "FRAGMENT " + id);
const glShaderProgram = GL.createProgram();
GL.attachShader(glShaderProgram, glShaderVertex);
GL.attachShader(glShaderProgram, glShaderFragment);
// start the linking stage:
GL.linkProgram(glShaderProgram);
return glShaderProgram;
}
//END WEBGL HELPERS
// affect some globalz:
GL = spec.GL;
CV = spec.canvasElement;
VIDEOTEXTURE = spec.videoTexture;
VIDEOTEXTURETRANSFORMMAT2 = spec.videoTransformMat2;
// create and size the 2D canvas and its drawing context:
CANVAS2D = document.createElement('canvas');
CANVAS2D.width = CV.width;
CANVAS2D.height = CV.height;
CTX = CANVAS2D.getContext('2d');
// create the WebGL texture with the canvas:
CANVASTEXTURE = GL.createTexture();
GL.bindTexture(GL.TEXTURE_2D, CANVASTEXTURE);
GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, CANVAS2D);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
// build the copy shader program:
const copyVertexShaderSource = "attribute vec2 position;\n\
uniform mat2 UVTransformMat2;\n\
varying vec2 vUV;\n\
void main(void){\n\
gl_Position = vec4(position, 0., 1.);\n\
vUV = vec2(0.5,0.5) + UVTransformMat2 * position;\n\
}";
const copyFragmentShaderSource = "precision lowp float;\n\
uniform sampler2D samplerImage;\n\
varying vec2 vUV;\n\
\n\
void main(void){\n\
gl_FragColor = texture2D(samplerImage, vUV);\n\
}";
SHADERCOPY = build_shaderProgram(copyVertexShaderSource, copyFragmentShaderSource, 'VIDEO');
const uSampler = GL.getUniformLocation(SHADERCOPY, 'samplerImage');
UUVTRANSFORM = GL.getUniformLocation(SHADERCOPY, 'UVTransformMat2');
GL.useProgram(SHADERCOPY);
GL.uniform1i(uSampler, 0);
return {
canvas: CANVAS2D,
ctx: CTX,
update_canvasTexture: function(){
CANVASTEXTURENEEDSUPDATE = true;
},
draw: function(){ // draw the video and the canvas above
GL.viewport(0, 0, CV.width, CV.height);
GL.useProgram(SHADERCOPY);
// enable blending:
GL.enable(GL.BLEND);
GL.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA);
// draw the video first:
GL.bindTexture(GL.TEXTURE_2D, VIDEOTEXTURE);
GL.uniformMatrix2fv(UUVTRANSFORM, false, VIDEOTEXTURETRANSFORMMAT2);
GL.drawElements(GL.TRIANGLES, 3, GL.UNSIGNED_SHORT, 0);
// then draw the canvas:
GL.bindTexture(GL.TEXTURE_2D, CANVASTEXTURE);
GL.uniformMatrix2fv(UUVTRANSFORM, false, [0.5, 0, 0, 0.5]);
if (CANVASTEXTURENEEDSUPDATE) {
GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, CANVAS2D);
}
GL.drawElements(GL.TRIANGLES, 3, GL.UNSIGNED_SHORT, 0);
GL.disable(GL.BLEND);
},
getCoordinates: function(detectedState){
COORDINATES.x = Math.round((0.5+0.5*detectedState.x-0.5*detectedState.s)*CV.width);
COORDINATES.y = Math.round((0.5+0.5*detectedState.y-0.5*detectedState.s)*CV.height);
COORDINATES.w = Math.round(detectedState.s*CV.width);
COORDINATES.h = COORDINATES.w;
return COORDINATES;
},
resize: function(){
CANVAS2D.width = CV.width;
CANVAS2D.height = CV.height;
}
}; //end Canvas2DDisplay return value
} //end JeelizCanvas2DHelper()