UNPKG

wcjs-multiscreen-renderer

Version:

renderer for WebChimera.js, that supported multiscreen rendering

226 lines (195 loc) 7.81 kB
function Texture(gl) { this.gl = gl; this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); 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); } Texture.prototype.bind = function (n, program, name) { var gl = this.gl; gl.activeTexture([gl.TEXTURE0, gl.TEXTURE1, gl.TEXTURE2][n]); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.uniform1i(gl.getUniformLocation(program, name), n); } Texture.prototype.fill = function (width, height, data) { var gl = this.gl; gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data); } function renderFrame(gl, videoFrame, width, height, uOffset, vOffset) { gl.y.fill(width, height, videoFrame.subarray(0, uOffset)); gl.u.fill(width >> 1, height >> 1, videoFrame.subarray(uOffset, vOffset)); gl.v.fill(width >> 1, height >> 1, videoFrame.subarray(vOffset, videoFrame.length)); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } function setupCanvas(canvas, options) { var gl = canvas.getContext( "webgl", {preserveDrawingBuffer: Boolean(options.preserveDrawingBuffer)} ); if (!gl) return gl; var program = gl.createProgram(); var vertexShaderSource = [ "attribute highp vec4 aVertexPosition;", "attribute vec2 aTextureCoord;", "varying highp vec2 vTextureCoord;", "void main(void) {", " gl_Position = aVertexPosition;", " vTextureCoord = aTextureCoord;", "}" ].join("\n"); var vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderSource); gl.compileShader(vertexShader); var fragmentShaderSource = [ "precision highp float;", "varying lowp vec2 vTextureCoord;", "uniform sampler2D YTexture;", "uniform sampler2D UTexture;", "uniform sampler2D VTexture;", "const mat4 YUV2RGB = mat4", "(", " 1.1643828125, 0, 1.59602734375, -.87078515625,", " 1.1643828125, -.39176171875, -.81296875, .52959375,", " 1.1643828125, 2.017234375, 0, -1.081390625,", " 0, 0, 0, 1", ");", "void main(void) {", " gl_FragColor = vec4( texture2D(YTexture, vTextureCoord).x, texture2D(UTexture, vTextureCoord).x, texture2D(VTexture, vTextureCoord).x, 1) * YUV2RGB;", "}" ].join("\n"); var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderSource); gl.compileShader(fragmentShader); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.log("Shader link failed."); } var vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); gl.enableVertexAttribArray(vertexPositionAttribute); var textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); gl.enableVertexAttribArray(textureCoordAttribute); var verticesBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0]), gl.STATIC_DRAW); gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); var texCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0]), gl.STATIC_DRAW); gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); gl.y = new Texture(gl); gl.u = new Texture(gl); gl.v = new Texture(gl); gl.y.bind(0, program, "YTexture"); gl.u.bind(1, program, "UTexture"); gl.v.bind(2, program, "VTexture"); return gl; } function frameSetup(canvas, gl, width, height) { canvas.width = width; canvas.height = height; gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); } module.exports = { main_context: null, contexts: [], vlc: null, options_g: { fallbackRenderer: false, preserveDrawingBuffer: false }, setMainContext: function (vlc, context) { this.main_context = context; this.vlc = vlc; this.main_context.gl = setupCanvas(context.canvas, this.options_g); }, addAdditionalContext: function (context) { for (var i = 0; i < this.contexts.length; i++) { if (this.contexts[i].id == context.id) { this.contexts[i] = context; this.contexts[i].gl = setupCanvas(context.canvas, this.options_g); return; } } context.gl = setupCanvas(context.canvas, this.options_g); this.contexts.push(context); }, removeContext: function (context) { for (var i = 0; i < this.contexts.length; i++) { if (this.contexts[i].id == context.id) { this.clearCanvas(this.contexts[i]); this.contexts.splice(i, 1); return; } } }, deinit: function (only_additional) { do { var context = this.contexts.pop; this.clearCanvas(context); } while (this.contexts.length > 0); if (only_additional == true) { return; } this.clearCanvas(this.main_context); }, init: function () { var that = this; if (this.main_context == null) { console.log("Set main context first"); return; } this.vlc.onFrameReady = function (frame) { if (frame.width != that.main_context.canvas.width || frame.height != that.main_context.canvas.height) { frameSetup(that.main_context.canvas, that.main_context.gl, frame.width, frame.height); } renderFrame(that.main_context.gl, frame, frame.width, frame.height, frame.uOffset, frame.vOffset); for (var i = 0; i < that.contexts.length; i++) { if (frame.width != that.contexts[i].canvas.width || frame.height != that.contexts[i].canvas.height) { frameSetup(that.contexts[i].canvas, that.contexts[i].gl, frame.width, frame.height); } renderFrame(that.contexts[i].gl, frame, frame.width, frame.height, frame.uOffset, frame.vOffset); } }; }, clearCanvas: function (context) { var gl = context.canvas.gl; var arr1 = new Uint8Array(1); var arr2 = new Uint8Array(1); arr1[0] = 0; arr2[0] = 128; gl.y.fill(1, 1, arr1); gl.u.fill(1, 1, arr2); gl.v.fill(1, 1, arr2); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // for (var i = 0; i < this.contexts.length; i++) { // gl = this.contexts[i].canvas.gl; // arr1 = new Uint8Array(1); // arr2 = new Uint8Array(1); // // arr1[0] = 0; // arr2[0] = 128; // // gl.y.fill(1, 1, arr1); // gl.u.fill(1, 1, arr2); // gl.v.fill(1, 1, arr2); // // gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // } }, };