diff --git a/packages/core/src/batch/BatchBuffer.js b/packages/core/src/batch/BatchBuffer.js deleted file mode 100644 index b80bc7e..0000000 --- a/packages/core/src/batch/BatchBuffer.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Used by the BatchRenderer - * - * @class - * @memberof PIXI - */ -export default class BatchBuffer -{ - /** - * @param {number} size - The size of the buffer in bytes. - */ - constructor(size) - { - this.vertices = new ArrayBuffer(size); - - /** - * View on the vertices as a Float32Array for positions - * - * @member {Float32Array} - */ - this.float32View = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array for uvs - * - * @member {Float32Array} - */ - this.uint32View = new Uint32Array(this.vertices); - } - - /** - * Destroys the buffer. - * - */ - destroy() - { - this.vertices = null; - this.float32View = null; - this.uint32View = null; - } -} diff --git a/packages/core/src/batch/BatchBuffer.js b/packages/core/src/batch/BatchBuffer.js deleted file mode 100644 index b80bc7e..0000000 --- a/packages/core/src/batch/BatchBuffer.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Used by the BatchRenderer - * - * @class - * @memberof PIXI - */ -export default class BatchBuffer -{ - /** - * @param {number} size - The size of the buffer in bytes. - */ - constructor(size) - { - this.vertices = new ArrayBuffer(size); - - /** - * View on the vertices as a Float32Array for positions - * - * @member {Float32Array} - */ - this.float32View = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array for uvs - * - * @member {Float32Array} - */ - this.uint32View = new Uint32Array(this.vertices); - } - - /** - * Destroys the buffer. - * - */ - destroy() - { - this.vertices = null; - this.float32View = null; - this.uint32View = null; - } -} diff --git a/packages/core/src/batch/BatchRenderer.js b/packages/core/src/batch/BatchRenderer.js index e15f6c5..4a454b1 100644 --- a/packages/core/src/batch/BatchRenderer.js +++ b/packages/core/src/batch/BatchRenderer.js @@ -1,11 +1,13 @@ import BatchDrawCall from './BatchDrawCall'; import BaseTexture from '../textures/BaseTexture'; -import State from '../state/State'; import ObjectRenderer from './ObjectRenderer'; +import State from '../state/State'; +import ViewableBuffer from '../geometry/ViewableBuffer'; + import checkMaxIfStatementsInShader from '../shader/utils/checkMaxIfStatementsInShader'; + import { settings } from '@pixi/settings'; import { premultiplyBlendMode, premultiplyTint, nextPow2, log2 } from '@pixi/utils'; -import BatchBuffer from './BatchBuffer'; import { ENV } from '@pixi/constants'; /** @@ -195,7 +197,7 @@ } /** - * Pool of `BatchBuffer` objects that are sorted in + * Pool of `ViewableBuffer` objects that are sorted in * order of increasing size. The flush method uses * the buffer with the least size above the amount * it requires. These are used for passing attributes. @@ -203,7 +205,7 @@ * The first buffer has a size of 8; each subsequent * buffer has double capacity of its previous. * - * @member {PIXI.BatchBuffer} + * @member {PIXI.ViewableBuffer} * @private * @see PIXI.BatchRenderer#getAttributeBuffer */ @@ -312,8 +314,7 @@ } /** - * Renders the content and empties the current batch. - * + * Renders the content _now_ and empties the current batch. */ flush() { @@ -322,52 +323,48 @@ return; } - const gl = this.renderer.gl; - const MAX_TEXTURES = this.MAX_TEXTURES; - const vertSize = this.vertexSize; - - const buffer = this.getAttributeBuffer(this._vertexCount); + const attributeBuffer = this.getAttributeBuffer(this._vertexCount); const indexBuffer = this.getIndexBuffer(this._indexCount); + const gl = this.renderer.gl; - const elements = this._bufferedElements; - const _drawCalls = this._drawCalls; - - const float32View = buffer.float32View; - const uint32View = buffer.uint32View; + const { + _bufferedElements: elements, + _drawCalls: drawCalls, + MAX_TEXTURES, + _packedGeometries: packedGeometries, + vertexSize, + } = this; const touch = this.renderer.textureGC.count; let index = 0; let _indexCount = 0; + let nextTexture; let currentTexture; + let textureCount = 0; + + let currentGroup = drawCalls[0]; let groupCount = 0; - let textureCount = 0; - let currentGroup = _drawCalls[0]; - - let blendMode = -1;// premultiplyBlendMode[elements[0]._texture.baseTexture.premultiplyAlpha ? 0 : ][elements[0].blendMode]; + let blendMode = -1;// blend-mode of previous element/sprite/object! currentGroup.textureCount = 0; currentGroup.start = 0; currentGroup.blend = blendMode; let TICK = ++BaseTexture._globalBatch; - let i; for (i = 0; i < this._bufferSize; ++i) { - // upload the sprite elements... - // they have all ready been calculated so we just need to push them into the buffer. - const sprite = elements[i]; elements[i] = null; - nextTexture = sprite._texture.baseTexture; - const spriteBlendMode = premultiplyBlendMode[nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; + const spriteBlendMode = premultiplyBlendMode[ + nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; if (blendMode !== spriteBlendMode) { @@ -393,7 +390,7 @@ currentGroup.size = _indexCount - currentGroup.start; - currentGroup = _drawCalls[groupCount++]; + currentGroup = drawCalls[groupCount++]; currentGroup.textureCount = 0; currentGroup.blend = blendMode; currentGroup.start = _indexCount; @@ -408,63 +405,49 @@ } } - this.packInterleavedGeometry(sprite, float32View, uint32View, indexBuffer, index, _indexCount);// argb, nextTexture._id, float32View, uint32View, indexBuffer, index, _indexCount); + this.packInterleavedGeometry(sprite, attributeBuffer, + indexBuffer, index, _indexCount); // push a graphics.. - index += (sprite.vertexData.length / 2) * vertSize; + index += (sprite.vertexData.length / 2) * vertexSize; _indexCount += sprite.indices.length; } BaseTexture._globalBatch = TICK; - currentGroup.size = _indexCount - currentGroup.start; if (!settings.CAN_UPLOAD_SAME_BUFFER) - { - // this is still needed for IOS performance.. - // it really does not like uploading to the same buffer in a single frame! + { /* Usually on iOS devices, where the browser doesn't + like uploads to the same buffer in a single frame. */ if (this._packedGeometryPoolSize <= this._flushId) { this._packedGeometryPoolSize++; - /* eslint-disable max-len */ - this._packedGeometries[this._flushId] = new (this.geometryClass)(); + packedGeometries[this._flushId] = new (this.geometryClass)(); } - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - // this.vertexBuffers[this._flushId].update(buffer.vertices, 0); - this.renderer.geometry.bind(this._packedGeometries[this._flushId]); - + this.renderer.geometry.bind(packedGeometries[this._flushId]); this.renderer.geometry.updateBuffers(); - this._flushId++; } else { // lets use the faster option, always use buffer number 0 - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - - // if (true)// this.spriteOnly) - // { - // this._packedGeometries[this._flushId].indexBuffer = this.defualtSpriteIndexBuffer; - // this._packedGeometries[this._flushId].buffers[1] = this.defualtSpriteIndexBuffer; - // } + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); this.renderer.geometry.updateBuffers(); } - // this.renderer.state.set(this.state); - const textureSystem = this.renderer.texture; const stateSystem = this.renderer.state; - // e.log(groupCount); - // / render the _drawCalls.. + // Upload textures and do the draw calls for (i = 0; i < groupCount; i++) { - const group = _drawCalls[i]; + const group = drawCalls[i]; const groupTextureCount = group.textureCount; for (let j = 0; j < groupTextureCount; j++) @@ -473,13 +456,7 @@ group.textures[j] = null; } - // this.state.blendMode = group.blend; - // this.state.blend = true; - - // this.renderer.state.setState(this.state); - // set the blend mode.. stateSystem.setBlendMode(group.blend); - gl.drawElements(group.type, group.size, gl.UNSIGNED_SHORT, group.start * 2); } @@ -507,7 +484,6 @@ /** * Stops and flushes the current batch. - * */ stop() { @@ -548,7 +524,7 @@ * can hold atleast `size` floats. * * @param {number} size - minimum capacity required - * @return {BatchBuffer} - buffer than can hold atleast `size` floats + * @return {ViewableBuffer} - buffer than can hold atleast `size` floats * @private */ getAttributeBuffer(size) @@ -567,7 +543,7 @@ if (!buffer) { - this._aBuffers[roundedSize] = buffer = new BatchBuffer(roundedSize * this.vertexSize * 4); + this._aBuffers[roundedSize] = buffer = new ViewableBuffer(roundedSize * this.vertexSize * 4); } return buffer; @@ -613,16 +589,19 @@ * present. * * @param {PIXI.Sprite} element - element being rendered - * @param {Float32Array} float32View - float32-view of the attribute buffer - * @param {Uint32Array} uint32View - uint32-view of the attribute buffer + * @param {PIXI.ViewableBuffer} attributeBuffer - attribute buffer. * @param {Uint16Array} indexBuffer - index buffer * @param {number} aIndex - number of floats already in the attribute buffer * @param {number} iIndex - number of indices already in `indexBuffer` */ - packInterleavedGeometry(element, - float32View, uint32View, indexBuffer, aIndex, iIndex) + packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) { - const p = aIndex / this.vertexSize; + const { + uint32View, + float32View, + } = attributeBuffer; + + const packedVertices = aIndex / this.vertexSize; const uvs = element.uvs; const indicies = element.indices; const vertexData = element.vertexData; @@ -647,7 +626,7 @@ for (let i = 0; i < indicies.length; i++) { - indexBuffer[iIndex++] = p + indicies[i]; + indexBuffer[iIndex++] = packedVertices + indicies[i]; } } } diff --git a/packages/core/src/batch/BatchBuffer.js b/packages/core/src/batch/BatchBuffer.js deleted file mode 100644 index b80bc7e..0000000 --- a/packages/core/src/batch/BatchBuffer.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Used by the BatchRenderer - * - * @class - * @memberof PIXI - */ -export default class BatchBuffer -{ - /** - * @param {number} size - The size of the buffer in bytes. - */ - constructor(size) - { - this.vertices = new ArrayBuffer(size); - - /** - * View on the vertices as a Float32Array for positions - * - * @member {Float32Array} - */ - this.float32View = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array for uvs - * - * @member {Float32Array} - */ - this.uint32View = new Uint32Array(this.vertices); - } - - /** - * Destroys the buffer. - * - */ - destroy() - { - this.vertices = null; - this.float32View = null; - this.uint32View = null; - } -} diff --git a/packages/core/src/batch/BatchRenderer.js b/packages/core/src/batch/BatchRenderer.js index e15f6c5..4a454b1 100644 --- a/packages/core/src/batch/BatchRenderer.js +++ b/packages/core/src/batch/BatchRenderer.js @@ -1,11 +1,13 @@ import BatchDrawCall from './BatchDrawCall'; import BaseTexture from '../textures/BaseTexture'; -import State from '../state/State'; import ObjectRenderer from './ObjectRenderer'; +import State from '../state/State'; +import ViewableBuffer from '../geometry/ViewableBuffer'; + import checkMaxIfStatementsInShader from '../shader/utils/checkMaxIfStatementsInShader'; + import { settings } from '@pixi/settings'; import { premultiplyBlendMode, premultiplyTint, nextPow2, log2 } from '@pixi/utils'; -import BatchBuffer from './BatchBuffer'; import { ENV } from '@pixi/constants'; /** @@ -195,7 +197,7 @@ } /** - * Pool of `BatchBuffer` objects that are sorted in + * Pool of `ViewableBuffer` objects that are sorted in * order of increasing size. The flush method uses * the buffer with the least size above the amount * it requires. These are used for passing attributes. @@ -203,7 +205,7 @@ * The first buffer has a size of 8; each subsequent * buffer has double capacity of its previous. * - * @member {PIXI.BatchBuffer} + * @member {PIXI.ViewableBuffer} * @private * @see PIXI.BatchRenderer#getAttributeBuffer */ @@ -312,8 +314,7 @@ } /** - * Renders the content and empties the current batch. - * + * Renders the content _now_ and empties the current batch. */ flush() { @@ -322,52 +323,48 @@ return; } - const gl = this.renderer.gl; - const MAX_TEXTURES = this.MAX_TEXTURES; - const vertSize = this.vertexSize; - - const buffer = this.getAttributeBuffer(this._vertexCount); + const attributeBuffer = this.getAttributeBuffer(this._vertexCount); const indexBuffer = this.getIndexBuffer(this._indexCount); + const gl = this.renderer.gl; - const elements = this._bufferedElements; - const _drawCalls = this._drawCalls; - - const float32View = buffer.float32View; - const uint32View = buffer.uint32View; + const { + _bufferedElements: elements, + _drawCalls: drawCalls, + MAX_TEXTURES, + _packedGeometries: packedGeometries, + vertexSize, + } = this; const touch = this.renderer.textureGC.count; let index = 0; let _indexCount = 0; + let nextTexture; let currentTexture; + let textureCount = 0; + + let currentGroup = drawCalls[0]; let groupCount = 0; - let textureCount = 0; - let currentGroup = _drawCalls[0]; - - let blendMode = -1;// premultiplyBlendMode[elements[0]._texture.baseTexture.premultiplyAlpha ? 0 : ][elements[0].blendMode]; + let blendMode = -1;// blend-mode of previous element/sprite/object! currentGroup.textureCount = 0; currentGroup.start = 0; currentGroup.blend = blendMode; let TICK = ++BaseTexture._globalBatch; - let i; for (i = 0; i < this._bufferSize; ++i) { - // upload the sprite elements... - // they have all ready been calculated so we just need to push them into the buffer. - const sprite = elements[i]; elements[i] = null; - nextTexture = sprite._texture.baseTexture; - const spriteBlendMode = premultiplyBlendMode[nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; + const spriteBlendMode = premultiplyBlendMode[ + nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; if (blendMode !== spriteBlendMode) { @@ -393,7 +390,7 @@ currentGroup.size = _indexCount - currentGroup.start; - currentGroup = _drawCalls[groupCount++]; + currentGroup = drawCalls[groupCount++]; currentGroup.textureCount = 0; currentGroup.blend = blendMode; currentGroup.start = _indexCount; @@ -408,63 +405,49 @@ } } - this.packInterleavedGeometry(sprite, float32View, uint32View, indexBuffer, index, _indexCount);// argb, nextTexture._id, float32View, uint32View, indexBuffer, index, _indexCount); + this.packInterleavedGeometry(sprite, attributeBuffer, + indexBuffer, index, _indexCount); // push a graphics.. - index += (sprite.vertexData.length / 2) * vertSize; + index += (sprite.vertexData.length / 2) * vertexSize; _indexCount += sprite.indices.length; } BaseTexture._globalBatch = TICK; - currentGroup.size = _indexCount - currentGroup.start; if (!settings.CAN_UPLOAD_SAME_BUFFER) - { - // this is still needed for IOS performance.. - // it really does not like uploading to the same buffer in a single frame! + { /* Usually on iOS devices, where the browser doesn't + like uploads to the same buffer in a single frame. */ if (this._packedGeometryPoolSize <= this._flushId) { this._packedGeometryPoolSize++; - /* eslint-disable max-len */ - this._packedGeometries[this._flushId] = new (this.geometryClass)(); + packedGeometries[this._flushId] = new (this.geometryClass)(); } - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - // this.vertexBuffers[this._flushId].update(buffer.vertices, 0); - this.renderer.geometry.bind(this._packedGeometries[this._flushId]); - + this.renderer.geometry.bind(packedGeometries[this._flushId]); this.renderer.geometry.updateBuffers(); - this._flushId++; } else { // lets use the faster option, always use buffer number 0 - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - - // if (true)// this.spriteOnly) - // { - // this._packedGeometries[this._flushId].indexBuffer = this.defualtSpriteIndexBuffer; - // this._packedGeometries[this._flushId].buffers[1] = this.defualtSpriteIndexBuffer; - // } + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); this.renderer.geometry.updateBuffers(); } - // this.renderer.state.set(this.state); - const textureSystem = this.renderer.texture; const stateSystem = this.renderer.state; - // e.log(groupCount); - // / render the _drawCalls.. + // Upload textures and do the draw calls for (i = 0; i < groupCount; i++) { - const group = _drawCalls[i]; + const group = drawCalls[i]; const groupTextureCount = group.textureCount; for (let j = 0; j < groupTextureCount; j++) @@ -473,13 +456,7 @@ group.textures[j] = null; } - // this.state.blendMode = group.blend; - // this.state.blend = true; - - // this.renderer.state.setState(this.state); - // set the blend mode.. stateSystem.setBlendMode(group.blend); - gl.drawElements(group.type, group.size, gl.UNSIGNED_SHORT, group.start * 2); } @@ -507,7 +484,6 @@ /** * Stops and flushes the current batch. - * */ stop() { @@ -548,7 +524,7 @@ * can hold atleast `size` floats. * * @param {number} size - minimum capacity required - * @return {BatchBuffer} - buffer than can hold atleast `size` floats + * @return {ViewableBuffer} - buffer than can hold atleast `size` floats * @private */ getAttributeBuffer(size) @@ -567,7 +543,7 @@ if (!buffer) { - this._aBuffers[roundedSize] = buffer = new BatchBuffer(roundedSize * this.vertexSize * 4); + this._aBuffers[roundedSize] = buffer = new ViewableBuffer(roundedSize * this.vertexSize * 4); } return buffer; @@ -613,16 +589,19 @@ * present. * * @param {PIXI.Sprite} element - element being rendered - * @param {Float32Array} float32View - float32-view of the attribute buffer - * @param {Uint32Array} uint32View - uint32-view of the attribute buffer + * @param {PIXI.ViewableBuffer} attributeBuffer - attribute buffer. * @param {Uint16Array} indexBuffer - index buffer * @param {number} aIndex - number of floats already in the attribute buffer * @param {number} iIndex - number of indices already in `indexBuffer` */ - packInterleavedGeometry(element, - float32View, uint32View, indexBuffer, aIndex, iIndex) + packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) { - const p = aIndex / this.vertexSize; + const { + uint32View, + float32View, + } = attributeBuffer; + + const packedVertices = aIndex / this.vertexSize; const uvs = element.uvs; const indicies = element.indices; const vertexData = element.vertexData; @@ -647,7 +626,7 @@ for (let i = 0; i < indicies.length; i++) { - indexBuffer[iIndex++] = p + indicies[i]; + indexBuffer[iIndex++] = packedVertices + indicies[i]; } } } diff --git a/packages/core/src/batch/ObjectRenderer.js b/packages/core/src/batch/ObjectRenderer.js index 0c851a9..1776347 100644 --- a/packages/core/src/batch/ObjectRenderer.js +++ b/packages/core/src/batch/ObjectRenderer.js @@ -1,35 +1,29 @@ -import System from '../System'; - /** - * Base for a common object renderer that can be used as a system renderer plugin. + * Base for a common object renderer that can be used as a + * system renderer plugin. * * @class * @extends PIXI.System * @memberof PIXI */ -export default class ObjectRenderer extends System +export default class ObjectRenderer { /** - * Starts the renderer and sets the shader - * + * @param {PIXI.Renderer} renderer - The renderer this manager works for. */ - start() + constructor(renderer) { - // set the shader.. + /** + * The renderer this manager works for. + * + * @member {PIXI.Renderer} + */ + this.renderer = renderer; } /** - * Stops the renderer - * - */ - stop() - { - this.flush(); - } - - /** - * Stub method for rendering content and emptying the current batch. - * + * Stub method that should be used to empty the current + * batch by rendering objects now. */ flush() { @@ -37,7 +31,37 @@ } /** - * Renders an object + * Generic destruction method that frees all resources. This + * should be called by subclasses. + */ + destroy() + { + this.renderer = null; + } + + /** + * Stub method that initializes any state required before + * rendering starts. It is different from the `prerender` + * signal, which occurs every frame, in that it is called + * whenever an object requests _this_ renderer specifically. + */ + start() + { + // set the shader.. + } + + /** + * Stops the renderer. It should free up any state and + * become dormant. + */ + stop() + { + this.flush(); + } + + /** + * Keeps the object to render. It doesn't have to be + * rendered immediately. * * @param {PIXI.DisplayObject} object - The object to render. */ diff --git a/packages/core/src/batch/BatchBuffer.js b/packages/core/src/batch/BatchBuffer.js deleted file mode 100644 index b80bc7e..0000000 --- a/packages/core/src/batch/BatchBuffer.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Used by the BatchRenderer - * - * @class - * @memberof PIXI - */ -export default class BatchBuffer -{ - /** - * @param {number} size - The size of the buffer in bytes. - */ - constructor(size) - { - this.vertices = new ArrayBuffer(size); - - /** - * View on the vertices as a Float32Array for positions - * - * @member {Float32Array} - */ - this.float32View = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array for uvs - * - * @member {Float32Array} - */ - this.uint32View = new Uint32Array(this.vertices); - } - - /** - * Destroys the buffer. - * - */ - destroy() - { - this.vertices = null; - this.float32View = null; - this.uint32View = null; - } -} diff --git a/packages/core/src/batch/BatchRenderer.js b/packages/core/src/batch/BatchRenderer.js index e15f6c5..4a454b1 100644 --- a/packages/core/src/batch/BatchRenderer.js +++ b/packages/core/src/batch/BatchRenderer.js @@ -1,11 +1,13 @@ import BatchDrawCall from './BatchDrawCall'; import BaseTexture from '../textures/BaseTexture'; -import State from '../state/State'; import ObjectRenderer from './ObjectRenderer'; +import State from '../state/State'; +import ViewableBuffer from '../geometry/ViewableBuffer'; + import checkMaxIfStatementsInShader from '../shader/utils/checkMaxIfStatementsInShader'; + import { settings } from '@pixi/settings'; import { premultiplyBlendMode, premultiplyTint, nextPow2, log2 } from '@pixi/utils'; -import BatchBuffer from './BatchBuffer'; import { ENV } from '@pixi/constants'; /** @@ -195,7 +197,7 @@ } /** - * Pool of `BatchBuffer` objects that are sorted in + * Pool of `ViewableBuffer` objects that are sorted in * order of increasing size. The flush method uses * the buffer with the least size above the amount * it requires. These are used for passing attributes. @@ -203,7 +205,7 @@ * The first buffer has a size of 8; each subsequent * buffer has double capacity of its previous. * - * @member {PIXI.BatchBuffer} + * @member {PIXI.ViewableBuffer} * @private * @see PIXI.BatchRenderer#getAttributeBuffer */ @@ -312,8 +314,7 @@ } /** - * Renders the content and empties the current batch. - * + * Renders the content _now_ and empties the current batch. */ flush() { @@ -322,52 +323,48 @@ return; } - const gl = this.renderer.gl; - const MAX_TEXTURES = this.MAX_TEXTURES; - const vertSize = this.vertexSize; - - const buffer = this.getAttributeBuffer(this._vertexCount); + const attributeBuffer = this.getAttributeBuffer(this._vertexCount); const indexBuffer = this.getIndexBuffer(this._indexCount); + const gl = this.renderer.gl; - const elements = this._bufferedElements; - const _drawCalls = this._drawCalls; - - const float32View = buffer.float32View; - const uint32View = buffer.uint32View; + const { + _bufferedElements: elements, + _drawCalls: drawCalls, + MAX_TEXTURES, + _packedGeometries: packedGeometries, + vertexSize, + } = this; const touch = this.renderer.textureGC.count; let index = 0; let _indexCount = 0; + let nextTexture; let currentTexture; + let textureCount = 0; + + let currentGroup = drawCalls[0]; let groupCount = 0; - let textureCount = 0; - let currentGroup = _drawCalls[0]; - - let blendMode = -1;// premultiplyBlendMode[elements[0]._texture.baseTexture.premultiplyAlpha ? 0 : ][elements[0].blendMode]; + let blendMode = -1;// blend-mode of previous element/sprite/object! currentGroup.textureCount = 0; currentGroup.start = 0; currentGroup.blend = blendMode; let TICK = ++BaseTexture._globalBatch; - let i; for (i = 0; i < this._bufferSize; ++i) { - // upload the sprite elements... - // they have all ready been calculated so we just need to push them into the buffer. - const sprite = elements[i]; elements[i] = null; - nextTexture = sprite._texture.baseTexture; - const spriteBlendMode = premultiplyBlendMode[nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; + const spriteBlendMode = premultiplyBlendMode[ + nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; if (blendMode !== spriteBlendMode) { @@ -393,7 +390,7 @@ currentGroup.size = _indexCount - currentGroup.start; - currentGroup = _drawCalls[groupCount++]; + currentGroup = drawCalls[groupCount++]; currentGroup.textureCount = 0; currentGroup.blend = blendMode; currentGroup.start = _indexCount; @@ -408,63 +405,49 @@ } } - this.packInterleavedGeometry(sprite, float32View, uint32View, indexBuffer, index, _indexCount);// argb, nextTexture._id, float32View, uint32View, indexBuffer, index, _indexCount); + this.packInterleavedGeometry(sprite, attributeBuffer, + indexBuffer, index, _indexCount); // push a graphics.. - index += (sprite.vertexData.length / 2) * vertSize; + index += (sprite.vertexData.length / 2) * vertexSize; _indexCount += sprite.indices.length; } BaseTexture._globalBatch = TICK; - currentGroup.size = _indexCount - currentGroup.start; if (!settings.CAN_UPLOAD_SAME_BUFFER) - { - // this is still needed for IOS performance.. - // it really does not like uploading to the same buffer in a single frame! + { /* Usually on iOS devices, where the browser doesn't + like uploads to the same buffer in a single frame. */ if (this._packedGeometryPoolSize <= this._flushId) { this._packedGeometryPoolSize++; - /* eslint-disable max-len */ - this._packedGeometries[this._flushId] = new (this.geometryClass)(); + packedGeometries[this._flushId] = new (this.geometryClass)(); } - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - // this.vertexBuffers[this._flushId].update(buffer.vertices, 0); - this.renderer.geometry.bind(this._packedGeometries[this._flushId]); - + this.renderer.geometry.bind(packedGeometries[this._flushId]); this.renderer.geometry.updateBuffers(); - this._flushId++; } else { // lets use the faster option, always use buffer number 0 - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - - // if (true)// this.spriteOnly) - // { - // this._packedGeometries[this._flushId].indexBuffer = this.defualtSpriteIndexBuffer; - // this._packedGeometries[this._flushId].buffers[1] = this.defualtSpriteIndexBuffer; - // } + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); this.renderer.geometry.updateBuffers(); } - // this.renderer.state.set(this.state); - const textureSystem = this.renderer.texture; const stateSystem = this.renderer.state; - // e.log(groupCount); - // / render the _drawCalls.. + // Upload textures and do the draw calls for (i = 0; i < groupCount; i++) { - const group = _drawCalls[i]; + const group = drawCalls[i]; const groupTextureCount = group.textureCount; for (let j = 0; j < groupTextureCount; j++) @@ -473,13 +456,7 @@ group.textures[j] = null; } - // this.state.blendMode = group.blend; - // this.state.blend = true; - - // this.renderer.state.setState(this.state); - // set the blend mode.. stateSystem.setBlendMode(group.blend); - gl.drawElements(group.type, group.size, gl.UNSIGNED_SHORT, group.start * 2); } @@ -507,7 +484,6 @@ /** * Stops and flushes the current batch. - * */ stop() { @@ -548,7 +524,7 @@ * can hold atleast `size` floats. * * @param {number} size - minimum capacity required - * @return {BatchBuffer} - buffer than can hold atleast `size` floats + * @return {ViewableBuffer} - buffer than can hold atleast `size` floats * @private */ getAttributeBuffer(size) @@ -567,7 +543,7 @@ if (!buffer) { - this._aBuffers[roundedSize] = buffer = new BatchBuffer(roundedSize * this.vertexSize * 4); + this._aBuffers[roundedSize] = buffer = new ViewableBuffer(roundedSize * this.vertexSize * 4); } return buffer; @@ -613,16 +589,19 @@ * present. * * @param {PIXI.Sprite} element - element being rendered - * @param {Float32Array} float32View - float32-view of the attribute buffer - * @param {Uint32Array} uint32View - uint32-view of the attribute buffer + * @param {PIXI.ViewableBuffer} attributeBuffer - attribute buffer. * @param {Uint16Array} indexBuffer - index buffer * @param {number} aIndex - number of floats already in the attribute buffer * @param {number} iIndex - number of indices already in `indexBuffer` */ - packInterleavedGeometry(element, - float32View, uint32View, indexBuffer, aIndex, iIndex) + packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) { - const p = aIndex / this.vertexSize; + const { + uint32View, + float32View, + } = attributeBuffer; + + const packedVertices = aIndex / this.vertexSize; const uvs = element.uvs; const indicies = element.indices; const vertexData = element.vertexData; @@ -647,7 +626,7 @@ for (let i = 0; i < indicies.length; i++) { - indexBuffer[iIndex++] = p + indicies[i]; + indexBuffer[iIndex++] = packedVertices + indicies[i]; } } } diff --git a/packages/core/src/batch/ObjectRenderer.js b/packages/core/src/batch/ObjectRenderer.js index 0c851a9..1776347 100644 --- a/packages/core/src/batch/ObjectRenderer.js +++ b/packages/core/src/batch/ObjectRenderer.js @@ -1,35 +1,29 @@ -import System from '../System'; - /** - * Base for a common object renderer that can be used as a system renderer plugin. + * Base for a common object renderer that can be used as a + * system renderer plugin. * * @class * @extends PIXI.System * @memberof PIXI */ -export default class ObjectRenderer extends System +export default class ObjectRenderer { /** - * Starts the renderer and sets the shader - * + * @param {PIXI.Renderer} renderer - The renderer this manager works for. */ - start() + constructor(renderer) { - // set the shader.. + /** + * The renderer this manager works for. + * + * @member {PIXI.Renderer} + */ + this.renderer = renderer; } /** - * Stops the renderer - * - */ - stop() - { - this.flush(); - } - - /** - * Stub method for rendering content and emptying the current batch. - * + * Stub method that should be used to empty the current + * batch by rendering objects now. */ flush() { @@ -37,7 +31,37 @@ } /** - * Renders an object + * Generic destruction method that frees all resources. This + * should be called by subclasses. + */ + destroy() + { + this.renderer = null; + } + + /** + * Stub method that initializes any state required before + * rendering starts. It is different from the `prerender` + * signal, which occurs every frame, in that it is called + * whenever an object requests _this_ renderer specifically. + */ + start() + { + // set the shader.. + } + + /** + * Stops the renderer. It should free up any state and + * become dormant. + */ + stop() + { + this.flush(); + } + + /** + * Keeps the object to render. It doesn't have to be + * rendered immediately. * * @param {PIXI.DisplayObject} object - The object to render. */ diff --git a/packages/core/src/geometry/ViewableBuffer.js b/packages/core/src/geometry/ViewableBuffer.js new file mode 100644 index 0000000..719c4e9 --- /dev/null +++ b/packages/core/src/geometry/ViewableBuffer.js @@ -0,0 +1,175 @@ +/** + * Flexible wrapper around `ArrayBuffer` that also provides + * typed array views on demand. + * + * @class + * @memberof PIXI + */ +export default class ViewableBuffer +{ + /** + * @param {number} size - The size of the buffer in bytes. + */ + constructor(size) + { + /** + * Underlying `ArrayBuffer` that holds all the data + * and is of capacity `size`. + * + * @member {ArrayBuffer} + */ + this.rawBinaryData = new ArrayBuffer(size); + } + + /** + * View on the raw binary data as a `Int8Array`. + * + * @member {Int8Array} + */ + get int8View() + { + if (!this._int8View) + { + this._int8View = new Int8Array(this.rawBinaryData); + } + + return this._int8View; + } + + /** + * View on the raw binary data as a `Uint8Array`. + * + * @member {Uint8Array} + */ + get uint8View() + { + if (!this._uint8View) + { + this._uint8View = new Uint8Array(this.rawBinaryData); + } + + return this._uint8View; + } + + /** + * View on the raw binary data as a `Int16Array`. + * + * @member {Int16Array} + */ + get int16View() + { + if (!this._int16View) + { + this._int16View = new Int16Array(this.rawBinaryData); + } + + return this._int16View; + } + + /** + * View on the raw binary data as a `Uint16Array`. + * + * @member {Uint16Array} + */ + get uint16View() + { + if (!this._uint16View) + { + this._uint16View = new Uint16Array(this.rawBinaryData); + } + + return this._uint16View; + } + + /** + * View on the raw binary data as a `Int32Array`. + * + * @member {Int32Array} + */ + get int32View() + { + if (!this._int32View) + { + this._int32View = new Int32Array(this.rawBinaryData); + } + + return this._int32View; + } + + /** + * View on the raw binary data as a `Uint32Array`. + * + * @member {Float32Array} + */ + get uint32View() + { + if (!this._uint32View) + { + this._uint32View = new Uint32Array(this.rawBinaryData); + } + + return this._uint32View; + } + + /** + * View on the raw binary data as a `Float32Array`. + * + * @member {Float32Array} + */ + get float32View() + { + if (!this._float32View) + { + this._float32View = new Float32Array(this.rawBinaryData); + } + + return this._float32View; + } + + /** + * Returns the view of the given type. + * + * @param {string} type - One of `int8`, `uint8`, `int16`, + * `uint16`, `int32`, `uint32`, and `float32`. + * @return typed array of given type + */ + view(type) + { + return this[`${type}View`]; + } + + /** + * Destroys all buffer references. Do not use after calling + * this. + */ + destroy() + { + this.rawBinaryData = null; + this._int8View = null; + this._uint8View = null; + this._int16View = null; + this._uint16View = null; + this._int32View = null; + this._uint32View = null; + this._float32View = null; + } + + static sizeOf(type) + { + switch (type) + { + case 'int8': + case 'uint8': + return 1; + case 'int16': + case 'uint16': + return 2; + case 'int32': + case 'uint32': + case 'float32': + return 4; + default: + throw new Error(`${type} isn't a valid view type`); + } + } +} diff --git a/packages/core/src/batch/BatchBuffer.js b/packages/core/src/batch/BatchBuffer.js deleted file mode 100644 index b80bc7e..0000000 --- a/packages/core/src/batch/BatchBuffer.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Used by the BatchRenderer - * - * @class - * @memberof PIXI - */ -export default class BatchBuffer -{ - /** - * @param {number} size - The size of the buffer in bytes. - */ - constructor(size) - { - this.vertices = new ArrayBuffer(size); - - /** - * View on the vertices as a Float32Array for positions - * - * @member {Float32Array} - */ - this.float32View = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array for uvs - * - * @member {Float32Array} - */ - this.uint32View = new Uint32Array(this.vertices); - } - - /** - * Destroys the buffer. - * - */ - destroy() - { - this.vertices = null; - this.float32View = null; - this.uint32View = null; - } -} diff --git a/packages/core/src/batch/BatchRenderer.js b/packages/core/src/batch/BatchRenderer.js index e15f6c5..4a454b1 100644 --- a/packages/core/src/batch/BatchRenderer.js +++ b/packages/core/src/batch/BatchRenderer.js @@ -1,11 +1,13 @@ import BatchDrawCall from './BatchDrawCall'; import BaseTexture from '../textures/BaseTexture'; -import State from '../state/State'; import ObjectRenderer from './ObjectRenderer'; +import State from '../state/State'; +import ViewableBuffer from '../geometry/ViewableBuffer'; + import checkMaxIfStatementsInShader from '../shader/utils/checkMaxIfStatementsInShader'; + import { settings } from '@pixi/settings'; import { premultiplyBlendMode, premultiplyTint, nextPow2, log2 } from '@pixi/utils'; -import BatchBuffer from './BatchBuffer'; import { ENV } from '@pixi/constants'; /** @@ -195,7 +197,7 @@ } /** - * Pool of `BatchBuffer` objects that are sorted in + * Pool of `ViewableBuffer` objects that are sorted in * order of increasing size. The flush method uses * the buffer with the least size above the amount * it requires. These are used for passing attributes. @@ -203,7 +205,7 @@ * The first buffer has a size of 8; each subsequent * buffer has double capacity of its previous. * - * @member {PIXI.BatchBuffer} + * @member {PIXI.ViewableBuffer} * @private * @see PIXI.BatchRenderer#getAttributeBuffer */ @@ -312,8 +314,7 @@ } /** - * Renders the content and empties the current batch. - * + * Renders the content _now_ and empties the current batch. */ flush() { @@ -322,52 +323,48 @@ return; } - const gl = this.renderer.gl; - const MAX_TEXTURES = this.MAX_TEXTURES; - const vertSize = this.vertexSize; - - const buffer = this.getAttributeBuffer(this._vertexCount); + const attributeBuffer = this.getAttributeBuffer(this._vertexCount); const indexBuffer = this.getIndexBuffer(this._indexCount); + const gl = this.renderer.gl; - const elements = this._bufferedElements; - const _drawCalls = this._drawCalls; - - const float32View = buffer.float32View; - const uint32View = buffer.uint32View; + const { + _bufferedElements: elements, + _drawCalls: drawCalls, + MAX_TEXTURES, + _packedGeometries: packedGeometries, + vertexSize, + } = this; const touch = this.renderer.textureGC.count; let index = 0; let _indexCount = 0; + let nextTexture; let currentTexture; + let textureCount = 0; + + let currentGroup = drawCalls[0]; let groupCount = 0; - let textureCount = 0; - let currentGroup = _drawCalls[0]; - - let blendMode = -1;// premultiplyBlendMode[elements[0]._texture.baseTexture.premultiplyAlpha ? 0 : ][elements[0].blendMode]; + let blendMode = -1;// blend-mode of previous element/sprite/object! currentGroup.textureCount = 0; currentGroup.start = 0; currentGroup.blend = blendMode; let TICK = ++BaseTexture._globalBatch; - let i; for (i = 0; i < this._bufferSize; ++i) { - // upload the sprite elements... - // they have all ready been calculated so we just need to push them into the buffer. - const sprite = elements[i]; elements[i] = null; - nextTexture = sprite._texture.baseTexture; - const spriteBlendMode = premultiplyBlendMode[nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; + const spriteBlendMode = premultiplyBlendMode[ + nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; if (blendMode !== spriteBlendMode) { @@ -393,7 +390,7 @@ currentGroup.size = _indexCount - currentGroup.start; - currentGroup = _drawCalls[groupCount++]; + currentGroup = drawCalls[groupCount++]; currentGroup.textureCount = 0; currentGroup.blend = blendMode; currentGroup.start = _indexCount; @@ -408,63 +405,49 @@ } } - this.packInterleavedGeometry(sprite, float32View, uint32View, indexBuffer, index, _indexCount);// argb, nextTexture._id, float32View, uint32View, indexBuffer, index, _indexCount); + this.packInterleavedGeometry(sprite, attributeBuffer, + indexBuffer, index, _indexCount); // push a graphics.. - index += (sprite.vertexData.length / 2) * vertSize; + index += (sprite.vertexData.length / 2) * vertexSize; _indexCount += sprite.indices.length; } BaseTexture._globalBatch = TICK; - currentGroup.size = _indexCount - currentGroup.start; if (!settings.CAN_UPLOAD_SAME_BUFFER) - { - // this is still needed for IOS performance.. - // it really does not like uploading to the same buffer in a single frame! + { /* Usually on iOS devices, where the browser doesn't + like uploads to the same buffer in a single frame. */ if (this._packedGeometryPoolSize <= this._flushId) { this._packedGeometryPoolSize++; - /* eslint-disable max-len */ - this._packedGeometries[this._flushId] = new (this.geometryClass)(); + packedGeometries[this._flushId] = new (this.geometryClass)(); } - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - // this.vertexBuffers[this._flushId].update(buffer.vertices, 0); - this.renderer.geometry.bind(this._packedGeometries[this._flushId]); - + this.renderer.geometry.bind(packedGeometries[this._flushId]); this.renderer.geometry.updateBuffers(); - this._flushId++; } else { // lets use the faster option, always use buffer number 0 - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - - // if (true)// this.spriteOnly) - // { - // this._packedGeometries[this._flushId].indexBuffer = this.defualtSpriteIndexBuffer; - // this._packedGeometries[this._flushId].buffers[1] = this.defualtSpriteIndexBuffer; - // } + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); this.renderer.geometry.updateBuffers(); } - // this.renderer.state.set(this.state); - const textureSystem = this.renderer.texture; const stateSystem = this.renderer.state; - // e.log(groupCount); - // / render the _drawCalls.. + // Upload textures and do the draw calls for (i = 0; i < groupCount; i++) { - const group = _drawCalls[i]; + const group = drawCalls[i]; const groupTextureCount = group.textureCount; for (let j = 0; j < groupTextureCount; j++) @@ -473,13 +456,7 @@ group.textures[j] = null; } - // this.state.blendMode = group.blend; - // this.state.blend = true; - - // this.renderer.state.setState(this.state); - // set the blend mode.. stateSystem.setBlendMode(group.blend); - gl.drawElements(group.type, group.size, gl.UNSIGNED_SHORT, group.start * 2); } @@ -507,7 +484,6 @@ /** * Stops and flushes the current batch. - * */ stop() { @@ -548,7 +524,7 @@ * can hold atleast `size` floats. * * @param {number} size - minimum capacity required - * @return {BatchBuffer} - buffer than can hold atleast `size` floats + * @return {ViewableBuffer} - buffer than can hold atleast `size` floats * @private */ getAttributeBuffer(size) @@ -567,7 +543,7 @@ if (!buffer) { - this._aBuffers[roundedSize] = buffer = new BatchBuffer(roundedSize * this.vertexSize * 4); + this._aBuffers[roundedSize] = buffer = new ViewableBuffer(roundedSize * this.vertexSize * 4); } return buffer; @@ -613,16 +589,19 @@ * present. * * @param {PIXI.Sprite} element - element being rendered - * @param {Float32Array} float32View - float32-view of the attribute buffer - * @param {Uint32Array} uint32View - uint32-view of the attribute buffer + * @param {PIXI.ViewableBuffer} attributeBuffer - attribute buffer. * @param {Uint16Array} indexBuffer - index buffer * @param {number} aIndex - number of floats already in the attribute buffer * @param {number} iIndex - number of indices already in `indexBuffer` */ - packInterleavedGeometry(element, - float32View, uint32View, indexBuffer, aIndex, iIndex) + packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) { - const p = aIndex / this.vertexSize; + const { + uint32View, + float32View, + } = attributeBuffer; + + const packedVertices = aIndex / this.vertexSize; const uvs = element.uvs; const indicies = element.indices; const vertexData = element.vertexData; @@ -647,7 +626,7 @@ for (let i = 0; i < indicies.length; i++) { - indexBuffer[iIndex++] = p + indicies[i]; + indexBuffer[iIndex++] = packedVertices + indicies[i]; } } } diff --git a/packages/core/src/batch/ObjectRenderer.js b/packages/core/src/batch/ObjectRenderer.js index 0c851a9..1776347 100644 --- a/packages/core/src/batch/ObjectRenderer.js +++ b/packages/core/src/batch/ObjectRenderer.js @@ -1,35 +1,29 @@ -import System from '../System'; - /** - * Base for a common object renderer that can be used as a system renderer plugin. + * Base for a common object renderer that can be used as a + * system renderer plugin. * * @class * @extends PIXI.System * @memberof PIXI */ -export default class ObjectRenderer extends System +export default class ObjectRenderer { /** - * Starts the renderer and sets the shader - * + * @param {PIXI.Renderer} renderer - The renderer this manager works for. */ - start() + constructor(renderer) { - // set the shader.. + /** + * The renderer this manager works for. + * + * @member {PIXI.Renderer} + */ + this.renderer = renderer; } /** - * Stops the renderer - * - */ - stop() - { - this.flush(); - } - - /** - * Stub method for rendering content and emptying the current batch. - * + * Stub method that should be used to empty the current + * batch by rendering objects now. */ flush() { @@ -37,7 +31,37 @@ } /** - * Renders an object + * Generic destruction method that frees all resources. This + * should be called by subclasses. + */ + destroy() + { + this.renderer = null; + } + + /** + * Stub method that initializes any state required before + * rendering starts. It is different from the `prerender` + * signal, which occurs every frame, in that it is called + * whenever an object requests _this_ renderer specifically. + */ + start() + { + // set the shader.. + } + + /** + * Stops the renderer. It should free up any state and + * become dormant. + */ + stop() + { + this.flush(); + } + + /** + * Keeps the object to render. It doesn't have to be + * rendered immediately. * * @param {PIXI.DisplayObject} object - The object to render. */ diff --git a/packages/core/src/geometry/ViewableBuffer.js b/packages/core/src/geometry/ViewableBuffer.js new file mode 100644 index 0000000..719c4e9 --- /dev/null +++ b/packages/core/src/geometry/ViewableBuffer.js @@ -0,0 +1,175 @@ +/** + * Flexible wrapper around `ArrayBuffer` that also provides + * typed array views on demand. + * + * @class + * @memberof PIXI + */ +export default class ViewableBuffer +{ + /** + * @param {number} size - The size of the buffer in bytes. + */ + constructor(size) + { + /** + * Underlying `ArrayBuffer` that holds all the data + * and is of capacity `size`. + * + * @member {ArrayBuffer} + */ + this.rawBinaryData = new ArrayBuffer(size); + } + + /** + * View on the raw binary data as a `Int8Array`. + * + * @member {Int8Array} + */ + get int8View() + { + if (!this._int8View) + { + this._int8View = new Int8Array(this.rawBinaryData); + } + + return this._int8View; + } + + /** + * View on the raw binary data as a `Uint8Array`. + * + * @member {Uint8Array} + */ + get uint8View() + { + if (!this._uint8View) + { + this._uint8View = new Uint8Array(this.rawBinaryData); + } + + return this._uint8View; + } + + /** + * View on the raw binary data as a `Int16Array`. + * + * @member {Int16Array} + */ + get int16View() + { + if (!this._int16View) + { + this._int16View = new Int16Array(this.rawBinaryData); + } + + return this._int16View; + } + + /** + * View on the raw binary data as a `Uint16Array`. + * + * @member {Uint16Array} + */ + get uint16View() + { + if (!this._uint16View) + { + this._uint16View = new Uint16Array(this.rawBinaryData); + } + + return this._uint16View; + } + + /** + * View on the raw binary data as a `Int32Array`. + * + * @member {Int32Array} + */ + get int32View() + { + if (!this._int32View) + { + this._int32View = new Int32Array(this.rawBinaryData); + } + + return this._int32View; + } + + /** + * View on the raw binary data as a `Uint32Array`. + * + * @member {Float32Array} + */ + get uint32View() + { + if (!this._uint32View) + { + this._uint32View = new Uint32Array(this.rawBinaryData); + } + + return this._uint32View; + } + + /** + * View on the raw binary data as a `Float32Array`. + * + * @member {Float32Array} + */ + get float32View() + { + if (!this._float32View) + { + this._float32View = new Float32Array(this.rawBinaryData); + } + + return this._float32View; + } + + /** + * Returns the view of the given type. + * + * @param {string} type - One of `int8`, `uint8`, `int16`, + * `uint16`, `int32`, `uint32`, and `float32`. + * @return typed array of given type + */ + view(type) + { + return this[`${type}View`]; + } + + /** + * Destroys all buffer references. Do not use after calling + * this. + */ + destroy() + { + this.rawBinaryData = null; + this._int8View = null; + this._uint8View = null; + this._int16View = null; + this._uint16View = null; + this._int32View = null; + this._uint32View = null; + this._float32View = null; + } + + static sizeOf(type) + { + switch (type) + { + case 'int8': + case 'uint8': + return 1; + case 'int16': + case 'uint16': + return 2; + case 'int32': + case 'uint32': + case 'float32': + return 4; + default: + throw new Error(`${type} isn't a valid view type`); + } + } +} diff --git a/packages/core/src/index.js b/packages/core/src/index.js index d4cb1fa..08ba1c1 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -38,3 +38,4 @@ export { default as Attribute } from './geometry/Attribute'; export { default as Buffer } from './geometry/Buffer'; export { default as Geometry } from './geometry/Geometry'; +export { default as ViewableBuffer } from './geometry/ViewableBuffer'; diff --git a/packages/core/src/batch/BatchBuffer.js b/packages/core/src/batch/BatchBuffer.js deleted file mode 100644 index b80bc7e..0000000 --- a/packages/core/src/batch/BatchBuffer.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Used by the BatchRenderer - * - * @class - * @memberof PIXI - */ -export default class BatchBuffer -{ - /** - * @param {number} size - The size of the buffer in bytes. - */ - constructor(size) - { - this.vertices = new ArrayBuffer(size); - - /** - * View on the vertices as a Float32Array for positions - * - * @member {Float32Array} - */ - this.float32View = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array for uvs - * - * @member {Float32Array} - */ - this.uint32View = new Uint32Array(this.vertices); - } - - /** - * Destroys the buffer. - * - */ - destroy() - { - this.vertices = null; - this.float32View = null; - this.uint32View = null; - } -} diff --git a/packages/core/src/batch/BatchRenderer.js b/packages/core/src/batch/BatchRenderer.js index e15f6c5..4a454b1 100644 --- a/packages/core/src/batch/BatchRenderer.js +++ b/packages/core/src/batch/BatchRenderer.js @@ -1,11 +1,13 @@ import BatchDrawCall from './BatchDrawCall'; import BaseTexture from '../textures/BaseTexture'; -import State from '../state/State'; import ObjectRenderer from './ObjectRenderer'; +import State from '../state/State'; +import ViewableBuffer from '../geometry/ViewableBuffer'; + import checkMaxIfStatementsInShader from '../shader/utils/checkMaxIfStatementsInShader'; + import { settings } from '@pixi/settings'; import { premultiplyBlendMode, premultiplyTint, nextPow2, log2 } from '@pixi/utils'; -import BatchBuffer from './BatchBuffer'; import { ENV } from '@pixi/constants'; /** @@ -195,7 +197,7 @@ } /** - * Pool of `BatchBuffer` objects that are sorted in + * Pool of `ViewableBuffer` objects that are sorted in * order of increasing size. The flush method uses * the buffer with the least size above the amount * it requires. These are used for passing attributes. @@ -203,7 +205,7 @@ * The first buffer has a size of 8; each subsequent * buffer has double capacity of its previous. * - * @member {PIXI.BatchBuffer} + * @member {PIXI.ViewableBuffer} * @private * @see PIXI.BatchRenderer#getAttributeBuffer */ @@ -312,8 +314,7 @@ } /** - * Renders the content and empties the current batch. - * + * Renders the content _now_ and empties the current batch. */ flush() { @@ -322,52 +323,48 @@ return; } - const gl = this.renderer.gl; - const MAX_TEXTURES = this.MAX_TEXTURES; - const vertSize = this.vertexSize; - - const buffer = this.getAttributeBuffer(this._vertexCount); + const attributeBuffer = this.getAttributeBuffer(this._vertexCount); const indexBuffer = this.getIndexBuffer(this._indexCount); + const gl = this.renderer.gl; - const elements = this._bufferedElements; - const _drawCalls = this._drawCalls; - - const float32View = buffer.float32View; - const uint32View = buffer.uint32View; + const { + _bufferedElements: elements, + _drawCalls: drawCalls, + MAX_TEXTURES, + _packedGeometries: packedGeometries, + vertexSize, + } = this; const touch = this.renderer.textureGC.count; let index = 0; let _indexCount = 0; + let nextTexture; let currentTexture; + let textureCount = 0; + + let currentGroup = drawCalls[0]; let groupCount = 0; - let textureCount = 0; - let currentGroup = _drawCalls[0]; - - let blendMode = -1;// premultiplyBlendMode[elements[0]._texture.baseTexture.premultiplyAlpha ? 0 : ][elements[0].blendMode]; + let blendMode = -1;// blend-mode of previous element/sprite/object! currentGroup.textureCount = 0; currentGroup.start = 0; currentGroup.blend = blendMode; let TICK = ++BaseTexture._globalBatch; - let i; for (i = 0; i < this._bufferSize; ++i) { - // upload the sprite elements... - // they have all ready been calculated so we just need to push them into the buffer. - const sprite = elements[i]; elements[i] = null; - nextTexture = sprite._texture.baseTexture; - const spriteBlendMode = premultiplyBlendMode[nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; + const spriteBlendMode = premultiplyBlendMode[ + nextTexture.premultiplyAlpha ? 1 : 0][sprite.blendMode]; if (blendMode !== spriteBlendMode) { @@ -393,7 +390,7 @@ currentGroup.size = _indexCount - currentGroup.start; - currentGroup = _drawCalls[groupCount++]; + currentGroup = drawCalls[groupCount++]; currentGroup.textureCount = 0; currentGroup.blend = blendMode; currentGroup.start = _indexCount; @@ -408,63 +405,49 @@ } } - this.packInterleavedGeometry(sprite, float32View, uint32View, indexBuffer, index, _indexCount);// argb, nextTexture._id, float32View, uint32View, indexBuffer, index, _indexCount); + this.packInterleavedGeometry(sprite, attributeBuffer, + indexBuffer, index, _indexCount); // push a graphics.. - index += (sprite.vertexData.length / 2) * vertSize; + index += (sprite.vertexData.length / 2) * vertexSize; _indexCount += sprite.indices.length; } BaseTexture._globalBatch = TICK; - currentGroup.size = _indexCount - currentGroup.start; if (!settings.CAN_UPLOAD_SAME_BUFFER) - { - // this is still needed for IOS performance.. - // it really does not like uploading to the same buffer in a single frame! + { /* Usually on iOS devices, where the browser doesn't + like uploads to the same buffer in a single frame. */ if (this._packedGeometryPoolSize <= this._flushId) { this._packedGeometryPoolSize++; - /* eslint-disable max-len */ - this._packedGeometries[this._flushId] = new (this.geometryClass)(); + packedGeometries[this._flushId] = new (this.geometryClass)(); } - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - // this.vertexBuffers[this._flushId].update(buffer.vertices, 0); - this.renderer.geometry.bind(this._packedGeometries[this._flushId]); - + this.renderer.geometry.bind(packedGeometries[this._flushId]); this.renderer.geometry.updateBuffers(); - this._flushId++; } else { // lets use the faster option, always use buffer number 0 - this._packedGeometries[this._flushId]._buffer.update(buffer.vertices, 0); - this._packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); - - // if (true)// this.spriteOnly) - // { - // this._packedGeometries[this._flushId].indexBuffer = this.defualtSpriteIndexBuffer; - // this._packedGeometries[this._flushId].buffers[1] = this.defualtSpriteIndexBuffer; - // } + packedGeometries[this._flushId]._buffer.update(attributeBuffer.vertices, 0); + packedGeometries[this._flushId]._indexBuffer.update(indexBuffer, 0); this.renderer.geometry.updateBuffers(); } - // this.renderer.state.set(this.state); - const textureSystem = this.renderer.texture; const stateSystem = this.renderer.state; - // e.log(groupCount); - // / render the _drawCalls.. + // Upload textures and do the draw calls for (i = 0; i < groupCount; i++) { - const group = _drawCalls[i]; + const group = drawCalls[i]; const groupTextureCount = group.textureCount; for (let j = 0; j < groupTextureCount; j++) @@ -473,13 +456,7 @@ group.textures[j] = null; } - // this.state.blendMode = group.blend; - // this.state.blend = true; - - // this.renderer.state.setState(this.state); - // set the blend mode.. stateSystem.setBlendMode(group.blend); - gl.drawElements(group.type, group.size, gl.UNSIGNED_SHORT, group.start * 2); } @@ -507,7 +484,6 @@ /** * Stops and flushes the current batch. - * */ stop() { @@ -548,7 +524,7 @@ * can hold atleast `size` floats. * * @param {number} size - minimum capacity required - * @return {BatchBuffer} - buffer than can hold atleast `size` floats + * @return {ViewableBuffer} - buffer than can hold atleast `size` floats * @private */ getAttributeBuffer(size) @@ -567,7 +543,7 @@ if (!buffer) { - this._aBuffers[roundedSize] = buffer = new BatchBuffer(roundedSize * this.vertexSize * 4); + this._aBuffers[roundedSize] = buffer = new ViewableBuffer(roundedSize * this.vertexSize * 4); } return buffer; @@ -613,16 +589,19 @@ * present. * * @param {PIXI.Sprite} element - element being rendered - * @param {Float32Array} float32View - float32-view of the attribute buffer - * @param {Uint32Array} uint32View - uint32-view of the attribute buffer + * @param {PIXI.ViewableBuffer} attributeBuffer - attribute buffer. * @param {Uint16Array} indexBuffer - index buffer * @param {number} aIndex - number of floats already in the attribute buffer * @param {number} iIndex - number of indices already in `indexBuffer` */ - packInterleavedGeometry(element, - float32View, uint32View, indexBuffer, aIndex, iIndex) + packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) { - const p = aIndex / this.vertexSize; + const { + uint32View, + float32View, + } = attributeBuffer; + + const packedVertices = aIndex / this.vertexSize; const uvs = element.uvs; const indicies = element.indices; const vertexData = element.vertexData; @@ -647,7 +626,7 @@ for (let i = 0; i < indicies.length; i++) { - indexBuffer[iIndex++] = p + indicies[i]; + indexBuffer[iIndex++] = packedVertices + indicies[i]; } } } diff --git a/packages/core/src/batch/ObjectRenderer.js b/packages/core/src/batch/ObjectRenderer.js index 0c851a9..1776347 100644 --- a/packages/core/src/batch/ObjectRenderer.js +++ b/packages/core/src/batch/ObjectRenderer.js @@ -1,35 +1,29 @@ -import System from '../System'; - /** - * Base for a common object renderer that can be used as a system renderer plugin. + * Base for a common object renderer that can be used as a + * system renderer plugin. * * @class * @extends PIXI.System * @memberof PIXI */ -export default class ObjectRenderer extends System +export default class ObjectRenderer { /** - * Starts the renderer and sets the shader - * + * @param {PIXI.Renderer} renderer - The renderer this manager works for. */ - start() + constructor(renderer) { - // set the shader.. + /** + * The renderer this manager works for. + * + * @member {PIXI.Renderer} + */ + this.renderer = renderer; } /** - * Stops the renderer - * - */ - stop() - { - this.flush(); - } - - /** - * Stub method for rendering content and emptying the current batch. - * + * Stub method that should be used to empty the current + * batch by rendering objects now. */ flush() { @@ -37,7 +31,37 @@ } /** - * Renders an object + * Generic destruction method that frees all resources. This + * should be called by subclasses. + */ + destroy() + { + this.renderer = null; + } + + /** + * Stub method that initializes any state required before + * rendering starts. It is different from the `prerender` + * signal, which occurs every frame, in that it is called + * whenever an object requests _this_ renderer specifically. + */ + start() + { + // set the shader.. + } + + /** + * Stops the renderer. It should free up any state and + * become dormant. + */ + stop() + { + this.flush(); + } + + /** + * Keeps the object to render. It doesn't have to be + * rendered immediately. * * @param {PIXI.DisplayObject} object - The object to render. */ diff --git a/packages/core/src/geometry/ViewableBuffer.js b/packages/core/src/geometry/ViewableBuffer.js new file mode 100644 index 0000000..719c4e9 --- /dev/null +++ b/packages/core/src/geometry/ViewableBuffer.js @@ -0,0 +1,175 @@ +/** + * Flexible wrapper around `ArrayBuffer` that also provides + * typed array views on demand. + * + * @class + * @memberof PIXI + */ +export default class ViewableBuffer +{ + /** + * @param {number} size - The size of the buffer in bytes. + */ + constructor(size) + { + /** + * Underlying `ArrayBuffer` that holds all the data + * and is of capacity `size`. + * + * @member {ArrayBuffer} + */ + this.rawBinaryData = new ArrayBuffer(size); + } + + /** + * View on the raw binary data as a `Int8Array`. + * + * @member {Int8Array} + */ + get int8View() + { + if (!this._int8View) + { + this._int8View = new Int8Array(this.rawBinaryData); + } + + return this._int8View; + } + + /** + * View on the raw binary data as a `Uint8Array`. + * + * @member {Uint8Array} + */ + get uint8View() + { + if (!this._uint8View) + { + this._uint8View = new Uint8Array(this.rawBinaryData); + } + + return this._uint8View; + } + + /** + * View on the raw binary data as a `Int16Array`. + * + * @member {Int16Array} + */ + get int16View() + { + if (!this._int16View) + { + this._int16View = new Int16Array(this.rawBinaryData); + } + + return this._int16View; + } + + /** + * View on the raw binary data as a `Uint16Array`. + * + * @member {Uint16Array} + */ + get uint16View() + { + if (!this._uint16View) + { + this._uint16View = new Uint16Array(this.rawBinaryData); + } + + return this._uint16View; + } + + /** + * View on the raw binary data as a `Int32Array`. + * + * @member {Int32Array} + */ + get int32View() + { + if (!this._int32View) + { + this._int32View = new Int32Array(this.rawBinaryData); + } + + return this._int32View; + } + + /** + * View on the raw binary data as a `Uint32Array`. + * + * @member {Float32Array} + */ + get uint32View() + { + if (!this._uint32View) + { + this._uint32View = new Uint32Array(this.rawBinaryData); + } + + return this._uint32View; + } + + /** + * View on the raw binary data as a `Float32Array`. + * + * @member {Float32Array} + */ + get float32View() + { + if (!this._float32View) + { + this._float32View = new Float32Array(this.rawBinaryData); + } + + return this._float32View; + } + + /** + * Returns the view of the given type. + * + * @param {string} type - One of `int8`, `uint8`, `int16`, + * `uint16`, `int32`, `uint32`, and `float32`. + * @return typed array of given type + */ + view(type) + { + return this[`${type}View`]; + } + + /** + * Destroys all buffer references. Do not use after calling + * this. + */ + destroy() + { + this.rawBinaryData = null; + this._int8View = null; + this._uint8View = null; + this._int16View = null; + this._uint16View = null; + this._int32View = null; + this._uint32View = null; + this._float32View = null; + } + + static sizeOf(type) + { + switch (type) + { + case 'int8': + case 'uint8': + return 1; + case 'int16': + case 'uint16': + return 2; + case 'int32': + case 'uint32': + case 'float32': + return 4; + default: + throw new Error(`${type} isn't a valid view type`); + } + } +} diff --git a/packages/core/src/index.js b/packages/core/src/index.js index d4cb1fa..08ba1c1 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -38,3 +38,4 @@ export { default as Attribute } from './geometry/Attribute'; export { default as Buffer } from './geometry/Buffer'; export { default as Geometry } from './geometry/Geometry'; +export { default as ViewableBuffer } from './geometry/ViewableBuffer'; diff --git a/packages/graphics/src/Graphics.js b/packages/graphics/src/Graphics.js index 10df4dd..596a872 100644 --- a/packages/graphics/src/Graphics.js +++ b/packages/graphics/src/Graphics.js @@ -158,6 +158,14 @@ this._transformID = -1; this.batchDirty = -1; + /** + * Renderer plugin for batching + * + * @member {string} + * @default 'batch' + */ + this.pluginName = 'batch'; + // Set default this.tint = 0xFFFFFF; this.blendMode = BLEND_MODES.NORMAL; @@ -864,7 +872,7 @@ } } - renderer.batch.setObjectRenderer(renderer.plugins.batch); + renderer.batch.setObjectRenderer(renderer.plugins[this.pluginName]); if (this.batches.length) { @@ -877,7 +885,7 @@ batch.worldAlpha = this.worldAlpha * batch.alpha; - renderer.plugins.batch.render(batch); + renderer.plugins[this.pluginName].render(batch); } } }