diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js index b906b71..478fab3 100644 --- a/src/mesh/Plane.js +++ b/src/mesh/Plane.js @@ -1,10 +1,4 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; -import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The Plane allows you to draw a texture across several points and them manipulate these points @@ -31,30 +25,7 @@ */ constructor(texture, verticesX, verticesY, opts = {}) { - const geometry = new Geometry(); - - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - geometry.addAttribute('aVertexPosition', new Float32Array(2), 2) - .addAttribute('aTextureCoord', new Float32Array(2), 2) - .addIndex(new Uint16Array(2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 4); - - uniforms.translationMatrix = this.transform.worldTransform; - - this.texture = texture; + super(texture, new Float32Array(1), new Float32Array(1), new Uint16Array(1), 4); this.segmentsX = this.verticesX = verticesX || 10; this.segmentsY = this.verticesY = verticesY || 10; @@ -62,63 +33,7 @@ this.meshWidth = opts.meshWidth || texture.width; this.meshHeight = opts.meshHeight || texture.height; - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; + this.refresh(); } /** @@ -184,13 +99,13 @@ this.uvs = new Float32Array(uvs); this.indices = new Uint16Array(indices); - this.geometry.getAttribute('aVertexPosition').data = this.vertices; - this.geometry.getAttribute('aTextureCoord').data = this.uvs; + this.geometry.aVertexPosition.data = this.vertices; + this.geometry.aTextureCoord.data = this.uvs; this.geometry.data.indexBuffer.data = this.indices; // ensure that the changes are uploaded - this.geometry.getAttribute('aVertexPosition').update(); - this.geometry.getAttribute('aTextureCoord').update(); + this.geometry.aVertexPosition.update(); + this.geometry.aTextureCoord.update(); this.geometry.data.indexBuffer.update(); } @@ -201,7 +116,7 @@ */ updateTransform() { - this.geometry.getAttribute('aVertexPosition').update(); + this.geometry.aVertexPosition.update(); this.containerUpdateTransform(); } } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js index b906b71..478fab3 100644 --- a/src/mesh/Plane.js +++ b/src/mesh/Plane.js @@ -1,10 +1,4 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; -import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The Plane allows you to draw a texture across several points and them manipulate these points @@ -31,30 +25,7 @@ */ constructor(texture, verticesX, verticesY, opts = {}) { - const geometry = new Geometry(); - - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - geometry.addAttribute('aVertexPosition', new Float32Array(2), 2) - .addAttribute('aTextureCoord', new Float32Array(2), 2) - .addIndex(new Uint16Array(2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 4); - - uniforms.translationMatrix = this.transform.worldTransform; - - this.texture = texture; + super(texture, new Float32Array(1), new Float32Array(1), new Uint16Array(1), 4); this.segmentsX = this.verticesX = verticesX || 10; this.segmentsY = this.verticesY = verticesY || 10; @@ -62,63 +33,7 @@ this.meshWidth = opts.meshWidth || texture.width; this.meshHeight = opts.meshHeight || texture.height; - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; + this.refresh(); } /** @@ -184,13 +99,13 @@ this.uvs = new Float32Array(uvs); this.indices = new Uint16Array(indices); - this.geometry.getAttribute('aVertexPosition').data = this.vertices; - this.geometry.getAttribute('aTextureCoord').data = this.uvs; + this.geometry.aVertexPosition.data = this.vertices; + this.geometry.aTextureCoord.data = this.uvs; this.geometry.data.indexBuffer.data = this.indices; // ensure that the changes are uploaded - this.geometry.getAttribute('aVertexPosition').update(); - this.geometry.getAttribute('aTextureCoord').update(); + this.geometry.aVertexPosition.update(); + this.geometry.aTextureCoord.update(); this.geometry.data.indexBuffer.update(); } @@ -201,7 +116,7 @@ */ updateTransform() { - this.geometry.getAttribute('aVertexPosition').update(); + this.geometry.aVertexPosition.update(); this.containerUpdateTransform(); } } diff --git a/src/mesh/RawMesh.js b/src/mesh/RawMesh.js new file mode 100644 index 0000000..761aa69 --- /dev/null +++ b/src/mesh/RawMesh.js @@ -0,0 +1,196 @@ +import * as core from '../core'; + +const tempPoint = new core.Point(); +const tempPolygon = new core.Polygon(); + +/** + * 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 + */ +export default class RawMesh extends core.Container +{ + /** + * @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) + { + super(); + + /** + * the geometry the mesh will use + * @type {PIXI.mesh.Geometry} + */ + 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.State} + */ + this.state = state || new core.State(); + + /** + * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. + * + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL + * @see PIXI.BLEND_MODES + */ + this.blendMode = core.BLEND_MODES.NORMAL; + this.state.blendMode = this.blendMode; + + /** + * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.RawMesh.DRAW_MODES} consts + * + * @member {number} + * @see PIXI.mesh.RawMesh.DRAW_MODES + */ + this.drawMode = drawMode; + + uniforms = uniforms || {}; + + // make sure to add required feilds + // 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) + { + uniforms[i] = shader.uniforms[i]; + } + } + + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ + this.uniforms = uniforms; + + /** + * A map of renderer IDs to webgl render data + * + * @private + * @member {object} + */ + this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; + + this.start = 0; + this.size = 0; + } + + /** + * Renders the object using the WebGL renderer + * + * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer + * @private + */ + _renderWebGL(renderer) + { + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); + } + + /** + * Renders the object using the Canvas renderer + * + * @private + * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. + */ + _renderCanvas(renderer) + { + renderer.plugins[this.pluginName].render(this); + } + + /** + * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. + * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * + * @private + */ + _calculateBounds() + { + // The position property could be set manually? + if (this.geometry.style.attributes.aVertexPosition) + { + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + // TODO - we can cache local bounds and use them if they are dirty (like graphics) + this._bounds.addVertices(this.transform, vertices, 0, vertices.length); + } + } + + /** + * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH + * + * @param {PIXI.Point} point the point to test + * @return {boolean} the result of the test + */ + containsPoint(point) + { + if (!this.getBounds().contains(point.x, point.y)) + { + return false; + } + + this.worldTransform.applyInverse(point, tempPoint); + + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + const points = tempPolygon.points; + const indices = this.geometry.getIndex().data; + const len = indices.length; + const step = this.drawMode === 4 ? 3 : 1; + + for (let i = 0; i + 2 < len; i += step) + { + const ind0 = indices[i] * 2; + const ind1 = indices[i + 1] * 2; + const ind2 = indices[i + 2] * 2; + + points[0] = vertices[ind0]; + points[1] = vertices[ind0 + 1]; + points[2] = vertices[ind1]; + points[3] = vertices[ind1 + 1]; + points[4] = vertices[ind2]; + points[5] = vertices[ind2 + 1]; + + if (tempPolygon.contains(tempPoint.x, tempPoint.y)) + { + return true; + } + } + + return false; + } +} diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js index b906b71..478fab3 100644 --- a/src/mesh/Plane.js +++ b/src/mesh/Plane.js @@ -1,10 +1,4 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; -import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The Plane allows you to draw a texture across several points and them manipulate these points @@ -31,30 +25,7 @@ */ constructor(texture, verticesX, verticesY, opts = {}) { - const geometry = new Geometry(); - - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - geometry.addAttribute('aVertexPosition', new Float32Array(2), 2) - .addAttribute('aTextureCoord', new Float32Array(2), 2) - .addIndex(new Uint16Array(2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 4); - - uniforms.translationMatrix = this.transform.worldTransform; - - this.texture = texture; + super(texture, new Float32Array(1), new Float32Array(1), new Uint16Array(1), 4); this.segmentsX = this.verticesX = verticesX || 10; this.segmentsY = this.verticesY = verticesY || 10; @@ -62,63 +33,7 @@ this.meshWidth = opts.meshWidth || texture.width; this.meshHeight = opts.meshHeight || texture.height; - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; + this.refresh(); } /** @@ -184,13 +99,13 @@ this.uvs = new Float32Array(uvs); this.indices = new Uint16Array(indices); - this.geometry.getAttribute('aVertexPosition').data = this.vertices; - this.geometry.getAttribute('aTextureCoord').data = this.uvs; + this.geometry.aVertexPosition.data = this.vertices; + this.geometry.aTextureCoord.data = this.uvs; this.geometry.data.indexBuffer.data = this.indices; // ensure that the changes are uploaded - this.geometry.getAttribute('aVertexPosition').update(); - this.geometry.getAttribute('aTextureCoord').update(); + this.geometry.aVertexPosition.update(); + this.geometry.aTextureCoord.update(); this.geometry.data.indexBuffer.update(); } @@ -201,7 +116,7 @@ */ updateTransform() { - this.geometry.getAttribute('aVertexPosition').update(); + this.geometry.aVertexPosition.update(); this.containerUpdateTransform(); } } diff --git a/src/mesh/RawMesh.js b/src/mesh/RawMesh.js new file mode 100644 index 0000000..761aa69 --- /dev/null +++ b/src/mesh/RawMesh.js @@ -0,0 +1,196 @@ +import * as core from '../core'; + +const tempPoint = new core.Point(); +const tempPolygon = new core.Polygon(); + +/** + * 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 + */ +export default class RawMesh extends core.Container +{ + /** + * @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) + { + super(); + + /** + * the geometry the mesh will use + * @type {PIXI.mesh.Geometry} + */ + 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.State} + */ + this.state = state || new core.State(); + + /** + * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. + * + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL + * @see PIXI.BLEND_MODES + */ + this.blendMode = core.BLEND_MODES.NORMAL; + this.state.blendMode = this.blendMode; + + /** + * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.RawMesh.DRAW_MODES} consts + * + * @member {number} + * @see PIXI.mesh.RawMesh.DRAW_MODES + */ + this.drawMode = drawMode; + + uniforms = uniforms || {}; + + // make sure to add required feilds + // 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) + { + uniforms[i] = shader.uniforms[i]; + } + } + + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ + this.uniforms = uniforms; + + /** + * A map of renderer IDs to webgl render data + * + * @private + * @member {object} + */ + this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; + + this.start = 0; + this.size = 0; + } + + /** + * Renders the object using the WebGL renderer + * + * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer + * @private + */ + _renderWebGL(renderer) + { + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); + } + + /** + * Renders the object using the Canvas renderer + * + * @private + * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. + */ + _renderCanvas(renderer) + { + renderer.plugins[this.pluginName].render(this); + } + + /** + * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. + * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * + * @private + */ + _calculateBounds() + { + // The position property could be set manually? + if (this.geometry.style.attributes.aVertexPosition) + { + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + // TODO - we can cache local bounds and use them if they are dirty (like graphics) + this._bounds.addVertices(this.transform, vertices, 0, vertices.length); + } + } + + /** + * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH + * + * @param {PIXI.Point} point the point to test + * @return {boolean} the result of the test + */ + containsPoint(point) + { + if (!this.getBounds().contains(point.x, point.y)) + { + return false; + } + + this.worldTransform.applyInverse(point, tempPoint); + + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + const points = tempPolygon.points; + const indices = this.geometry.getIndex().data; + const len = indices.length; + const step = this.drawMode === 4 ? 3 : 1; + + for (let i = 0; i + 2 < len; i += step) + { + const ind0 = indices[i] * 2; + const ind1 = indices[i + 1] * 2; + const ind2 = indices[i + 2] * 2; + + points[0] = vertices[ind0]; + points[1] = vertices[ind0 + 1]; + points[2] = vertices[ind1]; + points[3] = vertices[ind1 + 1]; + points[4] = vertices[ind2]; + points[5] = vertices[ind2 + 1]; + + if (tempPolygon.contains(tempPoint.x, tempPoint.y)) + { + return true; + } + } + + return false; + } +} diff --git a/src/mesh/Rope.js b/src/mesh/Rope.js index 58f121f..8a7afb2 100644 --- a/src/mesh/Rope.js +++ b/src/mesh/Rope.js @@ -1,10 +1,5 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The rope allows you to draw a texture across several points and them manipulate these points @@ -29,100 +24,15 @@ */ constructor(texture, points) { - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - const geometry = new Geometry(); - - geometry.addAttribute('aVertexPosition', new Float32Array(points.length * 4), 2) - .addAttribute('aTextureCoord', new Float32Array(points.length * 4), 2) - .addIndex(new Uint16Array(points.length * 2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 5); - - uniforms.translationMatrix = this.transform.worldTransform; + super(texture, new Float32Array(points.length * 4), + new Float32Array(points.length * 4), + new Uint16Array(points.length * 2), + 5); /* * @member {PIXI.Point[]} An array of points that determine the rope */ this.points = points; - - /** - * The tint applied to the rope. This is a hex value. A value of 0xFFFFFF will remove any tint effect. - * - * @private - * @member {number} - * @default 0xFFFFFF - */ - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - - this.texture = texture; - // wait for the texture to load - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; } /** @@ -263,4 +173,14 @@ this.containerUpdateTransform(); } + + /** + * When the texture is updated, this event will fire to update the scale and frame + * + * @private + */ + _onTextureUpdate() + { + this.refresh(); + } } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js index b906b71..478fab3 100644 --- a/src/mesh/Plane.js +++ b/src/mesh/Plane.js @@ -1,10 +1,4 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; -import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The Plane allows you to draw a texture across several points and them manipulate these points @@ -31,30 +25,7 @@ */ constructor(texture, verticesX, verticesY, opts = {}) { - const geometry = new Geometry(); - - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - geometry.addAttribute('aVertexPosition', new Float32Array(2), 2) - .addAttribute('aTextureCoord', new Float32Array(2), 2) - .addIndex(new Uint16Array(2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 4); - - uniforms.translationMatrix = this.transform.worldTransform; - - this.texture = texture; + super(texture, new Float32Array(1), new Float32Array(1), new Uint16Array(1), 4); this.segmentsX = this.verticesX = verticesX || 10; this.segmentsY = this.verticesY = verticesY || 10; @@ -62,63 +33,7 @@ this.meshWidth = opts.meshWidth || texture.width; this.meshHeight = opts.meshHeight || texture.height; - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; + this.refresh(); } /** @@ -184,13 +99,13 @@ this.uvs = new Float32Array(uvs); this.indices = new Uint16Array(indices); - this.geometry.getAttribute('aVertexPosition').data = this.vertices; - this.geometry.getAttribute('aTextureCoord').data = this.uvs; + this.geometry.aVertexPosition.data = this.vertices; + this.geometry.aTextureCoord.data = this.uvs; this.geometry.data.indexBuffer.data = this.indices; // ensure that the changes are uploaded - this.geometry.getAttribute('aVertexPosition').update(); - this.geometry.getAttribute('aTextureCoord').update(); + this.geometry.aVertexPosition.update(); + this.geometry.aTextureCoord.update(); this.geometry.data.indexBuffer.update(); } @@ -201,7 +116,7 @@ */ updateTransform() { - this.geometry.getAttribute('aVertexPosition').update(); + this.geometry.aVertexPosition.update(); this.containerUpdateTransform(); } } diff --git a/src/mesh/RawMesh.js b/src/mesh/RawMesh.js new file mode 100644 index 0000000..761aa69 --- /dev/null +++ b/src/mesh/RawMesh.js @@ -0,0 +1,196 @@ +import * as core from '../core'; + +const tempPoint = new core.Point(); +const tempPolygon = new core.Polygon(); + +/** + * 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 + */ +export default class RawMesh extends core.Container +{ + /** + * @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) + { + super(); + + /** + * the geometry the mesh will use + * @type {PIXI.mesh.Geometry} + */ + 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.State} + */ + this.state = state || new core.State(); + + /** + * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. + * + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL + * @see PIXI.BLEND_MODES + */ + this.blendMode = core.BLEND_MODES.NORMAL; + this.state.blendMode = this.blendMode; + + /** + * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.RawMesh.DRAW_MODES} consts + * + * @member {number} + * @see PIXI.mesh.RawMesh.DRAW_MODES + */ + this.drawMode = drawMode; + + uniforms = uniforms || {}; + + // make sure to add required feilds + // 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) + { + uniforms[i] = shader.uniforms[i]; + } + } + + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ + this.uniforms = uniforms; + + /** + * A map of renderer IDs to webgl render data + * + * @private + * @member {object} + */ + this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; + + this.start = 0; + this.size = 0; + } + + /** + * Renders the object using the WebGL renderer + * + * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer + * @private + */ + _renderWebGL(renderer) + { + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); + } + + /** + * Renders the object using the Canvas renderer + * + * @private + * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. + */ + _renderCanvas(renderer) + { + renderer.plugins[this.pluginName].render(this); + } + + /** + * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. + * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * + * @private + */ + _calculateBounds() + { + // The position property could be set manually? + if (this.geometry.style.attributes.aVertexPosition) + { + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + // TODO - we can cache local bounds and use them if they are dirty (like graphics) + this._bounds.addVertices(this.transform, vertices, 0, vertices.length); + } + } + + /** + * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH + * + * @param {PIXI.Point} point the point to test + * @return {boolean} the result of the test + */ + containsPoint(point) + { + if (!this.getBounds().contains(point.x, point.y)) + { + return false; + } + + this.worldTransform.applyInverse(point, tempPoint); + + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + const points = tempPolygon.points; + const indices = this.geometry.getIndex().data; + const len = indices.length; + const step = this.drawMode === 4 ? 3 : 1; + + for (let i = 0; i + 2 < len; i += step) + { + const ind0 = indices[i] * 2; + const ind1 = indices[i + 1] * 2; + const ind2 = indices[i + 2] * 2; + + points[0] = vertices[ind0]; + points[1] = vertices[ind0 + 1]; + points[2] = vertices[ind1]; + points[3] = vertices[ind1 + 1]; + points[4] = vertices[ind2]; + points[5] = vertices[ind2 + 1]; + + if (tempPolygon.contains(tempPoint.x, tempPoint.y)) + { + return true; + } + } + + return false; + } +} diff --git a/src/mesh/Rope.js b/src/mesh/Rope.js index 58f121f..8a7afb2 100644 --- a/src/mesh/Rope.js +++ b/src/mesh/Rope.js @@ -1,10 +1,5 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The rope allows you to draw a texture across several points and them manipulate these points @@ -29,100 +24,15 @@ */ constructor(texture, points) { - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - const geometry = new Geometry(); - - geometry.addAttribute('aVertexPosition', new Float32Array(points.length * 4), 2) - .addAttribute('aTextureCoord', new Float32Array(points.length * 4), 2) - .addIndex(new Uint16Array(points.length * 2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 5); - - uniforms.translationMatrix = this.transform.worldTransform; + super(texture, new Float32Array(points.length * 4), + new Float32Array(points.length * 4), + new Uint16Array(points.length * 2), + 5); /* * @member {PIXI.Point[]} An array of points that determine the rope */ this.points = points; - - /** - * The tint applied to the rope. This is a hex value. A value of 0xFFFFFF will remove any tint effect. - * - * @private - * @member {number} - * @default 0xFFFFFF - */ - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - - this.texture = texture; - // wait for the texture to load - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; } /** @@ -263,4 +173,14 @@ this.containerUpdateTransform(); } + + /** + * When the texture is updated, this event will fire to update the scale and frame + * + * @private + */ + _onTextureUpdate() + { + this.refresh(); + } } diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js index b4cb86d..0a60aff 100644 --- a/src/mesh/canvas/CanvasMeshRenderer.js +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -70,7 +70,7 @@ * Draws the object in Triangle Mesh mode * * @private - * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - the Mesh to render */ _renderTriangleMesh(mesh) { @@ -90,7 +90,7 @@ * Draws the object in triangle mode using canvas * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh */ _renderTriangles(mesh) { @@ -113,7 +113,7 @@ * Draws one of the triangles that from the Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh * @param {number} index0 - the index of the first vertex * @param {number} index1 - the index of the second vertex * @param {number} index2 - the index of the third vertex @@ -229,7 +229,7 @@ * Renders a flat Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - The Mesh to render */ renderMeshFlat(mesh) { diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js index b906b71..478fab3 100644 --- a/src/mesh/Plane.js +++ b/src/mesh/Plane.js @@ -1,10 +1,4 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; -import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The Plane allows you to draw a texture across several points and them manipulate these points @@ -31,30 +25,7 @@ */ constructor(texture, verticesX, verticesY, opts = {}) { - const geometry = new Geometry(); - - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - geometry.addAttribute('aVertexPosition', new Float32Array(2), 2) - .addAttribute('aTextureCoord', new Float32Array(2), 2) - .addIndex(new Uint16Array(2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 4); - - uniforms.translationMatrix = this.transform.worldTransform; - - this.texture = texture; + super(texture, new Float32Array(1), new Float32Array(1), new Uint16Array(1), 4); this.segmentsX = this.verticesX = verticesX || 10; this.segmentsY = this.verticesY = verticesY || 10; @@ -62,63 +33,7 @@ this.meshWidth = opts.meshWidth || texture.width; this.meshHeight = opts.meshHeight || texture.height; - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; + this.refresh(); } /** @@ -184,13 +99,13 @@ this.uvs = new Float32Array(uvs); this.indices = new Uint16Array(indices); - this.geometry.getAttribute('aVertexPosition').data = this.vertices; - this.geometry.getAttribute('aTextureCoord').data = this.uvs; + this.geometry.aVertexPosition.data = this.vertices; + this.geometry.aTextureCoord.data = this.uvs; this.geometry.data.indexBuffer.data = this.indices; // ensure that the changes are uploaded - this.geometry.getAttribute('aVertexPosition').update(); - this.geometry.getAttribute('aTextureCoord').update(); + this.geometry.aVertexPosition.update(); + this.geometry.aTextureCoord.update(); this.geometry.data.indexBuffer.update(); } @@ -201,7 +116,7 @@ */ updateTransform() { - this.geometry.getAttribute('aVertexPosition').update(); + this.geometry.aVertexPosition.update(); this.containerUpdateTransform(); } } diff --git a/src/mesh/RawMesh.js b/src/mesh/RawMesh.js new file mode 100644 index 0000000..761aa69 --- /dev/null +++ b/src/mesh/RawMesh.js @@ -0,0 +1,196 @@ +import * as core from '../core'; + +const tempPoint = new core.Point(); +const tempPolygon = new core.Polygon(); + +/** + * 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 + */ +export default class RawMesh extends core.Container +{ + /** + * @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) + { + super(); + + /** + * the geometry the mesh will use + * @type {PIXI.mesh.Geometry} + */ + 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.State} + */ + this.state = state || new core.State(); + + /** + * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. + * + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL + * @see PIXI.BLEND_MODES + */ + this.blendMode = core.BLEND_MODES.NORMAL; + this.state.blendMode = this.blendMode; + + /** + * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.RawMesh.DRAW_MODES} consts + * + * @member {number} + * @see PIXI.mesh.RawMesh.DRAW_MODES + */ + this.drawMode = drawMode; + + uniforms = uniforms || {}; + + // make sure to add required feilds + // 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) + { + uniforms[i] = shader.uniforms[i]; + } + } + + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ + this.uniforms = uniforms; + + /** + * A map of renderer IDs to webgl render data + * + * @private + * @member {object} + */ + this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; + + this.start = 0; + this.size = 0; + } + + /** + * Renders the object using the WebGL renderer + * + * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer + * @private + */ + _renderWebGL(renderer) + { + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); + } + + /** + * Renders the object using the Canvas renderer + * + * @private + * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. + */ + _renderCanvas(renderer) + { + renderer.plugins[this.pluginName].render(this); + } + + /** + * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. + * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * + * @private + */ + _calculateBounds() + { + // The position property could be set manually? + if (this.geometry.style.attributes.aVertexPosition) + { + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + // TODO - we can cache local bounds and use them if they are dirty (like graphics) + this._bounds.addVertices(this.transform, vertices, 0, vertices.length); + } + } + + /** + * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH + * + * @param {PIXI.Point} point the point to test + * @return {boolean} the result of the test + */ + containsPoint(point) + { + if (!this.getBounds().contains(point.x, point.y)) + { + return false; + } + + this.worldTransform.applyInverse(point, tempPoint); + + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + const points = tempPolygon.points; + const indices = this.geometry.getIndex().data; + const len = indices.length; + const step = this.drawMode === 4 ? 3 : 1; + + for (let i = 0; i + 2 < len; i += step) + { + const ind0 = indices[i] * 2; + const ind1 = indices[i + 1] * 2; + const ind2 = indices[i + 2] * 2; + + points[0] = vertices[ind0]; + points[1] = vertices[ind0 + 1]; + points[2] = vertices[ind1]; + points[3] = vertices[ind1 + 1]; + points[4] = vertices[ind2]; + points[5] = vertices[ind2 + 1]; + + if (tempPolygon.contains(tempPoint.x, tempPoint.y)) + { + return true; + } + } + + return false; + } +} diff --git a/src/mesh/Rope.js b/src/mesh/Rope.js index 58f121f..8a7afb2 100644 --- a/src/mesh/Rope.js +++ b/src/mesh/Rope.js @@ -1,10 +1,5 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The rope allows you to draw a texture across several points and them manipulate these points @@ -29,100 +24,15 @@ */ constructor(texture, points) { - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - const geometry = new Geometry(); - - geometry.addAttribute('aVertexPosition', new Float32Array(points.length * 4), 2) - .addAttribute('aTextureCoord', new Float32Array(points.length * 4), 2) - .addIndex(new Uint16Array(points.length * 2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 5); - - uniforms.translationMatrix = this.transform.worldTransform; + super(texture, new Float32Array(points.length * 4), + new Float32Array(points.length * 4), + new Uint16Array(points.length * 2), + 5); /* * @member {PIXI.Point[]} An array of points that determine the rope */ this.points = points; - - /** - * The tint applied to the rope. This is a hex value. A value of 0xFFFFFF will remove any tint effect. - * - * @private - * @member {number} - * @default 0xFFFFFF - */ - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - - this.texture = texture; - // wait for the texture to load - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; } /** @@ -263,4 +173,14 @@ this.containerUpdateTransform(); } + + /** + * When the texture is updated, this event will fire to update the scale and frame + * + * @private + */ + _onTextureUpdate() + { + this.refresh(); + } } diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js index b4cb86d..0a60aff 100644 --- a/src/mesh/canvas/CanvasMeshRenderer.js +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -70,7 +70,7 @@ * Draws the object in Triangle Mesh mode * * @private - * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - the Mesh to render */ _renderTriangleMesh(mesh) { @@ -90,7 +90,7 @@ * Draws the object in triangle mode using canvas * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh */ _renderTriangles(mesh) { @@ -113,7 +113,7 @@ * Draws one of the triangles that from the Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh * @param {number} index0 - the index of the first vertex * @param {number} index1 - the index of the second vertex * @param {number} index2 - the index of the third vertex @@ -229,7 +229,7 @@ * Renders a flat Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - The Mesh to render */ renderMeshFlat(mesh) { diff --git a/src/mesh/geometry/Geometry.js b/src/mesh/geometry/Geometry.js index 95ff4fd..b2cfa71 100644 --- a/src/mesh/geometry/Geometry.js +++ b/src/mesh/geometry/Geometry.js @@ -84,6 +84,9 @@ this.style.addAttribute(id, new Attribute(buffer.id, size, stride, start, normalised)); this.data.add(buffer.id, buffer); + // dynamically create an access point.. + this[id] = buffer; + return this; } diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js index b906b71..478fab3 100644 --- a/src/mesh/Plane.js +++ b/src/mesh/Plane.js @@ -1,10 +1,4 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; -import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The Plane allows you to draw a texture across several points and them manipulate these points @@ -31,30 +25,7 @@ */ constructor(texture, verticesX, verticesY, opts = {}) { - const geometry = new Geometry(); - - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - geometry.addAttribute('aVertexPosition', new Float32Array(2), 2) - .addAttribute('aTextureCoord', new Float32Array(2), 2) - .addIndex(new Uint16Array(2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 4); - - uniforms.translationMatrix = this.transform.worldTransform; - - this.texture = texture; + super(texture, new Float32Array(1), new Float32Array(1), new Uint16Array(1), 4); this.segmentsX = this.verticesX = verticesX || 10; this.segmentsY = this.verticesY = verticesY || 10; @@ -62,63 +33,7 @@ this.meshWidth = opts.meshWidth || texture.width; this.meshHeight = opts.meshHeight || texture.height; - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; + this.refresh(); } /** @@ -184,13 +99,13 @@ this.uvs = new Float32Array(uvs); this.indices = new Uint16Array(indices); - this.geometry.getAttribute('aVertexPosition').data = this.vertices; - this.geometry.getAttribute('aTextureCoord').data = this.uvs; + this.geometry.aVertexPosition.data = this.vertices; + this.geometry.aTextureCoord.data = this.uvs; this.geometry.data.indexBuffer.data = this.indices; // ensure that the changes are uploaded - this.geometry.getAttribute('aVertexPosition').update(); - this.geometry.getAttribute('aTextureCoord').update(); + this.geometry.aVertexPosition.update(); + this.geometry.aTextureCoord.update(); this.geometry.data.indexBuffer.update(); } @@ -201,7 +116,7 @@ */ updateTransform() { - this.geometry.getAttribute('aVertexPosition').update(); + this.geometry.aVertexPosition.update(); this.containerUpdateTransform(); } } diff --git a/src/mesh/RawMesh.js b/src/mesh/RawMesh.js new file mode 100644 index 0000000..761aa69 --- /dev/null +++ b/src/mesh/RawMesh.js @@ -0,0 +1,196 @@ +import * as core from '../core'; + +const tempPoint = new core.Point(); +const tempPolygon = new core.Polygon(); + +/** + * 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 + */ +export default class RawMesh extends core.Container +{ + /** + * @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) + { + super(); + + /** + * the geometry the mesh will use + * @type {PIXI.mesh.Geometry} + */ + 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.State} + */ + this.state = state || new core.State(); + + /** + * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. + * + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL + * @see PIXI.BLEND_MODES + */ + this.blendMode = core.BLEND_MODES.NORMAL; + this.state.blendMode = this.blendMode; + + /** + * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.RawMesh.DRAW_MODES} consts + * + * @member {number} + * @see PIXI.mesh.RawMesh.DRAW_MODES + */ + this.drawMode = drawMode; + + uniforms = uniforms || {}; + + // make sure to add required feilds + // 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) + { + uniforms[i] = shader.uniforms[i]; + } + } + + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ + this.uniforms = uniforms; + + /** + * A map of renderer IDs to webgl render data + * + * @private + * @member {object} + */ + this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; + + this.start = 0; + this.size = 0; + } + + /** + * Renders the object using the WebGL renderer + * + * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer + * @private + */ + _renderWebGL(renderer) + { + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); + } + + /** + * Renders the object using the Canvas renderer + * + * @private + * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. + */ + _renderCanvas(renderer) + { + renderer.plugins[this.pluginName].render(this); + } + + /** + * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. + * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * + * @private + */ + _calculateBounds() + { + // The position property could be set manually? + if (this.geometry.style.attributes.aVertexPosition) + { + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + // TODO - we can cache local bounds and use them if they are dirty (like graphics) + this._bounds.addVertices(this.transform, vertices, 0, vertices.length); + } + } + + /** + * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH + * + * @param {PIXI.Point} point the point to test + * @return {boolean} the result of the test + */ + containsPoint(point) + { + if (!this.getBounds().contains(point.x, point.y)) + { + return false; + } + + this.worldTransform.applyInverse(point, tempPoint); + + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + const points = tempPolygon.points; + const indices = this.geometry.getIndex().data; + const len = indices.length; + const step = this.drawMode === 4 ? 3 : 1; + + for (let i = 0; i + 2 < len; i += step) + { + const ind0 = indices[i] * 2; + const ind1 = indices[i + 1] * 2; + const ind2 = indices[i + 2] * 2; + + points[0] = vertices[ind0]; + points[1] = vertices[ind0 + 1]; + points[2] = vertices[ind1]; + points[3] = vertices[ind1 + 1]; + points[4] = vertices[ind2]; + points[5] = vertices[ind2 + 1]; + + if (tempPolygon.contains(tempPoint.x, tempPoint.y)) + { + return true; + } + } + + return false; + } +} diff --git a/src/mesh/Rope.js b/src/mesh/Rope.js index 58f121f..8a7afb2 100644 --- a/src/mesh/Rope.js +++ b/src/mesh/Rope.js @@ -1,10 +1,5 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The rope allows you to draw a texture across several points and them manipulate these points @@ -29,100 +24,15 @@ */ constructor(texture, points) { - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - const geometry = new Geometry(); - - geometry.addAttribute('aVertexPosition', new Float32Array(points.length * 4), 2) - .addAttribute('aTextureCoord', new Float32Array(points.length * 4), 2) - .addIndex(new Uint16Array(points.length * 2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 5); - - uniforms.translationMatrix = this.transform.worldTransform; + super(texture, new Float32Array(points.length * 4), + new Float32Array(points.length * 4), + new Uint16Array(points.length * 2), + 5); /* * @member {PIXI.Point[]} An array of points that determine the rope */ this.points = points; - - /** - * The tint applied to the rope. This is a hex value. A value of 0xFFFFFF will remove any tint effect. - * - * @private - * @member {number} - * @default 0xFFFFFF - */ - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - - this.texture = texture; - // wait for the texture to load - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; } /** @@ -263,4 +173,14 @@ this.containerUpdateTransform(); } + + /** + * When the texture is updated, this event will fire to update the scale and frame + * + * @private + */ + _onTextureUpdate() + { + this.refresh(); + } } diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js index b4cb86d..0a60aff 100644 --- a/src/mesh/canvas/CanvasMeshRenderer.js +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -70,7 +70,7 @@ * Draws the object in Triangle Mesh mode * * @private - * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - the Mesh to render */ _renderTriangleMesh(mesh) { @@ -90,7 +90,7 @@ * Draws the object in triangle mode using canvas * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh */ _renderTriangles(mesh) { @@ -113,7 +113,7 @@ * Draws one of the triangles that from the Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh * @param {number} index0 - the index of the first vertex * @param {number} index1 - the index of the second vertex * @param {number} index2 - the index of the third vertex @@ -229,7 +229,7 @@ * Renders a flat Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - The Mesh to render */ renderMeshFlat(mesh) { diff --git a/src/mesh/geometry/Geometry.js b/src/mesh/geometry/Geometry.js index 95ff4fd..b2cfa71 100644 --- a/src/mesh/geometry/Geometry.js +++ b/src/mesh/geometry/Geometry.js @@ -84,6 +84,9 @@ this.style.addAttribute(id, new Attribute(buffer.id, size, stride, start, normalised)); this.data.add(buffer.id, buffer); + // dynamically create an access point.. + this[id] = buffer; + return this; } diff --git a/src/mesh/index.js b/src/mesh/index.js index 30151f2..1ab5333 100644 --- a/src/mesh/index.js +++ b/src/mesh/index.js @@ -2,6 +2,7 @@ * @namespace PIXI.mesh */ export { default as Mesh } from './Mesh'; +export { default as RawMesh } from './RawMesh'; export { default as MeshRenderer } from './webgl/MeshRenderer'; export { default as CanvasMeshRenderer } from './canvas/CanvasMeshRenderer'; export { default as Attribute } from './geometry/Attribute'; diff --git a/src/core/renderers/webgl/ShaderManager.js b/src/core/renderers/webgl/ShaderManager.js index 19d5913..5ac65b3 100644 --- a/src/core/renderers/webgl/ShaderManager.js +++ b/src/core/renderers/webgl/ShaderManager.js @@ -36,6 +36,7 @@ * * @param {PIXI.Shader} shader - the new shader * @param {boolean} dontSync - false if the shader should automatically sync its uniforms. + * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader. */ bindShader(shader, dontSync) { @@ -52,6 +53,8 @@ { this.setUniforms(shader.uniforms); } + + return glShader; } /** diff --git a/src/core/shader/Shader.js b/src/core/shader/Shader.js index 76ffdae..30f5b4d 100644 --- a/src/core/shader/Shader.js +++ b/src/core/shader/Shader.js @@ -35,7 +35,9 @@ // pull out the vertex and shader uniforms if they are not specified.. // currently this does not extract structs only default types - this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + this.uniformData = uniforms || extractUniformsFromSrc(this.vertexSrc, this.fragmentSrc); + // TODO - 'projectionMatrix|uSampler|translationMatrix'); + this.attributeData = extractAttributesFromSrc(this.vertexSrc); this.uniforms = {}; diff --git a/src/core/shader/extractAttributesFromSrc.js b/src/core/shader/extractAttributesFromSrc.js index 5c618d5..f60da6f 100644 --- a/src/core/shader/extractAttributesFromSrc.js +++ b/src/core/shader/extractAttributesFromSrc.js @@ -11,8 +11,6 @@ function extractAttributesFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); - const attributesArray = []; let nameSplit; @@ -44,15 +42,12 @@ size *= Number(nameSplit[1]); } - if (!name.match(maskRegex)) - { - attributesArray.push({ - value: defaultValue(type, size), - name, - location: 0, - type, - }); - } + attributesArray.push({ + value: defaultValue(type, size), + name, + location: 0, + type, + }); } } diff --git a/src/core/shader/extractUniformsFromSrc.js b/src/core/shader/extractUniformsFromSrc.js index 2d0e81e..b8a3377 100644 --- a/src/core/shader/extractUniformsFromSrc.js +++ b/src/core/shader/extractUniformsFromSrc.js @@ -12,7 +12,7 @@ function extractUniformsFromString(string) { - const maskRegex = new RegExp('^(projectionMatrix|uSampler)$'); + const maskRegex = new RegExp('^(projectionMatrix|uSampler|translationMatrix)$'); const uniforms = {}; let nameSplit; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 192c65a..5a0fc88 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,209 +1,119 @@ +import RawMesh from './RawMesh'; +import Geometry from './geometry/Geometry'; import * as core from '../core'; +import { readFileSync } from 'fs'; +import { join } from 'path'; -const tempPoint = new core.Point(); -const tempPolygon = new core.Polygon(); +let meshShader; /** - * 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! - * + * Base mesh class * @class * @extends PIXI.Container * @memberof PIXI.mesh */ -export default class Mesh extends core.Container +export default class Mesh extends RawMesh { /** - * @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 + * @param {PIXI.Texture} texture - The texture to use + * @param {Float32Array} [vertices] - if you want to specify the vertices + * @param {Float32Array} [uvs] - if you want to specify the uvs + * @param {Uint16Array} [indices] - if you want to specify the indices + * @param {number} [drawMode] - the drawMode, can be any of the Mesh.DRAW_MODES consts */ - constructor(geometry, shader, uniforms, state, drawMode = core.DRAW_MODES.TRIANGLES) + constructor(texture, vertices, uvs, indices, drawMode) { - super(); + const geometry = new Geometry(); - /** - * the geometry the mesh will use - * @type {PIXI.mesh.Geometry} - */ - 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.State} - */ - this.state = state || new core.State(); - - /** - * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. - * - * @member {number} - * @default PIXI.BLEND_MODES.NORMAL - * @see PIXI.BLEND_MODES - */ - this.blendMode = core.BLEND_MODES.NORMAL; - this.state.blendMode = this.blendMode; - - /** - * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.Mesh.DRAW_MODES} consts - * - * @member {number} - * @see PIXI.mesh.Mesh.DRAW_MODES - */ - this.drawMode = drawMode; - - uniforms = uniforms || {}; - - // make sure to add required feilds - // if the user misses any uniforms we can add the default valujes from the shader - for (const i in shader.uniforms) + if (!meshShader) { - if (uniforms[i] === undefined) + meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), + readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); + } + + geometry.addAttribute('aVertexPosition', vertices, 2) + .addAttribute('aTextureCoord', uvs, 2) + .addIndex(indices); + + const uniforms = { + uSampler2: texture, + alpha: 1, + tint: new Float32Array([1, 1, 1]), + }; + + super(geometry, meshShader, uniforms, null, drawMode); + + this.texture = texture; + + this._tint = 0xFFFFFF; + this.tint = 0xFFFFFF; + } + + /** + * The tint applied to the Rope. This is a hex value. A value of + * 0xFFFFFF will remove any tint effect. + * + * @member {number} + * @memberof PIXI.Sprite# + * @default 0xFFFFFF + */ + get tint() + { + return this._tint; + } + + /** + * Sets the tint of the rope. + * + * @param {number} value - The value to set to. + */ + set tint(value) + { + this._tint = value; + core.utils.hex2rgb(this._tint, this.uniforms.tint); + } + + /** + * The texture that the mesh uses. + * + * @member {PIXI.Texture} + */ + get texture() + { + return this._texture; + } + + set texture(value) // eslint-disable-line require-jsdoc + { + if (this._texture === value) + { + return; + } + + this._texture = value; + this.uniforms.uSampler2 = this.texture; + + if (value) + { + // wait for the texture to load + if (value.baseTexture.hasLoaded) { - uniforms[i] = shader.uniforms[i]; + this._onTextureUpdate(); + } + else + { + value.once('update', this._onTextureUpdate, this); } } - - /** - * The way uniforms that will be used by the mesh's shader. - * @member {Object} - */ - this.uniforms = uniforms; - - /** - * A map of renderer IDs to webgl render data - * - * @private - * @member {object} - */ - this._glDatas = {}; - - /** - * Plugin that is responsible for rendering this element. - * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. - * - * @member {string} - * @default 'mesh' - */ - this.pluginName = 'mesh'; } /** - * Renders the object using the WebGL renderer - * - * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer - * @private - */ - _renderWebGL(renderer) - { - renderer.setObjectRenderer(renderer.plugins[this.pluginName]); - renderer.plugins[this.pluginName].render(this); - } - - /** - * Renders the object using the Canvas renderer - * - * @private - * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. - */ - _renderCanvas(renderer) - { - renderer.plugins[this.pluginName].render(this); - } - - /** - * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * When the texture is updated, this event will fire to update the scale and frame * * @private */ - _calculateBounds() + _onTextureUpdate() { - // The position property could be set manually? - if (this.geometry.style.attributes.aVertexPosition) - { - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - // TODO - we can cache local bounds and use them if they are dirty (like graphics) - this._bounds.addVertices(this.transform, vertices, 0, vertices.length); - } - } - - /** - * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH - * - * @param {PIXI.Point} point the point to test - * @return {boolean} the result of the test - */ - containsPoint(point) - { - if (!this.getBounds().contains(point.x, point.y)) - { - return false; - } - - this.worldTransform.applyInverse(point, tempPoint); - - const vertices = this.geometry.getAttribute('aVertexPosition').data; - - const points = tempPolygon.points; - const indices = this.geometry.getIndex().data; - const len = indices.length; - const step = this.drawMode === 4 ? 3 : 1; - - for (let i = 0; i + 2 < len; i += step) - { - const ind0 = indices[i] * 2; - const ind1 = indices[i + 1] * 2; - const ind2 = indices[i + 2] * 2; - - points[0] = vertices[ind0]; - points[1] = vertices[ind0 + 1]; - points[2] = vertices[ind1]; - points[3] = vertices[ind1 + 1]; - points[4] = vertices[ind2]; - points[5] = vertices[ind2 + 1]; - - if (tempPolygon.contains(tempPoint.x, tempPoint.y)) - { - return true; - } - } - - return false; + /* empty */ } } - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DRAW_MODES - * @property {number} DRAW_MODES.TRIANGLE_MESH - * @property {number} DRAW_MODES.TRIANGLES - */ -Mesh.DRAW_MODES = { - TRIANGLE_MESH: 1, - TRIANGLES: 2, - POINTS: 3, -}; - diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js index b906b71..478fab3 100644 --- a/src/mesh/Plane.js +++ b/src/mesh/Plane.js @@ -1,10 +1,4 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; -import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The Plane allows you to draw a texture across several points and them manipulate these points @@ -31,30 +25,7 @@ */ constructor(texture, verticesX, verticesY, opts = {}) { - const geometry = new Geometry(); - - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - geometry.addAttribute('aVertexPosition', new Float32Array(2), 2) - .addAttribute('aTextureCoord', new Float32Array(2), 2) - .addIndex(new Uint16Array(2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 4); - - uniforms.translationMatrix = this.transform.worldTransform; - - this.texture = texture; + super(texture, new Float32Array(1), new Float32Array(1), new Uint16Array(1), 4); this.segmentsX = this.verticesX = verticesX || 10; this.segmentsY = this.verticesY = verticesY || 10; @@ -62,63 +33,7 @@ this.meshWidth = opts.meshWidth || texture.width; this.meshHeight = opts.meshHeight || texture.height; - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; + this.refresh(); } /** @@ -184,13 +99,13 @@ this.uvs = new Float32Array(uvs); this.indices = new Uint16Array(indices); - this.geometry.getAttribute('aVertexPosition').data = this.vertices; - this.geometry.getAttribute('aTextureCoord').data = this.uvs; + this.geometry.aVertexPosition.data = this.vertices; + this.geometry.aTextureCoord.data = this.uvs; this.geometry.data.indexBuffer.data = this.indices; // ensure that the changes are uploaded - this.geometry.getAttribute('aVertexPosition').update(); - this.geometry.getAttribute('aTextureCoord').update(); + this.geometry.aVertexPosition.update(); + this.geometry.aTextureCoord.update(); this.geometry.data.indexBuffer.update(); } @@ -201,7 +116,7 @@ */ updateTransform() { - this.geometry.getAttribute('aVertexPosition').update(); + this.geometry.aVertexPosition.update(); this.containerUpdateTransform(); } } diff --git a/src/mesh/RawMesh.js b/src/mesh/RawMesh.js new file mode 100644 index 0000000..761aa69 --- /dev/null +++ b/src/mesh/RawMesh.js @@ -0,0 +1,196 @@ +import * as core from '../core'; + +const tempPoint = new core.Point(); +const tempPolygon = new core.Polygon(); + +/** + * 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 + */ +export default class RawMesh extends core.Container +{ + /** + * @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) + { + super(); + + /** + * the geometry the mesh will use + * @type {PIXI.mesh.Geometry} + */ + 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.State} + */ + this.state = state || new core.State(); + + /** + * The blend mode to be applied to the sprite. Set to `PIXI.BLEND_MODES.NORMAL` to remove any blend mode. + * + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL + * @see PIXI.BLEND_MODES + */ + this.blendMode = core.BLEND_MODES.NORMAL; + this.state.blendMode = this.blendMode; + + /** + * The way the Mesh should be drawn, can be any of the {@link PIXI.mesh.RawMesh.DRAW_MODES} consts + * + * @member {number} + * @see PIXI.mesh.RawMesh.DRAW_MODES + */ + this.drawMode = drawMode; + + uniforms = uniforms || {}; + + // make sure to add required feilds + // 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) + { + uniforms[i] = shader.uniforms[i]; + } + } + + /** + * The way uniforms that will be used by the mesh's shader. + * @member {Object} + */ + this.uniforms = uniforms; + + /** + * A map of renderer IDs to webgl render data + * + * @private + * @member {object} + */ + this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; + + this.start = 0; + this.size = 0; + } + + /** + * Renders the object using the WebGL renderer + * + * @param {PIXI.WebGLRenderer} renderer a reference to the WebGL renderer + * @private + */ + _renderWebGL(renderer) + { + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); + } + + /** + * Renders the object using the Canvas renderer + * + * @private + * @param {PIXI.CanvasRenderer} renderer - The canvas renderer. + */ + _renderCanvas(renderer) + { + renderer.plugins[this.pluginName].render(this); + } + + /** + * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. + * there must be a aVertexPosition attribute present in the geometry for bounds to be calcualted correctly. + * + * @private + */ + _calculateBounds() + { + // The position property could be set manually? + if (this.geometry.style.attributes.aVertexPosition) + { + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + // TODO - we can cache local bounds and use them if they are dirty (like graphics) + this._bounds.addVertices(this.transform, vertices, 0, vertices.length); + } + } + + /** + * Tests if a point is inside this mesh. Works only for TRIANGLE_MESH + * + * @param {PIXI.Point} point the point to test + * @return {boolean} the result of the test + */ + containsPoint(point) + { + if (!this.getBounds().contains(point.x, point.y)) + { + return false; + } + + this.worldTransform.applyInverse(point, tempPoint); + + const vertices = this.geometry.getAttribute('aVertexPosition').data; + + const points = tempPolygon.points; + const indices = this.geometry.getIndex().data; + const len = indices.length; + const step = this.drawMode === 4 ? 3 : 1; + + for (let i = 0; i + 2 < len; i += step) + { + const ind0 = indices[i] * 2; + const ind1 = indices[i + 1] * 2; + const ind2 = indices[i + 2] * 2; + + points[0] = vertices[ind0]; + points[1] = vertices[ind0 + 1]; + points[2] = vertices[ind1]; + points[3] = vertices[ind1 + 1]; + points[4] = vertices[ind2]; + points[5] = vertices[ind2 + 1]; + + if (tempPolygon.contains(tempPoint.x, tempPoint.y)) + { + return true; + } + } + + return false; + } +} diff --git a/src/mesh/Rope.js b/src/mesh/Rope.js index 58f121f..8a7afb2 100644 --- a/src/mesh/Rope.js +++ b/src/mesh/Rope.js @@ -1,10 +1,5 @@ import Mesh from './Mesh'; -import Geometry from './geometry/Geometry'; import * as core from '../core'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -let meshShader; /** * The rope allows you to draw a texture across several points and them manipulate these points @@ -29,100 +24,15 @@ */ constructor(texture, points) { - if (!meshShader) - { - meshShader = new core.Shader(readFileSync(join(__dirname, './webgl/mesh.vert'), 'utf8'), - readFileSync(join(__dirname, './webgl/mesh.frag'), 'utf8')); - } - - const geometry = new Geometry(); - - geometry.addAttribute('aVertexPosition', new Float32Array(points.length * 4), 2) - .addAttribute('aTextureCoord', new Float32Array(points.length * 4), 2) - .addIndex(new Uint16Array(points.length * 2)); - - const uniforms = { - uSampler2: texture, - alpha: 1, - translationMatrix: null, - tint: new Float32Array([1, 1, 1]), - }; - - super(geometry, meshShader, uniforms, null, 5); - - uniforms.translationMatrix = this.transform.worldTransform; + super(texture, new Float32Array(points.length * 4), + new Float32Array(points.length * 4), + new Uint16Array(points.length * 2), + 5); /* * @member {PIXI.Point[]} An array of points that determine the rope */ this.points = points; - - /** - * The tint applied to the rope. This is a hex value. A value of 0xFFFFFF will remove any tint effect. - * - * @private - * @member {number} - * @default 0xFFFFFF - */ - this._tint = 0xFFFFFF; - this.tint = 0xFFFFFF; - - this.texture = texture; - // wait for the texture to load - if (texture.baseTexture.hasLoaded) - { - this.refresh(); - } - else - { - texture.once('update', this.refresh, this); - } - } - - /** - * The tint applied to the Rope. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @memberof PIXI.Sprite# - * @default 0xFFFFFF - */ - get tint() - { - return this._tint; - } - - /** - * Sets the tint of the rope. - * - * @param {number} value - The value to set to. - */ - set tint(value) - { - this._tint = value; - core.utils.hex2rgb(this._tint, this.uniforms.tint); - } - - /** - * Sets the texture of the rope. - * - * @param {PIXI.Texture} value - The value to set to. - */ - set texture(value) - { - this._texture = value; - this.uniforms.uSampler2 = this.texture; - } - - /** - * The texture that the rope is using - * - * @member {PIXI.Texture} - * @memberof PIXI.Sprite# - */ - get texture() - { - return this._texture; } /** @@ -263,4 +173,14 @@ this.containerUpdateTransform(); } + + /** + * When the texture is updated, this event will fire to update the scale and frame + * + * @private + */ + _onTextureUpdate() + { + this.refresh(); + } } diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js index b4cb86d..0a60aff 100644 --- a/src/mesh/canvas/CanvasMeshRenderer.js +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -70,7 +70,7 @@ * Draws the object in Triangle Mesh mode * * @private - * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - the Mesh to render */ _renderTriangleMesh(mesh) { @@ -90,7 +90,7 @@ * Draws the object in triangle mode using canvas * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh */ _renderTriangles(mesh) { @@ -113,7 +113,7 @@ * Draws one of the triangles that from the Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - the current mesh + * @param {PIXI.mesh.RawMesh} mesh - the current mesh * @param {number} index0 - the index of the first vertex * @param {number} index1 - the index of the second vertex * @param {number} index2 - the index of the third vertex @@ -229,7 +229,7 @@ * Renders a flat Mesh * * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + * @param {PIXI.mesh.RawMesh} mesh - The Mesh to render */ renderMeshFlat(mesh) { diff --git a/src/mesh/geometry/Geometry.js b/src/mesh/geometry/Geometry.js index 95ff4fd..b2cfa71 100644 --- a/src/mesh/geometry/Geometry.js +++ b/src/mesh/geometry/Geometry.js @@ -84,6 +84,9 @@ this.style.addAttribute(id, new Attribute(buffer.id, size, stride, start, normalised)); this.data.add(buffer.id, buffer); + // dynamically create an access point.. + this[id] = buffer; + return this; } diff --git a/src/mesh/index.js b/src/mesh/index.js index 30151f2..1ab5333 100644 --- a/src/mesh/index.js +++ b/src/mesh/index.js @@ -2,6 +2,7 @@ * @namespace PIXI.mesh */ export { default as Mesh } from './Mesh'; +export { default as RawMesh } from './RawMesh'; export { default as MeshRenderer } from './webgl/MeshRenderer'; export { default as CanvasMeshRenderer } from './canvas/CanvasMeshRenderer'; export { default as Attribute } from './geometry/Attribute'; diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js index 2e66664..2eff855 100644 --- a/src/mesh/webgl/MeshRenderer.js +++ b/src/mesh/webgl/MeshRenderer.js @@ -36,20 +36,20 @@ /** * renders mesh * @private - * @param {PIXI.mesh.Mesh} mesh mesh instance + * @param {PIXI.mesh.RawMesh} mesh mesh instance */ render(mesh) { + // bind the shader.. + const glShader = this.renderer.shaderManager.bindShader(mesh.shader, true); + // set the shader props.. - if (mesh.uniforms.translationMatrix) + if (glShader.uniformData.translationMatrix) { // the transform! - mesh.uniforms.translationMatrix = mesh.transform.worldTransform.toArray(true); + glShader.uniforms.translationMatrix = mesh.transform.worldTransform.toArray(true); } - // bind the shader.. - this.renderer.shaderManager.bindShader(mesh.shader, true); - // set unifomrs.. this.renderer.shaderManager.setUniforms(mesh.uniforms); @@ -60,7 +60,7 @@ this.bindGeometry(mesh.geometry); // then render it.. - mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode); + mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start); } /** @@ -73,6 +73,7 @@ const vao = geometry.glVertexArrayObjects[this.CONTEXT_UID] || this.initGeometryVao(geometry); this.renderer.bindVao(vao); + const data = geometry.data; // TODO - optimise later! @@ -87,7 +88,6 @@ if (buffer._updateID !== glBuffer._updateID) { glBuffer._updateID = buffer._updateID; - // TODO - partial upload?? glBuffer.upload(buffer.data, 0); } @@ -128,8 +128,11 @@ } } - // first update the index buffer.. - vao.addIndex(geometry.data.indexBuffer._glBuffers[this.CONTEXT_UID]); + if (geometry.data.indexBuffer) + { + // first update the index buffer if we have one.. + vao.addIndex(geometry.data.indexBuffer._glBuffers[this.CONTEXT_UID]); + } const map = geometry.style.generateAttributeLocations();