Updating the StateManager so it supports renderToTexture and advanced State configs.

This commit is contained in:
Richard Davey 2017-02-07 18:44:26 +00:00
parent 8a1dc20211
commit 2510bee27c
6 changed files with 193 additions and 153 deletions

View file

@ -79,7 +79,7 @@ var CreateRenderer = function (game)
else
{
game.renderer = new CanvasRenderer(game);
game.context = game.renderer.context;
game.context = game.renderer.gameContext;
}
};

View file

@ -67,7 +67,7 @@ BaseLoader.prototype = {
start: function ()
{
console.log('BaseLoader start. Files to load:', this.list.size);
console.log(this.state.settings.key, 'BaseLoader start. Files to load:', this.list.size);
if (!this.isReady())
{
@ -247,7 +247,7 @@ BaseLoader.prototype = {
processComplete: function ()
{
console.log('Loader Complete. Loaded:', this.storage.size, 'Failed:', this.failed.size);
console.log(this.state.settings.key, 'Loader Complete. Loaded:', this.storage.size, 'Failed:', this.failed.size);
this.list.clear();
this.inflight.clear();

View file

@ -2,45 +2,43 @@ var CONST = require('../../const');
var DrawImage = require('./utils/DrawImage');
var BlitImage = require('./utils/BlitImage');
var GetBlendModes = require('./utils/GetBlendModes');
var GetContext = require('../../canvas/GetContext');
var CanvasRenderer = function (game)
{
/**
* @property {Phaser.Game} game - A reference to the currently running Game.
*/
// Needed?
this.game = game;
// Needed?
this.type = CONST.CANVAS;
// Read all the following from game config (or State config?)
this.clearBeforeRender = true;
this.transparent = false;
this.autoResize = false;
this.drawCount = 0;
// Read all the following from game config (or State config?)
// this.clearBeforeRender = true;
// this.transparent = false;
// this.autoResize = false;
// this.smoothProperty = Phaser.Canvas.getSmoothingPrefix(this.context);
this.roundPixels = false;
// this.roundPixels = false;
this.width = game.config.width * game.config.resolution;
this.height = game.config.height * game.config.resolution;
this.resolution = game.config.resolution;
this.view = game.canvas;
this.gameCanvas = game.canvas;
/**
* The canvas 2d context that everything is drawn with
* @property context
* @type CanvasRenderingContext2D
*/
this.context = this.view.getContext('2d', { alpha: true });
this.gameContext = GetContext(this.gameCanvas);
this.gameConfig = game.config;
this.currentContext = this.gameContext;
// Map to the required function
this.drawImage = DrawImage;
@ -73,31 +71,85 @@ CanvasRenderer.prototype = {
this.width = width * res;
this.height = height * res;
this.view.width = this.width;
this.view.height = this.height;
this.gameCanvas.width = this.width;
this.gameCanvas.height = this.height;
if (this.autoResize)
{
this.view.style.width = (this.width / res) + 'px';
this.view.style.height = (this.height / res) + 'px';
this.gameCanvas.style.width = (this.width / res) + 'px';
this.gameCanvas.style.height = (this.height / res) + 'px';
}
// if (this.smoothProperty)
// {
// this.context[this.smoothProperty] = (this.scaleMode === ScaleModes.LINEAR);
// this.gameContext[this.smoothProperty] = (this.scaleMode === ScaleModes.LINEAR);
// }
},
resetTransform: function ()
{
this.currentContext.setTransform(1, 0, 0, 1, 0, 0);
},
setBlendMode: function (blendMode)
{
if (this.currentBlendMode !== blendMode)
{
this.currentContext.globalCompositeOperation = blendMode;
this.currentBlendMode = blendMode;
}
},
setAlpha: function (alpha)
{
if (this.currentAlpha !== alpha)
{
this.currentContext.globalAlpha = alpha;
this.currentAlpha = alpha;
}
},
// Call at the start of the render loop
preRender: function ()
{
// console.log('%c render start ', 'color: #ffffff; background: #00ff00;');
var ctx = this.gameContext;
var config = this.gameConfig;
if (config.clearBeforeRender)
{
ctx.clearRect(0, 0, this.width, this.height);
}
if (!config.transparent)
{
ctx.fillStyle = config.backgroundColor;
ctx.fillRect(0, 0, this.width, this.height);
}
// Add Pre-render hook
this.drawCount = 0;
},
var ctx = this.context;
/**
* Renders the State.
*
* @method render
* @param {Phaser.State} state - The State to be rendered.
* @param {number} interpolationPercentage - The cumulative amount of time that hasn't been simulated yet, divided
* by the amount of time that will be simulated the next time update()
* runs. Useful for interpolating frames.
*/
render: function (state, list, interpolationPercentage)
{
var w = state.sys.width;
var h = state.sys.height;
var ctx = state.sys.context;
var settings = state.sys.settings;
this.currentContext = ctx;
ctx.setTransform(1, 0, 0, 1, 0, 0);
@ -117,53 +169,21 @@ CanvasRenderer.prototype = {
this.currentScaleMode = 0;
if (this.clearBeforeRender)
if (settings.renderToTexture)
{
ctx.clearRect(0, 0, this.width, this.height);
if (settings.clearBeforeRender)
{
ctx.clearRect(0, 0, w, h);
}
if (settings.backgroundColor)
{
ctx.fillStyle = settings.backgroundColor;
ctx.fillRect(0, 0, w, h);
}
}
// TEMP
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, this.width, this.height);
},
resetTransform: function ()
{
this.context.setTransform(1, 0, 0, 1, 0, 0);
},
setBlendMode: function (blendMode)
{
if (this.currentBlendMode !== blendMode)
{
this.context.globalCompositeOperation = blendMode;
this.currentBlendMode = blendMode;
}
},
setAlpha: function (alpha)
{
if (this.currentAlpha !== alpha)
{
this.context.globalAlpha = alpha;
this.currentAlpha = alpha;
}
},
/**
* Renders the State.
*
* @method render
* @param {Phaser.State} state - The State to be rendered.
* @param {number} interpolationPercentage - The cumulative amount of time that hasn't been simulated yet, divided
* by the amount of time that will be simulated the next time update()
* runs. Useful for interpolating frames.
*/
render: function (state, list, interpolationPercentage)
{
this.drawCount = list.length;
// console.log(this.drawCount);
this.drawCount += list.length;
for (var c = 0; c < list.length; c++)
{
@ -173,7 +193,16 @@ CanvasRenderer.prototype = {
}
// Reset the transform so going into the devs render function the context is ready for use
this.context.setTransform(1, 0, 0, 1, 0, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Call the State.render function
state.render(ctx, interpolationPercentage);
// Blast it to the Game Canvas (if needed)
if (settings.renderToTexture)
{
this.gameContext.drawImage(state.sys.canvas, 0, 0, w, h, settings.x, settings.y, w, h);
}
},
postRender: function ()
@ -187,14 +216,14 @@ CanvasRenderer.prototype = {
* Removes everything from the renderer and optionally removes the Canvas DOM element.
*
* @method destroy
* @param [removeView=true] {boolean} Removes the Canvas element from the DOM.
* @param [removegameCanvas=true] {boolean} Removes the Canvas element from the DOM.
*/
destroy: function ()
{
// CanvasPool
this.view = null;
this.context = null;
this.gameCanvas = null;
this.gameContext = null;
}
};

View file

@ -25,26 +25,33 @@ var Settings = {
key: GetObjectValue(config, 'key', ''),
active: GetObjectValue(config, 'active', false),
visible: GetObjectValue(config, 'visible', true),
scaleMode: GetObjectValue(config, 'scaleMode', ScaleModes.DEFAULT),
// Loader payload array
files: GetObjectValue(config, 'files', false),
// -1 means the State Manager will set it to be the Game dimensions
x: GetObjectValue(config, 'x', 0),
y: GetObjectValue(config, 'y', 0),
rotation: GetObjectValue(config, 'rotation', 0),
width: GetObjectValue(config, 'width', -1),
height: GetObjectValue(config, 'height', -1),
// Renderer Settings
// State Render Settings (applies only to this State)
clearBeforeRender: GetObjectValue(config, 'clearBeforeRender', true),
transparent: GetObjectValue(config, 'transparent', false),
autoResize: GetObjectValue(config, 'autoResize', false),
scaleMode: GetObjectValue(config, 'scaleMode', ScaleModes.DEFAULT),
roundPixels: GetObjectValue(config, 'roundPixels', false),
drawToPrimaryCanvas: GetObjectValue(config, 'drawToPrimaryCanvas', false),
// Loader payload array
dirtyRender: GetObjectValue(config, 'dirtyRender', false),
renderToTexture: GetObjectValue(config, 'renderToTexture', false),
files: GetObjectValue(config, 'files', false)
// The following only apply if renderToTexture is true
autoResize: GetObjectValue(config, 'autoResize', false),
transparent: GetObjectValue(config, 'transparent', false),
clearBeforeRender: GetObjectValue(config, 'clearBeforeRender', true),
backgroundColor: GetObjectValue(config, 'backgroundColor', false)
};
},

View file

@ -7,10 +7,13 @@
var CONST = require('../const');
var NOOP = require('../utils/NOOP');
var State = require('./State');
var Settings = require('./Settings');
var Systems = require('./Systems');
var GetObjectValue = require('../utils/object/GetObjectValue');
var EventDispatcher = require('../events/EventDispatcher');
var Rectangle = require('../geom/rectangle/Rectangle');
var CanvasPool = require('../dom/CanvasPool');
var CanvasInterpolation = require('../dom/CanvasInterpolation');
var GetContext = require('../canvas/GetContext');
/**
* The State Manager is responsible for loading, setting up and switching game states.
@ -132,25 +135,25 @@ StateManager.prototype = {
autoStart: autoStart
});
// console.log('StateManager not yet booted, adding to list', this._pending.length);
console.log('StateManager not yet booted, adding to list', this._pending.length);
return;
}
// console.log('StateManager.add', key, stateConfig, autoStart);
key = this.getKey(key, stateConfig);
console.log('StateManager.add', key, stateConfig, autoStart);
var newState;
if (stateConfig instanceof State)
{
// console.log('StateManager.add from instance', key);
console.log('StateManager.add from instance:', key);
newState = this.createStateFromInstance(key, stateConfig);
}
else if (typeof stateConfig === 'object')
{
// console.log('StateManager.add from object', key);
console.log('StateManager.add from object:', key);
stateConfig.key = key;
@ -158,7 +161,7 @@ StateManager.prototype = {
}
else if (typeof stateConfig === 'function')
{
// console.log('StateManager.add from function', key);
console.log('StateManager.add from function:', key);
newState = this.createStateFromFunction(key, stateConfig);
}
@ -256,55 +259,65 @@ StateManager.prototype = {
}
},
setupCallbacks: function (newState, stateConfig)
setupCallbacks: function (state, stateConfig)
{
if (stateConfig === undefined) { stateConfig = newState; }
if (stateConfig === undefined) { stateConfig = state; }
// Extract callbacks or set NOOP
newState.init = GetObjectValue(stateConfig, 'init', NOOP);
newState.preload = GetObjectValue(stateConfig, 'preload', NOOP);
newState.create = GetObjectValue(stateConfig, 'create', NOOP);
newState.shutdown = GetObjectValue(stateConfig, 'shutdown', NOOP);
state.init = GetObjectValue(stateConfig, 'init', NOOP);
state.preload = GetObjectValue(stateConfig, 'preload', NOOP);
state.create = GetObjectValue(stateConfig, 'create', NOOP);
state.shutdown = GetObjectValue(stateConfig, 'shutdown', NOOP);
// Game Loop level callbacks
newState.update = GetObjectValue(stateConfig, 'update', NOOP);
newState.render = GetObjectValue(stateConfig, 'render', NOOP);
state.update = GetObjectValue(stateConfig, 'update', NOOP);
state.render = GetObjectValue(stateConfig, 'render', NOOP);
return newState;
return state;
},
createStateDisplay: function (newState)
createStateDisplay: function (state)
{
return;
console.log('createStateDisplay', state.settings.key);
/*
var settings = newState.sys.settings;
var settings = state.sys.settings;
var x = settings.x;
var y = settings.y;
// var x = settings.x;
// var y = settings.y;
var width = settings.width;
var height = settings.height;
// Too late to do all this?
var config = this.game.config;
if (settings.width === -1)
if (config.renderType === CONST.CANVAS)
{
settings.width = this.game.config.width;
if (settings.renderToTexture)
{
console.log('renderToTexture');
state.sys.canvas = CanvasPool.create(state, width, height);
state.sys.context = GetContext(state.sys.canvas);
// Pixel Art mode?
if (config.pixelArt)
{
CanvasInterpolation.setCrisp(state.sys.canvas);
}
}
else
{
console.log('using game canvas');
state.sys.mask = new Rectangle(0, 0, width, height);
state.sys.canvas = this.game.canvas;
state.sys.context = this.game.context;
}
}
else if (config.renderType === CONST.WEBGL)
{
// state.sys.fbo = this.game.renderer.createFBO(state, x, y, width, height);
}
if (settings.height === -1)
{
settings.height = this.game.config.height;
}
if (this.game.config.renderType === CONST.WEBGL)
{
var width = settings.width;
var height = settings.height;
newState.sys.fbo = this.game.renderer.createFBO(newState, x, y, width, height);
}
*/
},
getState: function (key)
@ -339,10 +352,12 @@ StateManager.prototype = {
start: function (key)
{
console.log('start:', key);
// if not booted, then put state into a holding pattern
if (!this.game.isBooted)
{
// console.log('StateManager not yet booted, setting autoStart on pending list');
console.log('StateManager not yet booted, setting autoStart on pending list');
for (var i = 0; i < this._pending.length; i++)
{
@ -396,16 +411,16 @@ StateManager.prototype = {
payloadComplete: function (event)
{
console.log('payloadComplete');
var state = event.loader.state;
console.log('payloadComplete', state.sys.settings.key);
this.bootState(state);
},
bootState: function (state)
{
console.log('bootState', state);
console.log('bootState', state.sys.settings.key);
// + arguments
if (state.init)
@ -414,11 +429,11 @@ StateManager.prototype = {
}
var loader = state.sys.load;
loader.reset();
if (state.preload && loader)
if (state.preload)
{
loader.reset();
state.preload.call(state, this.game);
// Is the loader empty?
@ -444,10 +459,10 @@ StateManager.prototype = {
loadComplete: function (event)
{
console.log('loadComplete');
var state = event.loader.state;
console.log('loadComplete', state.sys.settings.key);
// Make sure to do load-update one last time before state is set to _created
// Stop doing this ...
@ -461,8 +476,11 @@ StateManager.prototype = {
startCreate: function (state)
{
console.log('startCreate', state.sys.settings.key);
if (state.create)
{
console.log('startCreate.call', state.sys.settings.key);
state.create.call(state);
}
@ -470,6 +488,8 @@ StateManager.prototype = {
var i = this.getStateIndex(state);
console.log('startCreate.index', state.sys.settings.key, i);
this.active.push({ index: i, state: state });
// Sort the 'active' array based on the index property

View file

@ -25,6 +25,13 @@ var Systems = function (state, config)
this.settings = Settings.create(config);
this.x = this.settings.x;
this.y = this.settings.y;
this.mask = null;
this.canvas;
this.context;
// CORE SYSTEMS / PROPERTIES
this.cache;
@ -39,7 +46,7 @@ var Systems = function (state, config)
this.tree;
// State properties
this.camera;
this.cameras;
this.children;
this.color;
this.data;
@ -143,35 +150,12 @@ Systems.prototype = {
camera.preRender();
state.camera = camera;
renderer.render(state, transform.flatRenderArray, interpolation, camera);
state.render(interpolation);
//state.render(interpolation);
camera.postRender();
}
},
// Called just once per frame, regardless of speed
/*
OLDrender: function (interpolation, renderer)
{
this.updates.start();
if (this.settings.visible && this.color.alpha !== 0)
{
var list = this.tree.search({
minX: this.camera.x,
minY: this.camera.y,
maxX: this.camera.right,
maxY: this.camera.bottom
});
renderer.render(this.state, list, interpolation);
}
this.updates.stop();
this.state.render(interpolation);
}
*/
};
module.exports = Systems;