| /** | |
| * Constructs a renderer object. | |
| * @param {WebGLRenderingContext} gl The GL context. | |
| * @constructor | |
| */ | |
| var Renderer = function (gl) { | |
| /** | |
| * The GL context. | |
| * @type {WebGLRenderingContext} | |
| * @private | |
| */ | |
| this.gl_ = gl; | |
| /** | |
| * The WebGLProgram. | |
| * @type {WebGLProgram} | |
| * @private | |
| */ | |
| this.program_ = gl.createProgram(); | |
| /** | |
| * @type {WebGLShader} | |
| * @private | |
| */ | |
| this.vertexShader_ = this.compileShader_( | |
| Renderer.vertexShaderSource_, gl.VERTEX_SHADER); | |
| /** | |
| * @type {WebGLShader} | |
| * @private | |
| */ | |
| this.fragmentShader_ = this.compileShader_( | |
| Renderer.fragmentShaderSource_, gl.FRAGMENT_SHADER); | |
| /** | |
| * Cached uniform locations. | |
| * @type {Object.<string, WebGLUniformLocation>} | |
| * @private | |
| */ | |
| this.uniformLocations_ = {}; | |
| /** | |
| * Cached attribute locations. | |
| * @type {Object.<string, WebGLActiveInfo>} | |
| * @private | |
| */ | |
| this.attribLocations_ = {}; | |
| /** | |
| * A vertex buffer containing a single quad with xy coordinates from [-1,-1] | |
| * to [1,1] and uv coordinates from [0,0] to [1,1]. | |
| * @private | |
| */ | |
| this.quadVertexBuffer_ = gl.createBuffer(); | |
| gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertexBuffer_); | |
| var vertices = new Float32Array( | |
| [-1.0, -1.0, 0.0, 1.0, | |
| +1.0, -1.0, 1.0, 1.0, | |
| -1.0, +1.0, 0.0, 0.0, | |
| 1.0, +1.0, 1.0, 0.0]); | |
| gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); | |
| // init shaders | |
| gl.attachShader(this.program_, this.vertexShader_); | |
| gl.attachShader(this.program_, this.fragmentShader_); | |
| gl.bindAttribLocation(this.program_, 0, 'vert'); | |
| gl.linkProgram(this.program_); | |
| gl.useProgram(this.program_); | |
| gl.enableVertexAttribArray(0); | |
| gl.enable(gl.DEPTH_TEST); | |
| gl.disable(gl.CULL_FACE); | |
| var count = gl.getProgramParameter(this.program_, gl.ACTIVE_UNIFORMS); | |
| for (var i = 0; i < /** @type {number} */(count); i++) { | |
| var info = gl.getActiveUniform(this.program_, i); | |
| var result = gl.getUniformLocation(this.program_, info.name); | |
| this.uniformLocations_[info.name] = result; | |
| } | |
| count = gl.getProgramParameter(this.program_, gl.ACTIVE_ATTRIBUTES); | |
| for (var i = 0; i < /** @type {number} */(count); i++) { | |
| var info = gl.getActiveAttrib(this.program_, i); | |
| var result = gl.getAttribLocation(this.program_, info.name); | |
| this.attribLocations_[info.name] = result; | |
| } | |
| }; | |
| Renderer.prototype.finishInit = function () { | |
| this.draw(); | |
| }; | |
| Renderer.prototype.createDxtTexture = function (dxtData, width, height, format) { | |
| var gl = this.gl_; | |
| var tex = gl.createTexture(); | |
| gl.bindTexture(gl.TEXTURE_2D, tex); | |
| gl.compressedTexImage2D( | |
| gl.TEXTURE_2D, | |
| 0, | |
| format, | |
| width, | |
| height, | |
| 0, | |
| dxtData); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
| 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.bindTexture(gl.TEXTURE_2D, null); | |
| return tex; | |
| }; | |
| Renderer.prototype.createCompressedTexture = function (data, width, height, format) { | |
| var gl = this.gl_; | |
| var tex = gl.createTexture(); | |
| gl.bindTexture(gl.TEXTURE_2D, tex); | |
| gl.compressedTexImage2D( | |
| gl.TEXTURE_2D, | |
| 0, | |
| format, | |
| width, | |
| height, | |
| 0, | |
| data); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
| 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.bindTexture(gl.TEXTURE_2D, null); | |
| return tex; | |
| }; | |
| Renderer.prototype.createHalfRGBATexture = function (data, width, height, format) { | |
| var gl = this.gl_; | |
| var tex = gl.createTexture(); | |
| gl.bindTexture(gl.TEXTURE_2D, tex); | |
| gl.texImage2D( | |
| gl.TEXTURE_2D, | |
| 0, | |
| gl.RGBA, | |
| width, | |
| height, | |
| 0, | |
| gl.RGBA, | |
| format, | |
| data); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
| 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.bindTexture(gl.TEXTURE_2D, null); | |
| return tex; | |
| }; | |
| Renderer.prototype.createRgb565Texture = function (rgb565Data, width, height) { | |
| var gl = this.gl_; | |
| var tex = gl.createTexture(); | |
| gl.bindTexture(gl.TEXTURE_2D, tex); | |
| gl.texImage2D( | |
| gl.TEXTURE_2D, | |
| 0, | |
| gl.RGB, | |
| width, | |
| height, | |
| 0, | |
| gl.RGB, | |
| gl.UNSIGNED_SHORT_5_6_5, | |
| rgb565Data); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
| 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.bindTexture(gl.TEXTURE_2D, null); | |
| return tex; | |
| }; | |
| Renderer.prototype.createRgbaTexture = function (rgbaData, width, height) { | |
| var gl = this.gl_; | |
| var tex = gl.createTexture(); | |
| gl.bindTexture(gl.TEXTURE_2D, tex); | |
| gl.texImage2D( | |
| gl.TEXTURE_2D, | |
| 0, | |
| gl.RGBA, | |
| width, | |
| height, | |
| 0, | |
| gl.RGBA, | |
| gl.UNSIGNED_BYTE, | |
| rgbaData); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
| 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.bindTexture(gl.TEXTURE_2D, null); | |
| return tex; | |
| }; | |
| Renderer.prototype.drawTexture = function (texture, width, height, mode, scale, linearToSRGBFlag) { | |
| var gl = this.gl_; | |
| // draw scene | |
| gl.clearColor(0, 0, 0, 1); | |
| gl.clearDepth(1.0); | |
| gl.viewport(0, 0, width, height); | |
| gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); | |
| gl.activeTexture(gl.TEXTURE0); | |
| gl.bindTexture(gl.TEXTURE_2D, texture); | |
| gl.uniform1i(this.uniformLocations_.texSampler, 0); | |
| var x = 0.0; | |
| var y = 0.0; | |
| if (mode == 1) | |
| x = 1.0; | |
| else if (mode == 2) | |
| y = 1.0; | |
| gl.uniform4f(this.uniformLocations_.control, x, y, scale, linearToSRGBFlag ? 1.0 : 0.0); | |
| gl.enableVertexAttribArray(this.attribLocations_.vert); | |
| gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertexBuffer_); | |
| gl.vertexAttribPointer(this.attribLocations_.vert, 4, gl.FLOAT, | |
| false, 0, 0); | |
| gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); | |
| }; | |
| /** | |
| * Compiles a GLSL shader and returns a WebGLShader. | |
| * @param {string} shaderSource The shader source code string. | |
| * @param {number} type Either VERTEX_SHADER or FRAGMENT_SHADER. | |
| * @return {WebGLShader} The new WebGLShader. | |
| * @private | |
| */ | |
| Renderer.prototype.compileShader_ = function (shaderSource, type) { | |
| var gl = this.gl_; | |
| var shader = gl.createShader(type); | |
| gl.shaderSource(shader, shaderSource); | |
| gl.compileShader(shader); | |
| return shader; | |
| }; | |
| /** | |
| * @type {string} | |
| * @private | |
| */ | |
| Renderer.vertexShaderSource_ = [ | |
| 'attribute vec4 vert;', | |
| 'varying vec2 v_texCoord;', | |
| 'void main() {', | |
| ' gl_Position = vec4(vert.xy, 0.0, 1.0);', | |
| ' v_texCoord = vert.zw;', | |
| '}' | |
| ].join('\n'); | |
| /** | |
| * @type {string} | |
| * @private ' gl_FragColor = texture2D(texSampler, v_texCoord);', | |
| */ | |
| Renderer.fragmentShaderSource_ = [ | |
| 'precision highp float;', | |
| 'uniform sampler2D texSampler;', | |
| 'uniform vec4 control;', | |
| 'varying vec2 v_texCoord;', | |
| // Function to convert linear RGB to sRGB | |
| 'vec3 linearToSrgb(vec3 linearRGB) {', | |
| ' vec3 srgbLow = linearRGB * 12.92;', | |
| ' vec3 srgbHigh = 1.055 * pow(linearRGB, vec3(1.0/2.4)) - 0.055;', | |
| ' return clamp(mix(srgbLow, srgbHigh, step(0.0031308, linearRGB)), 0.0, 1.0);', | |
| '}', | |
| 'void main() {', | |
| ' vec4 c;', | |
| ' c = texture2D(texSampler, v_texCoord);', | |
| ' c.rgb *= control.z;', | |
| ' if (control.x > 0.0)', | |
| ' {', | |
| ' c.w = 1.0;', | |
| ' }', | |
| ' else if (control.y > 0.0)', | |
| ' {', | |
| ' c.rgb = c.aaa; c.w = 1.0;', | |
| ' }', | |
| ' if (control.w > 0.0)', | |
| ' c.rgb = linearToSrgb(c.rgb);', | |
| ' gl_FragColor = c;', | |
| '}' | |
| ].join('\n'); |