UNPKG

tav-media

Version:

Cross platform media editing framework

189 lines (186 loc) 7.22 kB
/* eslint-disable prefer-destructuring */ export function createFrameBufferAndTexture(gl) { const texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); const targetTextureWidth = gl.canvas.width; const targetTextureHeight = gl.canvas.height; // define size and format of level 0 const level = 0; const internalFormat = gl.RGBA; const border = 0; const format = gl.RGBA; const type = gl.UNSIGNED_BYTE; const data = null; gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, targetTextureWidth, targetTextureHeight, border, format, type, data); // set the filtering so we don't need mips 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); const framebuffer = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); return { framebuffer, texture, }; } const PresentVertexShader = ` attribute vec4 a_position; attribute vec2 a_texcoord; uniform mat4 u_matrix; varying vec2 v_texcoord; void main() { gl_Position = u_matrix * a_position; v_texcoord = a_texcoord; } `; const PresentFragmentShader = ` precision mediump float; varying vec2 v_texcoord; uniform sampler2D u_texture; void main() { gl_FragColor = texture2D(u_texture, v_texcoord); } `; export function createTextureRenderer(gl) { const webPresentProgram = createProgramFromSources(gl, [PresentVertexShader, PresentFragmentShader]); const webPositionLocation = gl.getAttribLocation(webPresentProgram, 'a_position'); const webTexCoordLocation = gl.getAttribLocation(webPresentProgram, 'a_texcoord'); const webMatrixLocation = gl.getUniformLocation(webPresentProgram, 'u_matrix'); const webTextureLocation = gl.getUniformLocation(webPresentProgram, 'u_texture'); const positions = [0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1]; const texCoords = [0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1]; const positionBuffer = gl.createBuffer(); return function drawTexture(tex, width, height) { gl.viewport(0, 0, width, height); gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); const texcoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW); gl.bindTexture(gl.TEXTURE_2D, tex); gl.useProgram(webPresentProgram); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.enableVertexAttribArray(webPositionLocation); gl.vertexAttribPointer(webPositionLocation, 2, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); gl.enableVertexAttribArray(webTexCoordLocation); gl.vertexAttribPointer(webTexCoordLocation, 2, gl.FLOAT, false, 0, 0); let matrix = m4.orthographic(0, gl.canvas.width, gl.canvas.height, 0, -1, 1); matrix = m4.scale(matrix, width, height, 1); gl.uniformMatrix4fv(webMatrixLocation, false, matrix); gl.uniform1i(webTextureLocation, 0); gl.drawArrays(gl.TRIANGLES, 0, 6); }; } export function loadImageAndCreateTextureInfo(gl, url) { const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); // Fill the texture with a 1x1 blue pixel. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255])); // let's assume all images are not a power of 2 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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); const textureInfo = { width: 1, height: 1, texture: tex, }; const img = new Image(); img.addEventListener('load', () => { textureInfo.width = img.width; textureInfo.height = img.height; gl.bindTexture(gl.TEXTURE_2D, textureInfo.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); }); img.src = url; return textureInfo; } function loadShader(gl, shaderSource, shaderType) { const shader = gl.createShader(shaderType); gl.shaderSource(shader, shaderSource); gl.compileShader(shader); const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!compiled) { const lastError = gl.getShaderInfoLog(shader); console.error(`Error compiling shader: ${lastError}\n${shaderSource}`); gl.deleteShader(shader); return null; } return shader; } function createProgram(gl, shaders) { const program = gl.createProgram(); shaders.forEach((shader) => { gl.attachShader(program, shader); }); gl.linkProgram(program); const linked = gl.getProgramParameter(program, gl.LINK_STATUS); if (!linked) { const lastError = gl.getProgramInfoLog(program); console.error(`Error in program linking: ${lastError}\n${shaders.map((shader) => { const src = gl.getShaderSource(shader); const type = gl.getShaderParameter(shader, gl.SHADER_TYPE); return `${type}:\n${src}`; }).join('\n')}`); gl.deleteProgram(program); return null; } return program; } const defaultShaderType = [ 'VERTEX_SHADER', 'FRAGMENT_SHADER', ]; function createProgramFromSources(gl, shaderSources) { const shaders = []; for (let ii = 0; ii < shaderSources.length; ++ii) { shaders.push(loadShader(gl, shaderSources[ii], gl[defaultShaderType[ii]])); } return createProgram(gl, shaders); } class m4 { static orthographic(left, right, bottom, top, near, far) { const dst = new Float32Array(16); dst[0] = 2 / (right - left); dst[1] = 0; dst[2] = 0; dst[3] = 0; dst[4] = 0; dst[5] = 2 / (top - bottom); dst[6] = 0; dst[7] = 0; dst[8] = 0; dst[9] = 0; dst[10] = 2 / (far - near); dst[11] = 0; dst[12] = (left + right) / (left - right); dst[13] = (bottom + top) / (bottom - top); dst[14] = (near + far) / (near - far); dst[15] = 1; return dst; } static scale(m, sx, sy, sz) { const dst = new Float32Array(16); dst[0] = sx * m[0 * 4 + 0]; dst[1] = sx * m[0 * 4 + 1]; dst[2] = sx * m[0 * 4 + 2]; dst[3] = sx * m[0 * 4 + 3]; dst[4] = sy * m[1 * 4 + 0]; dst[5] = sy * m[1 * 4 + 1]; dst[6] = sy * m[1 * 4 + 2]; dst[7] = sy * m[1 * 4 + 3]; dst[8] = sz * m[2 * 4 + 0]; dst[9] = sz * m[2 * 4 + 1]; dst[10] = sz * m[2 * 4 + 2]; dst[11] = sz * m[2 * 4 + 3]; dst[12] = m[12]; dst[13] = m[13]; dst[14] = m[14]; dst[15] = m[15]; return dst; } }