diff --git a/src/pixi/renderers/webgl/PixiShader.js b/src/pixi/renderers/webgl/PixiShader.js index 2cce59c..3b4ceb9 100644 --- a/src/pixi/renderers/webgl/PixiShader.js +++ b/src/pixi/renderers/webgl/PixiShader.js @@ -32,7 +32,7 @@ */ this.textureCount = 0; -} +}; /** * @method PIXI.PixiShader#init @@ -49,7 +49,7 @@ this.uSampler = gl.getUniformLocation(program, "uSampler"); this.projectionVector = gl.getUniformLocation(program, "projectionVector"); this.offsetVector = gl.getUniformLocation(program, "offsetVector"); - //this.dimensions = gl.getUniformLocation(this.program, "dimensions"); + this.dimensions = gl.getUniformLocation(program, "dimensions"); // get and store the attributes this.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); @@ -62,189 +62,78 @@ // get the uniform locations.. this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key); } + + this.initUniforms(); this.program = program; -} +}; /** -* Updates the shader uniform values. +* Initialises the shader uniform values. * Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/ * http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf * -* @method PIXI.PixiShader#syncUniforms +* @method PIXI.PixiShader#initUniforms */ -PIXI.PixiShader.prototype.syncUniforms = function() +PIXI.PixiShader.prototype.initUniforms = function() { this.textureCount = 1; - var gl = PIXI.gl; + var uniform; for (var key in this.uniforms) { - var type = this.uniforms[key].type; - var transpose = false; + var uniform = this.uniforms[key]; + var type = uniform.type; - if (this.uniforms[key].transpose) + if (type == 'sampler2D') { - transpose = this.uniforms[key].transpose; - } + uniform._init = false; - if (type == "1f") - { - // void uniform1f(WebGLUniformLocation? location, GLfloat x); - gl.uniform1f(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "1fv") - { - // void uniform1fv(WebGLUniformLocation? location, Float32Array v); - // void uniform1fv(WebGLUniformLocation? location, sequence v); - gl.uniform1fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "1i") - { - // void uniform1i(WebGLUniformLocation? location, GLint x); - gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "1iv") - { - // void uniform1iv(WebGLUniformLocation? location, Int32Array v); - // void uniform1iv(WebGLUniformLocation? location, sequence v); - gl.uniform1i(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "2f") - { - // void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y); - gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); - } - else if (type == "2fv") - { - // void uniform2fv(WebGLUniformLocation? location, Float32Array v); - // void uniform2fv(WebGLUniformLocation? location, sequence v); - gl.uniform2fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "2i") - { - // void uniform2i(WebGLUniformLocation? location, GLint x, GLint y); - gl.uniform2i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); - } - else if (type == "2iv") - { - // void uniform2iv(WebGLUniformLocation? location, Int32Array v); - // void uniform2iv(WebGLUniformLocation? location, sequence v); - gl.uniform2iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "3f") - { - // void uniform3f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z); - gl.uniform3f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); - } - else if (type == "3fv") - { - // void uniform3fv(WebGLUniformLocation? location, Float32Array v); - // void uniform3fv(WebGLUniformLocation? location, sequence v); - gl.uniform3fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "3i") - { - // void uniform3i(WebGLUniformLocation? location, GLint x, GLint y, GLint z); - gl.uniform3i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); - } - else if (type == "3iv") - { - // void uniform3iv(WebGLUniformLocation? location, Int32Array v); - // void uniform3iv(WebGLUniformLocation? location, sequence v); - gl.uniform3iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "4f") - { - // void uniform4f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - gl.uniform4f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); - } - else if (type == "4fv") - { - // void uniform4fv(WebGLUniformLocation? location, Float32Array v); - // void uniform4fv(WebGLUniformLocation? location, sequence v); - gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "4i") - { - // void uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w); - gl.uniform4i(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z, this.uniforms[key].value.w); - } - else if (type == "4iv") - { - // void uniform4iv(WebGLUniformLocation? location, Int32Array v); - // void uniform4iv(WebGLUniformLocation? location, sequence v); - gl.uniform4iv(this.uniforms[key].uniformLocation, this.uniforms[key].value); - } - else if (type == "mat2") - { - // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); - // void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); - gl.uniformMatrix2fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); - } - else if (type == "mat3") - { - // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); - // void uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); - gl.uniformMatrix3fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); - } - else if (type == "mat4") - { - // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value); - // void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, sequence value); - gl.uniformMatrix4fv(this.uniforms[key].uniformLocation, transpose, this.uniforms[key].value); - } - else if (type == "sampler2D") - { - if (this.uniforms[key].value && this.uniforms[key].value.baseTexture.hasLoaded) + if (uniform.value !== null) { - var texture = this.uniforms[key].value.baseTexture._glTexture; - var image = this.uniforms[key].value.baseTexture.source; - var format = gl.RGBA; + this.initSampler2D(uniform); + } + } + else if (type == 'mat2' || type == 'mat3' || type == 'mat4') + { + // These require special handling + uniform.glMatrix = true; + uniform.glValueLength = 1; - if (this.uniforms[key].format && this.uniforms[key].format == 'luminance') - { - format = gl.LUMINANCE; - } + if (type == 'mat2') + { + uniform.glFunc = PIXI.gl.uniformMatrix2fv; + } + else if (type == 'mat3') + { + uniform.glFunc = PIXI.gl.uniformMatrix3fv; + } + else if (type == 'mat4') + { + uniform.glFunc = PIXI.gl.uniformMatrix4fv; + } + } + else + { + // GL function reference + uniform.glFunc = PIXI.gl['uniform' + type]; - gl.activeTexture(gl['TEXTURE' + this.textureCount]); - - if (this.uniforms[key].wrap) - { - if (this.uniforms[key].wrap == 'no-repeat' || this.uniforms[key].wrap === false) - { - this.createGLTextureLinear(gl, image, texture); - } - else if (this.uniforms[key].wrap == 'repeat' || this.uniforms[key].wrap === true) - { - this.createGLTexture(gl, image, format, texture); - } - else if (this.uniforms[key].wrap == 'nearest-repeat') - { - this.createGLTextureNearestRepeat(gl, image, texture); - } - else if (this.uniforms[key].wrap == 'nearest') - { - this.createGLTextureNearest(gl, image, texture); - } - else if (this.uniforms[key].wrap == 'audio') - { - this.createAudioTexture(gl, texture); - } - else if (this.uniforms[key].wrap == 'keyboard') - { - this.createKeyboardTexture(gl, texture); - } - } - else - { - this.createGLTextureLinear(gl, image, texture); - } - - gl.uniform1i(this.uniforms[key].uniformLocation, this.textureCount); - - this.textureCount++; + if (type == '2f' || type == '2i') + { + uniform.glValueLength = 2; + } + else if (type == '3f' || type == '3i') + { + uniform.glValueLength = 3; + } + else if (type == '4f' || type == '4i') + { + uniform.glValueLength = 4; + } + else + { + uniform.glValueLength = 1; } } } @@ -252,99 +141,133 @@ }; /** -* Binds the given texture and image data. The texture is set to REPEAT. -* Code based on Effects.js from ShaderToy.com -* @method PIXI.PixiShader#createGLTexture +* Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture is has loaded) +* +* @method PIXI.PixiShader#initSampler2D */ -PIXI.PixiShader.prototype.createGLTexture = function(gl, image, format, texture) +PIXI.PixiShader.prototype.initSampler2D = function(uniform) { - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, image); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - gl.generateMipmap(gl.TEXTURE_2D); -} + if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded) + { + return; + } + + PIXI.gl.activeTexture(PIXI.gl['TEXTURE' + this.textureCount]); + PIXI.gl.bindTexture(PIXI.gl.TEXTURE_2D, uniform.value.baseTexture._glTexture); + + // Extended texture data + if (uniform.textureData) + { + var data = uniform.textureData; + + // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D); + // GLTextureLinear = mag/min linear, wrap clamp + // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat + // GLTextureNearest = mag/min nearest, wrap clamp + // AudioTexture = whatever + luminance + width 512, height 2, border 0 + // KeyTexture = whatever + luminance + width 256, height 2, border 0 + + // magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST + // wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT + + var magFilter = (data.magFilter) ? data.magFilter : PIXI.gl.LINEAR; + var minFilter = (data.minFilter) ? data.minFilter : PIXI.gl.LINEAR; + var wrapS = (data.wrapS) ? data.wrapS : PIXI.gl.CLAMP_TO_EDGE; + var wrapT = (data.wrapT) ? data.wrapT : PIXI.gl.CLAMP_TO_EDGE; + var format = (data.luminance) ? PIXI.gl.LUMINANCE : PIXI.gl.RGBA; + + if (data.repeat) + { + wrapS = PIXI.gl.REPEAT; + wrapT = PIXI.gl.REPEAT; + } + + PIXI.gl.pixelStorei(PIXI.gl.UNPACK_FLIP_Y_WEBGL, false); + + if (data.width) + { + var width = (data.width) ? data.width : 512; + var height = (data.height) ? data.height : 2; + var border = (data.border) ? data.border : 0; + + // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels); + PIXI.gl.texImage2D(PIXI.gl.TEXTURE_2D, 0, format, width, height, border, format, PIXI.gl.UNSIGNED_BYTE, null); + } + else + { + // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels); + PIXI.gl.texImage2D(PIXI.gl.TEXTURE_2D, 0, format, PIXI.gl.RGBA, PIXI.gl.UNSIGNED_BYTE, uniform.value.baseTexture.source); + } + + PIXI.gl.texParameteri(PIXI.gl.TEXTURE_2D, PIXI.gl.TEXTURE_MAG_FILTER, magFilter); + PIXI.gl.texParameteri(PIXI.gl.TEXTURE_2D, PIXI.gl.TEXTURE_MIN_FILTER, minFilter); + PIXI.gl.texParameteri(PIXI.gl.TEXTURE_2D, PIXI.gl.TEXTURE_WRAP_S, wrapS); + PIXI.gl.texParameteri(PIXI.gl.TEXTURE_2D, PIXI.gl.TEXTURE_WRAP_T, wrapT); + } + + PIXI.gl.uniform1i(uniform.uniformLocation, this.textureCount); + + uniform._init = true; + + this.textureCount++; + +}; /** -* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE. -* Code based on Effects.js from ShaderToy.com -* @method PIXI.PixiShader#createGLTextureLinear +* Updates the shader uniform values. +* +* @method PIXI.PixiShader#syncUniforms */ -PIXI.PixiShader.prototype.createGLTextureLinear = function(gl, image, texture) +PIXI.PixiShader.prototype.syncUniforms = function() { - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - 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); -} + this.textureCount = 1; + var uniform; -/** -* Binds the given texture and image data. The texture is set to REPEAT with NEAREST. -* Code based on Effects.js from ShaderToy.com -* @method PIXI.PixiShader#createGLTextureNearestRepeat -*/ -PIXI.PixiShader.prototype.createGLTextureNearestRepeat = function(gl, image, texture) -{ - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - 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.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); -} + // This would probably be faster in an array and it would guarantee key order + for (var key in this.uniforms) + { + uniform = this.uniforms[key]; -/** -* Binds the given texture and image data. The texture is set to CLAMP_TO_EDGE with NEAREST. -* Code based on Effects.js from ShaderToy.com -* @method PIXI.PixiShader#createGLTextureNearest -*/ -PIXI.PixiShader.prototype.createGLTextureNearest = function(gl, image, texture) -{ - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - 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); -} - -/** -* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with real-time audio data. -* Code based on Effects.js from ShaderToy.com -* @method PIXI.PixiShader#createAudioTexture -*/ -PIXI.PixiShader.prototype.createAudioTexture = function(gl, texture) -{ - 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.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 512, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); -} - -/** -* Binds the given texture data. The texture is set to CLAMP_TO_EDGE with LUMINANCE. Designed for use with keyboard input data. -* Code based on Effects.js from ShaderToy.com -* @method PIXI.PixiShader#createKeyboardTexture -*/ -PIXI.PixiShader.prototype.createKeyboardTexture = function(gl, texture) -{ - gl.bindTexture(gl.TEXTURE_2D, texture ); - 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.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 256, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); -} + if (uniform.glValueLength == 1) + { + if (uniform.glMatrix === true) + { + uniform.glFunc.call(PIXI.gl, uniform.uniformLocation, uniform.transpose, uniform.value); + } + else + { + uniform.glFunc.call(PIXI.gl, uniform.uniformLocation, uniform.value); + } + } + else if (uniform.glValueLength == 2) + { + uniform.glFunc.call(PIXI.gl, uniform.uniformLocation, uniform.value.x, uniform.value.y); + } + else if (uniform.glValueLength == 3) + { + uniform.glFunc.call(PIXI.gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z); + } + else if (uniform.glValueLength == 4) + { + uniform.glFunc.call(PIXI.gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w); + } + else if (uniform.type == 'sampler2D') + { + if (uniform._init) + { + PIXI.gl.activeTexture(PIXI.gl['TEXTURE' + this.textureCount]); + PIXI.gl.bindTexture(PIXI.gl.TEXTURE_2D, uniform.value.baseTexture._glTexture); + PIXI.gl.uniform1i(uniform.uniformLocation, this.textureCount); + this.textureCount++; + } + else + { + this.initSampler2D(uniform); + } + } + } + +}; PIXI.PixiShader.defaultVertexSrc = [