diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 4719b6a..2ced6dc 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,6 +1,4 @@ import * as core from '../core'; -import glCore from 'pixi-gl-core'; -import Shader from './webgl/MeshShader'; const tempPoint = new core.Point(); const tempPolygon = new core.Polygon(); @@ -59,11 +57,17 @@ this.indices = indices || new Uint16Array([0, 1, 3, 2]); /** - * Whether the Mesh is dirty or not + * Version of mesh uvs are dirty or not * * @member {number} */ this.dirty = 0; + + /** + * Version of mesh indices + * + * @member {number} + */ this.indexDirty = 0; /** @@ -122,62 +126,8 @@ */ _renderWebGL(renderer) { - // get rid of any thing that may be batching. - renderer.flush(); - - // renderer.plugins.mesh.render(this); - const gl = renderer.gl; - let glData = this._glDatas[renderer.CONTEXT_UID]; - - if (!glData) - { - glData = { - shader: new Shader(gl), - vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.vertices, gl.STREAM_DRAW), - uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.uvs, gl.STREAM_DRAW), - indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW), - // build the vao object that will render.. - vao: new glCore.VertexArrayObject(gl), - dirty: this.dirty, - indexDirty: this.indexDirty, - }; - - // build the vao object that will render.. - glData.vao = new glCore.VertexArrayObject(gl) - .addIndex(glData.indexBuffer) - .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) - .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); - - this._glDatas[renderer.CONTEXT_UID] = glData; - } - - if (this.dirty !== glData.dirty) - { - glData.dirty = this.dirty; - glData.uvBuffer.upload(); - } - - if (this.indexDirty !== glData.indexDirty) - { - glData.indexDirty = this.indexDirty; - glData.indexBuffer.upload(); - } - - glData.vertexBuffer.upload(); - - renderer.bindShader(glData.shader); - renderer.bindTexture(this._texture, 0); - renderer.state.setBlendMode(this.blendMode); - - glData.shader.uniforms.translationMatrix = this.worldTransform.toArray(true); - glData.shader.uniforms.alpha = this.worldAlpha; - glData.shader.uniforms.tint = this.tintRgb; - - const drawMode = this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - glData.vao.bind() - .draw(drawMode, this.indices.length) - .unbind(); + renderer.setObjectRenderer(renderer.plugins.mesh); + renderer.plugins.mesh.render(this); } /** @@ -188,240 +138,7 @@ */ _renderCanvas(renderer) { - const context = renderer.context; - - const transform = this.worldTransform; - const res = renderer.resolution; - - if (renderer.roundPixels) - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - (transform.tx * res) | 0, - (transform.ty * res) | 0 - ); - } - else - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - transform.tx * res, - transform.ty * res - ); - } - - if (this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) - { - this._renderCanvasTriangleMesh(context); - } - else - { - this._renderCanvasTriangles(context); - } - } - - /** - * Draws the object in Triangle Mesh mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - The current drawing context - */ - _renderCanvasTriangleMesh(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const length = vertices.length / 2; - - // this.count++; - - for (let i = 0; i < length - 2; i++) - { - // draw some triangles! - const index = i * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } - } - - /** - * Draws the object in triangle mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - */ - _renderCanvasTriangles(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const indices = this.indices; - const length = indices.length; - // this.count++; - - for (let i = 0; i < length; i += 3) - { - // draw some triangles! - const index0 = indices[i] * 2; - const index1 = indices[i + 1] * 2; - const index2 = indices[i + 2] * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } - } - - /** - * Draws one of the triangles that form this Mesh - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - * @param {Float32Array} vertices - a reference to the vertices of the Mesh - * @param {Float32Array} uvs - a reference to the uvs of the 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 - */ - _renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2) - { - const base = this._texture.baseTexture; - const textureSource = base.source; - const textureWidth = base.width; - const textureHeight = base.height; - - const u0 = uvs[index0] * base.width; - const u1 = uvs[index1] * base.width; - const u2 = uvs[index2] * base.width; - const v0 = uvs[index0 + 1] * base.height; - const v1 = uvs[index1 + 1] * base.height; - const v2 = uvs[index2 + 1] * base.height; - - let x0 = vertices[index0]; - let x1 = vertices[index1]; - let x2 = vertices[index2]; - let y0 = vertices[index0 + 1]; - let y1 = vertices[index1 + 1]; - let y2 = vertices[index2 + 1]; - - if (this.canvasPadding > 0) - { - const paddingX = this.canvasPadding / this.worldTransform.a; - const paddingY = this.canvasPadding / this.worldTransform.d; - const centerX = (x0 + x1 + x2) / 3; - const centerY = (y0 + y1 + y2) / 3; - - let normX = x0 - centerX; - let normY = y0 - centerY; - - let dist = Math.sqrt((normX * normX) + (normY * normY)); - - x0 = centerX + ((normX / dist) * (dist + paddingX)); - y0 = centerY + ((normY / dist) * (dist + paddingY)); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x1 = centerX + ((normX / dist) * (dist + paddingX)); - y1 = centerY + ((normY / dist) * (dist + paddingY)); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x2 = centerX + ((normX / dist) * (dist + paddingX)); - y2 = centerY + ((normY / dist) * (dist + paddingY)); - } - - context.save(); - context.beginPath(); - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform( - deltaA / delta, - deltaD / delta, - deltaB / delta, - deltaE / delta, - deltaC / delta, - deltaF / delta - ); - - context.drawImage( - textureSource, - 0, - 0, - textureWidth * base.resolution, - textureHeight * base.resolution, - 0, - 0, - textureWidth, - textureHeight - ); - - context.restore(); - } - - /** - * Renders a flat Mesh - * - * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render - */ - renderMeshFlat(mesh) - { - const context = this.context; - const vertices = mesh.vertices; - const length = vertices.length / 2; - - // this.count++; - - context.beginPath(); - - for (let i = 1; i < length - 2; ++i) - { - // draw some triangles! - const index = i * 2; - - const x0 = vertices[index]; - const y0 = vertices[index + 1]; - - const x1 = vertices[index + 2]; - const y1 = vertices[index + 3]; - - const x2 = vertices[index + 4]; - const y2 = vertices[index + 5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); + renderer.plugins.mesh.render(this); } /** diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 4719b6a..2ced6dc 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,6 +1,4 @@ import * as core from '../core'; -import glCore from 'pixi-gl-core'; -import Shader from './webgl/MeshShader'; const tempPoint = new core.Point(); const tempPolygon = new core.Polygon(); @@ -59,11 +57,17 @@ this.indices = indices || new Uint16Array([0, 1, 3, 2]); /** - * Whether the Mesh is dirty or not + * Version of mesh uvs are dirty or not * * @member {number} */ this.dirty = 0; + + /** + * Version of mesh indices + * + * @member {number} + */ this.indexDirty = 0; /** @@ -122,62 +126,8 @@ */ _renderWebGL(renderer) { - // get rid of any thing that may be batching. - renderer.flush(); - - // renderer.plugins.mesh.render(this); - const gl = renderer.gl; - let glData = this._glDatas[renderer.CONTEXT_UID]; - - if (!glData) - { - glData = { - shader: new Shader(gl), - vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.vertices, gl.STREAM_DRAW), - uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.uvs, gl.STREAM_DRAW), - indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW), - // build the vao object that will render.. - vao: new glCore.VertexArrayObject(gl), - dirty: this.dirty, - indexDirty: this.indexDirty, - }; - - // build the vao object that will render.. - glData.vao = new glCore.VertexArrayObject(gl) - .addIndex(glData.indexBuffer) - .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) - .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); - - this._glDatas[renderer.CONTEXT_UID] = glData; - } - - if (this.dirty !== glData.dirty) - { - glData.dirty = this.dirty; - glData.uvBuffer.upload(); - } - - if (this.indexDirty !== glData.indexDirty) - { - glData.indexDirty = this.indexDirty; - glData.indexBuffer.upload(); - } - - glData.vertexBuffer.upload(); - - renderer.bindShader(glData.shader); - renderer.bindTexture(this._texture, 0); - renderer.state.setBlendMode(this.blendMode); - - glData.shader.uniforms.translationMatrix = this.worldTransform.toArray(true); - glData.shader.uniforms.alpha = this.worldAlpha; - glData.shader.uniforms.tint = this.tintRgb; - - const drawMode = this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - glData.vao.bind() - .draw(drawMode, this.indices.length) - .unbind(); + renderer.setObjectRenderer(renderer.plugins.mesh); + renderer.plugins.mesh.render(this); } /** @@ -188,240 +138,7 @@ */ _renderCanvas(renderer) { - const context = renderer.context; - - const transform = this.worldTransform; - const res = renderer.resolution; - - if (renderer.roundPixels) - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - (transform.tx * res) | 0, - (transform.ty * res) | 0 - ); - } - else - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - transform.tx * res, - transform.ty * res - ); - } - - if (this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) - { - this._renderCanvasTriangleMesh(context); - } - else - { - this._renderCanvasTriangles(context); - } - } - - /** - * Draws the object in Triangle Mesh mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - The current drawing context - */ - _renderCanvasTriangleMesh(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const length = vertices.length / 2; - - // this.count++; - - for (let i = 0; i < length - 2; i++) - { - // draw some triangles! - const index = i * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } - } - - /** - * Draws the object in triangle mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - */ - _renderCanvasTriangles(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const indices = this.indices; - const length = indices.length; - // this.count++; - - for (let i = 0; i < length; i += 3) - { - // draw some triangles! - const index0 = indices[i] * 2; - const index1 = indices[i + 1] * 2; - const index2 = indices[i + 2] * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } - } - - /** - * Draws one of the triangles that form this Mesh - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - * @param {Float32Array} vertices - a reference to the vertices of the Mesh - * @param {Float32Array} uvs - a reference to the uvs of the 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 - */ - _renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2) - { - const base = this._texture.baseTexture; - const textureSource = base.source; - const textureWidth = base.width; - const textureHeight = base.height; - - const u0 = uvs[index0] * base.width; - const u1 = uvs[index1] * base.width; - const u2 = uvs[index2] * base.width; - const v0 = uvs[index0 + 1] * base.height; - const v1 = uvs[index1 + 1] * base.height; - const v2 = uvs[index2 + 1] * base.height; - - let x0 = vertices[index0]; - let x1 = vertices[index1]; - let x2 = vertices[index2]; - let y0 = vertices[index0 + 1]; - let y1 = vertices[index1 + 1]; - let y2 = vertices[index2 + 1]; - - if (this.canvasPadding > 0) - { - const paddingX = this.canvasPadding / this.worldTransform.a; - const paddingY = this.canvasPadding / this.worldTransform.d; - const centerX = (x0 + x1 + x2) / 3; - const centerY = (y0 + y1 + y2) / 3; - - let normX = x0 - centerX; - let normY = y0 - centerY; - - let dist = Math.sqrt((normX * normX) + (normY * normY)); - - x0 = centerX + ((normX / dist) * (dist + paddingX)); - y0 = centerY + ((normY / dist) * (dist + paddingY)); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x1 = centerX + ((normX / dist) * (dist + paddingX)); - y1 = centerY + ((normY / dist) * (dist + paddingY)); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x2 = centerX + ((normX / dist) * (dist + paddingX)); - y2 = centerY + ((normY / dist) * (dist + paddingY)); - } - - context.save(); - context.beginPath(); - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform( - deltaA / delta, - deltaD / delta, - deltaB / delta, - deltaE / delta, - deltaC / delta, - deltaF / delta - ); - - context.drawImage( - textureSource, - 0, - 0, - textureWidth * base.resolution, - textureHeight * base.resolution, - 0, - 0, - textureWidth, - textureHeight - ); - - context.restore(); - } - - /** - * Renders a flat Mesh - * - * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render - */ - renderMeshFlat(mesh) - { - const context = this.context; - const vertices = mesh.vertices; - const length = vertices.length / 2; - - // this.count++; - - context.beginPath(); - - for (let i = 1; i < length - 2; ++i) - { - // draw some triangles! - const index = i * 2; - - const x0 = vertices[index]; - const y0 = vertices[index + 1]; - - const x1 = vertices[index + 2]; - const y1 = vertices[index + 3]; - - const x2 = vertices[index + 4]; - const y2 = vertices[index + 5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); + renderer.plugins.mesh.render(this); } /** diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js new file mode 100644 index 0000000..a1ad74c --- /dev/null +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -0,0 +1,276 @@ +import * as core from '../../core'; +import { default as Mesh } from '../Mesh'; + +/** + * Renderer dedicated to meshes. + * + * @class + * @private + * @memberof PIXI + */ +export default class MeshSpriteRenderer +{ + /** + * @param {PIXI.CanvasRenderer} renderer - The renderer this downport works for + */ + constructor(renderer) + { + this.renderer = renderer; + } + + /** + * Renders the Mesh + * + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + render(mesh) + { + const renderer = this.renderer; + const context = renderer.context; + + const transform = mesh.worldTransform; + const res = renderer.resolution; + + if (renderer.roundPixels) + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + (transform.tx * res) | 0, + (transform.ty * res) | 0 + ); + } + else + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + transform.tx * res, + transform.ty * res + ); + } + + if (mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) + { + this._renderTriangleMesh(mesh); + } + else + { + this._renderTriangles(mesh); + } + } + + /** + * Draws the object in Triangle Mesh mode + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + _renderTriangleMesh(mesh) + { + // draw triangles!! + const length = mesh.vertices.length / 2; + + for (let i = 0; i < length - 2; i++) + { + // draw some triangles! + const index = i * 2; + + this._renderDrawTriangle(mesh, index, (index + 2), (index + 4)); + } + } + + /** + * Draws the object in triangle mode using canvas + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the current mesh + */ + _renderTriangles(mesh) + { + // draw triangles!! + const indices = mesh.indices; + const length = indices.length; + + for (let i = 0; i < length; i += 3) + { + // draw some triangles! + const index0 = indices[i] * 2; + const index1 = indices[i + 1] * 2; + const index2 = indices[i + 2] * 2; + + this._renderDrawTriangle(mesh, index0, index1, index2); + } + } + + /** + * Draws one of the triangles that from the Mesh + * + * @private + * @param {PIXI.mesh.Mesh} 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 + */ + _renderDrawTriangle(mesh, index0, index1, index2) + { + const context = this.renderer.context; + const uvs = mesh.uvs; + const vertices = mesh.vertices; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + const base = texture.baseTexture; + const textureSource = base.source; + const textureWidth = base.width; + const textureHeight = base.height; + + const u0 = uvs[index0] * base.width; + const u1 = uvs[index1] * base.width; + const u2 = uvs[index2] * base.width; + const v0 = uvs[index0 + 1] * base.height; + const v1 = uvs[index1 + 1] * base.height; + const v2 = uvs[index2 + 1] * base.height; + + let x0 = vertices[index0]; + let x1 = vertices[index1]; + let x2 = vertices[index2]; + let y0 = vertices[index0 + 1]; + let y1 = vertices[index1 + 1]; + let y2 = vertices[index2 + 1]; + + if (mesh.canvasPadding > 0) + { + const paddingX = mesh.canvasPadding / mesh.worldTransform.a; + const paddingY = mesh.canvasPadding / mesh.worldTransform.d; + const centerX = (x0 + x1 + x2) / 3; + const centerY = (y0 + y1 + y2) / 3; + + let normX = x0 - centerX; + let normY = y0 - centerY; + + let dist = Math.sqrt((normX * normX) + (normY * normY)); + + x0 = centerX + ((normX / dist) * (dist + paddingX)); + y0 = centerY + ((normY / dist) * (dist + paddingY)); + + // + + normX = x1 - centerX; + normY = y1 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x1 = centerX + ((normX / dist) * (dist + paddingX)); + y1 = centerY + ((normY / dist) * (dist + paddingY)); + + normX = x2 - centerX; + normY = y2 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x2 = centerX + ((normX / dist) * (dist + paddingX)); + y2 = centerY + ((normY / dist) * (dist + paddingY)); + } + + context.save(); + context.beginPath(); + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + context.closePath(); + + context.clip(); + + // Compute matrix transform + const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); + const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); + const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); + const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); + const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); + const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); + const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); + + context.transform( + deltaA / delta, + deltaD / delta, + deltaB / delta, + deltaE / delta, + deltaC / delta, + deltaF / delta + ); + + context.drawImage( + textureSource, + 0, + 0, + textureWidth * base.resolution, + textureHeight * base.resolution, + 0, + 0, + textureWidth, + textureHeight + ); + + context.restore(); + } + + /** + * Renders a flat Mesh + * + * @private + * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + */ + renderMeshFlat(mesh) + { + const context = this.renderer.context; + const vertices = mesh.vertices; + const length = vertices.length / 2; + + // this.count++; + + context.beginPath(); + + for (let i = 1; i < length - 2; ++i) + { + // draw some triangles! + const index = i * 2; + + const x0 = vertices[index]; + const y0 = vertices[index + 1]; + + const x1 = vertices[index + 2]; + const y1 = vertices[index + 3]; + + const x2 = vertices[index + 4]; + const y2 = vertices[index + 5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + } + + context.fillStyle = '#FF0000'; + context.fill(); + context.closePath(); + } + + /** + * destroy the the renderer. + * + */ + destroy() + { + this.renderer = null; + } +} + +core.CanvasRenderer.registerPlugin('mesh', MeshSpriteRenderer); diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 4719b6a..2ced6dc 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,6 +1,4 @@ import * as core from '../core'; -import glCore from 'pixi-gl-core'; -import Shader from './webgl/MeshShader'; const tempPoint = new core.Point(); const tempPolygon = new core.Polygon(); @@ -59,11 +57,17 @@ this.indices = indices || new Uint16Array([0, 1, 3, 2]); /** - * Whether the Mesh is dirty or not + * Version of mesh uvs are dirty or not * * @member {number} */ this.dirty = 0; + + /** + * Version of mesh indices + * + * @member {number} + */ this.indexDirty = 0; /** @@ -122,62 +126,8 @@ */ _renderWebGL(renderer) { - // get rid of any thing that may be batching. - renderer.flush(); - - // renderer.plugins.mesh.render(this); - const gl = renderer.gl; - let glData = this._glDatas[renderer.CONTEXT_UID]; - - if (!glData) - { - glData = { - shader: new Shader(gl), - vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.vertices, gl.STREAM_DRAW), - uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.uvs, gl.STREAM_DRAW), - indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW), - // build the vao object that will render.. - vao: new glCore.VertexArrayObject(gl), - dirty: this.dirty, - indexDirty: this.indexDirty, - }; - - // build the vao object that will render.. - glData.vao = new glCore.VertexArrayObject(gl) - .addIndex(glData.indexBuffer) - .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) - .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); - - this._glDatas[renderer.CONTEXT_UID] = glData; - } - - if (this.dirty !== glData.dirty) - { - glData.dirty = this.dirty; - glData.uvBuffer.upload(); - } - - if (this.indexDirty !== glData.indexDirty) - { - glData.indexDirty = this.indexDirty; - glData.indexBuffer.upload(); - } - - glData.vertexBuffer.upload(); - - renderer.bindShader(glData.shader); - renderer.bindTexture(this._texture, 0); - renderer.state.setBlendMode(this.blendMode); - - glData.shader.uniforms.translationMatrix = this.worldTransform.toArray(true); - glData.shader.uniforms.alpha = this.worldAlpha; - glData.shader.uniforms.tint = this.tintRgb; - - const drawMode = this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - glData.vao.bind() - .draw(drawMode, this.indices.length) - .unbind(); + renderer.setObjectRenderer(renderer.plugins.mesh); + renderer.plugins.mesh.render(this); } /** @@ -188,240 +138,7 @@ */ _renderCanvas(renderer) { - const context = renderer.context; - - const transform = this.worldTransform; - const res = renderer.resolution; - - if (renderer.roundPixels) - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - (transform.tx * res) | 0, - (transform.ty * res) | 0 - ); - } - else - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - transform.tx * res, - transform.ty * res - ); - } - - if (this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) - { - this._renderCanvasTriangleMesh(context); - } - else - { - this._renderCanvasTriangles(context); - } - } - - /** - * Draws the object in Triangle Mesh mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - The current drawing context - */ - _renderCanvasTriangleMesh(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const length = vertices.length / 2; - - // this.count++; - - for (let i = 0; i < length - 2; i++) - { - // draw some triangles! - const index = i * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } - } - - /** - * Draws the object in triangle mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - */ - _renderCanvasTriangles(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const indices = this.indices; - const length = indices.length; - // this.count++; - - for (let i = 0; i < length; i += 3) - { - // draw some triangles! - const index0 = indices[i] * 2; - const index1 = indices[i + 1] * 2; - const index2 = indices[i + 2] * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } - } - - /** - * Draws one of the triangles that form this Mesh - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - * @param {Float32Array} vertices - a reference to the vertices of the Mesh - * @param {Float32Array} uvs - a reference to the uvs of the 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 - */ - _renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2) - { - const base = this._texture.baseTexture; - const textureSource = base.source; - const textureWidth = base.width; - const textureHeight = base.height; - - const u0 = uvs[index0] * base.width; - const u1 = uvs[index1] * base.width; - const u2 = uvs[index2] * base.width; - const v0 = uvs[index0 + 1] * base.height; - const v1 = uvs[index1 + 1] * base.height; - const v2 = uvs[index2 + 1] * base.height; - - let x0 = vertices[index0]; - let x1 = vertices[index1]; - let x2 = vertices[index2]; - let y0 = vertices[index0 + 1]; - let y1 = vertices[index1 + 1]; - let y2 = vertices[index2 + 1]; - - if (this.canvasPadding > 0) - { - const paddingX = this.canvasPadding / this.worldTransform.a; - const paddingY = this.canvasPadding / this.worldTransform.d; - const centerX = (x0 + x1 + x2) / 3; - const centerY = (y0 + y1 + y2) / 3; - - let normX = x0 - centerX; - let normY = y0 - centerY; - - let dist = Math.sqrt((normX * normX) + (normY * normY)); - - x0 = centerX + ((normX / dist) * (dist + paddingX)); - y0 = centerY + ((normY / dist) * (dist + paddingY)); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x1 = centerX + ((normX / dist) * (dist + paddingX)); - y1 = centerY + ((normY / dist) * (dist + paddingY)); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x2 = centerX + ((normX / dist) * (dist + paddingX)); - y2 = centerY + ((normY / dist) * (dist + paddingY)); - } - - context.save(); - context.beginPath(); - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform( - deltaA / delta, - deltaD / delta, - deltaB / delta, - deltaE / delta, - deltaC / delta, - deltaF / delta - ); - - context.drawImage( - textureSource, - 0, - 0, - textureWidth * base.resolution, - textureHeight * base.resolution, - 0, - 0, - textureWidth, - textureHeight - ); - - context.restore(); - } - - /** - * Renders a flat Mesh - * - * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render - */ - renderMeshFlat(mesh) - { - const context = this.context; - const vertices = mesh.vertices; - const length = vertices.length / 2; - - // this.count++; - - context.beginPath(); - - for (let i = 1; i < length - 2; ++i) - { - // draw some triangles! - const index = i * 2; - - const x0 = vertices[index]; - const y0 = vertices[index + 1]; - - const x1 = vertices[index + 2]; - const y1 = vertices[index + 3]; - - const x2 = vertices[index + 4]; - const y2 = vertices[index + 5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); + renderer.plugins.mesh.render(this); } /** diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js new file mode 100644 index 0000000..a1ad74c --- /dev/null +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -0,0 +1,276 @@ +import * as core from '../../core'; +import { default as Mesh } from '../Mesh'; + +/** + * Renderer dedicated to meshes. + * + * @class + * @private + * @memberof PIXI + */ +export default class MeshSpriteRenderer +{ + /** + * @param {PIXI.CanvasRenderer} renderer - The renderer this downport works for + */ + constructor(renderer) + { + this.renderer = renderer; + } + + /** + * Renders the Mesh + * + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + render(mesh) + { + const renderer = this.renderer; + const context = renderer.context; + + const transform = mesh.worldTransform; + const res = renderer.resolution; + + if (renderer.roundPixels) + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + (transform.tx * res) | 0, + (transform.ty * res) | 0 + ); + } + else + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + transform.tx * res, + transform.ty * res + ); + } + + if (mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) + { + this._renderTriangleMesh(mesh); + } + else + { + this._renderTriangles(mesh); + } + } + + /** + * Draws the object in Triangle Mesh mode + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + _renderTriangleMesh(mesh) + { + // draw triangles!! + const length = mesh.vertices.length / 2; + + for (let i = 0; i < length - 2; i++) + { + // draw some triangles! + const index = i * 2; + + this._renderDrawTriangle(mesh, index, (index + 2), (index + 4)); + } + } + + /** + * Draws the object in triangle mode using canvas + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the current mesh + */ + _renderTriangles(mesh) + { + // draw triangles!! + const indices = mesh.indices; + const length = indices.length; + + for (let i = 0; i < length; i += 3) + { + // draw some triangles! + const index0 = indices[i] * 2; + const index1 = indices[i + 1] * 2; + const index2 = indices[i + 2] * 2; + + this._renderDrawTriangle(mesh, index0, index1, index2); + } + } + + /** + * Draws one of the triangles that from the Mesh + * + * @private + * @param {PIXI.mesh.Mesh} 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 + */ + _renderDrawTriangle(mesh, index0, index1, index2) + { + const context = this.renderer.context; + const uvs = mesh.uvs; + const vertices = mesh.vertices; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + const base = texture.baseTexture; + const textureSource = base.source; + const textureWidth = base.width; + const textureHeight = base.height; + + const u0 = uvs[index0] * base.width; + const u1 = uvs[index1] * base.width; + const u2 = uvs[index2] * base.width; + const v0 = uvs[index0 + 1] * base.height; + const v1 = uvs[index1 + 1] * base.height; + const v2 = uvs[index2 + 1] * base.height; + + let x0 = vertices[index0]; + let x1 = vertices[index1]; + let x2 = vertices[index2]; + let y0 = vertices[index0 + 1]; + let y1 = vertices[index1 + 1]; + let y2 = vertices[index2 + 1]; + + if (mesh.canvasPadding > 0) + { + const paddingX = mesh.canvasPadding / mesh.worldTransform.a; + const paddingY = mesh.canvasPadding / mesh.worldTransform.d; + const centerX = (x0 + x1 + x2) / 3; + const centerY = (y0 + y1 + y2) / 3; + + let normX = x0 - centerX; + let normY = y0 - centerY; + + let dist = Math.sqrt((normX * normX) + (normY * normY)); + + x0 = centerX + ((normX / dist) * (dist + paddingX)); + y0 = centerY + ((normY / dist) * (dist + paddingY)); + + // + + normX = x1 - centerX; + normY = y1 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x1 = centerX + ((normX / dist) * (dist + paddingX)); + y1 = centerY + ((normY / dist) * (dist + paddingY)); + + normX = x2 - centerX; + normY = y2 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x2 = centerX + ((normX / dist) * (dist + paddingX)); + y2 = centerY + ((normY / dist) * (dist + paddingY)); + } + + context.save(); + context.beginPath(); + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + context.closePath(); + + context.clip(); + + // Compute matrix transform + const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); + const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); + const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); + const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); + const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); + const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); + const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); + + context.transform( + deltaA / delta, + deltaD / delta, + deltaB / delta, + deltaE / delta, + deltaC / delta, + deltaF / delta + ); + + context.drawImage( + textureSource, + 0, + 0, + textureWidth * base.resolution, + textureHeight * base.resolution, + 0, + 0, + textureWidth, + textureHeight + ); + + context.restore(); + } + + /** + * Renders a flat Mesh + * + * @private + * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + */ + renderMeshFlat(mesh) + { + const context = this.renderer.context; + const vertices = mesh.vertices; + const length = vertices.length / 2; + + // this.count++; + + context.beginPath(); + + for (let i = 1; i < length - 2; ++i) + { + // draw some triangles! + const index = i * 2; + + const x0 = vertices[index]; + const y0 = vertices[index + 1]; + + const x1 = vertices[index + 2]; + const y1 = vertices[index + 3]; + + const x2 = vertices[index + 4]; + const y2 = vertices[index + 5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + } + + context.fillStyle = '#FF0000'; + context.fill(); + context.closePath(); + } + + /** + * destroy the the renderer. + * + */ + destroy() + { + this.renderer = null; + } +} + +core.CanvasRenderer.registerPlugin('mesh', MeshSpriteRenderer); diff --git a/src/mesh/index.js b/src/mesh/index.js index 473d22a..4d1cad6 100644 --- a/src/mesh/index.js +++ b/src/mesh/index.js @@ -2,7 +2,8 @@ * @namespace PIXI.mesh */ export { default as Mesh } from './Mesh'; +export { default as MeshRenderer } from './webgl/MeshRenderer'; +export { default as CanvasMeshRenderer } from './canvas/CanvasMeshRenderer'; export { default as Plane } from './Plane'; export { default as NineSlicePlane } from './NineSlicePlane'; export { default as Rope } from './Rope'; -export { default as MeshShader } from './webgl/MeshShader'; diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 4719b6a..2ced6dc 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,6 +1,4 @@ import * as core from '../core'; -import glCore from 'pixi-gl-core'; -import Shader from './webgl/MeshShader'; const tempPoint = new core.Point(); const tempPolygon = new core.Polygon(); @@ -59,11 +57,17 @@ this.indices = indices || new Uint16Array([0, 1, 3, 2]); /** - * Whether the Mesh is dirty or not + * Version of mesh uvs are dirty or not * * @member {number} */ this.dirty = 0; + + /** + * Version of mesh indices + * + * @member {number} + */ this.indexDirty = 0; /** @@ -122,62 +126,8 @@ */ _renderWebGL(renderer) { - // get rid of any thing that may be batching. - renderer.flush(); - - // renderer.plugins.mesh.render(this); - const gl = renderer.gl; - let glData = this._glDatas[renderer.CONTEXT_UID]; - - if (!glData) - { - glData = { - shader: new Shader(gl), - vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.vertices, gl.STREAM_DRAW), - uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.uvs, gl.STREAM_DRAW), - indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW), - // build the vao object that will render.. - vao: new glCore.VertexArrayObject(gl), - dirty: this.dirty, - indexDirty: this.indexDirty, - }; - - // build the vao object that will render.. - glData.vao = new glCore.VertexArrayObject(gl) - .addIndex(glData.indexBuffer) - .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) - .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); - - this._glDatas[renderer.CONTEXT_UID] = glData; - } - - if (this.dirty !== glData.dirty) - { - glData.dirty = this.dirty; - glData.uvBuffer.upload(); - } - - if (this.indexDirty !== glData.indexDirty) - { - glData.indexDirty = this.indexDirty; - glData.indexBuffer.upload(); - } - - glData.vertexBuffer.upload(); - - renderer.bindShader(glData.shader); - renderer.bindTexture(this._texture, 0); - renderer.state.setBlendMode(this.blendMode); - - glData.shader.uniforms.translationMatrix = this.worldTransform.toArray(true); - glData.shader.uniforms.alpha = this.worldAlpha; - glData.shader.uniforms.tint = this.tintRgb; - - const drawMode = this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - glData.vao.bind() - .draw(drawMode, this.indices.length) - .unbind(); + renderer.setObjectRenderer(renderer.plugins.mesh); + renderer.plugins.mesh.render(this); } /** @@ -188,240 +138,7 @@ */ _renderCanvas(renderer) { - const context = renderer.context; - - const transform = this.worldTransform; - const res = renderer.resolution; - - if (renderer.roundPixels) - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - (transform.tx * res) | 0, - (transform.ty * res) | 0 - ); - } - else - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - transform.tx * res, - transform.ty * res - ); - } - - if (this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) - { - this._renderCanvasTriangleMesh(context); - } - else - { - this._renderCanvasTriangles(context); - } - } - - /** - * Draws the object in Triangle Mesh mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - The current drawing context - */ - _renderCanvasTriangleMesh(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const length = vertices.length / 2; - - // this.count++; - - for (let i = 0; i < length - 2; i++) - { - // draw some triangles! - const index = i * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } - } - - /** - * Draws the object in triangle mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - */ - _renderCanvasTriangles(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const indices = this.indices; - const length = indices.length; - // this.count++; - - for (let i = 0; i < length; i += 3) - { - // draw some triangles! - const index0 = indices[i] * 2; - const index1 = indices[i + 1] * 2; - const index2 = indices[i + 2] * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } - } - - /** - * Draws one of the triangles that form this Mesh - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - * @param {Float32Array} vertices - a reference to the vertices of the Mesh - * @param {Float32Array} uvs - a reference to the uvs of the 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 - */ - _renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2) - { - const base = this._texture.baseTexture; - const textureSource = base.source; - const textureWidth = base.width; - const textureHeight = base.height; - - const u0 = uvs[index0] * base.width; - const u1 = uvs[index1] * base.width; - const u2 = uvs[index2] * base.width; - const v0 = uvs[index0 + 1] * base.height; - const v1 = uvs[index1 + 1] * base.height; - const v2 = uvs[index2 + 1] * base.height; - - let x0 = vertices[index0]; - let x1 = vertices[index1]; - let x2 = vertices[index2]; - let y0 = vertices[index0 + 1]; - let y1 = vertices[index1 + 1]; - let y2 = vertices[index2 + 1]; - - if (this.canvasPadding > 0) - { - const paddingX = this.canvasPadding / this.worldTransform.a; - const paddingY = this.canvasPadding / this.worldTransform.d; - const centerX = (x0 + x1 + x2) / 3; - const centerY = (y0 + y1 + y2) / 3; - - let normX = x0 - centerX; - let normY = y0 - centerY; - - let dist = Math.sqrt((normX * normX) + (normY * normY)); - - x0 = centerX + ((normX / dist) * (dist + paddingX)); - y0 = centerY + ((normY / dist) * (dist + paddingY)); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x1 = centerX + ((normX / dist) * (dist + paddingX)); - y1 = centerY + ((normY / dist) * (dist + paddingY)); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x2 = centerX + ((normX / dist) * (dist + paddingX)); - y2 = centerY + ((normY / dist) * (dist + paddingY)); - } - - context.save(); - context.beginPath(); - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform( - deltaA / delta, - deltaD / delta, - deltaB / delta, - deltaE / delta, - deltaC / delta, - deltaF / delta - ); - - context.drawImage( - textureSource, - 0, - 0, - textureWidth * base.resolution, - textureHeight * base.resolution, - 0, - 0, - textureWidth, - textureHeight - ); - - context.restore(); - } - - /** - * Renders a flat Mesh - * - * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render - */ - renderMeshFlat(mesh) - { - const context = this.context; - const vertices = mesh.vertices; - const length = vertices.length / 2; - - // this.count++; - - context.beginPath(); - - for (let i = 1; i < length - 2; ++i) - { - // draw some triangles! - const index = i * 2; - - const x0 = vertices[index]; - const y0 = vertices[index + 1]; - - const x1 = vertices[index + 2]; - const y1 = vertices[index + 3]; - - const x2 = vertices[index + 4]; - const y2 = vertices[index + 5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); + renderer.plugins.mesh.render(this); } /** diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js new file mode 100644 index 0000000..a1ad74c --- /dev/null +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -0,0 +1,276 @@ +import * as core from '../../core'; +import { default as Mesh } from '../Mesh'; + +/** + * Renderer dedicated to meshes. + * + * @class + * @private + * @memberof PIXI + */ +export default class MeshSpriteRenderer +{ + /** + * @param {PIXI.CanvasRenderer} renderer - The renderer this downport works for + */ + constructor(renderer) + { + this.renderer = renderer; + } + + /** + * Renders the Mesh + * + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + render(mesh) + { + const renderer = this.renderer; + const context = renderer.context; + + const transform = mesh.worldTransform; + const res = renderer.resolution; + + if (renderer.roundPixels) + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + (transform.tx * res) | 0, + (transform.ty * res) | 0 + ); + } + else + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + transform.tx * res, + transform.ty * res + ); + } + + if (mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) + { + this._renderTriangleMesh(mesh); + } + else + { + this._renderTriangles(mesh); + } + } + + /** + * Draws the object in Triangle Mesh mode + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + _renderTriangleMesh(mesh) + { + // draw triangles!! + const length = mesh.vertices.length / 2; + + for (let i = 0; i < length - 2; i++) + { + // draw some triangles! + const index = i * 2; + + this._renderDrawTriangle(mesh, index, (index + 2), (index + 4)); + } + } + + /** + * Draws the object in triangle mode using canvas + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the current mesh + */ + _renderTriangles(mesh) + { + // draw triangles!! + const indices = mesh.indices; + const length = indices.length; + + for (let i = 0; i < length; i += 3) + { + // draw some triangles! + const index0 = indices[i] * 2; + const index1 = indices[i + 1] * 2; + const index2 = indices[i + 2] * 2; + + this._renderDrawTriangle(mesh, index0, index1, index2); + } + } + + /** + * Draws one of the triangles that from the Mesh + * + * @private + * @param {PIXI.mesh.Mesh} 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 + */ + _renderDrawTriangle(mesh, index0, index1, index2) + { + const context = this.renderer.context; + const uvs = mesh.uvs; + const vertices = mesh.vertices; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + const base = texture.baseTexture; + const textureSource = base.source; + const textureWidth = base.width; + const textureHeight = base.height; + + const u0 = uvs[index0] * base.width; + const u1 = uvs[index1] * base.width; + const u2 = uvs[index2] * base.width; + const v0 = uvs[index0 + 1] * base.height; + const v1 = uvs[index1 + 1] * base.height; + const v2 = uvs[index2 + 1] * base.height; + + let x0 = vertices[index0]; + let x1 = vertices[index1]; + let x2 = vertices[index2]; + let y0 = vertices[index0 + 1]; + let y1 = vertices[index1 + 1]; + let y2 = vertices[index2 + 1]; + + if (mesh.canvasPadding > 0) + { + const paddingX = mesh.canvasPadding / mesh.worldTransform.a; + const paddingY = mesh.canvasPadding / mesh.worldTransform.d; + const centerX = (x0 + x1 + x2) / 3; + const centerY = (y0 + y1 + y2) / 3; + + let normX = x0 - centerX; + let normY = y0 - centerY; + + let dist = Math.sqrt((normX * normX) + (normY * normY)); + + x0 = centerX + ((normX / dist) * (dist + paddingX)); + y0 = centerY + ((normY / dist) * (dist + paddingY)); + + // + + normX = x1 - centerX; + normY = y1 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x1 = centerX + ((normX / dist) * (dist + paddingX)); + y1 = centerY + ((normY / dist) * (dist + paddingY)); + + normX = x2 - centerX; + normY = y2 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x2 = centerX + ((normX / dist) * (dist + paddingX)); + y2 = centerY + ((normY / dist) * (dist + paddingY)); + } + + context.save(); + context.beginPath(); + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + context.closePath(); + + context.clip(); + + // Compute matrix transform + const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); + const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); + const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); + const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); + const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); + const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); + const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); + + context.transform( + deltaA / delta, + deltaD / delta, + deltaB / delta, + deltaE / delta, + deltaC / delta, + deltaF / delta + ); + + context.drawImage( + textureSource, + 0, + 0, + textureWidth * base.resolution, + textureHeight * base.resolution, + 0, + 0, + textureWidth, + textureHeight + ); + + context.restore(); + } + + /** + * Renders a flat Mesh + * + * @private + * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + */ + renderMeshFlat(mesh) + { + const context = this.renderer.context; + const vertices = mesh.vertices; + const length = vertices.length / 2; + + // this.count++; + + context.beginPath(); + + for (let i = 1; i < length - 2; ++i) + { + // draw some triangles! + const index = i * 2; + + const x0 = vertices[index]; + const y0 = vertices[index + 1]; + + const x1 = vertices[index + 2]; + const y1 = vertices[index + 3]; + + const x2 = vertices[index + 4]; + const y2 = vertices[index + 5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + } + + context.fillStyle = '#FF0000'; + context.fill(); + context.closePath(); + } + + /** + * destroy the the renderer. + * + */ + destroy() + { + this.renderer = null; + } +} + +core.CanvasRenderer.registerPlugin('mesh', MeshSpriteRenderer); diff --git a/src/mesh/index.js b/src/mesh/index.js index 473d22a..4d1cad6 100644 --- a/src/mesh/index.js +++ b/src/mesh/index.js @@ -2,7 +2,8 @@ * @namespace PIXI.mesh */ export { default as Mesh } from './Mesh'; +export { default as MeshRenderer } from './webgl/MeshRenderer'; +export { default as CanvasMeshRenderer } from './canvas/CanvasMeshRenderer'; export { default as Plane } from './Plane'; export { default as NineSlicePlane } from './NineSlicePlane'; export { default as Rope } from './Rope'; -export { default as MeshShader } from './webgl/MeshShader'; diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js new file mode 100644 index 0000000..73d78e6 --- /dev/null +++ b/src/mesh/webgl/MeshRenderer.js @@ -0,0 +1,108 @@ +import * as core from '../../core'; +import glCore from 'pixi-gl-core'; +import { default as Mesh } from '../Mesh'; + +const glslify = require('glslify'); // eslint-disable-line no-undef + +/** + * WebGL renderer plugin for tiling sprites + */ +export class MeshRenderer extends core.ObjectRenderer { + + /** + * constructor for renderer + * + * @param {WebGLRenderer} renderer The renderer this tiling awesomeness works for. + */ + constructor(renderer) + { + super(renderer); + + this.shader = null; + } + + /** + * Sets up the renderer context and necessary buffers. + * + * @private + */ + onContextChange() + { + const gl = this.renderer.gl; + + this.shader = new core.Shader(gl, + glslify('./mesh.vert'), + glslify('./mesh.frag')); + } + + /** + * renders mesh + * + * @param {PIXI.mesh.Mesh} mesh mesh instance + */ + render(mesh) + { + const renderer = this.renderer; + const gl = renderer.gl; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + let glData = mesh._glDatas[renderer.CONTEXT_UID]; + + if (!glData) + { + glData = { + shader: this.shader, + vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.vertices, gl.STREAM_DRAW), + uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.uvs, gl.STREAM_DRAW), + indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, mesh.indices, gl.STATIC_DRAW), + // build the vao object that will render.. + vao: new glCore.VertexArrayObject(gl), + dirty: mesh.dirty, + indexDirty: mesh.indexDirty, + }; + + // build the vao object that will render.. + glData.vao = new glCore.VertexArrayObject(gl) + .addIndex(glData.indexBuffer) + .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) + .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); + + mesh._glDatas[renderer.CONTEXT_UID] = glData; + } + + if (mesh.dirty !== glData.dirty) + { + glData.dirty = mesh.dirty; + glData.uvBuffer.upload(); + } + + if (mesh.indexDirty !== glData.indexDirty) + { + glData.indexDirty = mesh.indexDirty; + glData.indexBuffer.upload(); + } + + glData.vertexBuffer.upload(); + + renderer.bindShader(glData.shader); + renderer.bindTexture(texture, 0); + renderer.state.setBlendMode(mesh.blendMode); + + glData.shader.uniforms.translationMatrix = mesh.worldTransform.toArray(true); + glData.shader.uniforms.alpha = mesh.worldAlpha; + glData.shader.uniforms.tint = mesh.tintRgb; + + const drawMode = mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; + + glData.vao.bind() + .draw(drawMode, mesh.indices.length) + .unbind(); + } +} + +core.WebGLRenderer.registerPlugin('mesh', MeshRenderer); diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 4719b6a..2ced6dc 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,6 +1,4 @@ import * as core from '../core'; -import glCore from 'pixi-gl-core'; -import Shader from './webgl/MeshShader'; const tempPoint = new core.Point(); const tempPolygon = new core.Polygon(); @@ -59,11 +57,17 @@ this.indices = indices || new Uint16Array([0, 1, 3, 2]); /** - * Whether the Mesh is dirty or not + * Version of mesh uvs are dirty or not * * @member {number} */ this.dirty = 0; + + /** + * Version of mesh indices + * + * @member {number} + */ this.indexDirty = 0; /** @@ -122,62 +126,8 @@ */ _renderWebGL(renderer) { - // get rid of any thing that may be batching. - renderer.flush(); - - // renderer.plugins.mesh.render(this); - const gl = renderer.gl; - let glData = this._glDatas[renderer.CONTEXT_UID]; - - if (!glData) - { - glData = { - shader: new Shader(gl), - vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.vertices, gl.STREAM_DRAW), - uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.uvs, gl.STREAM_DRAW), - indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW), - // build the vao object that will render.. - vao: new glCore.VertexArrayObject(gl), - dirty: this.dirty, - indexDirty: this.indexDirty, - }; - - // build the vao object that will render.. - glData.vao = new glCore.VertexArrayObject(gl) - .addIndex(glData.indexBuffer) - .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) - .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); - - this._glDatas[renderer.CONTEXT_UID] = glData; - } - - if (this.dirty !== glData.dirty) - { - glData.dirty = this.dirty; - glData.uvBuffer.upload(); - } - - if (this.indexDirty !== glData.indexDirty) - { - glData.indexDirty = this.indexDirty; - glData.indexBuffer.upload(); - } - - glData.vertexBuffer.upload(); - - renderer.bindShader(glData.shader); - renderer.bindTexture(this._texture, 0); - renderer.state.setBlendMode(this.blendMode); - - glData.shader.uniforms.translationMatrix = this.worldTransform.toArray(true); - glData.shader.uniforms.alpha = this.worldAlpha; - glData.shader.uniforms.tint = this.tintRgb; - - const drawMode = this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - glData.vao.bind() - .draw(drawMode, this.indices.length) - .unbind(); + renderer.setObjectRenderer(renderer.plugins.mesh); + renderer.plugins.mesh.render(this); } /** @@ -188,240 +138,7 @@ */ _renderCanvas(renderer) { - const context = renderer.context; - - const transform = this.worldTransform; - const res = renderer.resolution; - - if (renderer.roundPixels) - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - (transform.tx * res) | 0, - (transform.ty * res) | 0 - ); - } - else - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - transform.tx * res, - transform.ty * res - ); - } - - if (this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) - { - this._renderCanvasTriangleMesh(context); - } - else - { - this._renderCanvasTriangles(context); - } - } - - /** - * Draws the object in Triangle Mesh mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - The current drawing context - */ - _renderCanvasTriangleMesh(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const length = vertices.length / 2; - - // this.count++; - - for (let i = 0; i < length - 2; i++) - { - // draw some triangles! - const index = i * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } - } - - /** - * Draws the object in triangle mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - */ - _renderCanvasTriangles(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const indices = this.indices; - const length = indices.length; - // this.count++; - - for (let i = 0; i < length; i += 3) - { - // draw some triangles! - const index0 = indices[i] * 2; - const index1 = indices[i + 1] * 2; - const index2 = indices[i + 2] * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } - } - - /** - * Draws one of the triangles that form this Mesh - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - * @param {Float32Array} vertices - a reference to the vertices of the Mesh - * @param {Float32Array} uvs - a reference to the uvs of the 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 - */ - _renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2) - { - const base = this._texture.baseTexture; - const textureSource = base.source; - const textureWidth = base.width; - const textureHeight = base.height; - - const u0 = uvs[index0] * base.width; - const u1 = uvs[index1] * base.width; - const u2 = uvs[index2] * base.width; - const v0 = uvs[index0 + 1] * base.height; - const v1 = uvs[index1 + 1] * base.height; - const v2 = uvs[index2 + 1] * base.height; - - let x0 = vertices[index0]; - let x1 = vertices[index1]; - let x2 = vertices[index2]; - let y0 = vertices[index0 + 1]; - let y1 = vertices[index1 + 1]; - let y2 = vertices[index2 + 1]; - - if (this.canvasPadding > 0) - { - const paddingX = this.canvasPadding / this.worldTransform.a; - const paddingY = this.canvasPadding / this.worldTransform.d; - const centerX = (x0 + x1 + x2) / 3; - const centerY = (y0 + y1 + y2) / 3; - - let normX = x0 - centerX; - let normY = y0 - centerY; - - let dist = Math.sqrt((normX * normX) + (normY * normY)); - - x0 = centerX + ((normX / dist) * (dist + paddingX)); - y0 = centerY + ((normY / dist) * (dist + paddingY)); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x1 = centerX + ((normX / dist) * (dist + paddingX)); - y1 = centerY + ((normY / dist) * (dist + paddingY)); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x2 = centerX + ((normX / dist) * (dist + paddingX)); - y2 = centerY + ((normY / dist) * (dist + paddingY)); - } - - context.save(); - context.beginPath(); - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform( - deltaA / delta, - deltaD / delta, - deltaB / delta, - deltaE / delta, - deltaC / delta, - deltaF / delta - ); - - context.drawImage( - textureSource, - 0, - 0, - textureWidth * base.resolution, - textureHeight * base.resolution, - 0, - 0, - textureWidth, - textureHeight - ); - - context.restore(); - } - - /** - * Renders a flat Mesh - * - * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render - */ - renderMeshFlat(mesh) - { - const context = this.context; - const vertices = mesh.vertices; - const length = vertices.length / 2; - - // this.count++; - - context.beginPath(); - - for (let i = 1; i < length - 2; ++i) - { - // draw some triangles! - const index = i * 2; - - const x0 = vertices[index]; - const y0 = vertices[index + 1]; - - const x1 = vertices[index + 2]; - const y1 = vertices[index + 3]; - - const x2 = vertices[index + 4]; - const y2 = vertices[index + 5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); + renderer.plugins.mesh.render(this); } /** diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js new file mode 100644 index 0000000..a1ad74c --- /dev/null +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -0,0 +1,276 @@ +import * as core from '../../core'; +import { default as Mesh } from '../Mesh'; + +/** + * Renderer dedicated to meshes. + * + * @class + * @private + * @memberof PIXI + */ +export default class MeshSpriteRenderer +{ + /** + * @param {PIXI.CanvasRenderer} renderer - The renderer this downport works for + */ + constructor(renderer) + { + this.renderer = renderer; + } + + /** + * Renders the Mesh + * + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + render(mesh) + { + const renderer = this.renderer; + const context = renderer.context; + + const transform = mesh.worldTransform; + const res = renderer.resolution; + + if (renderer.roundPixels) + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + (transform.tx * res) | 0, + (transform.ty * res) | 0 + ); + } + else + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + transform.tx * res, + transform.ty * res + ); + } + + if (mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) + { + this._renderTriangleMesh(mesh); + } + else + { + this._renderTriangles(mesh); + } + } + + /** + * Draws the object in Triangle Mesh mode + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + _renderTriangleMesh(mesh) + { + // draw triangles!! + const length = mesh.vertices.length / 2; + + for (let i = 0; i < length - 2; i++) + { + // draw some triangles! + const index = i * 2; + + this._renderDrawTriangle(mesh, index, (index + 2), (index + 4)); + } + } + + /** + * Draws the object in triangle mode using canvas + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the current mesh + */ + _renderTriangles(mesh) + { + // draw triangles!! + const indices = mesh.indices; + const length = indices.length; + + for (let i = 0; i < length; i += 3) + { + // draw some triangles! + const index0 = indices[i] * 2; + const index1 = indices[i + 1] * 2; + const index2 = indices[i + 2] * 2; + + this._renderDrawTriangle(mesh, index0, index1, index2); + } + } + + /** + * Draws one of the triangles that from the Mesh + * + * @private + * @param {PIXI.mesh.Mesh} 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 + */ + _renderDrawTriangle(mesh, index0, index1, index2) + { + const context = this.renderer.context; + const uvs = mesh.uvs; + const vertices = mesh.vertices; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + const base = texture.baseTexture; + const textureSource = base.source; + const textureWidth = base.width; + const textureHeight = base.height; + + const u0 = uvs[index0] * base.width; + const u1 = uvs[index1] * base.width; + const u2 = uvs[index2] * base.width; + const v0 = uvs[index0 + 1] * base.height; + const v1 = uvs[index1 + 1] * base.height; + const v2 = uvs[index2 + 1] * base.height; + + let x0 = vertices[index0]; + let x1 = vertices[index1]; + let x2 = vertices[index2]; + let y0 = vertices[index0 + 1]; + let y1 = vertices[index1 + 1]; + let y2 = vertices[index2 + 1]; + + if (mesh.canvasPadding > 0) + { + const paddingX = mesh.canvasPadding / mesh.worldTransform.a; + const paddingY = mesh.canvasPadding / mesh.worldTransform.d; + const centerX = (x0 + x1 + x2) / 3; + const centerY = (y0 + y1 + y2) / 3; + + let normX = x0 - centerX; + let normY = y0 - centerY; + + let dist = Math.sqrt((normX * normX) + (normY * normY)); + + x0 = centerX + ((normX / dist) * (dist + paddingX)); + y0 = centerY + ((normY / dist) * (dist + paddingY)); + + // + + normX = x1 - centerX; + normY = y1 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x1 = centerX + ((normX / dist) * (dist + paddingX)); + y1 = centerY + ((normY / dist) * (dist + paddingY)); + + normX = x2 - centerX; + normY = y2 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x2 = centerX + ((normX / dist) * (dist + paddingX)); + y2 = centerY + ((normY / dist) * (dist + paddingY)); + } + + context.save(); + context.beginPath(); + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + context.closePath(); + + context.clip(); + + // Compute matrix transform + const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); + const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); + const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); + const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); + const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); + const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); + const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); + + context.transform( + deltaA / delta, + deltaD / delta, + deltaB / delta, + deltaE / delta, + deltaC / delta, + deltaF / delta + ); + + context.drawImage( + textureSource, + 0, + 0, + textureWidth * base.resolution, + textureHeight * base.resolution, + 0, + 0, + textureWidth, + textureHeight + ); + + context.restore(); + } + + /** + * Renders a flat Mesh + * + * @private + * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + */ + renderMeshFlat(mesh) + { + const context = this.renderer.context; + const vertices = mesh.vertices; + const length = vertices.length / 2; + + // this.count++; + + context.beginPath(); + + for (let i = 1; i < length - 2; ++i) + { + // draw some triangles! + const index = i * 2; + + const x0 = vertices[index]; + const y0 = vertices[index + 1]; + + const x1 = vertices[index + 2]; + const y1 = vertices[index + 3]; + + const x2 = vertices[index + 4]; + const y2 = vertices[index + 5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + } + + context.fillStyle = '#FF0000'; + context.fill(); + context.closePath(); + } + + /** + * destroy the the renderer. + * + */ + destroy() + { + this.renderer = null; + } +} + +core.CanvasRenderer.registerPlugin('mesh', MeshSpriteRenderer); diff --git a/src/mesh/index.js b/src/mesh/index.js index 473d22a..4d1cad6 100644 --- a/src/mesh/index.js +++ b/src/mesh/index.js @@ -2,7 +2,8 @@ * @namespace PIXI.mesh */ export { default as Mesh } from './Mesh'; +export { default as MeshRenderer } from './webgl/MeshRenderer'; +export { default as CanvasMeshRenderer } from './canvas/CanvasMeshRenderer'; export { default as Plane } from './Plane'; export { default as NineSlicePlane } from './NineSlicePlane'; export { default as Rope } from './Rope'; -export { default as MeshShader } from './webgl/MeshShader'; diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js new file mode 100644 index 0000000..73d78e6 --- /dev/null +++ b/src/mesh/webgl/MeshRenderer.js @@ -0,0 +1,108 @@ +import * as core from '../../core'; +import glCore from 'pixi-gl-core'; +import { default as Mesh } from '../Mesh'; + +const glslify = require('glslify'); // eslint-disable-line no-undef + +/** + * WebGL renderer plugin for tiling sprites + */ +export class MeshRenderer extends core.ObjectRenderer { + + /** + * constructor for renderer + * + * @param {WebGLRenderer} renderer The renderer this tiling awesomeness works for. + */ + constructor(renderer) + { + super(renderer); + + this.shader = null; + } + + /** + * Sets up the renderer context and necessary buffers. + * + * @private + */ + onContextChange() + { + const gl = this.renderer.gl; + + this.shader = new core.Shader(gl, + glslify('./mesh.vert'), + glslify('./mesh.frag')); + } + + /** + * renders mesh + * + * @param {PIXI.mesh.Mesh} mesh mesh instance + */ + render(mesh) + { + const renderer = this.renderer; + const gl = renderer.gl; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + let glData = mesh._glDatas[renderer.CONTEXT_UID]; + + if (!glData) + { + glData = { + shader: this.shader, + vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.vertices, gl.STREAM_DRAW), + uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.uvs, gl.STREAM_DRAW), + indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, mesh.indices, gl.STATIC_DRAW), + // build the vao object that will render.. + vao: new glCore.VertexArrayObject(gl), + dirty: mesh.dirty, + indexDirty: mesh.indexDirty, + }; + + // build the vao object that will render.. + glData.vao = new glCore.VertexArrayObject(gl) + .addIndex(glData.indexBuffer) + .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) + .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); + + mesh._glDatas[renderer.CONTEXT_UID] = glData; + } + + if (mesh.dirty !== glData.dirty) + { + glData.dirty = mesh.dirty; + glData.uvBuffer.upload(); + } + + if (mesh.indexDirty !== glData.indexDirty) + { + glData.indexDirty = mesh.indexDirty; + glData.indexBuffer.upload(); + } + + glData.vertexBuffer.upload(); + + renderer.bindShader(glData.shader); + renderer.bindTexture(texture, 0); + renderer.state.setBlendMode(mesh.blendMode); + + glData.shader.uniforms.translationMatrix = mesh.worldTransform.toArray(true); + glData.shader.uniforms.alpha = mesh.worldAlpha; + glData.shader.uniforms.tint = mesh.tintRgb; + + const drawMode = mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; + + glData.vao.bind() + .draw(drawMode, mesh.indices.length) + .unbind(); + } +} + +core.WebGLRenderer.registerPlugin('mesh', MeshRenderer); diff --git a/src/mesh/webgl/MeshShader.js b/src/mesh/webgl/MeshShader.js deleted file mode 100644 index 1bbdc0e..0000000 --- a/src/mesh/webgl/MeshShader.js +++ /dev/null @@ -1,46 +0,0 @@ -import Shader from '../../core/Shader'; - -/** - * @class - * @extends PIXI.Shader - * @memberof PIXI.mesh - */ -export default class MeshShader extends Shader -{ - /** - * @param {WebGLRenderingContext} gl - The WebGLRenderingContext. - */ - constructor(gl) - { - super( - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - - 'uniform mat3 translationMatrix;', - 'uniform mat3 projectionMatrix;', - - 'varying vec2 vTextureCoord;', - - 'void main(void){', - ' gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', // eslint-disable-line max-len - ' vTextureCoord = aTextureCoord;', - '}', - ].join('\n'), - [ - 'varying vec2 vTextureCoord;', - 'uniform float alpha;', - 'uniform vec3 tint;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vec4(tint * alpha, alpha);', - // ' gl_FragColor = vec4(1.0);', - '}', - ].join('\n') - ); - } -} diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 4719b6a..2ced6dc 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,6 +1,4 @@ import * as core from '../core'; -import glCore from 'pixi-gl-core'; -import Shader from './webgl/MeshShader'; const tempPoint = new core.Point(); const tempPolygon = new core.Polygon(); @@ -59,11 +57,17 @@ this.indices = indices || new Uint16Array([0, 1, 3, 2]); /** - * Whether the Mesh is dirty or not + * Version of mesh uvs are dirty or not * * @member {number} */ this.dirty = 0; + + /** + * Version of mesh indices + * + * @member {number} + */ this.indexDirty = 0; /** @@ -122,62 +126,8 @@ */ _renderWebGL(renderer) { - // get rid of any thing that may be batching. - renderer.flush(); - - // renderer.plugins.mesh.render(this); - const gl = renderer.gl; - let glData = this._glDatas[renderer.CONTEXT_UID]; - - if (!glData) - { - glData = { - shader: new Shader(gl), - vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.vertices, gl.STREAM_DRAW), - uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.uvs, gl.STREAM_DRAW), - indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW), - // build the vao object that will render.. - vao: new glCore.VertexArrayObject(gl), - dirty: this.dirty, - indexDirty: this.indexDirty, - }; - - // build the vao object that will render.. - glData.vao = new glCore.VertexArrayObject(gl) - .addIndex(glData.indexBuffer) - .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) - .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); - - this._glDatas[renderer.CONTEXT_UID] = glData; - } - - if (this.dirty !== glData.dirty) - { - glData.dirty = this.dirty; - glData.uvBuffer.upload(); - } - - if (this.indexDirty !== glData.indexDirty) - { - glData.indexDirty = this.indexDirty; - glData.indexBuffer.upload(); - } - - glData.vertexBuffer.upload(); - - renderer.bindShader(glData.shader); - renderer.bindTexture(this._texture, 0); - renderer.state.setBlendMode(this.blendMode); - - glData.shader.uniforms.translationMatrix = this.worldTransform.toArray(true); - glData.shader.uniforms.alpha = this.worldAlpha; - glData.shader.uniforms.tint = this.tintRgb; - - const drawMode = this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - glData.vao.bind() - .draw(drawMode, this.indices.length) - .unbind(); + renderer.setObjectRenderer(renderer.plugins.mesh); + renderer.plugins.mesh.render(this); } /** @@ -188,240 +138,7 @@ */ _renderCanvas(renderer) { - const context = renderer.context; - - const transform = this.worldTransform; - const res = renderer.resolution; - - if (renderer.roundPixels) - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - (transform.tx * res) | 0, - (transform.ty * res) | 0 - ); - } - else - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - transform.tx * res, - transform.ty * res - ); - } - - if (this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) - { - this._renderCanvasTriangleMesh(context); - } - else - { - this._renderCanvasTriangles(context); - } - } - - /** - * Draws the object in Triangle Mesh mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - The current drawing context - */ - _renderCanvasTriangleMesh(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const length = vertices.length / 2; - - // this.count++; - - for (let i = 0; i < length - 2; i++) - { - // draw some triangles! - const index = i * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } - } - - /** - * Draws the object in triangle mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - */ - _renderCanvasTriangles(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const indices = this.indices; - const length = indices.length; - // this.count++; - - for (let i = 0; i < length; i += 3) - { - // draw some triangles! - const index0 = indices[i] * 2; - const index1 = indices[i + 1] * 2; - const index2 = indices[i + 2] * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } - } - - /** - * Draws one of the triangles that form this Mesh - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - * @param {Float32Array} vertices - a reference to the vertices of the Mesh - * @param {Float32Array} uvs - a reference to the uvs of the 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 - */ - _renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2) - { - const base = this._texture.baseTexture; - const textureSource = base.source; - const textureWidth = base.width; - const textureHeight = base.height; - - const u0 = uvs[index0] * base.width; - const u1 = uvs[index1] * base.width; - const u2 = uvs[index2] * base.width; - const v0 = uvs[index0 + 1] * base.height; - const v1 = uvs[index1 + 1] * base.height; - const v2 = uvs[index2 + 1] * base.height; - - let x0 = vertices[index0]; - let x1 = vertices[index1]; - let x2 = vertices[index2]; - let y0 = vertices[index0 + 1]; - let y1 = vertices[index1 + 1]; - let y2 = vertices[index2 + 1]; - - if (this.canvasPadding > 0) - { - const paddingX = this.canvasPadding / this.worldTransform.a; - const paddingY = this.canvasPadding / this.worldTransform.d; - const centerX = (x0 + x1 + x2) / 3; - const centerY = (y0 + y1 + y2) / 3; - - let normX = x0 - centerX; - let normY = y0 - centerY; - - let dist = Math.sqrt((normX * normX) + (normY * normY)); - - x0 = centerX + ((normX / dist) * (dist + paddingX)); - y0 = centerY + ((normY / dist) * (dist + paddingY)); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x1 = centerX + ((normX / dist) * (dist + paddingX)); - y1 = centerY + ((normY / dist) * (dist + paddingY)); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x2 = centerX + ((normX / dist) * (dist + paddingX)); - y2 = centerY + ((normY / dist) * (dist + paddingY)); - } - - context.save(); - context.beginPath(); - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform( - deltaA / delta, - deltaD / delta, - deltaB / delta, - deltaE / delta, - deltaC / delta, - deltaF / delta - ); - - context.drawImage( - textureSource, - 0, - 0, - textureWidth * base.resolution, - textureHeight * base.resolution, - 0, - 0, - textureWidth, - textureHeight - ); - - context.restore(); - } - - /** - * Renders a flat Mesh - * - * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render - */ - renderMeshFlat(mesh) - { - const context = this.context; - const vertices = mesh.vertices; - const length = vertices.length / 2; - - // this.count++; - - context.beginPath(); - - for (let i = 1; i < length - 2; ++i) - { - // draw some triangles! - const index = i * 2; - - const x0 = vertices[index]; - const y0 = vertices[index + 1]; - - const x1 = vertices[index + 2]; - const y1 = vertices[index + 3]; - - const x2 = vertices[index + 4]; - const y2 = vertices[index + 5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); + renderer.plugins.mesh.render(this); } /** diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js new file mode 100644 index 0000000..a1ad74c --- /dev/null +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -0,0 +1,276 @@ +import * as core from '../../core'; +import { default as Mesh } from '../Mesh'; + +/** + * Renderer dedicated to meshes. + * + * @class + * @private + * @memberof PIXI + */ +export default class MeshSpriteRenderer +{ + /** + * @param {PIXI.CanvasRenderer} renderer - The renderer this downport works for + */ + constructor(renderer) + { + this.renderer = renderer; + } + + /** + * Renders the Mesh + * + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + render(mesh) + { + const renderer = this.renderer; + const context = renderer.context; + + const transform = mesh.worldTransform; + const res = renderer.resolution; + + if (renderer.roundPixels) + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + (transform.tx * res) | 0, + (transform.ty * res) | 0 + ); + } + else + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + transform.tx * res, + transform.ty * res + ); + } + + if (mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) + { + this._renderTriangleMesh(mesh); + } + else + { + this._renderTriangles(mesh); + } + } + + /** + * Draws the object in Triangle Mesh mode + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + _renderTriangleMesh(mesh) + { + // draw triangles!! + const length = mesh.vertices.length / 2; + + for (let i = 0; i < length - 2; i++) + { + // draw some triangles! + const index = i * 2; + + this._renderDrawTriangle(mesh, index, (index + 2), (index + 4)); + } + } + + /** + * Draws the object in triangle mode using canvas + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the current mesh + */ + _renderTriangles(mesh) + { + // draw triangles!! + const indices = mesh.indices; + const length = indices.length; + + for (let i = 0; i < length; i += 3) + { + // draw some triangles! + const index0 = indices[i] * 2; + const index1 = indices[i + 1] * 2; + const index2 = indices[i + 2] * 2; + + this._renderDrawTriangle(mesh, index0, index1, index2); + } + } + + /** + * Draws one of the triangles that from the Mesh + * + * @private + * @param {PIXI.mesh.Mesh} 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 + */ + _renderDrawTriangle(mesh, index0, index1, index2) + { + const context = this.renderer.context; + const uvs = mesh.uvs; + const vertices = mesh.vertices; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + const base = texture.baseTexture; + const textureSource = base.source; + const textureWidth = base.width; + const textureHeight = base.height; + + const u0 = uvs[index0] * base.width; + const u1 = uvs[index1] * base.width; + const u2 = uvs[index2] * base.width; + const v0 = uvs[index0 + 1] * base.height; + const v1 = uvs[index1 + 1] * base.height; + const v2 = uvs[index2 + 1] * base.height; + + let x0 = vertices[index0]; + let x1 = vertices[index1]; + let x2 = vertices[index2]; + let y0 = vertices[index0 + 1]; + let y1 = vertices[index1 + 1]; + let y2 = vertices[index2 + 1]; + + if (mesh.canvasPadding > 0) + { + const paddingX = mesh.canvasPadding / mesh.worldTransform.a; + const paddingY = mesh.canvasPadding / mesh.worldTransform.d; + const centerX = (x0 + x1 + x2) / 3; + const centerY = (y0 + y1 + y2) / 3; + + let normX = x0 - centerX; + let normY = y0 - centerY; + + let dist = Math.sqrt((normX * normX) + (normY * normY)); + + x0 = centerX + ((normX / dist) * (dist + paddingX)); + y0 = centerY + ((normY / dist) * (dist + paddingY)); + + // + + normX = x1 - centerX; + normY = y1 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x1 = centerX + ((normX / dist) * (dist + paddingX)); + y1 = centerY + ((normY / dist) * (dist + paddingY)); + + normX = x2 - centerX; + normY = y2 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x2 = centerX + ((normX / dist) * (dist + paddingX)); + y2 = centerY + ((normY / dist) * (dist + paddingY)); + } + + context.save(); + context.beginPath(); + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + context.closePath(); + + context.clip(); + + // Compute matrix transform + const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); + const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); + const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); + const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); + const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); + const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); + const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); + + context.transform( + deltaA / delta, + deltaD / delta, + deltaB / delta, + deltaE / delta, + deltaC / delta, + deltaF / delta + ); + + context.drawImage( + textureSource, + 0, + 0, + textureWidth * base.resolution, + textureHeight * base.resolution, + 0, + 0, + textureWidth, + textureHeight + ); + + context.restore(); + } + + /** + * Renders a flat Mesh + * + * @private + * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + */ + renderMeshFlat(mesh) + { + const context = this.renderer.context; + const vertices = mesh.vertices; + const length = vertices.length / 2; + + // this.count++; + + context.beginPath(); + + for (let i = 1; i < length - 2; ++i) + { + // draw some triangles! + const index = i * 2; + + const x0 = vertices[index]; + const y0 = vertices[index + 1]; + + const x1 = vertices[index + 2]; + const y1 = vertices[index + 3]; + + const x2 = vertices[index + 4]; + const y2 = vertices[index + 5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + } + + context.fillStyle = '#FF0000'; + context.fill(); + context.closePath(); + } + + /** + * destroy the the renderer. + * + */ + destroy() + { + this.renderer = null; + } +} + +core.CanvasRenderer.registerPlugin('mesh', MeshSpriteRenderer); diff --git a/src/mesh/index.js b/src/mesh/index.js index 473d22a..4d1cad6 100644 --- a/src/mesh/index.js +++ b/src/mesh/index.js @@ -2,7 +2,8 @@ * @namespace PIXI.mesh */ export { default as Mesh } from './Mesh'; +export { default as MeshRenderer } from './webgl/MeshRenderer'; +export { default as CanvasMeshRenderer } from './canvas/CanvasMeshRenderer'; export { default as Plane } from './Plane'; export { default as NineSlicePlane } from './NineSlicePlane'; export { default as Rope } from './Rope'; -export { default as MeshShader } from './webgl/MeshShader'; diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js new file mode 100644 index 0000000..73d78e6 --- /dev/null +++ b/src/mesh/webgl/MeshRenderer.js @@ -0,0 +1,108 @@ +import * as core from '../../core'; +import glCore from 'pixi-gl-core'; +import { default as Mesh } from '../Mesh'; + +const glslify = require('glslify'); // eslint-disable-line no-undef + +/** + * WebGL renderer plugin for tiling sprites + */ +export class MeshRenderer extends core.ObjectRenderer { + + /** + * constructor for renderer + * + * @param {WebGLRenderer} renderer The renderer this tiling awesomeness works for. + */ + constructor(renderer) + { + super(renderer); + + this.shader = null; + } + + /** + * Sets up the renderer context and necessary buffers. + * + * @private + */ + onContextChange() + { + const gl = this.renderer.gl; + + this.shader = new core.Shader(gl, + glslify('./mesh.vert'), + glslify('./mesh.frag')); + } + + /** + * renders mesh + * + * @param {PIXI.mesh.Mesh} mesh mesh instance + */ + render(mesh) + { + const renderer = this.renderer; + const gl = renderer.gl; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + let glData = mesh._glDatas[renderer.CONTEXT_UID]; + + if (!glData) + { + glData = { + shader: this.shader, + vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.vertices, gl.STREAM_DRAW), + uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.uvs, gl.STREAM_DRAW), + indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, mesh.indices, gl.STATIC_DRAW), + // build the vao object that will render.. + vao: new glCore.VertexArrayObject(gl), + dirty: mesh.dirty, + indexDirty: mesh.indexDirty, + }; + + // build the vao object that will render.. + glData.vao = new glCore.VertexArrayObject(gl) + .addIndex(glData.indexBuffer) + .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) + .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); + + mesh._glDatas[renderer.CONTEXT_UID] = glData; + } + + if (mesh.dirty !== glData.dirty) + { + glData.dirty = mesh.dirty; + glData.uvBuffer.upload(); + } + + if (mesh.indexDirty !== glData.indexDirty) + { + glData.indexDirty = mesh.indexDirty; + glData.indexBuffer.upload(); + } + + glData.vertexBuffer.upload(); + + renderer.bindShader(glData.shader); + renderer.bindTexture(texture, 0); + renderer.state.setBlendMode(mesh.blendMode); + + glData.shader.uniforms.translationMatrix = mesh.worldTransform.toArray(true); + glData.shader.uniforms.alpha = mesh.worldAlpha; + glData.shader.uniforms.tint = mesh.tintRgb; + + const drawMode = mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; + + glData.vao.bind() + .draw(drawMode, mesh.indices.length) + .unbind(); + } +} + +core.WebGLRenderer.registerPlugin('mesh', MeshRenderer); diff --git a/src/mesh/webgl/MeshShader.js b/src/mesh/webgl/MeshShader.js deleted file mode 100644 index 1bbdc0e..0000000 --- a/src/mesh/webgl/MeshShader.js +++ /dev/null @@ -1,46 +0,0 @@ -import Shader from '../../core/Shader'; - -/** - * @class - * @extends PIXI.Shader - * @memberof PIXI.mesh - */ -export default class MeshShader extends Shader -{ - /** - * @param {WebGLRenderingContext} gl - The WebGLRenderingContext. - */ - constructor(gl) - { - super( - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - - 'uniform mat3 translationMatrix;', - 'uniform mat3 projectionMatrix;', - - 'varying vec2 vTextureCoord;', - - 'void main(void){', - ' gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', // eslint-disable-line max-len - ' vTextureCoord = aTextureCoord;', - '}', - ].join('\n'), - [ - 'varying vec2 vTextureCoord;', - 'uniform float alpha;', - 'uniform vec3 tint;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vec4(tint * alpha, alpha);', - // ' gl_FragColor = vec4(1.0);', - '}', - ].join('\n') - ); - } -} diff --git a/src/mesh/webgl/mesh.frag b/src/mesh/webgl/mesh.frag new file mode 100644 index 0000000..9e0b634 --- /dev/null +++ b/src/mesh/webgl/mesh.frag @@ -0,0 +1,10 @@ +varying vec2 vTextureCoord; +uniform float alpha; +uniform vec3 tint; + +uniform sampler2D uSampler; + +void main(void) +{ + gl_FragColor = texture2D(uSampler, vTextureCoord) * vec4(tint * alpha, alpha); +} diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 4719b6a..2ced6dc 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -1,6 +1,4 @@ import * as core from '../core'; -import glCore from 'pixi-gl-core'; -import Shader from './webgl/MeshShader'; const tempPoint = new core.Point(); const tempPolygon = new core.Polygon(); @@ -59,11 +57,17 @@ this.indices = indices || new Uint16Array([0, 1, 3, 2]); /** - * Whether the Mesh is dirty or not + * Version of mesh uvs are dirty or not * * @member {number} */ this.dirty = 0; + + /** + * Version of mesh indices + * + * @member {number} + */ this.indexDirty = 0; /** @@ -122,62 +126,8 @@ */ _renderWebGL(renderer) { - // get rid of any thing that may be batching. - renderer.flush(); - - // renderer.plugins.mesh.render(this); - const gl = renderer.gl; - let glData = this._glDatas[renderer.CONTEXT_UID]; - - if (!glData) - { - glData = { - shader: new Shader(gl), - vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.vertices, gl.STREAM_DRAW), - uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, this.uvs, gl.STREAM_DRAW), - indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW), - // build the vao object that will render.. - vao: new glCore.VertexArrayObject(gl), - dirty: this.dirty, - indexDirty: this.indexDirty, - }; - - // build the vao object that will render.. - glData.vao = new glCore.VertexArrayObject(gl) - .addIndex(glData.indexBuffer) - .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) - .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); - - this._glDatas[renderer.CONTEXT_UID] = glData; - } - - if (this.dirty !== glData.dirty) - { - glData.dirty = this.dirty; - glData.uvBuffer.upload(); - } - - if (this.indexDirty !== glData.indexDirty) - { - glData.indexDirty = this.indexDirty; - glData.indexBuffer.upload(); - } - - glData.vertexBuffer.upload(); - - renderer.bindShader(glData.shader); - renderer.bindTexture(this._texture, 0); - renderer.state.setBlendMode(this.blendMode); - - glData.shader.uniforms.translationMatrix = this.worldTransform.toArray(true); - glData.shader.uniforms.alpha = this.worldAlpha; - glData.shader.uniforms.tint = this.tintRgb; - - const drawMode = this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - glData.vao.bind() - .draw(drawMode, this.indices.length) - .unbind(); + renderer.setObjectRenderer(renderer.plugins.mesh); + renderer.plugins.mesh.render(this); } /** @@ -188,240 +138,7 @@ */ _renderCanvas(renderer) { - const context = renderer.context; - - const transform = this.worldTransform; - const res = renderer.resolution; - - if (renderer.roundPixels) - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - (transform.tx * res) | 0, - (transform.ty * res) | 0 - ); - } - else - { - context.setTransform( - transform.a * res, - transform.b * res, - transform.c * res, - transform.d * res, - transform.tx * res, - transform.ty * res - ); - } - - if (this.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) - { - this._renderCanvasTriangleMesh(context); - } - else - { - this._renderCanvasTriangles(context); - } - } - - /** - * Draws the object in Triangle Mesh mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - The current drawing context - */ - _renderCanvasTriangleMesh(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const length = vertices.length / 2; - - // this.count++; - - for (let i = 0; i < length - 2; i++) - { - // draw some triangles! - const index = i * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } - } - - /** - * Draws the object in triangle mode using canvas - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - */ - _renderCanvasTriangles(context) - { - // draw triangles!! - const vertices = this.vertices; - const uvs = this.uvs; - const indices = this.indices; - const length = indices.length; - // this.count++; - - for (let i = 0; i < length; i += 3) - { - // draw some triangles! - const index0 = indices[i] * 2; - const index1 = indices[i + 1] * 2; - const index2 = indices[i + 2] * 2; - - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } - } - - /** - * Draws one of the triangles that form this Mesh - * - * @private - * @param {CanvasRenderingContext2D} context - the current drawing context - * @param {Float32Array} vertices - a reference to the vertices of the Mesh - * @param {Float32Array} uvs - a reference to the uvs of the 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 - */ - _renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2) - { - const base = this._texture.baseTexture; - const textureSource = base.source; - const textureWidth = base.width; - const textureHeight = base.height; - - const u0 = uvs[index0] * base.width; - const u1 = uvs[index1] * base.width; - const u2 = uvs[index2] * base.width; - const v0 = uvs[index0 + 1] * base.height; - const v1 = uvs[index1 + 1] * base.height; - const v2 = uvs[index2 + 1] * base.height; - - let x0 = vertices[index0]; - let x1 = vertices[index1]; - let x2 = vertices[index2]; - let y0 = vertices[index0 + 1]; - let y1 = vertices[index1 + 1]; - let y2 = vertices[index2 + 1]; - - if (this.canvasPadding > 0) - { - const paddingX = this.canvasPadding / this.worldTransform.a; - const paddingY = this.canvasPadding / this.worldTransform.d; - const centerX = (x0 + x1 + x2) / 3; - const centerY = (y0 + y1 + y2) / 3; - - let normX = x0 - centerX; - let normY = y0 - centerY; - - let dist = Math.sqrt((normX * normX) + (normY * normY)); - - x0 = centerX + ((normX / dist) * (dist + paddingX)); - y0 = centerY + ((normY / dist) * (dist + paddingY)); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x1 = centerX + ((normX / dist) * (dist + paddingX)); - y1 = centerY + ((normY / dist) * (dist + paddingY)); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt((normX * normX) + (normY * normY)); - x2 = centerX + ((normX / dist) * (dist + paddingX)); - y2 = centerY + ((normY / dist) * (dist + paddingY)); - } - - context.save(); - context.beginPath(); - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform( - deltaA / delta, - deltaD / delta, - deltaB / delta, - deltaE / delta, - deltaC / delta, - deltaF / delta - ); - - context.drawImage( - textureSource, - 0, - 0, - textureWidth * base.resolution, - textureHeight * base.resolution, - 0, - 0, - textureWidth, - textureHeight - ); - - context.restore(); - } - - /** - * Renders a flat Mesh - * - * @private - * @param {PIXI.mesh.Mesh} mesh - The Mesh to render - */ - renderMeshFlat(mesh) - { - const context = this.context; - const vertices = mesh.vertices; - const length = vertices.length / 2; - - // this.count++; - - context.beginPath(); - - for (let i = 1; i < length - 2; ++i) - { - // draw some triangles! - const index = i * 2; - - const x0 = vertices[index]; - const y0 = vertices[index + 1]; - - const x1 = vertices[index + 2]; - const y1 = vertices[index + 3]; - - const x2 = vertices[index + 4]; - const y2 = vertices[index + 5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); + renderer.plugins.mesh.render(this); } /** diff --git a/src/mesh/canvas/CanvasMeshRenderer.js b/src/mesh/canvas/CanvasMeshRenderer.js new file mode 100644 index 0000000..a1ad74c --- /dev/null +++ b/src/mesh/canvas/CanvasMeshRenderer.js @@ -0,0 +1,276 @@ +import * as core from '../../core'; +import { default as Mesh } from '../Mesh'; + +/** + * Renderer dedicated to meshes. + * + * @class + * @private + * @memberof PIXI + */ +export default class MeshSpriteRenderer +{ + /** + * @param {PIXI.CanvasRenderer} renderer - The renderer this downport works for + */ + constructor(renderer) + { + this.renderer = renderer; + } + + /** + * Renders the Mesh + * + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + render(mesh) + { + const renderer = this.renderer; + const context = renderer.context; + + const transform = mesh.worldTransform; + const res = renderer.resolution; + + if (renderer.roundPixels) + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + (transform.tx * res) | 0, + (transform.ty * res) | 0 + ); + } + else + { + context.setTransform( + transform.a * res, + transform.b * res, + transform.c * res, + transform.d * res, + transform.tx * res, + transform.ty * res + ); + } + + if (mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH) + { + this._renderTriangleMesh(mesh); + } + else + { + this._renderTriangles(mesh); + } + } + + /** + * Draws the object in Triangle Mesh mode + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the Mesh to render + */ + _renderTriangleMesh(mesh) + { + // draw triangles!! + const length = mesh.vertices.length / 2; + + for (let i = 0; i < length - 2; i++) + { + // draw some triangles! + const index = i * 2; + + this._renderDrawTriangle(mesh, index, (index + 2), (index + 4)); + } + } + + /** + * Draws the object in triangle mode using canvas + * + * @private + * @param {PIXI.mesh.Mesh} mesh - the current mesh + */ + _renderTriangles(mesh) + { + // draw triangles!! + const indices = mesh.indices; + const length = indices.length; + + for (let i = 0; i < length; i += 3) + { + // draw some triangles! + const index0 = indices[i] * 2; + const index1 = indices[i + 1] * 2; + const index2 = indices[i + 2] * 2; + + this._renderDrawTriangle(mesh, index0, index1, index2); + } + } + + /** + * Draws one of the triangles that from the Mesh + * + * @private + * @param {PIXI.mesh.Mesh} 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 + */ + _renderDrawTriangle(mesh, index0, index1, index2) + { + const context = this.renderer.context; + const uvs = mesh.uvs; + const vertices = mesh.vertices; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + const base = texture.baseTexture; + const textureSource = base.source; + const textureWidth = base.width; + const textureHeight = base.height; + + const u0 = uvs[index0] * base.width; + const u1 = uvs[index1] * base.width; + const u2 = uvs[index2] * base.width; + const v0 = uvs[index0 + 1] * base.height; + const v1 = uvs[index1 + 1] * base.height; + const v2 = uvs[index2 + 1] * base.height; + + let x0 = vertices[index0]; + let x1 = vertices[index1]; + let x2 = vertices[index2]; + let y0 = vertices[index0 + 1]; + let y1 = vertices[index1 + 1]; + let y2 = vertices[index2 + 1]; + + if (mesh.canvasPadding > 0) + { + const paddingX = mesh.canvasPadding / mesh.worldTransform.a; + const paddingY = mesh.canvasPadding / mesh.worldTransform.d; + const centerX = (x0 + x1 + x2) / 3; + const centerY = (y0 + y1 + y2) / 3; + + let normX = x0 - centerX; + let normY = y0 - centerY; + + let dist = Math.sqrt((normX * normX) + (normY * normY)); + + x0 = centerX + ((normX / dist) * (dist + paddingX)); + y0 = centerY + ((normY / dist) * (dist + paddingY)); + + // + + normX = x1 - centerX; + normY = y1 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x1 = centerX + ((normX / dist) * (dist + paddingX)); + y1 = centerY + ((normY / dist) * (dist + paddingY)); + + normX = x2 - centerX; + normY = y2 - centerY; + + dist = Math.sqrt((normX * normX) + (normY * normY)); + x2 = centerX + ((normX / dist) * (dist + paddingX)); + y2 = centerY + ((normY / dist) * (dist + paddingY)); + } + + context.save(); + context.beginPath(); + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + context.closePath(); + + context.clip(); + + // Compute matrix transform + const delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); + const deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); + const deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); + const deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); + const deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); + const deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); + const deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); + + context.transform( + deltaA / delta, + deltaD / delta, + deltaB / delta, + deltaE / delta, + deltaC / delta, + deltaF / delta + ); + + context.drawImage( + textureSource, + 0, + 0, + textureWidth * base.resolution, + textureHeight * base.resolution, + 0, + 0, + textureWidth, + textureHeight + ); + + context.restore(); + } + + /** + * Renders a flat Mesh + * + * @private + * @param {PIXI.mesh.Mesh} mesh - The Mesh to render + */ + renderMeshFlat(mesh) + { + const context = this.renderer.context; + const vertices = mesh.vertices; + const length = vertices.length / 2; + + // this.count++; + + context.beginPath(); + + for (let i = 1; i < length - 2; ++i) + { + // draw some triangles! + const index = i * 2; + + const x0 = vertices[index]; + const y0 = vertices[index + 1]; + + const x1 = vertices[index + 2]; + const y1 = vertices[index + 3]; + + const x2 = vertices[index + 4]; + const y2 = vertices[index + 5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + } + + context.fillStyle = '#FF0000'; + context.fill(); + context.closePath(); + } + + /** + * destroy the the renderer. + * + */ + destroy() + { + this.renderer = null; + } +} + +core.CanvasRenderer.registerPlugin('mesh', MeshSpriteRenderer); diff --git a/src/mesh/index.js b/src/mesh/index.js index 473d22a..4d1cad6 100644 --- a/src/mesh/index.js +++ b/src/mesh/index.js @@ -2,7 +2,8 @@ * @namespace PIXI.mesh */ export { default as Mesh } from './Mesh'; +export { default as MeshRenderer } from './webgl/MeshRenderer'; +export { default as CanvasMeshRenderer } from './canvas/CanvasMeshRenderer'; export { default as Plane } from './Plane'; export { default as NineSlicePlane } from './NineSlicePlane'; export { default as Rope } from './Rope'; -export { default as MeshShader } from './webgl/MeshShader'; diff --git a/src/mesh/webgl/MeshRenderer.js b/src/mesh/webgl/MeshRenderer.js new file mode 100644 index 0000000..73d78e6 --- /dev/null +++ b/src/mesh/webgl/MeshRenderer.js @@ -0,0 +1,108 @@ +import * as core from '../../core'; +import glCore from 'pixi-gl-core'; +import { default as Mesh } from '../Mesh'; + +const glslify = require('glslify'); // eslint-disable-line no-undef + +/** + * WebGL renderer plugin for tiling sprites + */ +export class MeshRenderer extends core.ObjectRenderer { + + /** + * constructor for renderer + * + * @param {WebGLRenderer} renderer The renderer this tiling awesomeness works for. + */ + constructor(renderer) + { + super(renderer); + + this.shader = null; + } + + /** + * Sets up the renderer context and necessary buffers. + * + * @private + */ + onContextChange() + { + const gl = this.renderer.gl; + + this.shader = new core.Shader(gl, + glslify('./mesh.vert'), + glslify('./mesh.frag')); + } + + /** + * renders mesh + * + * @param {PIXI.mesh.Mesh} mesh mesh instance + */ + render(mesh) + { + const renderer = this.renderer; + const gl = renderer.gl; + const texture = mesh._texture; + + if (!texture.valid) + { + return; + } + + let glData = mesh._glDatas[renderer.CONTEXT_UID]; + + if (!glData) + { + glData = { + shader: this.shader, + vertexBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.vertices, gl.STREAM_DRAW), + uvBuffer: glCore.GLBuffer.createVertexBuffer(gl, mesh.uvs, gl.STREAM_DRAW), + indexBuffer: glCore.GLBuffer.createIndexBuffer(gl, mesh.indices, gl.STATIC_DRAW), + // build the vao object that will render.. + vao: new glCore.VertexArrayObject(gl), + dirty: mesh.dirty, + indexDirty: mesh.indexDirty, + }; + + // build the vao object that will render.. + glData.vao = new glCore.VertexArrayObject(gl) + .addIndex(glData.indexBuffer) + .addAttribute(glData.vertexBuffer, glData.shader.attributes.aVertexPosition, gl.FLOAT, false, 2 * 4, 0) + .addAttribute(glData.uvBuffer, glData.shader.attributes.aTextureCoord, gl.FLOAT, false, 2 * 4, 0); + + mesh._glDatas[renderer.CONTEXT_UID] = glData; + } + + if (mesh.dirty !== glData.dirty) + { + glData.dirty = mesh.dirty; + glData.uvBuffer.upload(); + } + + if (mesh.indexDirty !== glData.indexDirty) + { + glData.indexDirty = mesh.indexDirty; + glData.indexBuffer.upload(); + } + + glData.vertexBuffer.upload(); + + renderer.bindShader(glData.shader); + renderer.bindTexture(texture, 0); + renderer.state.setBlendMode(mesh.blendMode); + + glData.shader.uniforms.translationMatrix = mesh.worldTransform.toArray(true); + glData.shader.uniforms.alpha = mesh.worldAlpha; + glData.shader.uniforms.tint = mesh.tintRgb; + + const drawMode = mesh.drawMode === Mesh.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; + + glData.vao.bind() + .draw(drawMode, mesh.indices.length) + .unbind(); + } +} + +core.WebGLRenderer.registerPlugin('mesh', MeshRenderer); diff --git a/src/mesh/webgl/MeshShader.js b/src/mesh/webgl/MeshShader.js deleted file mode 100644 index 1bbdc0e..0000000 --- a/src/mesh/webgl/MeshShader.js +++ /dev/null @@ -1,46 +0,0 @@ -import Shader from '../../core/Shader'; - -/** - * @class - * @extends PIXI.Shader - * @memberof PIXI.mesh - */ -export default class MeshShader extends Shader -{ - /** - * @param {WebGLRenderingContext} gl - The WebGLRenderingContext. - */ - constructor(gl) - { - super( - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - - 'uniform mat3 translationMatrix;', - 'uniform mat3 projectionMatrix;', - - 'varying vec2 vTextureCoord;', - - 'void main(void){', - ' gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', // eslint-disable-line max-len - ' vTextureCoord = aTextureCoord;', - '}', - ].join('\n'), - [ - 'varying vec2 vTextureCoord;', - 'uniform float alpha;', - 'uniform vec3 tint;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vec4(tint * alpha, alpha);', - // ' gl_FragColor = vec4(1.0);', - '}', - ].join('\n') - ); - } -} diff --git a/src/mesh/webgl/mesh.frag b/src/mesh/webgl/mesh.frag new file mode 100644 index 0000000..9e0b634 --- /dev/null +++ b/src/mesh/webgl/mesh.frag @@ -0,0 +1,10 @@ +varying vec2 vTextureCoord; +uniform float alpha; +uniform vec3 tint; + +uniform sampler2D uSampler; + +void main(void) +{ + gl_FragColor = texture2D(uSampler, vTextureCoord) * vec4(tint * alpha, alpha); +} diff --git a/src/mesh/webgl/mesh.vert b/src/mesh/webgl/mesh.vert new file mode 100644 index 0000000..a337aef --- /dev/null +++ b/src/mesh/webgl/mesh.vert @@ -0,0 +1,14 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; + +uniform mat3 translationMatrix; +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); + + vTextureCoord = aTextureCoord; +}