diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/shader/generateUniformsSync.js b/src/core/shader/generateUniformsSync.js index 04180d5..d024589 100644 --- a/src/core/shader/generateUniformsSync.js +++ b/src/core/shader/generateUniformsSync.js @@ -86,7 +86,7 @@ { uniformData.${i}.value = location; gl.uniform1i(uniformData.${i}.location, location);\n; // eslint-disable-line max-len -}` +}`; } else if (data.type === 'mat3') { @@ -117,7 +117,7 @@ cacheValue[1] = value[1]; gl.uniform2f(uniformData.${i}.location, value[0], value[1]); } -}\n` +}\n`; } else { diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/shader/generateUniformsSync.js b/src/core/shader/generateUniformsSync.js index 04180d5..d024589 100644 --- a/src/core/shader/generateUniformsSync.js +++ b/src/core/shader/generateUniformsSync.js @@ -86,7 +86,7 @@ { uniformData.${i}.value = location; gl.uniform1i(uniformData.${i}.location, location);\n; // eslint-disable-line max-len -}` +}`; } else if (data.type === 'mat3') { @@ -117,7 +117,7 @@ cacheValue[1] = value[1]; gl.uniform2f(uniformData.${i}.location, value[0], value[1]); } -}\n` +}\n`; } else { diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 2adc05c..5ddff24 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,7 +1,18 @@ import * as core from '../core'; /** - * Base mesh class + * Base mesh class. + * The reason for this class is to empower you to have maximum flexbilty to render any kind of webGL you can think of. + * This class assumes a certain level of webGL knowledge. + * If you know a bit this should abstract enough away to make you life easier! + * Pretty much ALL WebGL can be broken down into the following: + * Geometry - The structure and data for the mesh. This can include anything from positions, uvs, normals, colors etc.. + * Shader - This is the shader that pixi will render the geometry with. (attributes in the shader must match the geometry!) + * Uniforms - These are the values passed to the shader when the mesh is rendered. + * As a shader can be resued accross multiple objects, it made sense to allow uniforms to exist outside of the shader + * State - This is the state of WebGL required to render the mesh. + * Through a combination of the above elements you can render anything you want, 2D or 3D! + * * @class * @extends PIXI.Container * @memberof PIXI.mesh @@ -11,6 +22,9 @@ /** * @param {PIXI.mesh.Geometry} geometry the geometry the mesh will use * @param {PIXI.Shader} shader the shader the mesh will use + * @param {Object} uniforms the uniform values that this mesh will specifically use + * (will automatically be generated of not supplied) + * @param {PIXI.State} state the state that the webGL context is required to be in to render the mesh * @param {number} drawMode the drawMode, can be any of the PIXI.DRAW_MODES consts */ constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) @@ -23,8 +37,16 @@ */ this.geometry = geometry; + /** + * the shader the mesh will use + * @type {PIXI.Shader} + */ this.shader = shader; + /** + * the webGL state the mesh requires to render + * @type {PIXI.Shader} + */ this.state = state || new core.State(); /** @@ -35,7 +57,8 @@ * @see PIXI.BLEND_MODES */ this.blendMode = core.BLEND_MODES.SCREEN; - this.state.blendMode = this.blendMode + this.state.blendMode = this.blendMode; + /** * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts * @@ -47,14 +70,19 @@ uniforms = uniforms || {}; // make sure to add required feilds - for(let i in shader.uniforms) + // if the user misses any uniforms we can add the default valujes from the shader + for (const i in shader.uniforms) { - if(uniforms[i] === undefined) + if (uniforms[i] === undefined) { uniforms[i] = shader.uniforms[i]; } } + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ this.uniforms = uniforms; /** diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/shader/generateUniformsSync.js b/src/core/shader/generateUniformsSync.js index 04180d5..d024589 100644 --- a/src/core/shader/generateUniformsSync.js +++ b/src/core/shader/generateUniformsSync.js @@ -86,7 +86,7 @@ { uniformData.${i}.value = location; gl.uniform1i(uniformData.${i}.location, location);\n; // eslint-disable-line max-len -}` +}`; } else if (data.type === 'mat3') { @@ -117,7 +117,7 @@ cacheValue[1] = value[1]; gl.uniform2f(uniformData.${i}.location, value[0], value[1]); } -}\n` +}\n`; } else { diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 2adc05c..5ddff24 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,7 +1,18 @@ import * as core from '../core'; /** - * Base mesh class + * Base mesh class. + * The reason for this class is to empower you to have maximum flexbilty to render any kind of webGL you can think of. + * This class assumes a certain level of webGL knowledge. + * If you know a bit this should abstract enough away to make you life easier! + * Pretty much ALL WebGL can be broken down into the following: + * Geometry - The structure and data for the mesh. This can include anything from positions, uvs, normals, colors etc.. + * Shader - This is the shader that pixi will render the geometry with. (attributes in the shader must match the geometry!) + * Uniforms - These are the values passed to the shader when the mesh is rendered. + * As a shader can be resued accross multiple objects, it made sense to allow uniforms to exist outside of the shader + * State - This is the state of WebGL required to render the mesh. + * Through a combination of the above elements you can render anything you want, 2D or 3D! + * * @class * @extends PIXI.Container * @memberof PIXI.mesh @@ -11,6 +22,9 @@ /** * @param {PIXI.mesh.Geometry} geometry the geometry the mesh will use * @param {PIXI.Shader} shader the shader the mesh will use + * @param {Object} uniforms the uniform values that this mesh will specifically use + * (will automatically be generated of not supplied) + * @param {PIXI.State} state the state that the webGL context is required to be in to render the mesh * @param {number} drawMode the drawMode, can be any of the PIXI.DRAW_MODES consts */ constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) @@ -23,8 +37,16 @@ */ this.geometry = geometry; + /** + * the shader the mesh will use + * @type {PIXI.Shader} + */ this.shader = shader; + /** + * the webGL state the mesh requires to render + * @type {PIXI.Shader} + */ this.state = state || new core.State(); /** @@ -35,7 +57,8 @@ * @see PIXI.BLEND_MODES */ this.blendMode = core.BLEND_MODES.SCREEN; - this.state.blendMode = this.blendMode + this.state.blendMode = this.blendMode; + /** * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts * @@ -47,14 +70,19 @@ uniforms = uniforms || {}; // make sure to add required feilds - for(let i in shader.uniforms) + // if the user misses any uniforms we can add the default valujes from the shader + for (const i in shader.uniforms) { - if(uniforms[i] === undefined) + if (uniforms[i] === undefined) { uniforms[i] = shader.uniforms[i]; } } + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ this.uniforms = uniforms; /** diff --git a/src/mesh/geometry/Buffer.js b/src/mesh/geometry/Buffer.js index c8b5f56..2a42938 100644 --- a/src/mesh/geometry/Buffer.js +++ b/src/mesh/geometry/Buffer.js @@ -1,39 +1,32 @@ let UID = 0; +/* eslint-disable max-len */ + /** - * Helper class to create a webGL buffer + * A wrapper for data so that it can be used and uploaded by webGL * * @class - * @memberof PIXI.glCore - * @param gl {WebGLRenderingContext} The current WebGL rendering context - * @param type {gl.ARRAY_BUFFER | gl.ELEMENT_ARRAY_BUFFER} @mat - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data - * @param drawType {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} + * @memberof PIXI */ export default class Buffer { + /** + * @param {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the data to store in the buffer. + */ constructor(data) { /** - * The type of the buffer - * - * @member {gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER} - */ - // this.type = type || gl.ARRAY_BUFFER; - - /** - * The draw type of the buffer - * - * @member {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} - */ - // this.drawType = drawType || gl.STATIC_DRAW; - - /** * The data in the buffer, as a typed array * - * @member {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} + * @type {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the array / typedArray */ this.data = data; + /** + * A map of renderer IDs to webgl buffer + * + * @private + * @member {object} + */ this._glBuffers = []; this._updateID = 0; @@ -41,10 +34,9 @@ this.id = UID++; } + // TODO could explore flagging only a partial upload? /** - * Uploads the buffer to the GPU - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data to upload - * @param offset {Number} if only a subset of the data should be uploaded, this is the amount of data to subtract + * flags this buffer as requiring an upload to the GPU */ update() { @@ -53,7 +45,6 @@ /** * Destroys the buffer - * */ destroy() { @@ -65,12 +56,20 @@ this.data = null; } + /** + * Helper function that creates a buffer based on an array or TypedArray + * + * @static + * @param {TypedArray| Array} data the TypedArray that the buffer will store. If this is a regular Array it will be converted to a Float32Array. + * @return {PIXI.Buffer} A new Buffer based on the data provided. + */ static from(data) { - if(data instanceof Array) + if (data instanceof Array) { data = new Float32Array(data); } + return new Buffer(data); } } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/shader/generateUniformsSync.js b/src/core/shader/generateUniformsSync.js index 04180d5..d024589 100644 --- a/src/core/shader/generateUniformsSync.js +++ b/src/core/shader/generateUniformsSync.js @@ -86,7 +86,7 @@ { uniformData.${i}.value = location; gl.uniform1i(uniformData.${i}.location, location);\n; // eslint-disable-line max-len -}` +}`; } else if (data.type === 'mat3') { @@ -117,7 +117,7 @@ cacheValue[1] = value[1]; gl.uniform2f(uniformData.${i}.location, value[0], value[1]); } -}\n` +}\n`; } else { diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 2adc05c..5ddff24 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,7 +1,18 @@ import * as core from '../core'; /** - * Base mesh class + * Base mesh class. + * The reason for this class is to empower you to have maximum flexbilty to render any kind of webGL you can think of. + * This class assumes a certain level of webGL knowledge. + * If you know a bit this should abstract enough away to make you life easier! + * Pretty much ALL WebGL can be broken down into the following: + * Geometry - The structure and data for the mesh. This can include anything from positions, uvs, normals, colors etc.. + * Shader - This is the shader that pixi will render the geometry with. (attributes in the shader must match the geometry!) + * Uniforms - These are the values passed to the shader when the mesh is rendered. + * As a shader can be resued accross multiple objects, it made sense to allow uniforms to exist outside of the shader + * State - This is the state of WebGL required to render the mesh. + * Through a combination of the above elements you can render anything you want, 2D or 3D! + * * @class * @extends PIXI.Container * @memberof PIXI.mesh @@ -11,6 +22,9 @@ /** * @param {PIXI.mesh.Geometry} geometry the geometry the mesh will use * @param {PIXI.Shader} shader the shader the mesh will use + * @param {Object} uniforms the uniform values that this mesh will specifically use + * (will automatically be generated of not supplied) + * @param {PIXI.State} state the state that the webGL context is required to be in to render the mesh * @param {number} drawMode the drawMode, can be any of the PIXI.DRAW_MODES consts */ constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) @@ -23,8 +37,16 @@ */ this.geometry = geometry; + /** + * the shader the mesh will use + * @type {PIXI.Shader} + */ this.shader = shader; + /** + * the webGL state the mesh requires to render + * @type {PIXI.Shader} + */ this.state = state || new core.State(); /** @@ -35,7 +57,8 @@ * @see PIXI.BLEND_MODES */ this.blendMode = core.BLEND_MODES.SCREEN; - this.state.blendMode = this.blendMode + this.state.blendMode = this.blendMode; + /** * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts * @@ -47,14 +70,19 @@ uniforms = uniforms || {}; // make sure to add required feilds - for(let i in shader.uniforms) + // if the user misses any uniforms we can add the default valujes from the shader + for (const i in shader.uniforms) { - if(uniforms[i] === undefined) + if (uniforms[i] === undefined) { uniforms[i] = shader.uniforms[i]; } } + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ this.uniforms = uniforms; /** diff --git a/src/mesh/geometry/Buffer.js b/src/mesh/geometry/Buffer.js index c8b5f56..2a42938 100644 --- a/src/mesh/geometry/Buffer.js +++ b/src/mesh/geometry/Buffer.js @@ -1,39 +1,32 @@ let UID = 0; +/* eslint-disable max-len */ + /** - * Helper class to create a webGL buffer + * A wrapper for data so that it can be used and uploaded by webGL * * @class - * @memberof PIXI.glCore - * @param gl {WebGLRenderingContext} The current WebGL rendering context - * @param type {gl.ARRAY_BUFFER | gl.ELEMENT_ARRAY_BUFFER} @mat - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data - * @param drawType {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} + * @memberof PIXI */ export default class Buffer { + /** + * @param {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the data to store in the buffer. + */ constructor(data) { /** - * The type of the buffer - * - * @member {gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER} - */ - // this.type = type || gl.ARRAY_BUFFER; - - /** - * The draw type of the buffer - * - * @member {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} - */ - // this.drawType = drawType || gl.STATIC_DRAW; - - /** * The data in the buffer, as a typed array * - * @member {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} + * @type {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the array / typedArray */ this.data = data; + /** + * A map of renderer IDs to webgl buffer + * + * @private + * @member {object} + */ this._glBuffers = []; this._updateID = 0; @@ -41,10 +34,9 @@ this.id = UID++; } + // TODO could explore flagging only a partial upload? /** - * Uploads the buffer to the GPU - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data to upload - * @param offset {Number} if only a subset of the data should be uploaded, this is the amount of data to subtract + * flags this buffer as requiring an upload to the GPU */ update() { @@ -53,7 +45,6 @@ /** * Destroys the buffer - * */ destroy() { @@ -65,12 +56,20 @@ this.data = null; } + /** + * Helper function that creates a buffer based on an array or TypedArray + * + * @static + * @param {TypedArray| Array} data the TypedArray that the buffer will store. If this is a regular Array it will be converted to a Float32Array. + * @return {PIXI.Buffer} A new Buffer based on the data provided. + */ static from(data) { - if(data instanceof Array) + if (data instanceof Array) { data = new Float32Array(data); } + return new Buffer(data); } } diff --git a/src/mesh/geometry/Geometry.js b/src/mesh/geometry/Geometry.js index 0c2f8df..f1e090c 100644 --- a/src/mesh/geometry/Geometry.js +++ b/src/mesh/geometry/Geometry.js @@ -3,27 +3,77 @@ import GeometryStyle from './GeometryStyle'; import GeometryData from './GeometryData'; -var UID = 0; +/* eslint-disable max-len */ -class Geometry +/** + * The Geometry represents a model. It consists of two components: + * GeometryStyle - The structure of the model such as the attributes layout + * GeometryData - the data of the model - this consits of buffers. + * + * This can include anything from positions, uvs, normals, colors etc.. + * + * Geometry can be defined without passing in a style or data if required (thats how I prefer!) + * + * ```js + * let geometry = new PIXI.Geometry(); + * + * geometry.addAttribute('positions', [0, 0, 100, 0, 100, 100, 0, 100], 2); + * geometry.addAttribute('uvs', [0,0,1,0,1,1,0,1],2) + * geometry.addIndex([0,1,2,1,3,2]) + * + * ``` + * @class + * @memberof PIXI.Geometry + */ +export default class Geometry { + /** + * @param {PIXI.GeometryData} data optional structure of the model such as the attributes layout + * @param {PIXI.GeometryStyle} style optional data of the model, this consists of buffers. + */ constructor(data, style) { + /** + * the style of the geometry + * @type {PIXI.GeometryStyle} + */ this.style = style || new GeometryStyle(); + + /** + * the data of the geometry + * @type {PIXI.GeometryData} + */ this.data = data || new GeometryData(); + /** + * A map of renderer IDs to webgl VAOs + * + * @private + * @type {Array} + */ this.glVertexArrayObjects = []; - - this.id = UID++; } + /** + * + * Adds an attribute to the geometry + * + * @param {String} id - the name of the attribute (matching up to a shader) + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the attribute . You can also provide an Array and a buffer will be created from it. + * @param {Number} [size=2] the size of the attribute. If you hava 2 floats per vertex (eg position x and y) this would be 2 + * @param {Number} [stride=0] How far apart (in floats) the start of each value is. (used for interleaving data) + * @param {Number} [start=0] How far into the array to start reading values (used for interleaving data) + * @param {Boolean} [normalised=false] should the data be normalised. + * + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addAttribute(id, buffer, size = 2, stride = 0, start = 0, normalised = false) { // check if this is a buffer! if (!buffer.data) { // its an array! - if(buffer instanceof Array) + if (buffer instanceof Array) { buffer = new Float32Array(buffer); } @@ -37,45 +87,47 @@ return this; } + /** + * returns the requested attribute + * + * @param {String} id the name of the attribute required + * @return {PIXI.Attribute} the attribute requested. + */ getAttribute(id) { return this.data[this.style.attributes[id].buffer]; } + /** + * + * Adds an index buffer to the geometry + * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer. + * + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it. + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addIndex(buffer) { - if (!buffer.data) - { - // its an array! - if(buffer instanceof Array) - { - buffer = new Uint16Array(buffer); - } - - buffer = new Buffer(buffer); - } - this.data.addIndex(buffer); return this; } + /** + * returns the index buffer + * + * @return {PIXI.Buffer} the index buffer. + */ getIndex() { return this.data.indexBuffer; } + /** + * Destroys the geometry. + */ destroy() { - //TODO - this is wrong! - for (let i = 0; i < this.buffers.length; i++) - { - this.buffers[i].destroy(); - } - - this.buffers = null; - this.attributes = null; - for (let i = 0; i < this.glVertexArrayObjects.length; i++) { this.glVertexArrayObjects[i].destroy(); @@ -83,9 +135,7 @@ this.glVertexArrayObjects = null; - this.indexBuffer.destroy(); - this.indexBuffer = null; + this.data.destroy(); + this.style.destroy(); } } - -export default Geometry; diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/shader/generateUniformsSync.js b/src/core/shader/generateUniformsSync.js index 04180d5..d024589 100644 --- a/src/core/shader/generateUniformsSync.js +++ b/src/core/shader/generateUniformsSync.js @@ -86,7 +86,7 @@ { uniformData.${i}.value = location; gl.uniform1i(uniformData.${i}.location, location);\n; // eslint-disable-line max-len -}` +}`; } else if (data.type === 'mat3') { @@ -117,7 +117,7 @@ cacheValue[1] = value[1]; gl.uniform2f(uniformData.${i}.location, value[0], value[1]); } -}\n` +}\n`; } else { diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 2adc05c..5ddff24 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,7 +1,18 @@ import * as core from '../core'; /** - * Base mesh class + * Base mesh class. + * The reason for this class is to empower you to have maximum flexbilty to render any kind of webGL you can think of. + * This class assumes a certain level of webGL knowledge. + * If you know a bit this should abstract enough away to make you life easier! + * Pretty much ALL WebGL can be broken down into the following: + * Geometry - The structure and data for the mesh. This can include anything from positions, uvs, normals, colors etc.. + * Shader - This is the shader that pixi will render the geometry with. (attributes in the shader must match the geometry!) + * Uniforms - These are the values passed to the shader when the mesh is rendered. + * As a shader can be resued accross multiple objects, it made sense to allow uniforms to exist outside of the shader + * State - This is the state of WebGL required to render the mesh. + * Through a combination of the above elements you can render anything you want, 2D or 3D! + * * @class * @extends PIXI.Container * @memberof PIXI.mesh @@ -11,6 +22,9 @@ /** * @param {PIXI.mesh.Geometry} geometry the geometry the mesh will use * @param {PIXI.Shader} shader the shader the mesh will use + * @param {Object} uniforms the uniform values that this mesh will specifically use + * (will automatically be generated of not supplied) + * @param {PIXI.State} state the state that the webGL context is required to be in to render the mesh * @param {number} drawMode the drawMode, can be any of the PIXI.DRAW_MODES consts */ constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) @@ -23,8 +37,16 @@ */ this.geometry = geometry; + /** + * the shader the mesh will use + * @type {PIXI.Shader} + */ this.shader = shader; + /** + * the webGL state the mesh requires to render + * @type {PIXI.Shader} + */ this.state = state || new core.State(); /** @@ -35,7 +57,8 @@ * @see PIXI.BLEND_MODES */ this.blendMode = core.BLEND_MODES.SCREEN; - this.state.blendMode = this.blendMode + this.state.blendMode = this.blendMode; + /** * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts * @@ -47,14 +70,19 @@ uniforms = uniforms || {}; // make sure to add required feilds - for(let i in shader.uniforms) + // if the user misses any uniforms we can add the default valujes from the shader + for (const i in shader.uniforms) { - if(uniforms[i] === undefined) + if (uniforms[i] === undefined) { uniforms[i] = shader.uniforms[i]; } } + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ this.uniforms = uniforms; /** diff --git a/src/mesh/geometry/Buffer.js b/src/mesh/geometry/Buffer.js index c8b5f56..2a42938 100644 --- a/src/mesh/geometry/Buffer.js +++ b/src/mesh/geometry/Buffer.js @@ -1,39 +1,32 @@ let UID = 0; +/* eslint-disable max-len */ + /** - * Helper class to create a webGL buffer + * A wrapper for data so that it can be used and uploaded by webGL * * @class - * @memberof PIXI.glCore - * @param gl {WebGLRenderingContext} The current WebGL rendering context - * @param type {gl.ARRAY_BUFFER | gl.ELEMENT_ARRAY_BUFFER} @mat - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data - * @param drawType {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} + * @memberof PIXI */ export default class Buffer { + /** + * @param {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the data to store in the buffer. + */ constructor(data) { /** - * The type of the buffer - * - * @member {gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER} - */ - // this.type = type || gl.ARRAY_BUFFER; - - /** - * The draw type of the buffer - * - * @member {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} - */ - // this.drawType = drawType || gl.STATIC_DRAW; - - /** * The data in the buffer, as a typed array * - * @member {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} + * @type {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the array / typedArray */ this.data = data; + /** + * A map of renderer IDs to webgl buffer + * + * @private + * @member {object} + */ this._glBuffers = []; this._updateID = 0; @@ -41,10 +34,9 @@ this.id = UID++; } + // TODO could explore flagging only a partial upload? /** - * Uploads the buffer to the GPU - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data to upload - * @param offset {Number} if only a subset of the data should be uploaded, this is the amount of data to subtract + * flags this buffer as requiring an upload to the GPU */ update() { @@ -53,7 +45,6 @@ /** * Destroys the buffer - * */ destroy() { @@ -65,12 +56,20 @@ this.data = null; } + /** + * Helper function that creates a buffer based on an array or TypedArray + * + * @static + * @param {TypedArray| Array} data the TypedArray that the buffer will store. If this is a regular Array it will be converted to a Float32Array. + * @return {PIXI.Buffer} A new Buffer based on the data provided. + */ static from(data) { - if(data instanceof Array) + if (data instanceof Array) { data = new Float32Array(data); } + return new Buffer(data); } } diff --git a/src/mesh/geometry/Geometry.js b/src/mesh/geometry/Geometry.js index 0c2f8df..f1e090c 100644 --- a/src/mesh/geometry/Geometry.js +++ b/src/mesh/geometry/Geometry.js @@ -3,27 +3,77 @@ import GeometryStyle from './GeometryStyle'; import GeometryData from './GeometryData'; -var UID = 0; +/* eslint-disable max-len */ -class Geometry +/** + * The Geometry represents a model. It consists of two components: + * GeometryStyle - The structure of the model such as the attributes layout + * GeometryData - the data of the model - this consits of buffers. + * + * This can include anything from positions, uvs, normals, colors etc.. + * + * Geometry can be defined without passing in a style or data if required (thats how I prefer!) + * + * ```js + * let geometry = new PIXI.Geometry(); + * + * geometry.addAttribute('positions', [0, 0, 100, 0, 100, 100, 0, 100], 2); + * geometry.addAttribute('uvs', [0,0,1,0,1,1,0,1],2) + * geometry.addIndex([0,1,2,1,3,2]) + * + * ``` + * @class + * @memberof PIXI.Geometry + */ +export default class Geometry { + /** + * @param {PIXI.GeometryData} data optional structure of the model such as the attributes layout + * @param {PIXI.GeometryStyle} style optional data of the model, this consists of buffers. + */ constructor(data, style) { + /** + * the style of the geometry + * @type {PIXI.GeometryStyle} + */ this.style = style || new GeometryStyle(); + + /** + * the data of the geometry + * @type {PIXI.GeometryData} + */ this.data = data || new GeometryData(); + /** + * A map of renderer IDs to webgl VAOs + * + * @private + * @type {Array} + */ this.glVertexArrayObjects = []; - - this.id = UID++; } + /** + * + * Adds an attribute to the geometry + * + * @param {String} id - the name of the attribute (matching up to a shader) + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the attribute . You can also provide an Array and a buffer will be created from it. + * @param {Number} [size=2] the size of the attribute. If you hava 2 floats per vertex (eg position x and y) this would be 2 + * @param {Number} [stride=0] How far apart (in floats) the start of each value is. (used for interleaving data) + * @param {Number} [start=0] How far into the array to start reading values (used for interleaving data) + * @param {Boolean} [normalised=false] should the data be normalised. + * + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addAttribute(id, buffer, size = 2, stride = 0, start = 0, normalised = false) { // check if this is a buffer! if (!buffer.data) { // its an array! - if(buffer instanceof Array) + if (buffer instanceof Array) { buffer = new Float32Array(buffer); } @@ -37,45 +87,47 @@ return this; } + /** + * returns the requested attribute + * + * @param {String} id the name of the attribute required + * @return {PIXI.Attribute} the attribute requested. + */ getAttribute(id) { return this.data[this.style.attributes[id].buffer]; } + /** + * + * Adds an index buffer to the geometry + * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer. + * + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it. + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addIndex(buffer) { - if (!buffer.data) - { - // its an array! - if(buffer instanceof Array) - { - buffer = new Uint16Array(buffer); - } - - buffer = new Buffer(buffer); - } - this.data.addIndex(buffer); return this; } + /** + * returns the index buffer + * + * @return {PIXI.Buffer} the index buffer. + */ getIndex() { return this.data.indexBuffer; } + /** + * Destroys the geometry. + */ destroy() { - //TODO - this is wrong! - for (let i = 0; i < this.buffers.length; i++) - { - this.buffers[i].destroy(); - } - - this.buffers = null; - this.attributes = null; - for (let i = 0; i < this.glVertexArrayObjects.length; i++) { this.glVertexArrayObjects[i].destroy(); @@ -83,9 +135,7 @@ this.glVertexArrayObjects = null; - this.indexBuffer.destroy(); - this.indexBuffer = null; + this.data.destroy(); + this.style.destroy(); } } - -export default Geometry; diff --git a/src/mesh/geometry/GeometryData.js b/src/mesh/geometry/GeometryData.js index 4d988a5..290d7aa 100644 --- a/src/mesh/geometry/GeometryData.js +++ b/src/mesh/geometry/GeometryData.js @@ -1,13 +1,64 @@ +/* eslint-disable max-len */ + +/** + * GeometryData - the data of the geometry - this consits of attribute buffers and one index buffer. + * + * This can include anything from positions, uvs, normals, colors etc.. + * + * ```js + * let geometryData = new PIXI.GeometryData(); + * + * geometryData.add('positions', [0,1,0,2,3]); + * geometryData.add('uvs', [0,0,1,0,1,1,0,1]); + * geometryData.addIndex([0,1,2,1,3,2]) + * + * ``` + * @class + * @memberof PIXI.GeometryData + */ export default class GeometryData { + /** + * + */ constructor() { + /** + * an array of {PIXI.Buffer} belonging to the geometryData + * @type {Array} + */ this.buffers = []; + + /** + * the index buffer data for the geometry + * @type {PIXI.Buffer} + */ this.indexBuffer = null; } + /** + * + * Adds an buffer to the geometryData + * + * @param {String} id - the name of the buffer (matching up to a geometry style) + * @param {PIXI.Buffer} [buffer] the buffer that holds the data mapping to a geometry attribute. You can also provide an Array and a buffer will be created from it. + * + * @return {PIXI.GeometryData} returns self, useful for chaining. + */ add(id, buffer) { + // bit of duplicate code here and in geometry.. + if (!buffer.data) + { + // its an array! + if (buffer instanceof Array) + { + buffer = new Float32Array(buffer); + } + + buffer = new Buffer(buffer); + } + // only one! if (this.buffers.indexOf(buffer) === -1) { @@ -18,8 +69,27 @@ return this; } + /** + * + * Adds an index buffer to the geometryData + * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer. + * + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it. + * @return {PIXI.GeometryData} returns self, useful for chaining. + */ addIndex(buffer) { + if (!buffer.data) + { + // its an array! + if (buffer instanceof Array) + { + buffer = new Uint16Array(buffer); + } + + buffer = new Buffer(buffer); + } + buffer.index = true; this.indexBuffer = buffer; @@ -30,4 +100,20 @@ return this; } -} \ No newline at end of file + + /** + * Destroys the geometry data. + */ + destroy() + { + for (let i = 0; i < this.buffers.length; i++) + { + this.buffers[i].destroy(); + } + + this.buffers = null; + + this.indexBuffer.destroy(); + this.indexBuffer = null; + } +} diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/shader/generateUniformsSync.js b/src/core/shader/generateUniformsSync.js index 04180d5..d024589 100644 --- a/src/core/shader/generateUniformsSync.js +++ b/src/core/shader/generateUniformsSync.js @@ -86,7 +86,7 @@ { uniformData.${i}.value = location; gl.uniform1i(uniformData.${i}.location, location);\n; // eslint-disable-line max-len -}` +}`; } else if (data.type === 'mat3') { @@ -117,7 +117,7 @@ cacheValue[1] = value[1]; gl.uniform2f(uniformData.${i}.location, value[0], value[1]); } -}\n` +}\n`; } else { diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 2adc05c..5ddff24 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,7 +1,18 @@ import * as core from '../core'; /** - * Base mesh class + * Base mesh class. + * The reason for this class is to empower you to have maximum flexbilty to render any kind of webGL you can think of. + * This class assumes a certain level of webGL knowledge. + * If you know a bit this should abstract enough away to make you life easier! + * Pretty much ALL WebGL can be broken down into the following: + * Geometry - The structure and data for the mesh. This can include anything from positions, uvs, normals, colors etc.. + * Shader - This is the shader that pixi will render the geometry with. (attributes in the shader must match the geometry!) + * Uniforms - These are the values passed to the shader when the mesh is rendered. + * As a shader can be resued accross multiple objects, it made sense to allow uniforms to exist outside of the shader + * State - This is the state of WebGL required to render the mesh. + * Through a combination of the above elements you can render anything you want, 2D or 3D! + * * @class * @extends PIXI.Container * @memberof PIXI.mesh @@ -11,6 +22,9 @@ /** * @param {PIXI.mesh.Geometry} geometry the geometry the mesh will use * @param {PIXI.Shader} shader the shader the mesh will use + * @param {Object} uniforms the uniform values that this mesh will specifically use + * (will automatically be generated of not supplied) + * @param {PIXI.State} state the state that the webGL context is required to be in to render the mesh * @param {number} drawMode the drawMode, can be any of the PIXI.DRAW_MODES consts */ constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) @@ -23,8 +37,16 @@ */ this.geometry = geometry; + /** + * the shader the mesh will use + * @type {PIXI.Shader} + */ this.shader = shader; + /** + * the webGL state the mesh requires to render + * @type {PIXI.Shader} + */ this.state = state || new core.State(); /** @@ -35,7 +57,8 @@ * @see PIXI.BLEND_MODES */ this.blendMode = core.BLEND_MODES.SCREEN; - this.state.blendMode = this.blendMode + this.state.blendMode = this.blendMode; + /** * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts * @@ -47,14 +70,19 @@ uniforms = uniforms || {}; // make sure to add required feilds - for(let i in shader.uniforms) + // if the user misses any uniforms we can add the default valujes from the shader + for (const i in shader.uniforms) { - if(uniforms[i] === undefined) + if (uniforms[i] === undefined) { uniforms[i] = shader.uniforms[i]; } } + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ this.uniforms = uniforms; /** diff --git a/src/mesh/geometry/Buffer.js b/src/mesh/geometry/Buffer.js index c8b5f56..2a42938 100644 --- a/src/mesh/geometry/Buffer.js +++ b/src/mesh/geometry/Buffer.js @@ -1,39 +1,32 @@ let UID = 0; +/* eslint-disable max-len */ + /** - * Helper class to create a webGL buffer + * A wrapper for data so that it can be used and uploaded by webGL * * @class - * @memberof PIXI.glCore - * @param gl {WebGLRenderingContext} The current WebGL rendering context - * @param type {gl.ARRAY_BUFFER | gl.ELEMENT_ARRAY_BUFFER} @mat - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data - * @param drawType {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} + * @memberof PIXI */ export default class Buffer { + /** + * @param {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the data to store in the buffer. + */ constructor(data) { /** - * The type of the buffer - * - * @member {gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER} - */ - // this.type = type || gl.ARRAY_BUFFER; - - /** - * The draw type of the buffer - * - * @member {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} - */ - // this.drawType = drawType || gl.STATIC_DRAW; - - /** * The data in the buffer, as a typed array * - * @member {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} + * @type {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the array / typedArray */ this.data = data; + /** + * A map of renderer IDs to webgl buffer + * + * @private + * @member {object} + */ this._glBuffers = []; this._updateID = 0; @@ -41,10 +34,9 @@ this.id = UID++; } + // TODO could explore flagging only a partial upload? /** - * Uploads the buffer to the GPU - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data to upload - * @param offset {Number} if only a subset of the data should be uploaded, this is the amount of data to subtract + * flags this buffer as requiring an upload to the GPU */ update() { @@ -53,7 +45,6 @@ /** * Destroys the buffer - * */ destroy() { @@ -65,12 +56,20 @@ this.data = null; } + /** + * Helper function that creates a buffer based on an array or TypedArray + * + * @static + * @param {TypedArray| Array} data the TypedArray that the buffer will store. If this is a regular Array it will be converted to a Float32Array. + * @return {PIXI.Buffer} A new Buffer based on the data provided. + */ static from(data) { - if(data instanceof Array) + if (data instanceof Array) { data = new Float32Array(data); } + return new Buffer(data); } } diff --git a/src/mesh/geometry/Geometry.js b/src/mesh/geometry/Geometry.js index 0c2f8df..f1e090c 100644 --- a/src/mesh/geometry/Geometry.js +++ b/src/mesh/geometry/Geometry.js @@ -3,27 +3,77 @@ import GeometryStyle from './GeometryStyle'; import GeometryData from './GeometryData'; -var UID = 0; +/* eslint-disable max-len */ -class Geometry +/** + * The Geometry represents a model. It consists of two components: + * GeometryStyle - The structure of the model such as the attributes layout + * GeometryData - the data of the model - this consits of buffers. + * + * This can include anything from positions, uvs, normals, colors etc.. + * + * Geometry can be defined without passing in a style or data if required (thats how I prefer!) + * + * ```js + * let geometry = new PIXI.Geometry(); + * + * geometry.addAttribute('positions', [0, 0, 100, 0, 100, 100, 0, 100], 2); + * geometry.addAttribute('uvs', [0,0,1,0,1,1,0,1],2) + * geometry.addIndex([0,1,2,1,3,2]) + * + * ``` + * @class + * @memberof PIXI.Geometry + */ +export default class Geometry { + /** + * @param {PIXI.GeometryData} data optional structure of the model such as the attributes layout + * @param {PIXI.GeometryStyle} style optional data of the model, this consists of buffers. + */ constructor(data, style) { + /** + * the style of the geometry + * @type {PIXI.GeometryStyle} + */ this.style = style || new GeometryStyle(); + + /** + * the data of the geometry + * @type {PIXI.GeometryData} + */ this.data = data || new GeometryData(); + /** + * A map of renderer IDs to webgl VAOs + * + * @private + * @type {Array} + */ this.glVertexArrayObjects = []; - - this.id = UID++; } + /** + * + * Adds an attribute to the geometry + * + * @param {String} id - the name of the attribute (matching up to a shader) + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the attribute . You can also provide an Array and a buffer will be created from it. + * @param {Number} [size=2] the size of the attribute. If you hava 2 floats per vertex (eg position x and y) this would be 2 + * @param {Number} [stride=0] How far apart (in floats) the start of each value is. (used for interleaving data) + * @param {Number} [start=0] How far into the array to start reading values (used for interleaving data) + * @param {Boolean} [normalised=false] should the data be normalised. + * + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addAttribute(id, buffer, size = 2, stride = 0, start = 0, normalised = false) { // check if this is a buffer! if (!buffer.data) { // its an array! - if(buffer instanceof Array) + if (buffer instanceof Array) { buffer = new Float32Array(buffer); } @@ -37,45 +87,47 @@ return this; } + /** + * returns the requested attribute + * + * @param {String} id the name of the attribute required + * @return {PIXI.Attribute} the attribute requested. + */ getAttribute(id) { return this.data[this.style.attributes[id].buffer]; } + /** + * + * Adds an index buffer to the geometry + * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer. + * + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it. + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addIndex(buffer) { - if (!buffer.data) - { - // its an array! - if(buffer instanceof Array) - { - buffer = new Uint16Array(buffer); - } - - buffer = new Buffer(buffer); - } - this.data.addIndex(buffer); return this; } + /** + * returns the index buffer + * + * @return {PIXI.Buffer} the index buffer. + */ getIndex() { return this.data.indexBuffer; } + /** + * Destroys the geometry. + */ destroy() { - //TODO - this is wrong! - for (let i = 0; i < this.buffers.length; i++) - { - this.buffers[i].destroy(); - } - - this.buffers = null; - this.attributes = null; - for (let i = 0; i < this.glVertexArrayObjects.length; i++) { this.glVertexArrayObjects[i].destroy(); @@ -83,9 +135,7 @@ this.glVertexArrayObjects = null; - this.indexBuffer.destroy(); - this.indexBuffer = null; + this.data.destroy(); + this.style.destroy(); } } - -export default Geometry; diff --git a/src/mesh/geometry/GeometryData.js b/src/mesh/geometry/GeometryData.js index 4d988a5..290d7aa 100644 --- a/src/mesh/geometry/GeometryData.js +++ b/src/mesh/geometry/GeometryData.js @@ -1,13 +1,64 @@ +/* eslint-disable max-len */ + +/** + * GeometryData - the data of the geometry - this consits of attribute buffers and one index buffer. + * + * This can include anything from positions, uvs, normals, colors etc.. + * + * ```js + * let geometryData = new PIXI.GeometryData(); + * + * geometryData.add('positions', [0,1,0,2,3]); + * geometryData.add('uvs', [0,0,1,0,1,1,0,1]); + * geometryData.addIndex([0,1,2,1,3,2]) + * + * ``` + * @class + * @memberof PIXI.GeometryData + */ export default class GeometryData { + /** + * + */ constructor() { + /** + * an array of {PIXI.Buffer} belonging to the geometryData + * @type {Array} + */ this.buffers = []; + + /** + * the index buffer data for the geometry + * @type {PIXI.Buffer} + */ this.indexBuffer = null; } + /** + * + * Adds an buffer to the geometryData + * + * @param {String} id - the name of the buffer (matching up to a geometry style) + * @param {PIXI.Buffer} [buffer] the buffer that holds the data mapping to a geometry attribute. You can also provide an Array and a buffer will be created from it. + * + * @return {PIXI.GeometryData} returns self, useful for chaining. + */ add(id, buffer) { + // bit of duplicate code here and in geometry.. + if (!buffer.data) + { + // its an array! + if (buffer instanceof Array) + { + buffer = new Float32Array(buffer); + } + + buffer = new Buffer(buffer); + } + // only one! if (this.buffers.indexOf(buffer) === -1) { @@ -18,8 +69,27 @@ return this; } + /** + * + * Adds an index buffer to the geometryData + * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer. + * + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it. + * @return {PIXI.GeometryData} returns self, useful for chaining. + */ addIndex(buffer) { + if (!buffer.data) + { + // its an array! + if (buffer instanceof Array) + { + buffer = new Uint16Array(buffer); + } + + buffer = new Buffer(buffer); + } + buffer.index = true; this.indexBuffer = buffer; @@ -30,4 +100,20 @@ return this; } -} \ No newline at end of file + + /** + * Destroys the geometry data. + */ + destroy() + { + for (let i = 0; i < this.buffers.length; i++) + { + this.buffers[i].destroy(); + } + + this.buffers = null; + + this.indexBuffer.destroy(); + this.indexBuffer = null; + } +} diff --git a/src/mesh/geometry/GeometryStyle.js b/src/mesh/geometry/GeometryStyle.js index e626483..f18bd6b 100644 --- a/src/mesh/geometry/GeometryStyle.js +++ b/src/mesh/geometry/GeometryStyle.js @@ -1,12 +1,42 @@ +/** + * GeometryStyle represents the structure of the geometry such as the attributes layout. + * + * ```js + * let geometryStyle = new PIXI.GeometryStyle(); + * + * geometryStyle.addAttribute('positions, new PIXI.Attribute('positionBuffer', 2)); + * geometryStyle.addAttribute('uvs', new PIXI.Attribute('uvsBuffer', 2); + * + * ``` + * @class + * @memberof PIXI.GeometryStyle + */ export default class GeometryStyle { + /** + * + */ constructor() { + /** + * key-value pair contains all the attributes for this style + * + * @member {Object} + */ this.attributes = {}; - - this.indexBuffer = null; } + // TODO rename this to add? + + /** + * + * Adds an attribute to the geometryStyle + * + * @param {String} id - the name of the attribute (matching up to a shader) + * @param {PIXI.Attribute} [attribute] the Attribute that you would like to add to the style. + * + * @return {PIXI.GeometryStyle} returns self, useful for chaining. + */ addAttribute(id, attribute) { this.attributes[id] = attribute; @@ -14,13 +44,14 @@ return this; } - addIndex(buffer) - { - this.indexBuffer = buffer; - - return this; - } - + /** + * generates a map of what the locations of the attributes will be. + * All attributes locations are assigned in alphabetical order just like the {PIXI.Shader} attribute locations. + * This ensures that all geometries and shaders will be compatible if they have the same attributes. + * + * @private + * @return {object} map with key-value pairs mapping attribute names to locations (ints). + */ generateAttributeLocations() { const array = []; @@ -40,15 +71,14 @@ map[array[i]] = i; } - console.log(map) - return map; } + /** + * Destroys the geometryStyle. + */ destroy() { this.attributes = null; - - this.indexBuffer = null; } -} \ No newline at end of file +} diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index df55793..e27a954 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -31,11 +31,17 @@ this.shader = null; } + /** + * Changes the current shader to the one given in parameter + * + * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + */ bindShader(shader, dontSync) { const glShader = shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); - // if (this.shader !== shader) + if (this.shader !== shader) { this.shader = shader; this.renderer._bindGLShader(glShader); @@ -43,10 +49,15 @@ if (!dontSync) { - this.syncUniforms(glShader, shader); + this.setUniforms(shader.uniforms); } } + /** + * Uploads the uniforms values to the currently bound shader. + * + * @param {object} uniforms - the uniforms valiues that be applied to the current shader + */ setUniforms(uniforms) { const shader = this.shader; @@ -55,11 +66,24 @@ shader.syncUniforms(glShader.uniformData, uniforms, this.gl); } + /** + * Returns the underlying GLShade rof the currently bound shader. + * This can be handy for when you to have a little more control over the setting of your uniforms. + * + * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context + */ getGLShader() { - return this.shader.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader); + return this.shader.glShaders[this.renderer.CONTEXT_UID]; } + /** + * Generates a GLShader verion of the Shader provided. + * + * @private + * @param {PIXI.Shader} shader the shader that the glShader will be based on. + * @return {PIXI.glCore.GLShader} A shiney new GLShader + */ generateShader(shader) { const attribMap = {}; @@ -77,87 +101,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(glShader, shader) - { - const uniformData = shader.uniformData; - - // 0 is reserverd for the pixi texture so we start at 1! - let textureCount = 0; - - // TODO don't need to use the uniform - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniformData[i].value !== 0) - { - if (uniformData[i].value.baseTexture) - { - glShader.uniforms[i] = this.renderer.bindTexture(uniformData[i].value, textureCount, true); - } - else - { - glShader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - gl.activeTexture(gl.TEXTURE0 + textureCount); - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniformData[i].value.a !== undefined) - { - glShader.uniforms[i] = uniformData[i].value.toArray(true); - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniformData[i].value.x !== undefined) - { - const val = glShader.uniforms[i] || new Float32Array(2); - - val[0] = uniformData[i].value.x; - val[1] = uniformData[i].value.y; - glShader.uniforms[i] = val; - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else if (uniformData[i].type === 'float') - { - if (glShader.uniforms.data[i].value !== uniformData[i].value) - { - glShader.uniforms[i] = uniformData[i].value; - } - } - else - { - glShader.uniforms[i] = uniformData[i].value; - } - } - } - - /** * Destroys this manager and removes all its textures */ destroy() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index f7781fe..3ca5b5e 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -440,15 +440,24 @@ return this; } - bindShader(shader, dontSync) - { - this.shaderManager.bindShader(shader, dontSync); - } - /** * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @return {PIXI.WebGLRenderer} Returns itself. + */ + bindShader(shader, dontSync) + { + this.shaderManager.bindShader(shader, dontSync); + + return this; + } + + /** + * Changes the current GLShader to the one given in parameter + * + * @param {PIXI.glCore.Shader} shader - the new glShader * @return {PIXI.WebGLRenderer} Returns itself. */ _bindGLShader(shader) @@ -516,8 +525,7 @@ } else { - - if(this.boundTextures[location] === texture) + if (this.boundTextures[location] === texture) { return location; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 381238a..7d4b849 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -2,8 +2,6 @@ import RenderTarget from '../utils/RenderTarget'; import Quad from '../utils/Quad'; import { Rectangle } from '../../../math'; -import { GLShader } from 'pixi-gl-core'; -import { PRECISION } from '../../../const'; import * as filterTransforms from '../filters/filterTransforms'; import bitTwiddle from 'bit-twiddle'; @@ -47,7 +45,6 @@ // know about sprites! this.quad = new Quad(this.gl, renderer.state.attribState); - this.shaderCache = {}; // todo add default! this.pool = {}; @@ -139,8 +136,6 @@ // bind the render target renderer.bindRenderTarget(renderTarget); renderTarget.clear(); - - } /** @@ -217,43 +212,14 @@ const renderer = this.renderer; const gl = renderer.gl; -/* - let shader = filter.glShaders[renderer.CONTEXT_UID]; - - // cacheing.. - if (!shader) - { - if (filter.glShaderKey) - { - shader = this.shaderCache[filter.glShaderKey]; - - if (!shader) - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - - filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; - } - } - else - { - shader = new GLShader(this.gl, filter.vertexSrc, filter.fragmentSrc, PRECISION.DEFAULT); - filter.glShaders[renderer.CONTEXT_UID] = shader; - } - - // TODO - this only needs to be done once? - renderer.bindVao(null); - - this.quad.initVao(shader); - } -*/ renderer.bindShader(filter, true); // TODO theres a better way! // quad can be a mesh and we then should be able to pull this off without accessing the shader directly const shader = renderer.shaderManager.getGLShader(); -// renderer.shaderManager.upd - if(!this.firstRun) + // TODO change quad to mesh.. + if (!this.firstRun) { this.firstRun = true; renderer.bindVao(null); @@ -261,7 +227,6 @@ this.quad.initVao(shader); } - renderer.bindVao(this.quad.vao); renderer.bindRenderTarget(output); @@ -315,7 +280,6 @@ } renderer.shaderManager.setUniforms(filter.uniforms); - // this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); @@ -332,120 +296,6 @@ } /** - * Uploads the uniforms of the filter. - * - * @param {GLShader} shader - The underlying gl shader. - * @param {PIXI.Filter} filter - The filter we are synchronizing. - */ - syncUniforms(shader, filter) - { - const uniformData = filter.uniformData; - const uniforms = filter.uniforms; - - // 0 is reserved for the pixi texture so we start at 1! - let textureCount = 1; - let currentState; - - if (shader.uniforms.data.filterArea) - { - currentState = this.filterData.stack[this.filterData.index]; - const filterArea = shader.uniforms.filterArea; - - filterArea[0] = currentState.renderTarget.size.width; - filterArea[1] = currentState.renderTarget.size.height; - filterArea[2] = currentState.sourceFrame.x; - filterArea[3] = currentState.sourceFrame.y; - - shader.uniforms.filterArea = filterArea; - } - - // use this to clamp displaced texture coords so they belong to filterArea - // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) - { - currentState = this.filterData.stack[this.filterData.index]; - - const filterClamp = shader.uniforms.filterClamp; - - filterClamp[0] = 0; - filterClamp[1] = 0; - filterClamp[2] = (currentState.sourceFrame.width - 1) / currentState.renderTarget.size.width; - filterClamp[3] = (currentState.sourceFrame.height - 1) / currentState.renderTarget.size.height; - - shader.uniforms.filterClamp = filterClamp; - } - - // TODO Cacheing layer.. - for (const i in uniformData) - { - if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) - { - if (uniforms[i].baseTexture) - { - shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); - } - else - { - shader.uniforms[i] = textureCount; - - // TODO - // this is helpful as renderTargets can also be set. - // Although thinking about it, we could probably - // make the filter texture cache return a RenderTexture - // rather than a renderTarget - const gl = this.renderer.gl; - - this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; - gl.activeTexture(gl.TEXTURE0 + textureCount); - - uniforms[i].texture.bind(); - } - - textureCount++; - } - else if (uniformData[i].type === 'mat3') - { - // check if its pixi matrix.. - if (uniforms[i].a !== undefined) - { - shader.uniforms[i] = uniforms[i].toArray(true); - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'vec2') - { - // check if its a point.. - if (uniforms[i].x !== undefined) - { - const val = shader.uniforms[i] || new Float32Array(2); - - val[0] = uniforms[i].x; - val[1] = uniforms[i].y; - shader.uniforms[i] = val; - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - else if (uniformData[i].type === 'float') - { - if (shader.uniforms.data[i].value !== uniformData[i]) - { - shader.uniforms[i] = uniforms[i]; - } - } - else - { - shader.uniforms[i] = uniforms[i]; - } - } - } - - /** * Gets a render target from the pool, or creates a new one. * * @param {boolean} clear - Should we clear the render texture when we get it? diff --git a/src/core/renderers/webgl/managers/StateManager.js b/src/core/renderers/webgl/managers/StateManager.js index 157402a..8d7419f 100755 --- a/src/core/renderers/webgl/managers/StateManager.js +++ b/src/core/renderers/webgl/managers/StateManager.js @@ -160,7 +160,8 @@ /** * Sets the polygon offset. * - * @param {number} value - The blend mode to set to. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale */ setPolygonOffset(value, scale) { diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 826e1b0..76ffdae 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -45,7 +45,7 @@ // does the trick for now though! for (const i in this.uniformData) { - if(!this.uniforms[i]) + if (!this.uniforms[i]) { this.uniforms[i] = this.uniformData[i].value; } diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 8e6518b..5c618d5 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -31,7 +31,7 @@ const splitLine = line.split(' '); const startIndex = splitLine.indexOf('attribute'); - const type = splitLine[startIndex+1]; + const type = splitLine[startIndex + 1]; let name = splitLine[startIndex + 2]; let size = 1; @@ -68,7 +68,7 @@ attrib.location = i; attributes[attrib.name] = attrib; } - + return attributes; } diff --git a/src/core/shader/generateUniformsSync.js b/src/core/shader/generateUniformsSync.js index 04180d5..d024589 100644 --- a/src/core/shader/generateUniformsSync.js +++ b/src/core/shader/generateUniformsSync.js @@ -86,7 +86,7 @@ { uniformData.${i}.value = location; gl.uniform1i(uniformData.${i}.location, location);\n; // eslint-disable-line max-len -}` +}`; } else if (data.type === 'mat3') { @@ -117,7 +117,7 @@ cacheValue[1] = value[1]; gl.uniform2f(uniformData.${i}.location, value[0], value[1]); } -}\n` +}\n`; } else { diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 2adc05c..5ddff24 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,7 +1,18 @@ import * as core from '../core'; /** - * Base mesh class + * Base mesh class. + * The reason for this class is to empower you to have maximum flexbilty to render any kind of webGL you can think of. + * This class assumes a certain level of webGL knowledge. + * If you know a bit this should abstract enough away to make you life easier! + * Pretty much ALL WebGL can be broken down into the following: + * Geometry - The structure and data for the mesh. This can include anything from positions, uvs, normals, colors etc.. + * Shader - This is the shader that pixi will render the geometry with. (attributes in the shader must match the geometry!) + * Uniforms - These are the values passed to the shader when the mesh is rendered. + * As a shader can be resued accross multiple objects, it made sense to allow uniforms to exist outside of the shader + * State - This is the state of WebGL required to render the mesh. + * Through a combination of the above elements you can render anything you want, 2D or 3D! + * * @class * @extends PIXI.Container * @memberof PIXI.mesh @@ -11,6 +22,9 @@ /** * @param {PIXI.mesh.Geometry} geometry the geometry the mesh will use * @param {PIXI.Shader} shader the shader the mesh will use + * @param {Object} uniforms the uniform values that this mesh will specifically use + * (will automatically be generated of not supplied) + * @param {PIXI.State} state the state that the webGL context is required to be in to render the mesh * @param {number} drawMode the drawMode, can be any of the PIXI.DRAW_MODES consts */ constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) @@ -23,8 +37,16 @@ */ this.geometry = geometry; + /** + * the shader the mesh will use + * @type {PIXI.Shader} + */ this.shader = shader; + /** + * the webGL state the mesh requires to render + * @type {PIXI.Shader} + */ this.state = state || new core.State(); /** @@ -35,7 +57,8 @@ * @see PIXI.BLEND_MODES */ this.blendMode = core.BLEND_MODES.SCREEN; - this.state.blendMode = this.blendMode + this.state.blendMode = this.blendMode; + /** * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts * @@ -47,14 +70,19 @@ uniforms = uniforms || {}; // make sure to add required feilds - for(let i in shader.uniforms) + // if the user misses any uniforms we can add the default valujes from the shader + for (const i in shader.uniforms) { - if(uniforms[i] === undefined) + if (uniforms[i] === undefined) { uniforms[i] = shader.uniforms[i]; } } + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ this.uniforms = uniforms; /** diff --git a/src/mesh/geometry/Buffer.js b/src/mesh/geometry/Buffer.js index c8b5f56..2a42938 100644 --- a/src/mesh/geometry/Buffer.js +++ b/src/mesh/geometry/Buffer.js @@ -1,39 +1,32 @@ let UID = 0; +/* eslint-disable max-len */ + /** - * Helper class to create a webGL buffer + * A wrapper for data so that it can be used and uploaded by webGL * * @class - * @memberof PIXI.glCore - * @param gl {WebGLRenderingContext} The current WebGL rendering context - * @param type {gl.ARRAY_BUFFER | gl.ELEMENT_ARRAY_BUFFER} @mat - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data - * @param drawType {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} + * @memberof PIXI */ export default class Buffer { + /** + * @param {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the data to store in the buffer. + */ constructor(data) { /** - * The type of the buffer - * - * @member {gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER} - */ - // this.type = type || gl.ARRAY_BUFFER; - - /** - * The draw type of the buffer - * - * @member {gl.STATIC_DRAW|gl.DYNAMIC_DRAW|gl.STREAM_DRAW} - */ - // this.drawType = drawType || gl.STATIC_DRAW; - - /** * The data in the buffer, as a typed array * - * @member {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} + * @type {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} data the array / typedArray */ this.data = data; + /** + * A map of renderer IDs to webgl buffer + * + * @private + * @member {object} + */ this._glBuffers = []; this._updateID = 0; @@ -41,10 +34,9 @@ this.id = UID++; } + // TODO could explore flagging only a partial upload? /** - * Uploads the buffer to the GPU - * @param data {ArrayBuffer| SharedArrayBuffer|ArrayBufferView} an array of data to upload - * @param offset {Number} if only a subset of the data should be uploaded, this is the amount of data to subtract + * flags this buffer as requiring an upload to the GPU */ update() { @@ -53,7 +45,6 @@ /** * Destroys the buffer - * */ destroy() { @@ -65,12 +56,20 @@ this.data = null; } + /** + * Helper function that creates a buffer based on an array or TypedArray + * + * @static + * @param {TypedArray| Array} data the TypedArray that the buffer will store. If this is a regular Array it will be converted to a Float32Array. + * @return {PIXI.Buffer} A new Buffer based on the data provided. + */ static from(data) { - if(data instanceof Array) + if (data instanceof Array) { data = new Float32Array(data); } + return new Buffer(data); } } diff --git a/src/mesh/geometry/Geometry.js b/src/mesh/geometry/Geometry.js index 0c2f8df..f1e090c 100644 --- a/src/mesh/geometry/Geometry.js +++ b/src/mesh/geometry/Geometry.js @@ -3,27 +3,77 @@ import GeometryStyle from './GeometryStyle'; import GeometryData from './GeometryData'; -var UID = 0; +/* eslint-disable max-len */ -class Geometry +/** + * The Geometry represents a model. It consists of two components: + * GeometryStyle - The structure of the model such as the attributes layout + * GeometryData - the data of the model - this consits of buffers. + * + * This can include anything from positions, uvs, normals, colors etc.. + * + * Geometry can be defined without passing in a style or data if required (thats how I prefer!) + * + * ```js + * let geometry = new PIXI.Geometry(); + * + * geometry.addAttribute('positions', [0, 0, 100, 0, 100, 100, 0, 100], 2); + * geometry.addAttribute('uvs', [0,0,1,0,1,1,0,1],2) + * geometry.addIndex([0,1,2,1,3,2]) + * + * ``` + * @class + * @memberof PIXI.Geometry + */ +export default class Geometry { + /** + * @param {PIXI.GeometryData} data optional structure of the model such as the attributes layout + * @param {PIXI.GeometryStyle} style optional data of the model, this consists of buffers. + */ constructor(data, style) { + /** + * the style of the geometry + * @type {PIXI.GeometryStyle} + */ this.style = style || new GeometryStyle(); + + /** + * the data of the geometry + * @type {PIXI.GeometryData} + */ this.data = data || new GeometryData(); + /** + * A map of renderer IDs to webgl VAOs + * + * @private + * @type {Array} + */ this.glVertexArrayObjects = []; - - this.id = UID++; } + /** + * + * Adds an attribute to the geometry + * + * @param {String} id - the name of the attribute (matching up to a shader) + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the attribute . You can also provide an Array and a buffer will be created from it. + * @param {Number} [size=2] the size of the attribute. If you hava 2 floats per vertex (eg position x and y) this would be 2 + * @param {Number} [stride=0] How far apart (in floats) the start of each value is. (used for interleaving data) + * @param {Number} [start=0] How far into the array to start reading values (used for interleaving data) + * @param {Boolean} [normalised=false] should the data be normalised. + * + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addAttribute(id, buffer, size = 2, stride = 0, start = 0, normalised = false) { // check if this is a buffer! if (!buffer.data) { // its an array! - if(buffer instanceof Array) + if (buffer instanceof Array) { buffer = new Float32Array(buffer); } @@ -37,45 +87,47 @@ return this; } + /** + * returns the requested attribute + * + * @param {String} id the name of the attribute required + * @return {PIXI.Attribute} the attribute requested. + */ getAttribute(id) { return this.data[this.style.attributes[id].buffer]; } + /** + * + * Adds an index buffer to the geometry + * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer. + * + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it. + * @return {PIXI.Geometry} returns self, useful for chaining. + */ addIndex(buffer) { - if (!buffer.data) - { - // its an array! - if(buffer instanceof Array) - { - buffer = new Uint16Array(buffer); - } - - buffer = new Buffer(buffer); - } - this.data.addIndex(buffer); return this; } + /** + * returns the index buffer + * + * @return {PIXI.Buffer} the index buffer. + */ getIndex() { return this.data.indexBuffer; } + /** + * Destroys the geometry. + */ destroy() { - //TODO - this is wrong! - for (let i = 0; i < this.buffers.length; i++) - { - this.buffers[i].destroy(); - } - - this.buffers = null; - this.attributes = null; - for (let i = 0; i < this.glVertexArrayObjects.length; i++) { this.glVertexArrayObjects[i].destroy(); @@ -83,9 +135,7 @@ this.glVertexArrayObjects = null; - this.indexBuffer.destroy(); - this.indexBuffer = null; + this.data.destroy(); + this.style.destroy(); } } - -export default Geometry; diff --git a/src/mesh/geometry/GeometryData.js b/src/mesh/geometry/GeometryData.js index 4d988a5..290d7aa 100644 --- a/src/mesh/geometry/GeometryData.js +++ b/src/mesh/geometry/GeometryData.js @@ -1,13 +1,64 @@ +/* eslint-disable max-len */ + +/** + * GeometryData - the data of the geometry - this consits of attribute buffers and one index buffer. + * + * This can include anything from positions, uvs, normals, colors etc.. + * + * ```js + * let geometryData = new PIXI.GeometryData(); + * + * geometryData.add('positions', [0,1,0,2,3]); + * geometryData.add('uvs', [0,0,1,0,1,1,0,1]); + * geometryData.addIndex([0,1,2,1,3,2]) + * + * ``` + * @class + * @memberof PIXI.GeometryData + */ export default class GeometryData { + /** + * + */ constructor() { + /** + * an array of {PIXI.Buffer} belonging to the geometryData + * @type {Array} + */ this.buffers = []; + + /** + * the index buffer data for the geometry + * @type {PIXI.Buffer} + */ this.indexBuffer = null; } + /** + * + * Adds an buffer to the geometryData + * + * @param {String} id - the name of the buffer (matching up to a geometry style) + * @param {PIXI.Buffer} [buffer] the buffer that holds the data mapping to a geometry attribute. You can also provide an Array and a buffer will be created from it. + * + * @return {PIXI.GeometryData} returns self, useful for chaining. + */ add(id, buffer) { + // bit of duplicate code here and in geometry.. + if (!buffer.data) + { + // its an array! + if (buffer instanceof Array) + { + buffer = new Float32Array(buffer); + } + + buffer = new Buffer(buffer); + } + // only one! if (this.buffers.indexOf(buffer) === -1) { @@ -18,8 +69,27 @@ return this; } + /** + * + * Adds an index buffer to the geometryData + * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer. + * + * @param {PIXI.Buffer} [buffer] the buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it. + * @return {PIXI.GeometryData} returns self, useful for chaining. + */ addIndex(buffer) { + if (!buffer.data) + { + // its an array! + if (buffer instanceof Array) + { + buffer = new Uint16Array(buffer); + } + + buffer = new Buffer(buffer); + } + buffer.index = true; this.indexBuffer = buffer; @@ -30,4 +100,20 @@ return this; } -} \ No newline at end of file + + /** + * Destroys the geometry data. + */ + destroy() + { + for (let i = 0; i < this.buffers.length; i++) + { + this.buffers[i].destroy(); + } + + this.buffers = null; + + this.indexBuffer.destroy(); + this.indexBuffer = null; + } +} diff --git a/src/mesh/geometry/GeometryStyle.js b/src/mesh/geometry/GeometryStyle.js index e626483..f18bd6b 100644 --- a/src/mesh/geometry/GeometryStyle.js +++ b/src/mesh/geometry/GeometryStyle.js @@ -1,12 +1,42 @@ +/** + * GeometryStyle represents the structure of the geometry such as the attributes layout. + * + * ```js + * let geometryStyle = new PIXI.GeometryStyle(); + * + * geometryStyle.addAttribute('positions, new PIXI.Attribute('positionBuffer', 2)); + * geometryStyle.addAttribute('uvs', new PIXI.Attribute('uvsBuffer', 2); + * + * ``` + * @class + * @memberof PIXI.GeometryStyle + */ export default class GeometryStyle { + /** + * + */ constructor() { + /** + * key-value pair contains all the attributes for this style + * + * @member {Object} + */ this.attributes = {}; - - this.indexBuffer = null; } + // TODO rename this to add? + + /** + * + * Adds an attribute to the geometryStyle + * + * @param {String} id - the name of the attribute (matching up to a shader) + * @param {PIXI.Attribute} [attribute] the Attribute that you would like to add to the style. + * + * @return {PIXI.GeometryStyle} returns self, useful for chaining. + */ addAttribute(id, attribute) { this.attributes[id] = attribute; @@ -14,13 +44,14 @@ return this; } - addIndex(buffer) - { - this.indexBuffer = buffer; - - return this; - } - + /** + * generates a map of what the locations of the attributes will be. + * All attributes locations are assigned in alphabetical order just like the {PIXI.Shader} attribute locations. + * This ensures that all geometries and shaders will be compatible if they have the same attributes. + * + * @private + * @return {object} map with key-value pairs mapping attribute names to locations (ints). + */ generateAttributeLocations() { const array = []; @@ -40,15 +71,14 @@ map[array[i]] = i; } - console.log(map) - return map; } + /** + * Destroys the geometryStyle. + */ destroy() { this.attributes = null; - - this.indexBuffer = null; } -} \ No newline at end of file +} diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js index 225f85b..2e66664 100644 --- a/src/mesh/webgl/MeshRenderer.js +++ b/src/mesh/webgl/MeshRenderer.js @@ -50,8 +50,6 @@ // bind the shader.. this.renderer.shaderManager.bindShader(mesh.shader, true); - var glShader = this.renderer.shaderManager.getGLShader(); - // set unifomrs.. this.renderer.shaderManager.setUniforms(mesh.uniforms); @@ -151,7 +149,6 @@ }, gl.FLOAT, false, attribute.stride, attribute.start); } - geometry.glVertexArrayObjects[this.CONTEXT_UID] = vao; return vao;