mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-19 01:28:29 +00:00
141 lines
5.0 KiB
JavaScript
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()
|