From b0ce81bec0fb4b0433ce09eb4e029a4566487a33 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 19 Sep 2016 23:31:20 +0100 Subject: [PATCH] Multiple Batched Texture support is now available. This is a WebGL feature that can seriously decrease the volume of draw calls made in complex, or asset heavy, games. To enable it you can either use the new renderer type `Phaser.WEBGL_MULTI`, or you can pass the property `multiTexture: true` in a Phaser.Game configuration object. Once enabled, it cannot be disabled. `game.renderer.setTexturePriority` is the method that goes with the Multiple Texture support. It takes an array as its single argument. The array consists of Phaser.Cache image key strings. Phaser will then try to batch as many of the textures as it can, depending on the hardware limits. If for example the GPU can only batch 8 textures, and you provide an array of 16, then only the first 8 in the array will be batched. --- README.md | 4 +- src/Phaser.js | 7 ++ src/core/Game.js | 86 +++++++++++++++++++++-- src/pixi/renderers/webgl/WebGLRenderer.js | 19 ++++- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e2cf6ce05..dee9ad037 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,8 @@ You can read all about the philosophy behind Lazer [here](http://phaser.io/news/ ### New Features +* Multiple Batched Texture support is now available. This is a WebGL feature that can seriously decrease the volume of draw calls made in complex, or asset heavy, games. To enable it you can either use the new renderer type `Phaser.WEBGL_MULTI`, or you can pass the property `multiTexture: true` in a Phaser.Game configuration object. Once enabled, it cannot be disabled. +* `game.renderer.setTexturePriority` is the method that goes with the Multiple Texture support. It takes an array as its single argument. The array consists of Phaser.Cache image key strings. Phaser will then try to batch as many of the textures as it can, depending on the hardware limits. If for example the GPU can only batch 8 textures, and you provide an array of 16, then only the first 8 in the array will be batched. * Weapon.multiFire is a new property that allows you to set a Weapon as being allowed to call `fire` as many times as you like, per game loop. This allows a single Weapon instance to fire multiple bullets. * Weapon.fire has two new arguments: `offsetX` and `offsetY`. If the bullet is fired from a tracked Sprite or Pointer, or the `from` argument is set, this applies a horizontal and vertical offset from the launch position. * Weapon.fireOffset attempts to fire a single Bullet from a tracked Sprite or Pointer, but applies an offset to the position first. This is a shorter form of calling `Weapon.fire` and passing in the offset arguments. @@ -320,7 +322,7 @@ You can read all about the philosophy behind Lazer [here](http://phaser.io/news/ * TypeScript definitions fixes and updates (thanks @chriteixeira @StealthC @Lopdo) * Docs typo fixes (thanks @JTronLabs @samme) * `Phaser.Line.fromSprite` now uses the Sprite.centerX and centerY properties if the `useCenter` argument is true. Before it required you to have overridden the Sprite and added the property yourself (thanks @samme #2729) -* +* Updated the pointer check code in the Device class, to get rid of the message `Navigator.pointerEnabled is a non-standard API added for experiments only. It will be removed in near future.` in Chrome. * ### Bug Fixes diff --git a/src/Phaser.js b/src/Phaser.js index fa66d02ac..11f898c05 100644 --- a/src/Phaser.js +++ b/src/Phaser.js @@ -51,6 +51,13 @@ var Phaser = Phaser || { // jshint ignore:line */ HEADLESS: 3, + /** + * WebGL Renderer with MultiTexture support enabled. + * @constant + * @type {integer} + */ + WEBGL_MULTI: 4, + /** * Direction constant. * @constant diff --git a/src/core/Game.js b/src/core/Game.js index e02c2f141..860e9be45 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -5,17 +5,65 @@ */ /** -* This is where the magic happens. The Game object is the heart of your game, -* providing quick access to common functions and handling the boot process. +* The Phaser.Game object is the main controller for the entire Phaser game. It is responsible +* for handling the boot process, parsing the configuration values, creating the renderer, +* and setting-up all of the Phaser systems, such as physics, sound and input. +* Once that is complete it will start the default State, and then begin the main game loop. +* +* You can access lots of the Phaser systems via the properties on the `game` object. For +* example `game.renderer` is the Renderer, `game.sound` is the Sound Manager, and so on. +* +* Anywhere you can access the `game` property, you can access all of these core systems. +* For example a Sprite has a `game` property, allowing you to talk to the various parts +* of Phaser directly, without having to look after your own references. +* +* In it's most simplest form, a Phaser game can be created by providing the arguments +* to the constructor: +* +* ``` +* var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create }); +* ``` +* +* In the example above it is passing in a State object directly. You can also use the State +* Manager to do this: +* +* ``` +* var game = new Phaser.Game(800, 600, Phaser.AUTO); +* game.state.add('Boot', BasicGame.Boot); +* game.state.add('Preloader', BasicGame.Preloader); +* game.state.add('MainMenu', BasicGame.MainMenu); +* game.state.add('Game', BasicGame.Game); +* game.state.start('Boot'); * -* "Hell, there are no rules here - we're trying to accomplish something." -* Thomas A. Edison +* ``` +* In the example above, 4 States are added to the State Manager, and Phaser is told to +* start running the `Boot` state when it has finished initializing. There are example +* project templates you can use in the Phaser GitHub repo, inside the `resources` folder. +* +* Instead of specifying arguments you can also pass a single object instead: +* +* ``` +* var config = { +* width: 800, +* height: 600, +* renderer: Phaser.AUTO, +* antialias: true, +* multiTexture: true, +* state: { +* preload: preload, +* create: create, +* update: update +* } +* } +* +* var game = new Phaser.Game(config); +* ``` * * @class Phaser.Game * @constructor * @param {number|string} [width=800] - The width of your game in game pixels. If given as a string the value must be between 0 and 100 and will be used as the percentage width of the parent container, or the browser window if no parent is given. * @param {number|string} [height=600] - The height of your game in game pixels. If given as a string the value must be between 0 and 100 and will be used as the percentage height of the parent container, or the browser window if no parent is given. -* @param {number} [renderer=Phaser.AUTO] - Which renderer to use: Phaser.AUTO will auto-detect, Phaser.WEBGL, Phaser.CANVAS or Phaser.HEADLESS (no rendering at all). +* @param {number} [renderer=Phaser.AUTO] - Which renderer to use: Phaser.AUTO will auto-detect, Phaser.WEBGL, Phaser.WEBGL_MULTI, Phaser.CANVAS or Phaser.HEADLESS (no rendering at all). * @param {string|HTMLElement} [parent=''] - The DOM element into which this games canvas will be injected. Either a DOM ID (string) or the element itself. * @param {object} [state=null] - The default state object. A object consisting of Phaser.State functions (preload, create, update, render) or null. * @param {boolean} [transparent=false] - Use a transparent canvas background or not. @@ -25,7 +73,7 @@ Phaser.Game = function (width, height, renderer, parent, state, transparent, antialias, physicsConfig) { /** - * @property {number} id - Phaser Game ID (for when Pixi supports multiple instances). + * @property {number} id - Phaser Game ID * @readonly */ this.id = Phaser.GAMES.push(this) - 1; @@ -101,6 +149,19 @@ Phaser.Game = function (width, height, renderer, parent, state, transparent, ant */ this.antialias = true; + /** + * Has support for Multiple bound Textures in WebGL been enabled? This is a read-only property. + * To set it you need to either specify `Phaser.WEBGL_MULTI` as the renderer type, or use the Game + * Configuration object with the property `multiTexture` set to true. It has to be enabled before + * Pixi boots, and cannot be changed after the game is running. Once enabled, take advantage of it + * via the `game.renderer.setTexturePriority` method. + * + * @property {boolean} multiTexture + * @default + * @readOnly + */ + this.multiTexture = false; + /** * @property {boolean} preserveDrawingBuffer - The value of the preserveDrawingBuffer flag affects whether or not the contents of the stencil buffer is retained after rendering. * @default @@ -122,7 +183,7 @@ Phaser.Game = function (width, height, renderer, parent, state, transparent, ant this.renderer = null; /** - * @property {number} renderType - The Renderer this game will use. Either Phaser.AUTO, Phaser.CANVAS, Phaser.WEBGL, or Phaser.HEADLESS. + * @property {number} renderType - The Renderer this game will use. Either Phaser.AUTO, Phaser.CANVAS, Phaser.WEBGL, Phaser.WEBGL_MULTI or Phaser.HEADLESS. * @readonly */ this.renderType = Phaser.AUTO; @@ -482,6 +543,11 @@ Phaser.Game.prototype = { this.antialias = config['antialias']; } + if (config['multiTexture'] !== undefined) + { + this.multiTexture = config['multiTexture']; + } + if (config['resolution']) { this.resolution = config['resolution']; @@ -718,6 +784,12 @@ Phaser.Game.prototype = { else { // They requested WebGL and their browser supports it + + if (this.multiTexture || this.renderType === Phaser.WEBGL_MULTI) + { + PIXI.enableMultiTexture(); + } + this.renderType = Phaser.WEBGL; this.renderer = new PIXI.WebGLRenderer(this); diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index dec3efff7..798d9afd5 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -244,16 +244,33 @@ PIXI.WebGLRenderer.prototype.initContext = function() this.resize(this.width, this.height); }; +/** +* If Multi Texture support has been enabled, then calling this method will enable batching on the given +* textures. The texture collection is an array of keys, that map to Phaser.Cache image entries. +* +* The number of textures that can be batched is dependent on hardware. If you provide more textures +* than can be batched by the GPU, then only those at the start of the array will be used. Generally +* you shouldn't provide more than 16 textures to this method. You can check the hardware limit +* via the `maxTextures` property. +* +* Note: Throws a warning if you haven't enabled Multiple Texture batching support in the Phaser Game config. +* +* @method setTexturePriority +* @param textureNameCollection {Array} An Array of Texture Cache keys to use for multi-texture batching. +*/ PIXI.WebGLRenderer.prototype.setTexturePriority = function (textureNameCollection) { + if (!PIXI._enableMultiTextureToggle) { - console.warn('Phaser: Can\'t call setTexturePriority if multi texture batching isn\'t enabled'); + console.warn('setTexturePriority error: Multi Texture support hasn\'t been enabled in the Phaser Game Config.'); return; } + var maxTextures = this.maxTextures; var imageCache = this.game.cache._cache.image; var imageName = null; var gl = this.gl; + // We start from 1 because framebuffer texture uses unit 0. for (var index = 0; index < textureNameCollection.length; ++index) {