mirror of
https://github.com/photonstorm/phaser
synced 2024-11-27 15:12:18 +00:00
Merge pull request #1 from photonstorm/master
Cleaned down, ready for new WebGL Renderer.
This commit is contained in:
commit
bc605465ac
12 changed files with 1177 additions and 472 deletions
659
v3/src/renderer/archived-webgl/WebGLRenderer.js
Normal file
659
v3/src/renderer/archived-webgl/WebGLRenderer.js
Normal file
|
@ -0,0 +1,659 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @author Mat Groves (@Doormat23)
|
||||
* @copyright 2016 Photon Storm Ltd.
|
||||
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
||||
*/
|
||||
|
||||
var CONST = require('../../const');
|
||||
var CreateEmptyTexture = require('./utils/CreateEmptyTexture');
|
||||
var QuadFBO = require('./utils/QuadFBO');
|
||||
var BatchManager = require('./BatchManager');
|
||||
var ShaderManager = require('./ShaderManager');
|
||||
|
||||
/**
|
||||
* A WebgL based renderer.
|
||||
*
|
||||
* @class Phaser.Renderer.WebGL
|
||||
* @constructor
|
||||
* @param {Phaser.Game} game - Game reference to the currently running game.
|
||||
*/
|
||||
var WebGLRenderer = function (game)
|
||||
{
|
||||
/**
|
||||
* @property {Phaser.Game} game - A reference to the currently running Game.
|
||||
*/
|
||||
this.game = game;
|
||||
|
||||
this.type = CONST.WEBGL;
|
||||
|
||||
// Read all the following from game config
|
||||
this.clearBeforeRender = true;
|
||||
|
||||
this.transparent = false;
|
||||
|
||||
this.autoResize = false;
|
||||
|
||||
this.preserveDrawingBuffer = false;
|
||||
|
||||
this.width = game.config.width * game.config.resolution;
|
||||
|
||||
this.height = game.config.height * game.config.resolution;
|
||||
|
||||
this.resolution = game.config.resolution;
|
||||
|
||||
this.clipUnitX = 2 / this.width;
|
||||
|
||||
this.clipUnitY = 2 / this.height;
|
||||
|
||||
this.view = game.canvas;
|
||||
|
||||
// this.stencilBufferLimit = 6;
|
||||
|
||||
this.multiTexture = false;
|
||||
|
||||
this.extensions = {};
|
||||
|
||||
/**
|
||||
* @property _contextOptions
|
||||
* @type Object
|
||||
* @private
|
||||
this.contextOptions = {
|
||||
alpha: this.transparent,
|
||||
antialias: game.antialias,
|
||||
premultipliedAlpha: this.transparent && this.transparent !== 'notMultiplied',
|
||||
stencil: true,
|
||||
preserveDrawingBuffer: this.preserveDrawingBuffer
|
||||
};
|
||||
*/
|
||||
|
||||
this.contextOptions = {
|
||||
alpha: true,
|
||||
antialias: true,
|
||||
premultipliedAlpha: true,
|
||||
stencil: true,
|
||||
preserveDrawingBuffer: false
|
||||
};
|
||||
|
||||
this.projection = { x: 0, y: 0 };
|
||||
|
||||
this.offset = { x: 0, y: 0 };
|
||||
|
||||
this.shaderManager = new ShaderManager(this);
|
||||
this.batch = new BatchManager(this, 4000);
|
||||
|
||||
// this.filterManager = new Phaser.Renderer.WebGL.FilterManager(this);
|
||||
// this.stencilManager = new Phaser.Renderer.WebGL.StencilManager(this);
|
||||
|
||||
this.gl = null;
|
||||
|
||||
this.emptyTexture = null;
|
||||
|
||||
this.textureArray = [];
|
||||
|
||||
this.currentBlendMode = -1;
|
||||
this.currentTextureSource = null;
|
||||
this.currentShader = null;
|
||||
|
||||
this.blendModes = [];
|
||||
|
||||
this.flipY = 1;
|
||||
|
||||
this.startTime = 0;
|
||||
this.endTime = 0;
|
||||
this.drawCount = 0;
|
||||
|
||||
this.contextLost = false;
|
||||
|
||||
this._fbErrors = {
|
||||
36054: 'Incomplete attachment',
|
||||
36055: 'Missing attachment',
|
||||
36057: 'Incomplete dimensions',
|
||||
36061: 'Framebuffer unsupported'
|
||||
};
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
||||
WebGLRenderer.prototype.constructor = WebGLRenderer;
|
||||
|
||||
WebGLRenderer.prototype = {
|
||||
|
||||
init: function ()
|
||||
{
|
||||
this.gl = this.view.getContext('webgl', this.contextOptions) || this.view.getContext('experimental-webgl', this.contextOptions);
|
||||
|
||||
if (!this.gl)
|
||||
{
|
||||
this.contextLost = true;
|
||||
throw new Error('This browser does not support WebGL. Try using the Canvas renderer.');
|
||||
}
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
this.maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
|
||||
|
||||
if (this.maxTextures === 1)
|
||||
{
|
||||
this.multiTexture = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.createMultiEmptyTextures();
|
||||
}
|
||||
|
||||
this.emptyTexture = CreateEmptyTexture(this.gl, 1, 1, 0, 0);
|
||||
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.CULL_FACE);
|
||||
gl.enable(gl.BLEND);
|
||||
|
||||
// Transparent
|
||||
// gl.clearColor(0, 0, 0, 0);
|
||||
|
||||
// Black
|
||||
gl.clearColor(1, 0, 0, 1);
|
||||
|
||||
this.shaderManager.init();
|
||||
this.batch.init();
|
||||
|
||||
// this.filterManager.init();
|
||||
// this.stencilManager.init();
|
||||
|
||||
this.resize(this.width, this.height);
|
||||
|
||||
// Load WebGL extension
|
||||
this.extensions.compression = {};
|
||||
|
||||
var etc1 = gl.getExtension('WEBGL_compressed_texture_etc1') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc1');
|
||||
var pvrtc = gl.getExtension('WEBGL_compressed_texture_pvrtc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
|
||||
var s3tc = gl.getExtension('WEBGL_compressed_texture_s3tc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
|
||||
|
||||
if (etc1)
|
||||
{
|
||||
this.extensions.compression.ETC1 = etc1;
|
||||
}
|
||||
|
||||
if (pvrtc)
|
||||
{
|
||||
this.extensions.compression.PVRTC = pvrtc;
|
||||
}
|
||||
|
||||
if (s3tc)
|
||||
{
|
||||
this.extensions.compression.S3TC = s3tc;
|
||||
}
|
||||
|
||||
// Map Blend Modes
|
||||
|
||||
var add = [ gl.SRC_ALPHA, gl.DST_ALPHA ];
|
||||
var normal = [ gl.ONE, gl.ONE_MINUS_SRC_ALPHA ];
|
||||
var multiply = [ gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA ];
|
||||
var screen = [ gl.SRC_ALPHA, gl.ONE ];
|
||||
|
||||
this.blendModes = [
|
||||
normal, add, multiply, screen, normal,
|
||||
normal, normal, normal, normal,
|
||||
normal, normal, normal, normal,
|
||||
normal, normal, normal, normal
|
||||
];
|
||||
},
|
||||
|
||||
// Bind empty multi-textures to avoid WebGL spam
|
||||
|
||||
createMultiEmptyTextures: function ()
|
||||
{
|
||||
if (this.maxTextures === 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.maxTextures; i++)
|
||||
{
|
||||
this.textureArray[i] = CreateEmptyTexture(this.gl, 1, 1, 0, i);
|
||||
}
|
||||
},
|
||||
|
||||
enableMultiTextureSupport: function (textureArray)
|
||||
{
|
||||
if (this.maxTextures === 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.multiTexture = true;
|
||||
|
||||
this.batch.spriteBatch = this.batch.multiTextureBatch;
|
||||
|
||||
if (Array.isArray(textureArray))
|
||||
{
|
||||
// index 0 is reserved?
|
||||
var index = 0;
|
||||
|
||||
for (var i = 0; i < textureArray.length; i++)
|
||||
{
|
||||
var texture = this.game.textures.get(textureArray[i]);
|
||||
|
||||
index = texture.setTextureIndex(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
disableMultiTextureSupport: function ()
|
||||
{
|
||||
this.multiTexture = false;
|
||||
|
||||
this.batch.spriteBatch = this.batch.singleTextureBatch;
|
||||
},
|
||||
|
||||
resize: function (width, height)
|
||||
{
|
||||
var res = this.game.config.resolution;
|
||||
|
||||
this.width = width * res;
|
||||
this.height = height * res;
|
||||
|
||||
this.view.width = this.width;
|
||||
this.view.height = this.height;
|
||||
|
||||
if (this.autoResize)
|
||||
{
|
||||
this.view.style.width = (this.width / res) + 'px';
|
||||
this.view.style.height = (this.height / res) + 'px';
|
||||
}
|
||||
|
||||
this.gl.viewport(0, 0, this.width, this.height);
|
||||
|
||||
this.clipUnitX = 2 / this.width;
|
||||
this.clipUnitY = 2 / this.height;
|
||||
|
||||
this.projection.x = (this.width / 2) / res;
|
||||
this.projection.y = -(this.height / 2) / res;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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, interpolationPercentage)
|
||||
{
|
||||
// console.log('%c render start ', 'color: #ffffff; background: #00ff00;');
|
||||
|
||||
// No point rendering if our context has been blown up!
|
||||
if (this.contextLost)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Add Pre-render hook
|
||||
|
||||
this.startTime = Date.now();
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
var fbo = state.sys.fbo;
|
||||
|
||||
fbo.activate();
|
||||
|
||||
// clear is needed for the FBO, otherwise corruption ...
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this.setBlendMode(CONST.blendModes.NORMAL);
|
||||
|
||||
this.drawCount = 0;
|
||||
|
||||
this.batch.start();
|
||||
|
||||
// Could move to the State Systems or MainLoop
|
||||
this.game.state.renderChildren(this, state, interpolationPercentage);
|
||||
|
||||
this.batch.stop();
|
||||
|
||||
// Call state.render here, so we can do some extra shizzle on the top
|
||||
// Maybe pass in the FBO texture too?
|
||||
|
||||
fbo.render(null);
|
||||
|
||||
// Unbind the fbo texture and replace it with an empty texture.
|
||||
// If we forget this we corrupt the main context texture!
|
||||
// or get `RENDER WARNING: there is no texture bound to the unit 0` spam in the console
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture);
|
||||
|
||||
this.endTime = Date.now();
|
||||
|
||||
// console.log('%c render end ', 'color: #ffffff; background: #ff0000;');
|
||||
|
||||
// Reset back to defaults
|
||||
// gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
||||
// gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
|
||||
// Add Post-render hook
|
||||
},
|
||||
|
||||
clipX: function (x)
|
||||
{
|
||||
return (this.clipUnitX * x) - 1;
|
||||
},
|
||||
|
||||
clipY: function (y)
|
||||
{
|
||||
return 1 - (this.clipUnitY * y);
|
||||
},
|
||||
|
||||
getVerticesFromRect: function (x, y, width, height)
|
||||
{
|
||||
// -1.0, -1.0, // 0 = bottom-left
|
||||
// 1.0, -1.0, // 1 = bottom-right
|
||||
// -1.0, 1.0, // 2 = top-left
|
||||
// 1.0, 1.0 // 3 = top-right
|
||||
|
||||
return [
|
||||
// bottom-left
|
||||
this.clipX(x), this.clipY(y + height),
|
||||
|
||||
// bottom-right
|
||||
this.clipX(x + width), this.clipY(y + height),
|
||||
|
||||
// top-left
|
||||
this.clipX(x), this.clipY(y),
|
||||
|
||||
// top-right
|
||||
this.clipX(x + width), this.clipY(y)
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the base texture from the GPU, useful for managing resources on the GPU.
|
||||
* A texture is still 100% usable and will simply be re-uploaded if there is a sprite on screen that is using it.
|
||||
*
|
||||
* @method unloadTexture
|
||||
*/
|
||||
unloadTexture: function (texture)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
var glTexture = texture._glTexture;
|
||||
|
||||
if (gl && glTexture)
|
||||
{
|
||||
gl.deleteTexture(glTexture);
|
||||
}
|
||||
|
||||
texture._glTexture = null;
|
||||
texture._dirty = false;
|
||||
},
|
||||
|
||||
// Takes a TextureSource object
|
||||
updateTexture: function (source)
|
||||
{
|
||||
if (source.compressionAlgorithm)
|
||||
{
|
||||
return this.updateCompressedTexture(source);
|
||||
}
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
if (!source.glTexture)
|
||||
{
|
||||
source.glTexture = gl.createTexture();
|
||||
}
|
||||
|
||||
// console.log('updateTexture', source.glTextureIndex);
|
||||
// console.log(source.image.currentSrc);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + source.glTextureIndex);
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, source.glTexture);
|
||||
|
||||
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, source.premultipliedAlpha);
|
||||
|
||||
// Throws a warning in Firefox: WebGL: texImage2D: Chosen format/type incured an expensive reformat: 0x1908/0x1401
|
||||
// @see https://github.com/mrdoob/three.js/issues/9109
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source.image);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, source.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
|
||||
if (source.mipmap && source.isPowerOf2)
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, source.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, source.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
}
|
||||
|
||||
if (source.isPowerOf2)
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
source.glDirty = false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/*
|
||||
updateCompressedTexture: function (texture)
|
||||
{
|
||||
if (!texture.hasLoaded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var gl = this.gl;
|
||||
var textureMetaData = texture.source;
|
||||
|
||||
if (!texture._glTextures)
|
||||
{
|
||||
texture._glTextures = gl.createTexture();
|
||||
}
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + texture.textureIndex);
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture._glTextures);
|
||||
|
||||
gl.compressedTexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
textureMetaData.glExtensionFormat,
|
||||
textureMetaData.width,
|
||||
textureMetaData.height,
|
||||
0,
|
||||
textureMetaData.textureData
|
||||
);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === Phaser.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
|
||||
if (texture.mipmap && Phaser.Math.isPowerOfTwo(texture.width, texture.height))
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === Phaser.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === Phaser.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
}
|
||||
|
||||
if (!texture._powerOf2)
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
|
||||
}
|
||||
|
||||
texture._dirty = false;
|
||||
|
||||
return true;
|
||||
},
|
||||
*/
|
||||
|
||||
// Blend Mode Manager
|
||||
|
||||
setBlendMode: function (newBlendMode)
|
||||
{
|
||||
if (this.currentBlendMode === newBlendMode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var blendModeWebGL = this.blendModes[newBlendMode];
|
||||
|
||||
if (blendModeWebGL)
|
||||
{
|
||||
this.currentBlendMode = newBlendMode;
|
||||
|
||||
this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// WebGL Mask Manager
|
||||
|
||||
pushMask: function (maskData)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
if (maskData.dirty)
|
||||
{
|
||||
// PIXI.WebGLGraphics.updateGraphics(maskData, gl);
|
||||
}
|
||||
|
||||
if (maskData._webGL === undefined || maskData._webGL.data === undefined || maskData._webGL.data.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.stencilManager.pushStencil(maskData, maskData._webGL.data[0]);
|
||||
},
|
||||
|
||||
popMask: function (maskData)
|
||||
{
|
||||
if (maskData._webGL === undefined || maskData._webGL.data === undefined || maskData._webGL.data.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.stencilManager.popStencil(maskData, maskData._webGL.data[0]);
|
||||
},
|
||||
|
||||
// Shader Utils
|
||||
|
||||
// PIXI.CompileVertexShader
|
||||
compileVertexShader: function (src)
|
||||
{
|
||||
return this.compileShader(src, this.gl.VERTEX_SHADER);
|
||||
},
|
||||
|
||||
// PIXI.CompileFragmentShader
|
||||
compileFragmentShader: function (src)
|
||||
{
|
||||
return this.compileShader(src, this.gl.FRAGMENT_SHADER);
|
||||
},
|
||||
|
||||
// PIXI._CompileShader
|
||||
compileShader: function (src, type)
|
||||
{
|
||||
if (Array.isArray(src))
|
||||
{
|
||||
src = src.join('\n');
|
||||
}
|
||||
|
||||
var shader = this.gl.createShader(type);
|
||||
this.gl.shaderSource(shader, src);
|
||||
this.gl.compileShader(shader);
|
||||
|
||||
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS))
|
||||
{
|
||||
console.log(this.gl.getShaderInfoLog(shader));
|
||||
return null;
|
||||
}
|
||||
|
||||
return shader;
|
||||
},
|
||||
|
||||
// PIXI.compileProgram
|
||||
compileProgram: function (vertexSrc, fragmentSrc)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
var fragmentShader = this.compileFragmentShader(fragmentSrc);
|
||||
var vertexShader = this.compileVertexShader(vertexSrc);
|
||||
|
||||
var shaderProgram = gl.createProgram();
|
||||
|
||||
gl.attachShader(shaderProgram, vertexShader);
|
||||
gl.attachShader(shaderProgram, fragmentShader);
|
||||
gl.linkProgram(shaderProgram);
|
||||
|
||||
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
|
||||
{
|
||||
console.log(gl.getProgramInfoLog(shaderProgram));
|
||||
console.log('Could not initialize shaders: Vertex & Fragment');
|
||||
console.log(vertexSrc.join('\n'));
|
||||
console.log(fragmentSrc.join('\n'));
|
||||
}
|
||||
|
||||
return shaderProgram;
|
||||
},
|
||||
|
||||
deleteProgram: function (program)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
gl.deleteProgram(program);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
createFBO: function (parent, x, y, width, height)
|
||||
{
|
||||
// Store in a local list so we can update size if the canvas size changes?
|
||||
return new QuadFBO(this, parent, x, y, width, height);
|
||||
},
|
||||
|
||||
destroy: function ()
|
||||
{
|
||||
this.projection = null;
|
||||
this.offset = null;
|
||||
|
||||
this.shaderManager.destroy();
|
||||
this.batch.destroy();
|
||||
this.maskManager.destroy();
|
||||
this.filterManager.destroy();
|
||||
|
||||
this.shaderManager = null;
|
||||
this.batch = null;
|
||||
this.maskManager = null;
|
||||
this.filterManager = null;
|
||||
|
||||
this.gl = null;
|
||||
this.renderSession = null;
|
||||
|
||||
// Phaser.CanvasPool.remove(this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = WebGLRenderer;
|
23
v3/src/renderer/archived-webgl/utils/CreateEmptyTexture.js
Normal file
23
v3/src/renderer/archived-webgl/utils/CreateEmptyTexture.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
var CONST = require('../../../const');
|
||||
|
||||
var CreateEmptyTexture = function (gl, width, height, scaleMode, textureIndex)
|
||||
{
|
||||
var texture = gl.createTexture();
|
||||
var glScaleMode = (scaleMode === CONST.scaleModes.LINEAR) ? gl.LINEAR : gl.NEAREST;
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + textureIndex);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
|
||||
// We'll read from this texture, but it won't have mipmaps, so turn them off:
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, glScaleMode);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, glScaleMode);
|
||||
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
||||
|
||||
return texture;
|
||||
};
|
||||
|
||||
module.exports = CreateEmptyTexture;
|
457
v3/src/renderer/archived-webgl/utils/QuadFBO.js
Normal file
457
v3/src/renderer/archived-webgl/utils/QuadFBO.js
Normal file
|
@ -0,0 +1,457 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2016 Photon Storm Ltd.
|
||||
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
||||
*/
|
||||
|
||||
var CreateEmptyTexture = require('./CreateEmptyTexture');
|
||||
|
||||
/**
|
||||
* Frame Buffer Object with drawing quad + shader
|
||||
*
|
||||
* @class Phaser.Renderer.Canvas
|
||||
* @constructor
|
||||
* @param {Phaser.Game} game - Game reference to the currently running game.
|
||||
*/
|
||||
var QuadFBO = function (renderer, parent, x, y, width, height)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
|
||||
this.parent = parent;
|
||||
|
||||
this.gl = renderer.gl;
|
||||
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
|
||||
this.textureIndex = 0;
|
||||
|
||||
this.clipX = function (x)
|
||||
{
|
||||
return (renderer.clipUnitX * x) - 1;
|
||||
};
|
||||
|
||||
this.clipY = function (y)
|
||||
{
|
||||
return 1 - (renderer.clipUnitY * y);
|
||||
};
|
||||
|
||||
this.vertexBuffer;
|
||||
this.indexBuffer;
|
||||
this.textureBuffer;
|
||||
|
||||
this.vertices;
|
||||
|
||||
this.texture;
|
||||
this.renderBuffer;
|
||||
this.frameBuffer;
|
||||
|
||||
this.program;
|
||||
this.aVertexPosition;
|
||||
this.aTextureCoord;
|
||||
|
||||
this._normal;
|
||||
this._twirl;
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
||||
QuadFBO.prototype.constructor = QuadFBO;
|
||||
|
||||
QuadFBO.prototype = {
|
||||
|
||||
init: function ()
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
// An FBO quad is made up of 2 triangles (A and B in the image below)
|
||||
//
|
||||
// 0 = Bottom Left (-1, -1)
|
||||
// 1 = Bottom Right (1, -1)
|
||||
// 2 = Top Left (-1, 1)
|
||||
// 3 = Top Right (1, 1)
|
||||
//
|
||||
// 2----3
|
||||
// |\ B|
|
||||
// | \ |
|
||||
// | \ |
|
||||
// | A \|
|
||||
// | \
|
||||
// 0----1
|
||||
|
||||
var width = this.renderer.width;
|
||||
var height = this.renderer.height;
|
||||
|
||||
this.indexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([ 0, 1, 2, 2, 1, 3 ]), gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
||||
|
||||
this.vertices = new Float32Array(8);
|
||||
|
||||
this.updateVerts();
|
||||
|
||||
this.vertexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
|
||||
|
||||
this.textureBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 0, 1, 0, 0, 1, 1, 1 ]), gl.STATIC_DRAW);
|
||||
|
||||
// Create a texture for our color buffer
|
||||
this.texture = CreateEmptyTexture(gl, width, height, 0, 0);
|
||||
|
||||
// The FBO's depth buffer
|
||||
this.renderBuffer = gl.createRenderbuffer();
|
||||
gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer);
|
||||
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
|
||||
|
||||
this.frameBuffer = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0);
|
||||
|
||||
// May need to optionally be: gl.DEPTH_STENCIL_ATTACHMENT
|
||||
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer);
|
||||
|
||||
var fbStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
||||
|
||||
if (fbStatus !== gl.FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
window.console.error('FrameBuffer Error: ', this.renderer._fbErrors[fbStatus]);
|
||||
}
|
||||
|
||||
this.createShader();
|
||||
},
|
||||
|
||||
// This whole function ought to be split out into the Shader Manager
|
||||
// so they can easily change the shader being used for an FBO.
|
||||
// This class will have to expose those shader attribs though.
|
||||
createShader: function ()
|
||||
{
|
||||
// Create the quad shader
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
var vertexSrc = [
|
||||
'attribute vec2 aVertexPosition;',
|
||||
'attribute vec2 aTextureCoord;',
|
||||
|
||||
'varying vec2 vTextureCoord;',
|
||||
|
||||
'void main(void) {',
|
||||
' vTextureCoord = aTextureCoord;',
|
||||
' gl_Position = vec4(aVertexPosition, 0.0, 1.0);',
|
||||
'}'
|
||||
];
|
||||
|
||||
var fragmentSrc = [
|
||||
'precision mediump float;',
|
||||
|
||||
'uniform sampler2D uSampler;',
|
||||
'uniform float time;',
|
||||
|
||||
'varying vec2 vTextureCoord;',
|
||||
|
||||
'void main(void) {',
|
||||
' gl_FragColor = texture2D(uSampler, vTextureCoord);',
|
||||
'}'
|
||||
];
|
||||
|
||||
var twirlFragmentSrc = [
|
||||
'precision mediump float;',
|
||||
|
||||
'uniform sampler2D uSampler;',
|
||||
'uniform float time;',
|
||||
|
||||
'varying vec2 vTextureCoord;',
|
||||
|
||||
'const float radius = 0.5;',
|
||||
'const float angle = 5.0;',
|
||||
'const vec2 offset = vec2(0.5, 0.5);',
|
||||
|
||||
'void main(void) {',
|
||||
' vec2 coord = vTextureCoord - offset;',
|
||||
' float distance = length(coord);',
|
||||
|
||||
' if (distance < radius) {',
|
||||
' float ratio = (radius - distance) / radius;',
|
||||
' float angleMod = ratio * ratio * angle;',
|
||||
' float s = sin(angleMod);',
|
||||
' float c = cos(angleMod);',
|
||||
' coord = vec2(coord.x * c - coord.y * s, coord.x * s + coord.y * c);',
|
||||
' }',
|
||||
|
||||
' gl_FragColor = texture2D(uSampler, coord + offset);',
|
||||
'}'
|
||||
];
|
||||
|
||||
var plasmaFragmentSrc = [
|
||||
|
||||
'precision mediump float;',
|
||||
|
||||
'uniform sampler2D uSampler;',
|
||||
'uniform float time;',
|
||||
|
||||
'varying vec2 vTextureCoord;',
|
||||
|
||||
'// Oldskool plasm shader. (c) Victor Korsun, bitekas@gmail.com; 1996-2013.',
|
||||
'//',
|
||||
'// Attribution-ShareAlike CC License.',
|
||||
|
||||
'//----------------',
|
||||
'const int ps = 2; // use values > 1..10 for oldskool',
|
||||
'const vec2 resolution = vec2(1280.0, 720.0);',
|
||||
'//----------------',
|
||||
|
||||
'void main(void) {',
|
||||
|
||||
'float x = gl_FragCoord.x / resolution.x * 1280.0;',
|
||||
'float y = gl_FragCoord.y / resolution.y * 720.0;',
|
||||
|
||||
'if (ps > 0)',
|
||||
'{',
|
||||
'x = float(int(x / float(ps)) * ps);',
|
||||
'y = float(int(y / float(ps)) * ps);',
|
||||
'}',
|
||||
|
||||
'float mov0 = x+y+sin(time)*10.+sin(x/90.)*70.+time*2.;',
|
||||
'float mov1 = (mov0 / 5. + sin(mov0 / 30.))/ 10. + time * 3.;',
|
||||
'float mov2 = mov1 + sin(mov1)*5. + time*1.0;',
|
||||
'float cl1 = sin(sin(mov1/4. + time)+mov1);',
|
||||
'float c1 = cl1 +mov2/2.-mov1-mov2+time;',
|
||||
'float c2 = sin(c1+sin(mov0/100.+time)+sin(y/57.+time/50.)+sin((x+y)/200.)*2.);',
|
||||
'float c3 = abs(sin(c2+cos((mov1+mov2+c2) / 10.)+cos((mov2) / 10.)+sin(x/80.)));',
|
||||
|
||||
'float dc = float(16-ps);',
|
||||
|
||||
'if (ps > 0)',
|
||||
'{',
|
||||
'cl1 = float(int(cl1*dc))/dc;',
|
||||
'c2 = float(int(c2*dc))/dc;',
|
||||
'c3 = float(int(c3*dc))/dc;',
|
||||
'}',
|
||||
|
||||
'gl_FragColor = vec4(cl1, c2, c3, 1.0);',
|
||||
|
||||
'}'
|
||||
];
|
||||
|
||||
|
||||
// This compiles, attaches and links the shader
|
||||
this._normal = this.renderer.compileProgram(vertexSrc, fragmentSrc);
|
||||
// this._twirl = this.renderer.compileProgram(vertexSrc, twirlFragmentSrc);
|
||||
this._twirl = this.renderer.compileProgram(vertexSrc, plasmaFragmentSrc);
|
||||
|
||||
this.program = this._normal;
|
||||
|
||||
this.aVertexPosition = gl.getAttribLocation(this.program, 'aVertexPosition');
|
||||
this.aTextureCoord = gl.getAttribLocation(this.program, 'aTextureCoord');
|
||||
},
|
||||
|
||||
setPosition: function (x, y)
|
||||
{
|
||||
if (x === undefined) { x = 0; }
|
||||
if (y === undefined) { y = 0; }
|
||||
|
||||
if (x !== this._x || y !== this._y)
|
||||
{
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
|
||||
this.updateVerts();
|
||||
}
|
||||
},
|
||||
|
||||
setSize: function (width, height)
|
||||
{
|
||||
if (width === undefined) { width = this.renderer.width; }
|
||||
if (height === undefined) { height = this.renderer.height; }
|
||||
|
||||
if (width !== this._width || height !== this._height)
|
||||
{
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
|
||||
this.updateVerts();
|
||||
}
|
||||
},
|
||||
|
||||
updateVerts: function ()
|
||||
{
|
||||
var x = this._x;
|
||||
var y = this._y;
|
||||
|
||||
var width = this._width;
|
||||
var height = this._height;
|
||||
|
||||
// Bottom Left
|
||||
this.vertices[0] = this.clipX(x);
|
||||
this.vertices[1] = this.clipY(y + height);
|
||||
|
||||
// Bottom Right
|
||||
this.vertices[2] = this.clipX(x + width);
|
||||
this.vertices[3] = this.clipY(y + height);
|
||||
|
||||
// Top Left
|
||||
this.vertices[4] = this.clipX(x);
|
||||
this.vertices[5] = this.clipY(y);
|
||||
|
||||
// Top Right
|
||||
this.vertices[6] = this.clipX(x + width);
|
||||
this.vertices[7] = this.clipY(y);
|
||||
},
|
||||
|
||||
activate: function ()
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer);
|
||||
|
||||
// FBO textures always use index zero
|
||||
this.renderer.textureArray[0] = this.texture;
|
||||
},
|
||||
|
||||
bindShader: function ()
|
||||
{
|
||||
var program = this.program;
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
gl.useProgram(program);
|
||||
|
||||
gl.uniform1i(gl.getUniformLocation(program, 'uSampler'), 0);
|
||||
gl.uniform1f(gl.getUniformLocation(program, 'time'), this.parent.sys.mainloop.frameDelta);
|
||||
|
||||
gl.enableVertexAttribArray(this.aTextureCoord);
|
||||
gl.enableVertexAttribArray(this.aVertexPosition);
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
|
||||
gl.vertexAttribPointer(this.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer);
|
||||
gl.vertexAttribPointer(this.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
|
||||
},
|
||||
|
||||
// destinationBuffer MUST be set, even if just to 'null'
|
||||
render: function (destinationBuffer)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
// Set the framebuffer to render to
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, destinationBuffer);
|
||||
|
||||
// Bind the texture we rendered to, for reading, always TEXTURE0
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
||||
|
||||
// The shader that will read from the fbo texture
|
||||
if (this.renderer.shaderManager.setShader(this.program))
|
||||
{
|
||||
this.bindShader();
|
||||
}
|
||||
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||||
|
||||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
|
||||
|
||||
this.renderer.drawCount++;
|
||||
},
|
||||
|
||||
destroy: function ()
|
||||
{
|
||||
|
||||
// TODO!
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Object.defineProperties(QuadFBO.prototype, {
|
||||
|
||||
x: {
|
||||
|
||||
enumerable: true,
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._x;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
if (value !== this._x)
|
||||
{
|
||||
this._x = value;
|
||||
this.updateVerts();
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
y: {
|
||||
|
||||
enumerable: true,
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._y;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
if (value !== this._y)
|
||||
{
|
||||
this._y = value;
|
||||
this.updateVerts();
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
width: {
|
||||
|
||||
enumerable: true,
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._width;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
if (value !== this._width)
|
||||
{
|
||||
this._width = value;
|
||||
this.updateVerts();
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
height: {
|
||||
|
||||
enumerable: true,
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._height;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
if (value !== this._height)
|
||||
{
|
||||
this._height = value;
|
||||
this.updateVerts();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = QuadFBO;
|
|
@ -7,110 +7,41 @@
|
|||
|
||||
var CONST = require('../../const');
|
||||
var CreateEmptyTexture = require('./utils/CreateEmptyTexture');
|
||||
var QuadFBO = require('./utils/QuadFBO');
|
||||
var BatchManager = require('./BatchManager');
|
||||
var ShaderManager = require('./ShaderManager');
|
||||
|
||||
/**
|
||||
* A WebgL based renderer.
|
||||
*
|
||||
* @class Phaser.Renderer.WebGL
|
||||
* @constructor
|
||||
* @param {Phaser.Game} game - Game reference to the currently running game.
|
||||
*/
|
||||
var WebGLRenderer = function (game)
|
||||
{
|
||||
/**
|
||||
* @property {Phaser.Game} game - A reference to the currently running Game.
|
||||
*/
|
||||
this.game = game;
|
||||
|
||||
this.type = CONST.WEBGL;
|
||||
|
||||
// Read all the following from game config
|
||||
this.clearBeforeRender = true;
|
||||
|
||||
this.transparent = false;
|
||||
|
||||
this.autoResize = false;
|
||||
|
||||
this.preserveDrawingBuffer = false;
|
||||
|
||||
this.width = game.config.width * game.config.resolution;
|
||||
|
||||
this.height = game.config.height * game.config.resolution;
|
||||
|
||||
this.resolution = game.config.resolution;
|
||||
|
||||
this.clipUnitX = 2 / this.width;
|
||||
|
||||
this.clipUnitY = 2 / this.height;
|
||||
|
||||
this.view = game.canvas;
|
||||
|
||||
// this.stencilBufferLimit = 6;
|
||||
// All of these settings will be able to be controlled via the Game Config
|
||||
this.config = {
|
||||
clearBeforeRender: true,
|
||||
transparent: false,
|
||||
autoResize: false,
|
||||
preserveDrawingBuffer: false,
|
||||
|
||||
this.multiTexture = false;
|
||||
|
||||
this.extensions = {};
|
||||
|
||||
/**
|
||||
* @property _contextOptions
|
||||
* @type Object
|
||||
* @private
|
||||
this.contextOptions = {
|
||||
alpha: this.transparent,
|
||||
antialias: game.antialias,
|
||||
premultipliedAlpha: this.transparent && this.transparent !== 'notMultiplied',
|
||||
stencil: true,
|
||||
preserveDrawingBuffer: this.preserveDrawingBuffer
|
||||
WebGLContextOptions: {
|
||||
alpha: true,
|
||||
antialias: true,
|
||||
premultipliedAlpha: true,
|
||||
stencil: true,
|
||||
preserveDrawingBuffer: false
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
this.contextOptions = {
|
||||
alpha: true,
|
||||
antialias: true,
|
||||
premultipliedAlpha: true,
|
||||
stencil: true,
|
||||
preserveDrawingBuffer: false
|
||||
};
|
||||
|
||||
this.projection = { x: 0, y: 0 };
|
||||
|
||||
this.offset = { x: 0, y: 0 };
|
||||
|
||||
this.shaderManager = new ShaderManager(this);
|
||||
this.batch = new BatchManager(this, 4000);
|
||||
|
||||
// this.filterManager = new Phaser.Renderer.WebGL.FilterManager(this);
|
||||
// this.stencilManager = new Phaser.Renderer.WebGL.StencilManager(this);
|
||||
|
||||
this.gl = null;
|
||||
|
||||
this.emptyTexture = null;
|
||||
|
||||
this.textureArray = [];
|
||||
|
||||
this.currentBlendMode = -1;
|
||||
this.currentTextureSource = null;
|
||||
this.currentShader = null;
|
||||
|
||||
this.blendModes = [];
|
||||
|
||||
this.flipY = 1;
|
||||
|
||||
this.startTime = 0;
|
||||
this.endTime = 0;
|
||||
this.drawCount = 0;
|
||||
|
||||
this.contextLost = false;
|
||||
this.maxTextures = 1;
|
||||
this.multiTexture = false;
|
||||
this.blendModes = [];
|
||||
|
||||
this._fbErrors = {
|
||||
36054: 'Incomplete attachment',
|
||||
36055: 'Missing attachment',
|
||||
36057: 'Incomplete dimensions',
|
||||
36061: 'Framebuffer unsupported'
|
||||
};
|
||||
this.gl = null;
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
@ -121,7 +52,7 @@ WebGLRenderer.prototype = {
|
|||
|
||||
init: function ()
|
||||
{
|
||||
this.gl = this.view.getContext('webgl', this.contextOptions) || this.view.getContext('experimental-webgl', this.contextOptions);
|
||||
this.gl = this.view.getContext('webgl', this.config.WebGLContextOptions) || this.view.getContext('experimental-webgl', this.config.WebGLContextOptions);
|
||||
|
||||
if (!this.gl)
|
||||
{
|
||||
|
@ -131,6 +62,9 @@ WebGLRenderer.prototype = {
|
|||
|
||||
var gl = this.gl;
|
||||
|
||||
/*
|
||||
// Will need supporting
|
||||
|
||||
this.maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
|
||||
|
||||
if (this.maxTextures === 1)
|
||||
|
@ -143,26 +77,19 @@ WebGLRenderer.prototype = {
|
|||
}
|
||||
|
||||
this.emptyTexture = CreateEmptyTexture(this.gl, 1, 1, 0, 0);
|
||||
*/
|
||||
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
gl.disable(gl.CULL_FACE);
|
||||
gl.enable(gl.BLEND);
|
||||
|
||||
// Transparent
|
||||
// gl.clearColor(0, 0, 0, 0);
|
||||
|
||||
// Black
|
||||
gl.clearColor(1, 0, 0, 1);
|
||||
|
||||
this.shaderManager.init();
|
||||
this.batch.init();
|
||||
|
||||
// this.filterManager.init();
|
||||
// this.stencilManager.init();
|
||||
|
||||
this.resize(this.width, this.height);
|
||||
|
||||
// Load WebGL extension
|
||||
/*
|
||||
// Will need supporting
|
||||
|
||||
this.extensions.compression = {};
|
||||
|
||||
var etc1 = gl.getExtension('WEBGL_compressed_texture_etc1') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc1');
|
||||
|
@ -183,6 +110,7 @@ WebGLRenderer.prototype = {
|
|||
{
|
||||
this.extensions.compression.S3TC = s3tc;
|
||||
}
|
||||
*/
|
||||
|
||||
// Map Blend Modes
|
||||
|
||||
|
@ -199,53 +127,6 @@ WebGLRenderer.prototype = {
|
|||
];
|
||||
},
|
||||
|
||||
// Bind empty multi-textures to avoid WebGL spam
|
||||
|
||||
createMultiEmptyTextures: function ()
|
||||
{
|
||||
if (this.maxTextures === 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.maxTextures; i++)
|
||||
{
|
||||
this.textureArray[i] = CreateEmptyTexture(this.gl, 1, 1, 0, i);
|
||||
}
|
||||
},
|
||||
|
||||
enableMultiTextureSupport: function (textureArray)
|
||||
{
|
||||
if (this.maxTextures === 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.multiTexture = true;
|
||||
|
||||
this.batch.spriteBatch = this.batch.multiTextureBatch;
|
||||
|
||||
if (Array.isArray(textureArray))
|
||||
{
|
||||
// index 0 is reserved?
|
||||
var index = 0;
|
||||
|
||||
for (var i = 0; i < textureArray.length; i++)
|
||||
{
|
||||
var texture = this.game.textures.get(textureArray[i]);
|
||||
|
||||
index = texture.setTextureIndex(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
disableMultiTextureSupport: function ()
|
||||
{
|
||||
this.multiTexture = false;
|
||||
|
||||
this.batch.spriteBatch = this.batch.singleTextureBatch;
|
||||
},
|
||||
|
||||
resize: function (width, height)
|
||||
{
|
||||
var res = this.game.config.resolution;
|
||||
|
@ -264,11 +145,13 @@ WebGLRenderer.prototype = {
|
|||
|
||||
this.gl.viewport(0, 0, this.width, this.height);
|
||||
|
||||
this.clipUnitX = 2 / this.width;
|
||||
this.clipUnitY = 2 / this.height;
|
||||
// Needed?
|
||||
// this.clipUnitX = 2 / this.width;
|
||||
// this.clipUnitY = 2 / this.height;
|
||||
|
||||
this.projection.x = (this.width / 2) / res;
|
||||
this.projection.y = -(this.height / 2) / res;
|
||||
// Needed?
|
||||
// this.projection.x = (this.width / 2) / res;
|
||||
// this.projection.y = -(this.height / 2) / res;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -292,10 +175,13 @@ WebGLRenderer.prototype = {
|
|||
|
||||
// Add Pre-render hook
|
||||
|
||||
this.startTime = Date.now();
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
/*
|
||||
|
||||
// This is the old render loop - add what you need here to replace it,
|
||||
// but please allow each State to render to its own Quad FBO
|
||||
|
||||
var fbo = state.sys.fbo;
|
||||
|
||||
fbo.activate();
|
||||
|
@ -305,8 +191,6 @@ WebGLRenderer.prototype = {
|
|||
|
||||
this.setBlendMode(CONST.blendModes.NORMAL);
|
||||
|
||||
this.drawCount = 0;
|
||||
|
||||
this.batch.start();
|
||||
|
||||
// Could move to the State Systems or MainLoop
|
||||
|
@ -324,334 +208,16 @@ WebGLRenderer.prototype = {
|
|||
// or get `RENDER WARNING: there is no texture bound to the unit 0` spam in the console
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.emptyTexture);
|
||||
|
||||
this.endTime = Date.now();
|
||||
*/
|
||||
|
||||
// console.log('%c render end ', 'color: #ffffff; background: #ff0000;');
|
||||
|
||||
// Reset back to defaults
|
||||
// gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
||||
// gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
|
||||
// Add Post-render hook
|
||||
},
|
||||
|
||||
clipX: function (x)
|
||||
{
|
||||
return (this.clipUnitX * x) - 1;
|
||||
},
|
||||
|
||||
clipY: function (y)
|
||||
{
|
||||
return 1 - (this.clipUnitY * y);
|
||||
},
|
||||
|
||||
getVerticesFromRect: function (x, y, width, height)
|
||||
{
|
||||
// -1.0, -1.0, // 0 = bottom-left
|
||||
// 1.0, -1.0, // 1 = bottom-right
|
||||
// -1.0, 1.0, // 2 = top-left
|
||||
// 1.0, 1.0 // 3 = top-right
|
||||
|
||||
return [
|
||||
// bottom-left
|
||||
this.clipX(x), this.clipY(y + height),
|
||||
|
||||
// bottom-right
|
||||
this.clipX(x + width), this.clipY(y + height),
|
||||
|
||||
// top-left
|
||||
this.clipX(x), this.clipY(y),
|
||||
|
||||
// top-right
|
||||
this.clipX(x + width), this.clipY(y)
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the base texture from the GPU, useful for managing resources on the GPU.
|
||||
* A texture is still 100% usable and will simply be re-uploaded if there is a sprite on screen that is using it.
|
||||
*
|
||||
* @method unloadTexture
|
||||
*/
|
||||
unloadTexture: function (texture)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
var glTexture = texture._glTexture;
|
||||
|
||||
if (gl && glTexture)
|
||||
{
|
||||
gl.deleteTexture(glTexture);
|
||||
}
|
||||
|
||||
texture._glTexture = null;
|
||||
texture._dirty = false;
|
||||
},
|
||||
|
||||
// Takes a TextureSource object
|
||||
updateTexture: function (source)
|
||||
{
|
||||
if (source.compressionAlgorithm)
|
||||
{
|
||||
return this.updateCompressedTexture(source);
|
||||
}
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
if (!source.glTexture)
|
||||
{
|
||||
source.glTexture = gl.createTexture();
|
||||
}
|
||||
|
||||
// console.log('updateTexture', source.glTextureIndex);
|
||||
// console.log(source.image.currentSrc);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + source.glTextureIndex);
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, source.glTexture);
|
||||
|
||||
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, source.premultipliedAlpha);
|
||||
|
||||
// Throws a warning in Firefox: WebGL: texImage2D: Chosen format/type incured an expensive reformat: 0x1908/0x1401
|
||||
// @see https://github.com/mrdoob/three.js/issues/9109
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source.image);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, source.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
|
||||
if (source.mipmap && source.isPowerOf2)
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, source.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, source.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
}
|
||||
|
||||
if (source.isPowerOf2)
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
source.glDirty = false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/*
|
||||
updateCompressedTexture: function (texture)
|
||||
{
|
||||
if (!texture.hasLoaded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var gl = this.gl;
|
||||
var textureMetaData = texture.source;
|
||||
|
||||
if (!texture._glTextures)
|
||||
{
|
||||
texture._glTextures = gl.createTexture();
|
||||
}
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0 + texture.textureIndex);
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture._glTextures);
|
||||
|
||||
gl.compressedTexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
textureMetaData.glExtensionFormat,
|
||||
textureMetaData.width,
|
||||
textureMetaData.height,
|
||||
0,
|
||||
textureMetaData.textureData
|
||||
);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === Phaser.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
|
||||
if (texture.mipmap && Phaser.Math.isPowerOfTwo(texture.width, texture.height))
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === Phaser.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === Phaser.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
|
||||
}
|
||||
|
||||
if (!texture._powerOf2)
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
|
||||
}
|
||||
|
||||
texture._dirty = false;
|
||||
|
||||
return true;
|
||||
},
|
||||
*/
|
||||
|
||||
// Blend Mode Manager
|
||||
|
||||
setBlendMode: function (newBlendMode)
|
||||
{
|
||||
if (this.currentBlendMode === newBlendMode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var blendModeWebGL = this.blendModes[newBlendMode];
|
||||
|
||||
if (blendModeWebGL)
|
||||
{
|
||||
this.currentBlendMode = newBlendMode;
|
||||
|
||||
this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// WebGL Mask Manager
|
||||
|
||||
pushMask: function (maskData)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
if (maskData.dirty)
|
||||
{
|
||||
// PIXI.WebGLGraphics.updateGraphics(maskData, gl);
|
||||
}
|
||||
|
||||
if (maskData._webGL === undefined || maskData._webGL.data === undefined || maskData._webGL.data.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.stencilManager.pushStencil(maskData, maskData._webGL.data[0]);
|
||||
},
|
||||
|
||||
popMask: function (maskData)
|
||||
{
|
||||
if (maskData._webGL === undefined || maskData._webGL.data === undefined || maskData._webGL.data.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.stencilManager.popStencil(maskData, maskData._webGL.data[0]);
|
||||
},
|
||||
|
||||
// Shader Utils
|
||||
|
||||
// PIXI.CompileVertexShader
|
||||
compileVertexShader: function (src)
|
||||
{
|
||||
return this.compileShader(src, this.gl.VERTEX_SHADER);
|
||||
},
|
||||
|
||||
// PIXI.CompileFragmentShader
|
||||
compileFragmentShader: function (src)
|
||||
{
|
||||
return this.compileShader(src, this.gl.FRAGMENT_SHADER);
|
||||
},
|
||||
|
||||
// PIXI._CompileShader
|
||||
compileShader: function (src, type)
|
||||
{
|
||||
if (Array.isArray(src))
|
||||
{
|
||||
src = src.join('\n');
|
||||
}
|
||||
|
||||
var shader = this.gl.createShader(type);
|
||||
this.gl.shaderSource(shader, src);
|
||||
this.gl.compileShader(shader);
|
||||
|
||||
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS))
|
||||
{
|
||||
console.log(this.gl.getShaderInfoLog(shader));
|
||||
return null;
|
||||
}
|
||||
|
||||
return shader;
|
||||
},
|
||||
|
||||
// PIXI.compileProgram
|
||||
compileProgram: function (vertexSrc, fragmentSrc)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
var fragmentShader = this.compileFragmentShader(fragmentSrc);
|
||||
var vertexShader = this.compileVertexShader(vertexSrc);
|
||||
|
||||
var shaderProgram = gl.createProgram();
|
||||
|
||||
gl.attachShader(shaderProgram, vertexShader);
|
||||
gl.attachShader(shaderProgram, fragmentShader);
|
||||
gl.linkProgram(shaderProgram);
|
||||
|
||||
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
|
||||
{
|
||||
console.log(gl.getProgramInfoLog(shaderProgram));
|
||||
console.log('Could not initialize shaders: Vertex & Fragment');
|
||||
console.log(vertexSrc.join('\n'));
|
||||
console.log(fragmentSrc.join('\n'));
|
||||
}
|
||||
|
||||
return shaderProgram;
|
||||
},
|
||||
|
||||
deleteProgram: function (program)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
gl.deleteProgram(program);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
createFBO: function (parent, x, y, width, height)
|
||||
{
|
||||
// Store in a local list so we can update size if the canvas size changes?
|
||||
return new QuadFBO(this, parent, x, y, width, height);
|
||||
},
|
||||
|
||||
destroy: function ()
|
||||
{
|
||||
this.projection = null;
|
||||
this.offset = null;
|
||||
|
||||
this.shaderManager.destroy();
|
||||
this.batch.destroy();
|
||||
this.maskManager.destroy();
|
||||
this.filterManager.destroy();
|
||||
|
||||
this.shaderManager = null;
|
||||
this.batch = null;
|
||||
this.maskManager = null;
|
||||
this.filterManager = null;
|
||||
|
||||
this.gl = null;
|
||||
this.renderSession = null;
|
||||
|
||||
// Phaser.CanvasPool.remove(this);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue