diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js index 9b7ab79..7d66b7a 100644 --- a/src/core/renderers/webgl/filters/Filter.js +++ b/src/core/renderers/webgl/filters/Filter.js @@ -1,16 +1,14 @@ -import extractUniformsFromSrc from './extractUniformsFromSrc'; +import Shader from '../../../shader/Shader'; import { uid } from '../../../utils'; import { BLEND_MODES } from '../../../const'; -const SOURCE_KEY_MAP = {}; - // let math = require('../../../math'); /** * @class * @memberof PIXI * @extends PIXI.Shader */ -class Filter +class Filter extends Shader { /** * @param {string} [vertexSrc] - The source of the vertex shader. @@ -19,45 +17,10 @@ */ constructor(vertexSrc, fragmentSrc, uniforms) { - /** - * The vertex shader. - * - * @member {string} - */ - this.vertexSrc = vertexSrc || Filter.defaultVertexSrc; - - /** - * The fragment shader. - * - * @member {string} - */ - this.fragmentSrc = fragmentSrc || Filter.defaultFragmentSrc; + super(vertexSrc, fragmentSrc, uniforms) this.blendMode = BLEND_MODES.NORMAL; - // pull out the vertex and shader uniforms if they are not specified.. - // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); - - this.uniforms = {}; - - for (const i in this.uniformData) - { - this.uniforms[i] = this.uniformData[i].value; - } - - // this is where we store shader references.. - // TODO we could cache this! - this.glShaders = {}; - - // used for cacheing.. sure there is a better way! - if (!SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]) - { - SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc] = uid(); - } - - this.glShaderKey = SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]; - /** * The padding of the filter. Some filters require extra space to breath such as a blur. * Increasing this will add extra width and height to the bounds of the object that the @@ -102,66 +65,6 @@ // or just do a regular render.. } - - /** - * The default vertex shader source - * - * @static - * @constant - */ - static get defaultVertexSrc() - { - return [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - - 'uniform mat3 projectionMatrix;', - 'uniform mat3 filterMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying vec2 vFilterCoord;', - - 'void main(void){', - ' gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', - ' vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;', - ' vTextureCoord = aTextureCoord ;', - '}', - ].join('\n'); - } - - /** - * The default fragment shader source - * - * @static - * @constant - */ - static get defaultFragmentSrc() - { - return [ - 'varying vec2 vTextureCoord;', - 'varying vec2 vFilterCoord;', - - 'uniform sampler2D uSampler;', - 'uniform sampler2D filterSampler;', - - 'void main(void){', - ' vec4 masky = texture2D(filterSampler, vFilterCoord);', - ' vec4 sample = texture2D(uSampler, vTextureCoord);', - ' vec4 color;', - ' if(mod(vFilterCoord.x, 1.0) > 0.5)', - ' {', - ' color = vec4(1.0, 0.0, 0.0, 1.0);', - ' }', - ' else', - ' {', - ' color = vec4(0.0, 1.0, 0.0, 1.0);', - ' }', - // ' gl_FragColor = vec4(mod(vFilterCoord.x, 1.5), vFilterCoord.y,0.0,1.0);', - ' gl_FragColor = mix(sample, masky, 0.5);', - ' gl_FragColor *= sample.a;', - '}', - ].join('\n'); - } } export default Filter; diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js index 9b7ab79..7d66b7a 100644 --- a/src/core/renderers/webgl/filters/Filter.js +++ b/src/core/renderers/webgl/filters/Filter.js @@ -1,16 +1,14 @@ -import extractUniformsFromSrc from './extractUniformsFromSrc'; +import Shader from '../../../shader/Shader'; import { uid } from '../../../utils'; import { BLEND_MODES } from '../../../const'; -const SOURCE_KEY_MAP = {}; - // let math = require('../../../math'); /** * @class * @memberof PIXI * @extends PIXI.Shader */ -class Filter +class Filter extends Shader { /** * @param {string} [vertexSrc] - The source of the vertex shader. @@ -19,45 +17,10 @@ */ constructor(vertexSrc, fragmentSrc, uniforms) { - /** - * The vertex shader. - * - * @member {string} - */ - this.vertexSrc = vertexSrc || Filter.defaultVertexSrc; - - /** - * The fragment shader. - * - * @member {string} - */ - this.fragmentSrc = fragmentSrc || Filter.defaultFragmentSrc; + super(vertexSrc, fragmentSrc, uniforms) this.blendMode = BLEND_MODES.NORMAL; - // pull out the vertex and shader uniforms if they are not specified.. - // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); - - this.uniforms = {}; - - for (const i in this.uniformData) - { - this.uniforms[i] = this.uniformData[i].value; - } - - // this is where we store shader references.. - // TODO we could cache this! - this.glShaders = {}; - - // used for cacheing.. sure there is a better way! - if (!SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]) - { - SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc] = uid(); - } - - this.glShaderKey = SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]; - /** * The padding of the filter. Some filters require extra space to breath such as a blur. * Increasing this will add extra width and height to the bounds of the object that the @@ -102,66 +65,6 @@ // or just do a regular render.. } - - /** - * The default vertex shader source - * - * @static - * @constant - */ - static get defaultVertexSrc() - { - return [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - - 'uniform mat3 projectionMatrix;', - 'uniform mat3 filterMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying vec2 vFilterCoord;', - - 'void main(void){', - ' gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', - ' vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;', - ' vTextureCoord = aTextureCoord ;', - '}', - ].join('\n'); - } - - /** - * The default fragment shader source - * - * @static - * @constant - */ - static get defaultFragmentSrc() - { - return [ - 'varying vec2 vTextureCoord;', - 'varying vec2 vFilterCoord;', - - 'uniform sampler2D uSampler;', - 'uniform sampler2D filterSampler;', - - 'void main(void){', - ' vec4 masky = texture2D(filterSampler, vFilterCoord);', - ' vec4 sample = texture2D(uSampler, vTextureCoord);', - ' vec4 color;', - ' if(mod(vFilterCoord.x, 1.0) > 0.5)', - ' {', - ' color = vec4(1.0, 0.0, 0.0, 1.0);', - ' }', - ' else', - ' {', - ' color = vec4(0.0, 1.0, 0.0, 1.0);', - ' }', - // ' gl_FragColor = vec4(mod(vFilterCoord.x, 1.5), vFilterCoord.y,0.0,1.0);', - ' gl_FragColor = mix(sample, masky, 0.5);', - ' gl_FragColor *= sample.a;', - '}', - ].join('\n'); - } } export default Filter; diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js new file mode 100644 index 0000000..9666db0 --- /dev/null +++ b/src/core/shader/Shader.js @@ -0,0 +1,108 @@ +import extractUniformsFromSrc from './extractUniformsFromSrc'; + +// let math = require('../../../math'); +/** + * @class + * @memberof PIXI + * @extends PIXI.Shader + */ +class Shader +{ + /** + * @param {string} [vertexSrc] - The source of the vertex shader. + * @param {string} [fragmentSrc] - The source of the fragment shader. + * @param {object} [uniforms] - Custom uniforms to use to augment the built-in ones. + */ + constructor(vertexSrc, fragmentSrc, uniforms) + { + /** + * The vertex shader. + * + * @member {string} + */ + this.vertexSrc = vertexSrc || Shader.defaultVertexSrc; + + /** + * The fragment shader. + * + * @member {string} + */ + this.fragmentSrc = fragmentSrc || Shader.defaultFragmentSrc; + + // pull out the vertex and shader uniforms if they are not specified.. + // currently this does not extract structs only default types + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + + this.uniforms = {}; + + for (const i in this.uniformData) + { + this.uniforms[i] = this.uniformData[i].value; + } + + // this is where we store shader references.. + // TODO we could cache this! + this.glShaders = {}; + } + + /** + * The default vertex shader source + * + * @static + * @constant + */ + static get defaultVertexSrc() + { + return [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + + 'uniform mat3 projectionMatrix;', + 'uniform mat3 filterMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying vec2 vFilterCoord;', + + 'void main(void){', + ' gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', + ' vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;', + ' vTextureCoord = aTextureCoord ;', + '}', + ].join('\n'); + } + + /** + * The default fragment shader source + * + * @static + * @constant + */ + static get defaultFragmentSrc() + { + return [ + 'varying vec2 vTextureCoord;', + 'varying vec2 vFilterCoord;', + + 'uniform sampler2D uSampler;', + 'uniform sampler2D filterSampler;', + + 'void main(void){', + ' vec4 masky = texture2D(filterSampler, vFilterCoord);', + ' vec4 sample = texture2D(uSampler, vTextureCoord);', + ' vec4 color;', + ' if(mod(vFilterCoord.x, 1.0) > 0.5)', + ' {', + ' color = vec4(1.0, 0.0, 0.0, 1.0);', + ' }', + ' else', + ' {', + ' color = vec4(0.0, 1.0, 0.0, 1.0);', + ' }', + ' gl_FragColor = mix(sample, masky, 0.5);', + ' gl_FragColor *= sample.a;', + '}', + ].join('\n'); + } +} + +export default Shader; diff --git a/src/core/renderers/webgl/filters/Filter.js b/src/core/renderers/webgl/filters/Filter.js index 9b7ab79..7d66b7a 100644 --- a/src/core/renderers/webgl/filters/Filter.js +++ b/src/core/renderers/webgl/filters/Filter.js @@ -1,16 +1,14 @@ -import extractUniformsFromSrc from './extractUniformsFromSrc'; +import Shader from '../../../shader/Shader'; import { uid } from '../../../utils'; import { BLEND_MODES } from '../../../const'; -const SOURCE_KEY_MAP = {}; - // let math = require('../../../math'); /** * @class * @memberof PIXI * @extends PIXI.Shader */ -class Filter +class Filter extends Shader { /** * @param {string} [vertexSrc] - The source of the vertex shader. @@ -19,45 +17,10 @@ */ constructor(vertexSrc, fragmentSrc, uniforms) { - /** - * The vertex shader. - * - * @member {string} - */ - this.vertexSrc = vertexSrc || Filter.defaultVertexSrc; - - /** - * The fragment shader. - * - * @member {string} - */ - this.fragmentSrc = fragmentSrc || Filter.defaultFragmentSrc; + super(vertexSrc, fragmentSrc, uniforms) this.blendMode = BLEND_MODES.NORMAL; - // pull out the vertex and shader uniforms if they are not specified.. - // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); - - this.uniforms = {}; - - for (const i in this.uniformData) - { - this.uniforms[i] = this.uniformData[i].value; - } - - // this is where we store shader references.. - // TODO we could cache this! - this.glShaders = {}; - - // used for cacheing.. sure there is a better way! - if (!SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]) - { - SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc] = uid(); - } - - this.glShaderKey = SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]; - /** * The padding of the filter. Some filters require extra space to breath such as a blur. * Increasing this will add extra width and height to the bounds of the object that the @@ -102,66 +65,6 @@ // or just do a regular render.. } - - /** - * The default vertex shader source - * - * @static - * @constant - */ - static get defaultVertexSrc() - { - return [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - - 'uniform mat3 projectionMatrix;', - 'uniform mat3 filterMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying vec2 vFilterCoord;', - - 'void main(void){', - ' gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', - ' vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;', - ' vTextureCoord = aTextureCoord ;', - '}', - ].join('\n'); - } - - /** - * The default fragment shader source - * - * @static - * @constant - */ - static get defaultFragmentSrc() - { - return [ - 'varying vec2 vTextureCoord;', - 'varying vec2 vFilterCoord;', - - 'uniform sampler2D uSampler;', - 'uniform sampler2D filterSampler;', - - 'void main(void){', - ' vec4 masky = texture2D(filterSampler, vFilterCoord);', - ' vec4 sample = texture2D(uSampler, vTextureCoord);', - ' vec4 color;', - ' if(mod(vFilterCoord.x, 1.0) > 0.5)', - ' {', - ' color = vec4(1.0, 0.0, 0.0, 1.0);', - ' }', - ' else', - ' {', - ' color = vec4(0.0, 1.0, 0.0, 1.0);', - ' }', - // ' gl_FragColor = vec4(mod(vFilterCoord.x, 1.5), vFilterCoord.y,0.0,1.0);', - ' gl_FragColor = mix(sample, masky, 0.5);', - ' gl_FragColor *= sample.a;', - '}', - ].join('\n'); - } } export default Filter; diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js new file mode 100644 index 0000000..9666db0 --- /dev/null +++ b/src/core/shader/Shader.js @@ -0,0 +1,108 @@ +import extractUniformsFromSrc from './extractUniformsFromSrc'; + +// let math = require('../../../math'); +/** + * @class + * @memberof PIXI + * @extends PIXI.Shader + */ +class Shader +{ + /** + * @param {string} [vertexSrc] - The source of the vertex shader. + * @param {string} [fragmentSrc] - The source of the fragment shader. + * @param {object} [uniforms] - Custom uniforms to use to augment the built-in ones. + */ + constructor(vertexSrc, fragmentSrc, uniforms) + { + /** + * The vertex shader. + * + * @member {string} + */ + this.vertexSrc = vertexSrc || Shader.defaultVertexSrc; + + /** + * The fragment shader. + * + * @member {string} + */ + this.fragmentSrc = fragmentSrc || Shader.defaultFragmentSrc; + + // pull out the vertex and shader uniforms if they are not specified.. + // currently this does not extract structs only default types + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + + this.uniforms = {}; + + for (const i in this.uniformData) + { + this.uniforms[i] = this.uniformData[i].value; + } + + // this is where we store shader references.. + // TODO we could cache this! + this.glShaders = {}; + } + + /** + * The default vertex shader source + * + * @static + * @constant + */ + static get defaultVertexSrc() + { + return [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + + 'uniform mat3 projectionMatrix;', + 'uniform mat3 filterMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying vec2 vFilterCoord;', + + 'void main(void){', + ' gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', + ' vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;', + ' vTextureCoord = aTextureCoord ;', + '}', + ].join('\n'); + } + + /** + * The default fragment shader source + * + * @static + * @constant + */ + static get defaultFragmentSrc() + { + return [ + 'varying vec2 vTextureCoord;', + 'varying vec2 vFilterCoord;', + + 'uniform sampler2D uSampler;', + 'uniform sampler2D filterSampler;', + + 'void main(void){', + ' vec4 masky = texture2D(filterSampler, vFilterCoord);', + ' vec4 sample = texture2D(uSampler, vTextureCoord);', + ' vec4 color;', + ' if(mod(vFilterCoord.x, 1.0) > 0.5)', + ' {', + ' color = vec4(1.0, 0.0, 0.0, 1.0);', + ' }', + ' else', + ' {', + ' color = vec4(0.0, 1.0, 0.0, 1.0);', + ' }', + ' gl_FragColor = mix(sample, masky, 0.5);', + ' gl_FragColor *= sample.a;', + '}', + ].join('\n'); + } +} + +export default Shader; diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js new file mode 100644 index 0000000..e803c40 --- /dev/null +++ b/src/core/shader/extractUniformsFromSrc.js @@ -0,0 +1,58 @@ +import glCore from 'pixi-gl-core'; + +const defaultValue = glCore.shader.defaultValue; + +export default function extractUniformsFromSrc(vertexSrc, fragmentSrc, mask) +{ + const vertUniforms = extractUniformsFromString(vertexSrc, mask); + const fragUniforms = extractUniformsFromString(fragmentSrc, mask); + + return Object.assign(vertUniforms, fragUniforms); +} + +function extractUniformsFromString(string) +{ + const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); + + const uniforms = {}; + let nameSplit; + + // clean the lines a little - remove extra spaces / teabs etc + // then split along ';' + const lines = string.replace(/\s+/g, ' ') + .split(/\s*;\s*/); + + // loop through.. + for (let i = 0; i < lines.length; i++) + { + const line = lines[i].trim(); + + if (line.indexOf('uniform') > -1) + { + const splitLine = line.split(' '); + const type = splitLine[1]; + + let name = splitLine[2]; + let size = 1; + + if (name.indexOf('[') > -1) + { + // array! + nameSplit = name.split(/\[|]/); + name = nameSplit[0]; + size *= Number(nameSplit[1]); + } + + if (!name.match(maskRegex)) + { + uniforms[name] = { + value: defaultValue(type, size), + name, + type, + }; + } + } + } + + return uniforms; +}