| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- JSMpeg.Renderer.WebGL = (function(){ "use strict";
-
- var WebGLRenderer = function(options) {
- this.canvas = options.canvas || document.createElement('canvas');
- this.width = this.canvas.width;
- this.height = this.canvas.height;
- this.enabled = true;
-
- var contextCreateOptions = {
- preserveDrawingBuffer: !!options.preserveDrawingBuffer,
- alpha: false,
- depth: false,
- stencil: false,
- antialias: false
- };
-
- this.gl =
- this.canvas.getContext('webgl', contextCreateOptions) ||
- this.canvas.getContext('experimental-webgl', contextCreateOptions);
-
- if (!this.gl) {
- throw new Error('Failed to get WebGL Context');
- }
-
- var gl = this.gl;
- var vertexAttr = null;
-
- // Init buffers
- var vertexBuffer = gl.createBuffer();
- var vertexCoords = new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]);
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- gl.bufferData(gl.ARRAY_BUFFER, vertexCoords, gl.STATIC_DRAW);
-
- // Setup the main YCrCbToRGBA shader
- this.program = this.createProgram(
- WebGLRenderer.SHADER.VERTEX_IDENTITY,
- WebGLRenderer.SHADER.FRAGMENT_YCRCB_TO_RGBA
- );
- vertexAttr = gl.getAttribLocation(this.program, 'vertex');
- gl.enableVertexAttribArray(vertexAttr);
- gl.vertexAttribPointer(vertexAttr, 2, gl.FLOAT, false, 0, 0);
-
- this.textureY = this.createTexture(0, 'textureY');
- this.textureCb = this.createTexture(1, 'textureCb');
- this.textureCr = this.createTexture(2, 'textureCr');
-
-
- // Setup the loading animation shader
- this.loadingProgram = this.createProgram(
- WebGLRenderer.SHADER.VERTEX_IDENTITY,
- WebGLRenderer.SHADER.FRAGMENT_LOADING
- );
- vertexAttr = gl.getAttribLocation(this.loadingProgram, 'vertex');
- gl.enableVertexAttribArray(vertexAttr);
- gl.vertexAttribPointer(vertexAttr, 2, gl.FLOAT, false, 0, 0);
-
- this.shouldCreateUnclampedViews = !this.allowsClampedTextureData();
- };
-
- WebGLRenderer.prototype.resize = function(width, height) {
- this.width = width|0;
- this.height = height|0;
-
- this.canvas.width = this.width;
- this.canvas.height = this.height;
-
- this.gl.useProgram(this.program);
- this.gl.viewport(0, 0, this.width, this.height);
- };
-
- WebGLRenderer.prototype.createTexture = function(index, name) {
- var gl = this.gl;
- var texture = gl.createTexture();
-
- gl.bindTexture(gl.TEXTURE_2D, 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);
- gl.uniform1i(gl.getUniformLocation(this.program, name), index);
-
- return texture;
- };
-
- WebGLRenderer.prototype.createProgram = function(vsh, fsh) {
- var gl = this.gl;
- var program = gl.createProgram();
-
- gl.attachShader(program, this.compileShader(gl.VERTEX_SHADER, vsh));
- gl.attachShader(program, this.compileShader(gl.FRAGMENT_SHADER, fsh));
- gl.linkProgram(program);
- gl.useProgram(program);
-
- return program;
- };
-
- WebGLRenderer.prototype.compileShader = function(type, source) {
- var gl = this.gl;
- var shader = gl.createShader(type);
- gl.shaderSource(shader, source);
- gl.compileShader(shader);
-
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
- throw new Error(gl.getShaderInfoLog(shader));
- }
-
- return shader;
- };
-
- WebGLRenderer.prototype.allowsClampedTextureData = function() {
- var gl = this.gl;
- var texture = gl.createTexture();
-
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(
- gl.TEXTURE_2D, 0, gl.LUMINANCE, 1, 1, 0,
- gl.LUMINANCE, gl.UNSIGNED_BYTE, new Uint8ClampedArray([0])
- );
- return (gl.getError() === 0);
- };
-
- WebGLRenderer.prototype.renderProgress = function(progress) {
- var gl = this.gl;
- var loc = gl.getUniformLocation(this.loadingProgram, 'progress');
- gl.uniform1f(loc, progress);
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
- };
-
- WebGLRenderer.prototype.render = function(y, cb, cr) {
- if (!this.enabled) {
- return;
- }
-
- var gl = this.gl;
- var w = ((this.width + 15) >> 4) << 4,
- h = this.height,
- w2 = w >> 1,
- h2 = h >> 1;
-
- // In some browsers WebGL doesn't like Uint8ClampedArrays (this is a bug
- // and should be fixed soon-ish), so we have to create a Uint8Array view
- // for each plane.
- if (this.shouldCreateUnclampedViews) {
- y = new Uint8Array(y.buffer),
- cb = new Uint8Array(cb.buffer),
- cr = new Uint8Array(cr.buffer);
- }
-
- this.updateTexture(gl.TEXTURE0, this.textureY, w, h, y);
- this.updateTexture(gl.TEXTURE1, this.textureCb, w2, h2, cb);
- this.updateTexture(gl.TEXTURE2, this.textureCr, w2, h2, cr);
-
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
- };
-
- WebGLRenderer.prototype.updateTexture = function(unit, texture, w, h, data) {
- var gl = this.gl;
- gl.activeTexture(unit);
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(
- gl.TEXTURE_2D, 0, gl.LUMINANCE, w, h, 0,
- gl.LUMINANCE, gl.UNSIGNED_BYTE, data
- );
- }
-
- WebGLRenderer.IsSupported = function() {
- try {
- if (!window.WebGLRenderingContext) {
- return false;
- }
-
- var canvas = document.createElement('canvas');
- return !!(
- canvas.getContext('webgl') ||
- canvas.getContext('experimental-webgl')
- );
- }
- catch (err) {
- return false;
- }
- };
-
- WebGLRenderer.SHADER = {
- FRAGMENT_YCRCB_TO_RGBA: [
- 'precision mediump float;',
- 'uniform sampler2D textureY;',
- 'uniform sampler2D textureCb;',
- 'uniform sampler2D textureCr;',
- 'varying vec2 texCoord;',
-
- 'mat4 rec601 = mat4(',
- '1.16438, 0.00000, 1.59603, -0.87079,',
- '1.16438, -0.39176, -0.81297, 0.52959,',
- '1.16438, 2.01723, 0.00000, -1.08139,',
- '0, 0, 0, 1',
- ');',
-
- 'void main() {',
- 'float y = texture2D(textureY, texCoord).r;',
- 'float cb = texture2D(textureCb, texCoord).r;',
- 'float cr = texture2D(textureCr, texCoord).r;',
-
- 'gl_FragColor = vec4(y, cr, cb, 1.0) * rec601;',
- '}'
- ].join('\n'),
-
- FRAGMENT_LOADING: [
- 'precision mediump float;',
- 'uniform float progress;',
- 'varying vec2 texCoord;',
-
- 'void main() {',
- 'float c = ceil(progress-(1.0-texCoord.y));',
- 'gl_FragColor = vec4(c,c,c,1);',
- '}'
- ].join('\n'),
-
- VERTEX_IDENTITY: [
- 'attribute vec2 vertex;',
- 'varying vec2 texCoord;',
-
- 'void main() {',
- 'texCoord = vertex;',
- 'gl_Position = vec4((vertex * 2.0 - 1.0) * vec2(1, -1), 0.0, 1.0);',
- '}'
- ].join('\n')
- };
-
- return WebGLRenderer;
-
- })();
-
|