diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js index 0d223a8..df904bb 100644 --- a/src/core/textures/BaseTexture.js +++ b/src/core/textures/BaseTexture.js @@ -736,7 +736,9 @@ /** * Helper function that creates a base texture based on the source you provide. - * The source can be - image url, image element, canvas element. + * The source can be - image url, image element, canvas element. If the + * source is an image url or an image element and not in the base texture + * cache, it will be created and loaded. * * @static * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js index 0d223a8..df904bb 100644 --- a/src/core/textures/BaseTexture.js +++ b/src/core/textures/BaseTexture.js @@ -736,7 +736,9 @@ /** * Helper function that creates a base texture based on the source you provide. - * The source can be - image url, image element, canvas element. + * The source can be - image url, image element, canvas element. If the + * source is an image url or an image element and not in the base texture + * cache, it will be created and loaded. * * @static * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js index 86f0873..2e7719b 100644 --- a/src/core/textures/VideoBaseTexture.js +++ b/src/core/textures/VideoBaseTexture.js @@ -196,6 +196,10 @@ { BaseTexture.removeFromCache(this.source._pixiId); delete this.source._pixiId; + + this.source.pause(); + this.source.src = ''; + this.source.load(); } super.destroy(); diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js index 0d223a8..df904bb 100644 --- a/src/core/textures/BaseTexture.js +++ b/src/core/textures/BaseTexture.js @@ -736,7 +736,9 @@ /** * Helper function that creates a base texture based on the source you provide. - * The source can be - image url, image element, canvas element. + * The source can be - image url, image element, canvas element. If the + * source is an image url or an image element and not in the base texture + * cache, it will be created and loaded. * * @static * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js index 86f0873..2e7719b 100644 --- a/src/core/textures/VideoBaseTexture.js +++ b/src/core/textures/VideoBaseTexture.js @@ -196,6 +196,10 @@ { BaseTexture.removeFromCache(this.source._pixiId); delete this.source._pixiId; + + this.source.pause(); + this.source.src = ''; + this.source.load(); } super.destroy(); diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js index c2824ed..4446003 100644 --- a/src/filters/alpha/AlphaFilter.js +++ b/src/filters/alpha/AlphaFilter.js @@ -22,9 +22,9 @@ export default class AlphaFilter extends core.Filter { /** - * + * @param {number} [alpha=1] Amount of alpha from 0 to 1, where 0 is transparent */ - constructor() + constructor(alpha = 1.0) { super( // vertex shader @@ -33,7 +33,7 @@ readFileSync(join(__dirname, './alpha.frag'), 'utf8') ); - this.alpha = 1.0; + this.alpha = alpha; this.glShaderKey = 'alpha'; } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js index 0d223a8..df904bb 100644 --- a/src/core/textures/BaseTexture.js +++ b/src/core/textures/BaseTexture.js @@ -736,7 +736,9 @@ /** * Helper function that creates a base texture based on the source you provide. - * The source can be - image url, image element, canvas element. + * The source can be - image url, image element, canvas element. If the + * source is an image url or an image element and not in the base texture + * cache, it will be created and loaded. * * @static * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js index 86f0873..2e7719b 100644 --- a/src/core/textures/VideoBaseTexture.js +++ b/src/core/textures/VideoBaseTexture.js @@ -196,6 +196,10 @@ { BaseTexture.removeFromCache(this.source._pixiId); delete this.source._pixiId; + + this.source.pause(); + this.source.src = ''; + this.source.load(); } super.destroy(); diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js index c2824ed..4446003 100644 --- a/src/filters/alpha/AlphaFilter.js +++ b/src/filters/alpha/AlphaFilter.js @@ -22,9 +22,9 @@ export default class AlphaFilter extends core.Filter { /** - * + * @param {number} [alpha=1] Amount of alpha from 0 to 1, where 0 is transparent */ - constructor() + constructor(alpha = 1.0) { super( // vertex shader @@ -33,7 +33,7 @@ readFileSync(join(__dirname, './alpha.frag'), 'utf8') ); - this.alpha = 1.0; + this.alpha = alpha; this.glShaderKey = 'alpha'; } diff --git a/src/filters/colormatrix/ColorMatrixFilter.js b/src/filters/colormatrix/ColorMatrixFilter.js index e1d647a..8ab60d9 100644 --- a/src/filters/colormatrix/ColorMatrixFilter.js +++ b/src/filters/colormatrix/ColorMatrixFilter.js @@ -8,7 +8,7 @@ * with a new set of RGBA color and alpha values. It's pretty powerful! * * ```js - * let colorMatrix = new PIXI.ColorMatrixFilter(); + * let colorMatrix = new PIXI.filters.ColorMatrixFilter(); * container.filters = [colorMatrix]; * colorMatrix.contrast(2); * ``` diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js index 0d223a8..df904bb 100644 --- a/src/core/textures/BaseTexture.js +++ b/src/core/textures/BaseTexture.js @@ -736,7 +736,9 @@ /** * Helper function that creates a base texture based on the source you provide. - * The source can be - image url, image element, canvas element. + * The source can be - image url, image element, canvas element. If the + * source is an image url or an image element and not in the base texture + * cache, it will be created and loaded. * * @static * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js index 86f0873..2e7719b 100644 --- a/src/core/textures/VideoBaseTexture.js +++ b/src/core/textures/VideoBaseTexture.js @@ -196,6 +196,10 @@ { BaseTexture.removeFromCache(this.source._pixiId); delete this.source._pixiId; + + this.source.pause(); + this.source.src = ''; + this.source.load(); } super.destroy(); diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js index c2824ed..4446003 100644 --- a/src/filters/alpha/AlphaFilter.js +++ b/src/filters/alpha/AlphaFilter.js @@ -22,9 +22,9 @@ export default class AlphaFilter extends core.Filter { /** - * + * @param {number} [alpha=1] Amount of alpha from 0 to 1, where 0 is transparent */ - constructor() + constructor(alpha = 1.0) { super( // vertex shader @@ -33,7 +33,7 @@ readFileSync(join(__dirname, './alpha.frag'), 'utf8') ); - this.alpha = 1.0; + this.alpha = alpha; this.glShaderKey = 'alpha'; } diff --git a/src/filters/colormatrix/ColorMatrixFilter.js b/src/filters/colormatrix/ColorMatrixFilter.js index e1d647a..8ab60d9 100644 --- a/src/filters/colormatrix/ColorMatrixFilter.js +++ b/src/filters/colormatrix/ColorMatrixFilter.js @@ -8,7 +8,7 @@ * with a new set of RGBA color and alpha values. It's pretty powerful! * * ```js - * let colorMatrix = new PIXI.ColorMatrixFilter(); + * let colorMatrix = new PIXI.filters.ColorMatrixFilter(); * container.filters = [colorMatrix]; * colorMatrix.contrast(2); * ``` diff --git a/src/particles/webgl/ParticleBuffer.js b/src/particles/webgl/ParticleBuffer.js index 0d41f66..e118769 100644 --- a/src/particles/webgl/ParticleBuffer.js +++ b/src/particles/webgl/ParticleBuffer.js @@ -259,12 +259,16 @@ destroy() { this.dynamicProperties = null; - this.dynamicData = null; this.dynamicBuffer.destroy(); + this.dynamicBuffer = null; + this.dynamicData = null; + this.dynamicDataUint32 = null; this.staticProperties = null; - this.staticData = null; this.staticBuffer.destroy(); + this.staticBuffer = null; + this.staticData = null; + this.staticDataUint32 = null; } } diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js index 0d223a8..df904bb 100644 --- a/src/core/textures/BaseTexture.js +++ b/src/core/textures/BaseTexture.js @@ -736,7 +736,9 @@ /** * Helper function that creates a base texture based on the source you provide. - * The source can be - image url, image element, canvas element. + * The source can be - image url, image element, canvas element. If the + * source is an image url or an image element and not in the base texture + * cache, it will be created and loaded. * * @static * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js index 86f0873..2e7719b 100644 --- a/src/core/textures/VideoBaseTexture.js +++ b/src/core/textures/VideoBaseTexture.js @@ -196,6 +196,10 @@ { BaseTexture.removeFromCache(this.source._pixiId); delete this.source._pixiId; + + this.source.pause(); + this.source.src = ''; + this.source.load(); } super.destroy(); diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js index c2824ed..4446003 100644 --- a/src/filters/alpha/AlphaFilter.js +++ b/src/filters/alpha/AlphaFilter.js @@ -22,9 +22,9 @@ export default class AlphaFilter extends core.Filter { /** - * + * @param {number} [alpha=1] Amount of alpha from 0 to 1, where 0 is transparent */ - constructor() + constructor(alpha = 1.0) { super( // vertex shader @@ -33,7 +33,7 @@ readFileSync(join(__dirname, './alpha.frag'), 'utf8') ); - this.alpha = 1.0; + this.alpha = alpha; this.glShaderKey = 'alpha'; } diff --git a/src/filters/colormatrix/ColorMatrixFilter.js b/src/filters/colormatrix/ColorMatrixFilter.js index e1d647a..8ab60d9 100644 --- a/src/filters/colormatrix/ColorMatrixFilter.js +++ b/src/filters/colormatrix/ColorMatrixFilter.js @@ -8,7 +8,7 @@ * with a new set of RGBA color and alpha values. It's pretty powerful! * * ```js - * let colorMatrix = new PIXI.ColorMatrixFilter(); + * let colorMatrix = new PIXI.filters.ColorMatrixFilter(); * container.filters = [colorMatrix]; * colorMatrix.contrast(2); * ``` diff --git a/src/particles/webgl/ParticleBuffer.js b/src/particles/webgl/ParticleBuffer.js index 0d41f66..e118769 100644 --- a/src/particles/webgl/ParticleBuffer.js +++ b/src/particles/webgl/ParticleBuffer.js @@ -259,12 +259,16 @@ destroy() { this.dynamicProperties = null; - this.dynamicData = null; this.dynamicBuffer.destroy(); + this.dynamicBuffer = null; + this.dynamicData = null; + this.dynamicDataUint32 = null; this.staticProperties = null; - this.staticData = null; this.staticBuffer.destroy(); + this.staticBuffer = null; + this.staticData = null; + this.staticDataUint32 = null; } } diff --git a/src/particles/webgl/ParticleShader.js b/src/particles/webgl/ParticleShader.js index b3584fe..d536190 100644 --- a/src/particles/webgl/ParticleShader.js +++ b/src/particles/webgl/ParticleShader.js @@ -31,10 +31,10 @@ 'varying vec4 vColor;', 'void main(void){', - ' vec2 v = aVertexPosition;', + ' float x = (aVertexPosition.x) * cos(aRotation) - (aVertexPosition.y) * sin(aRotation);', + ' float y = (aVertexPosition.x) * sin(aRotation) + (aVertexPosition.y) * cos(aRotation);', - ' v.x = (aVertexPosition.x) * cos(aRotation) - (aVertexPosition.y) * sin(aRotation);', - ' v.y = (aVertexPosition.x) * sin(aRotation) + (aVertexPosition.y) * cos(aRotation);', + ' vec2 v = vec2(x, y);', ' v = v + aPositionCoord;', ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', @@ -52,7 +52,6 @@ 'void main(void){', ' vec4 color = texture2D(uSampler, vTextureCoord) * vColor;', - ' if (color.a == 0.0) discard;', ' gl_FragColor = color;', '}', ].join('\n') diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index 53f2ae1..4702b5b 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -227,15 +227,15 @@ shader = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); filter.glShaders[renderer.CONTEXT_UID] = this.shaderCache[filter.glShaderKey] = shader; + this.managedFilters.push(filter); } } else { shader = filter.glShaders[renderer.CONTEXT_UID] = new Shader(this.gl, filter.vertexSrc, filter.fragmentSrc); + this.managedFilters.push(filter); } - this.managedFilters.push(filter); - // TODO - this only needs to be done once? renderer.bindVao(null); diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index 8fd44c1..9f2dda1 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -241,9 +241,19 @@ // copy textures.. for (i = 0; i < MAX_TEXTURES; ++i) { - boundTextures[i] = rendererBoundTextures[i]; - boundTextures[i]._virtalBoundId = i; + const bt = rendererBoundTextures[i]; + + if (bt._enabled === TICK) + { + boundTextures[i] = this.renderer.emptyTextures[i]; + continue; + } + + boundTextures[i] = bt; + bt._virtalBoundId = i; + bt._enabled = TICK; } + TICK++; for (i = 0; i < this.currentIndex; ++i) { diff --git a/src/core/text/TextMetrics.js b/src/core/text/TextMetrics.js index c4f32e1..904f4e6 100644 --- a/src/core/text/TextMetrics.js +++ b/src/core/text/TextMetrics.js @@ -106,6 +106,7 @@ // Greedy wrapping algorithm that will wrap words as the line grows longer // than its horizontal bounds. let result = ''; + const firstChar = text.charAt(0); const lines = text.split('\n'); const wordWrapWidth = style.wordWrapWidth; const characterCache = {}; @@ -142,7 +143,7 @@ } else { - if (c === 0) + if (c === 0 && (j > 0 || firstChar === ' ')) { result += ' '; } diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index c682a36..c7ab5c2 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -75,7 +75,8 @@ * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve - * spiked text issues. Default is 'miter' (creates a sharp corner). + * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel" + * (creates a squared corner). * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce * or increase the spikiness of rendered text. * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from @@ -93,7 +94,9 @@ { this.styleID = 0; - Object.assign(this, defaultStyle, style); + this.reset(); + + deepCopyProperties(this, style, style); } /** @@ -106,10 +109,7 @@ { const clonedProperties = {}; - for (const key in defaultStyle) - { - clonedProperties[key] = this[key]; - } + deepCopyProperties(clonedProperties, this, defaultStyle); return new TextStyle(clonedProperties); } @@ -119,7 +119,7 @@ */ reset() { - Object.assign(this, defaultStyle); + deepCopyProperties(this, defaultStyle, defaultStyle); } /** @@ -755,3 +755,20 @@ return true; } + +/** + * Utility function to ensure that object properties are copied by value, and not by reference + * + * @param {Object} target Target object to copy properties into + * @param {Object} source Source object for the proporties to copy + * @param {string} propertyObj Object containing properties names we want to loop over + */ +function deepCopyProperties(target, source, propertyObj) { + for (const prop in propertyObj) { + if (Array.isArray(source[prop])) { + target[prop] = source[prop].slice(); + } else { + target[prop] = source[prop]; + } + } +} diff --git a/src/core/textures/BaseTexture.js b/src/core/textures/BaseTexture.js index 0d223a8..df904bb 100644 --- a/src/core/textures/BaseTexture.js +++ b/src/core/textures/BaseTexture.js @@ -736,7 +736,9 @@ /** * Helper function that creates a base texture based on the source you provide. - * The source can be - image url, image element, canvas element. + * The source can be - image url, image element, canvas element. If the + * source is an image url or an image element and not in the base texture + * cache, it will be created and loaded. * * @static * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js index 86f0873..2e7719b 100644 --- a/src/core/textures/VideoBaseTexture.js +++ b/src/core/textures/VideoBaseTexture.js @@ -196,6 +196,10 @@ { BaseTexture.removeFromCache(this.source._pixiId); delete this.source._pixiId; + + this.source.pause(); + this.source.src = ''; + this.source.load(); } super.destroy(); diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js index c2824ed..4446003 100644 --- a/src/filters/alpha/AlphaFilter.js +++ b/src/filters/alpha/AlphaFilter.js @@ -22,9 +22,9 @@ export default class AlphaFilter extends core.Filter { /** - * + * @param {number} [alpha=1] Amount of alpha from 0 to 1, where 0 is transparent */ - constructor() + constructor(alpha = 1.0) { super( // vertex shader @@ -33,7 +33,7 @@ readFileSync(join(__dirname, './alpha.frag'), 'utf8') ); - this.alpha = 1.0; + this.alpha = alpha; this.glShaderKey = 'alpha'; } diff --git a/src/filters/colormatrix/ColorMatrixFilter.js b/src/filters/colormatrix/ColorMatrixFilter.js index e1d647a..8ab60d9 100644 --- a/src/filters/colormatrix/ColorMatrixFilter.js +++ b/src/filters/colormatrix/ColorMatrixFilter.js @@ -8,7 +8,7 @@ * with a new set of RGBA color and alpha values. It's pretty powerful! * * ```js - * let colorMatrix = new PIXI.ColorMatrixFilter(); + * let colorMatrix = new PIXI.filters.ColorMatrixFilter(); * container.filters = [colorMatrix]; * colorMatrix.contrast(2); * ``` diff --git a/src/particles/webgl/ParticleBuffer.js b/src/particles/webgl/ParticleBuffer.js index 0d41f66..e118769 100644 --- a/src/particles/webgl/ParticleBuffer.js +++ b/src/particles/webgl/ParticleBuffer.js @@ -259,12 +259,16 @@ destroy() { this.dynamicProperties = null; - this.dynamicData = null; this.dynamicBuffer.destroy(); + this.dynamicBuffer = null; + this.dynamicData = null; + this.dynamicDataUint32 = null; this.staticProperties = null; - this.staticData = null; this.staticBuffer.destroy(); + this.staticBuffer = null; + this.staticData = null; + this.staticDataUint32 = null; } } diff --git a/src/particles/webgl/ParticleShader.js b/src/particles/webgl/ParticleShader.js index b3584fe..d536190 100644 --- a/src/particles/webgl/ParticleShader.js +++ b/src/particles/webgl/ParticleShader.js @@ -31,10 +31,10 @@ 'varying vec4 vColor;', 'void main(void){', - ' vec2 v = aVertexPosition;', + ' float x = (aVertexPosition.x) * cos(aRotation) - (aVertexPosition.y) * sin(aRotation);', + ' float y = (aVertexPosition.x) * sin(aRotation) + (aVertexPosition.y) * cos(aRotation);', - ' v.x = (aVertexPosition.x) * cos(aRotation) - (aVertexPosition.y) * sin(aRotation);', - ' v.y = (aVertexPosition.x) * sin(aRotation) + (aVertexPosition.y) * cos(aRotation);', + ' vec2 v = vec2(x, y);', ' v = v + aPositionCoord;', ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', @@ -52,7 +52,6 @@ 'void main(void){', ' vec4 color = texture2D(uSampler, vTextureCoord) * vColor;', - ' if (color.a == 0.0) discard;', ' gl_FragColor = color;', '}', ].join('\n') diff --git a/test/core/TextStyle.js b/test/core/TextStyle.js index 49b99ef..1976333 100644 --- a/test/core/TextStyle.js +++ b/test/core/TextStyle.js @@ -50,4 +50,14 @@ expect(style.toFontString()).to.have.string('"Georgia","Arial","sans-serif"'); }); + + it('should not shared array / object references between different instances', function () + { + const defaultStyle = new PIXI.TextStyle(); + const style = new PIXI.TextStyle(); + + expect(defaultStyle.fillGradientStops.length).to.equal(style.fillGradientStops.length); + style.fillGradientStops.push(0); + expect(defaultStyle.fillGradientStops.length).to.not.equal(style.fillGradientStops.length); + }); });