phaser/src/renderer/webgl/WebGLRenderer.js

943 lines
27 KiB
JavaScript
Raw Normal View History

var Class = require('../../utils/Class');
var CONST = require('../../const');
2018-01-20 04:05:56 +00:00
var WebGLSnapshot = require('../snapshot/WebGLSnapshot');
var IsSizePowerOfTwo = require('../../math/pow2/IsSizePowerOfTwo');
2018-01-24 03:57:33 +00:00
var Utils = require('./Utils');
2018-01-17 21:25:43 +00:00
2018-01-22 21:21:47 +00:00
// Default Pipelines
2018-01-22 22:51:15 +00:00
var TextureTintPipeline = require('./pipelines/TextureTintPipeline');
var FlatTintPipeline = require('./pipelines/FlatTintPipeline');
var BitmapMaskPipeline = require('./pipelines/BitmapMaskPipeline');
2018-01-29 21:46:48 +00:00
var ForwardDiffuseLightPipeline = require('./pipelines/ForwardDiffuseLightPipeline');
2018-01-22 21:21:47 +00:00
2018-01-31 13:54:44 +00:00
/**
* @namespace Phaser.Renderer.WebGLRenderer
*/
2018-01-17 21:25:43 +00:00
var WebGLRenderer = new Class({
2016-12-07 02:28:22 +00:00
initialize:
2018-01-17 21:25:43 +00:00
function WebGLRenderer (game)
2016-12-07 02:28:22 +00:00
{
2018-01-17 21:25:43 +00:00
var renderer = this;
var contextCreationConfig = {
alpha: game.config.transparent,
depth: false, // enable when 3D is added in the future
antialias: game.config.antialias,
premultipliedAlpha: game.config.transparent,
stencil: true,
preserveDrawingBuffer: game.config.preserveDrawingBuffer,
failIfMajorPerformanceCaveat: false,
powerPreference: game.config.powerPreference
2018-01-17 21:25:43 +00:00
};
this.config = {
clearBeforeRender: game.config.clearBeforeRender,
pixelArt: game.config.pixelArt,
backgroundColor: game.config.backgroundColor,
contextCreation: contextCreationConfig,
resolution: game.config.resolution
};
this.game = game;
this.type = CONST.WEBGL;
this.width = game.config.width * game.config.resolution;
this.height = game.config.height * game.config.resolution;
2018-01-17 21:25:43 +00:00
this.canvas = game.canvas;
2018-01-24 00:40:20 +00:00
this.lostContextCallbacks = [];
this.restoredContextCallbacks = [];
2018-01-17 21:25:43 +00:00
this.blendModes = [];
this.nativeTextures = [];
2018-01-17 21:25:43 +00:00
this.contextLost = false;
this.autoResize = false;
this.pipelines = null;
2018-01-20 04:05:56 +00:00
this.snapshotState = {
callback: null,
type: null,
encoder: null
};
2018-01-17 21:25:43 +00:00
for (var i = 0; i <= 16; i++)
{
this.blendModes.push({ func: [ WebGLRenderingContext.ONE, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA ], equation: WebGLRenderingContext.FUNC_ADD });
}
2018-01-17 21:25:43 +00:00
this.blendModes[1].func = [ WebGLRenderingContext.ONE, WebGLRenderingContext.DST_ALPHA ];
this.blendModes[2].func = [ WebGLRenderingContext.DST_COLOR, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA ];
this.blendModes[3].func = [ WebGLRenderingContext.ONE, WebGLRenderingContext.ONE_MINUS_SRC_COLOR ];
2018-01-17 21:25:43 +00:00
// Intenal Renderer State (Textures, Framebuffers, Pipelines, Buffers, etc)
this.currentTextures = new Array(16);
this.currentFramebuffer = null;
this.currentPipeline = null;
2018-01-22 21:21:47 +00:00
this.currentProgram = null;
2018-01-17 21:25:43 +00:00
this.currentVertexBuffer = null;
this.currentIndexBuffer = null;
2018-01-22 21:21:47 +00:00
this.currentBlendMode = Infinity;
2018-01-24 18:55:23 +00:00
this.currentScissorEnabled = false;
this.currentScissor = new Uint32Array([0, 0, this.width, this.height]);
this.currentScissorIdx = 0;
this.scissorStack = new Uint32Array(4 * 1000);
2018-01-17 21:25:43 +00:00
// Setup context lost and restore event listeners
this.canvas.addEventListener('webglcontextlost', function (event) {
renderer.contextLost = true;
event.preventDefault();
2018-01-24 00:40:20 +00:00
for (var index = 0; index < renderer.lostContextCallbacks.length; ++index)
{
var callback = renderer.lostContextCallbacks[index];
callback[0].call(callback[1], renderer);
}
2018-01-17 21:25:43 +00:00
}, false);
2018-01-17 21:25:43 +00:00
this.canvas.addEventListener('webglcontextrestored', function (event) {
renderer.contextLost = false;
renderer.init(renderer.config);
2018-01-24 00:40:20 +00:00
for (var index = 0; index < renderer.restoredContextCallbacks.length; ++index)
{
var callback = renderer.restoredContextCallbacks[index];
callback[0].call(callback[1], renderer);
}
2018-01-17 21:25:43 +00:00
}, false);
// This are initialized post context creation
this.gl = null;
2018-01-17 21:25:43 +00:00
this.supportedExtensions = null;
this.extensions = {};
this.init(this.config);
},
init: function (config)
{
2018-01-17 21:25:43 +00:00
var canvas = this.canvas;
var clearColor = config.backgroundColor;
var gl = canvas.getContext('webgl', config.contextCreation) || canvas.getContext('experimental-webgl', config.contextCreation);
2018-01-17 21:25:43 +00:00
if (!gl)
2016-12-07 02:28:22 +00:00
{
this.contextLost = true;
2018-01-10 20:03:01 +00:00
throw new Error('This browser does not support WebGL. Try using the Canvas pipeline.');
2016-12-07 02:28:22 +00:00
}
2018-01-22 21:21:47 +00:00
this.gl = gl;
2018-01-17 21:25:43 +00:00
// Load supported extensions
this.supportedExtensions = gl.getSupportedExtensions();
2018-01-17 21:25:43 +00:00
// Setup initial WebGL state
2016-12-07 02:28:22 +00:00
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.CULL_FACE);
2018-01-17 21:25:43 +00:00
gl.disable(gl.SCISSOR_TEST);
2016-12-07 02:28:22 +00:00
gl.enable(gl.BLEND);
2018-01-17 21:25:43 +00:00
gl.clearColor(clearColor.redGL, clearColor.greenGL, clearColor.blueGL, 1.0);
2018-01-17 21:25:43 +00:00
// Initialize all textures to null
for (var index = 0; index < this.currentTextures.length; ++index)
{
2018-01-17 21:25:43 +00:00
this.currentTextures[index] = null;
}
2018-01-17 21:25:43 +00:00
// Clear previous pipelines and reload default ones
this.pipelines = {};
2018-01-22 22:51:15 +00:00
this.addPipeline('TextureTintPipeline', new TextureTintPipeline(this.game, gl, this));
this.addPipeline('FlatTintPipeline', new FlatTintPipeline(this.game, gl, this));
this.addPipeline('BitmapMaskPipeline', new BitmapMaskPipeline(this.game, gl, this));
2018-01-30 03:38:31 +00:00
this.addPipeline('Light2D', new ForwardDiffuseLightPipeline(this.game, gl, this));
2018-01-17 21:25:43 +00:00
this.setBlendMode(CONST.BlendModes.NORMAL);
this.resize(this.width, this.height, config.resolution);
2018-01-17 21:25:43 +00:00
return this;
},
2018-01-17 21:25:43 +00:00
resize: function (width, height, resolution)
{
2018-01-17 21:25:43 +00:00
var gl = this.gl;
2018-01-22 21:21:47 +00:00
var pipelines = this.pipelines;
2018-01-17 21:25:43 +00:00
this.width = width * resolution;
this.height = height * resolution;
this.canvas.width = this.width;
this.canvas.height = this.height;
2018-01-17 21:25:43 +00:00
if (this.autoResize)
{
2018-01-17 21:25:43 +00:00
this.canvas.style.width = (this.width / resolution) + 'px';
this.canvas.style.height = (this.height / resolution) + 'px';
}
2018-01-17 21:25:43 +00:00
gl.viewport(0, 0, this.width, this.height);
2018-01-17 21:25:43 +00:00
// Update all registered pipelines
2018-01-20 04:05:56 +00:00
for (var pipelineName in pipelines)
{
2018-01-22 21:21:47 +00:00
pipelines[pipelineName].resize(width, height, resolution);
2018-01-20 04:05:56 +00:00
}
2018-01-17 21:25:43 +00:00
return this;
},
2018-01-24 00:40:20 +00:00
onContextRestored: function (callback, target)
{
this.restoredContextCallbacks.push([callback, target]);
return this;
},
onContextLost: function (callback, target)
{
this.lostContextCallbacks.push([callback, target]);
return this;
},
2018-01-17 21:25:43 +00:00
hasExtension: function (extensionName)
{
2018-01-17 21:25:43 +00:00
return this.supportedExtensions ? this.supportedExtensions.indexOf(extensionName) : false;
},
2018-01-17 21:25:43 +00:00
getExtension: function (extensionName)
2017-01-19 23:20:36 +00:00
{
2018-01-17 21:25:43 +00:00
if (!this.hasExtension(extensionName)) return null;
2018-01-17 21:25:43 +00:00
if (!(extensionName in this.extensions))
2017-01-19 23:20:36 +00:00
{
2018-01-17 21:25:43 +00:00
this.extensions[extensionName] = this.gl.getExtension(extensionName);
2017-01-19 23:20:36 +00:00
}
2018-01-17 21:25:43 +00:00
return this.extensions[extensionName];
2017-01-19 23:20:36 +00:00
},
2018-01-20 04:05:56 +00:00
flush: function ()
{
if (this.currentPipeline)
{
this.currentPipeline.flush();
}
},
2018-01-17 21:25:43 +00:00
/* Renderer State Manipulation Functions */
2017-01-19 17:53:20 +00:00
2018-01-17 21:25:43 +00:00
hasPipeline: function (pipelineName)
2017-01-19 22:43:41 +00:00
{
2018-01-17 21:25:43 +00:00
return (pipelineName in this.pipelines);
2017-04-07 01:49:15 +00:00
},
2018-01-17 21:25:43 +00:00
getPipeline: function (pipelineName)
2017-04-07 01:49:15 +00:00
{
2018-01-17 21:25:43 +00:00
if (this.hasPipeline(pipelineName)) return this.pipelines[pipelineName];
return null;
2017-01-19 22:43:41 +00:00
},
2018-01-17 21:25:43 +00:00
removePipeline: function (pipelineName)
2016-12-07 02:28:22 +00:00
{
2018-01-17 21:25:43 +00:00
delete this.pipelines[pipelineName];
return this;
2016-12-07 02:28:22 +00:00
},
2018-01-17 21:25:43 +00:00
addPipeline: function (pipelineName, pipelineInstance)
2016-12-07 02:28:22 +00:00
{
2018-01-17 21:25:43 +00:00
if (!this.hasPipeline(pipelineName)) this.pipelines[pipelineName] = pipelineInstance;
else console.warn('Pipeline', pipelineName, ' already exists.');
2018-01-30 22:46:43 +00:00
pipelineInstance.name = pipelineName;
this.pipelines[pipelineName].resize(this.width, this.height, this.config.resolution);
2016-12-07 02:28:22 +00:00
2018-01-17 21:25:43 +00:00
return this;
},
2018-01-24 18:55:23 +00:00
setScissor: function (x, y, w, h)
{
var gl = this.gl;
2018-01-24 18:55:23 +00:00
var currentScissor = this.currentScissor;
var enabled = (x == 0 && y == 0 && w == gl.canvas.width && h == gl.canvas.height && w >= 0 && h >= 0);
if (currentScissor[0] !== x ||
currentScissor[1] !== y ||
currentScissor[2] !== w ||
currentScissor[3] !== h)
{
2018-01-24 03:57:33 +00:00
this.flush();
}
2018-01-24 18:55:23 +00:00
currentScissor[0] = x;
currentScissor[1] = y;
currentScissor[2] = w;
currentScissor[3] = h;
2018-01-24 18:55:23 +00:00
this.currentScissorEnabled = enabled;
2018-01-24 18:55:23 +00:00
if (enabled)
{
gl.disable(gl.SCISSOR_TEST);
2018-01-24 18:55:23 +00:00
return;
}
2018-01-24 18:55:23 +00:00
gl.enable(gl.SCISSOR_TEST);
gl.scissor(x, (gl.drawingBufferHeight - y - h), w, h);
return this;
},
pushScissor: function (x, y, w, h)
{
var scissorStack = this.scissorStack;
var stackIndex = this.currentScissorIdx;
var currentScissor = this.currentScissor;
scissorStack[stackIndex + 0] = currentScissor[0];
scissorStack[stackIndex + 1] = currentScissor[1];
scissorStack[stackIndex + 2] = currentScissor[2];
scissorStack[stackIndex + 3] = currentScissor[3];
this.currentScissorIdx += 4;
this.setScissor(x, y, w, h);
return this;
},
popScissor: function ()
{
var scissorStack = this.scissorStack;
var stackIndex = this.currentScissorIdx - 4;
var x = scissorStack[stackIndex + 0];
var y = scissorStack[stackIndex + 1];
var w = scissorStack[stackIndex + 2];
var h = scissorStack[stackIndex + 3];
this.currentScissorIdx = stackIndex;
this.setScissor(x, y, w, h);
return this;
},
2018-01-30 03:38:31 +00:00
setPipeline: function (pipelineInstance)
2018-01-20 04:05:56 +00:00
{
2018-01-25 05:26:14 +00:00
if (this.currentPipeline !== pipelineInstance ||
2018-01-30 03:38:31 +00:00
this.currentPipeline.vertexBuffer !== this.currentVertexBuffer ||
this.currentPipeline.program !== this.currentProgram)
2018-01-20 04:05:56 +00:00
{
2018-01-24 03:08:14 +00:00
this.flush();
2018-01-23 16:38:58 +00:00
this.currentPipeline = pipelineInstance;
2018-01-30 03:38:31 +00:00
this.currentPipeline.bind();
2018-01-20 04:05:56 +00:00
}
2018-01-25 05:26:14 +00:00
this.currentPipeline.onBind();
2018-01-23 19:29:47 +00:00
return this.currentPipeline;
2018-01-20 04:05:56 +00:00
},
2018-01-17 21:25:43 +00:00
setBlendMode: function (blendModeId)
{
var gl = this.gl;
2018-01-17 21:25:43 +00:00
var blendMode = this.blendModes[blendModeId];
2017-02-07 16:12:20 +00:00
if (blendModeId !== CONST.BlendModes.SKIP_CHECK &&
this.currentBlendMode !== blendModeId)
2017-01-19 17:53:20 +00:00
{
2018-01-20 04:05:56 +00:00
this.flush();
2017-12-15 04:07:16 +00:00
2018-01-17 21:25:43 +00:00
gl.enable(gl.BLEND);
gl.blendEquation(blendMode.equation);
2018-01-17 21:25:43 +00:00
if (blendMode.func.length > 2)
2017-11-06 22:12:19 +00:00
{
2018-01-17 21:25:43 +00:00
gl.blendFuncSeparate(blendMode.func[0], blendMode.func[1], blendMode.func[2], blendMode.func[3]);
2017-11-06 22:12:19 +00:00
}
2018-01-17 21:25:43 +00:00
else
2017-11-06 22:12:19 +00:00
{
2018-01-17 21:25:43 +00:00
gl.blendFunc(blendMode.func[0], blendMode.func[1]);
2017-11-06 22:12:19 +00:00
}
2018-01-17 21:25:43 +00:00
this.currentBlendMode = blendModeId;
2017-02-10 00:48:32 +00:00
}
2018-01-17 21:25:43 +00:00
return this;
2017-02-07 19:30:50 +00:00
},
2016-12-07 02:28:22 +00:00
2018-01-17 21:25:43 +00:00
setTexture2D: function (texture, textureUnit)
2017-02-07 19:30:50 +00:00
{
2018-01-17 21:25:43 +00:00
var gl = this.gl;
2017-05-16 19:15:01 +00:00
2018-01-17 21:25:43 +00:00
if (texture !== this.currentTextures[textureUnit])
2017-05-16 19:15:01 +00:00
{
2018-01-23 19:29:47 +00:00
this.flush();
2018-01-17 21:25:43 +00:00
gl.activeTexture(gl.TEXTURE0 + textureUnit);
gl.bindTexture(gl.TEXTURE_2D, texture);
2017-05-16 19:15:01 +00:00
2018-01-17 21:25:43 +00:00
this.currentTextures[textureUnit] = texture;
}
2016-12-07 02:28:22 +00:00
2018-01-17 21:25:43 +00:00
return this;
2017-05-16 19:15:01 +00:00
},
2018-01-17 21:25:43 +00:00
setFramebuffer: function (framebuffer)
2017-01-23 21:42:47 +00:00
{
var gl = this.gl;
2018-01-17 21:25:43 +00:00
if (framebuffer !== this.currentFramebuffer)
{
2018-01-23 19:29:47 +00:00
this.flush();
2018-01-17 21:25:43 +00:00
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
2018-01-25 05:26:14 +00:00
this.currentFramebuffer = framebuffer;
}
2018-01-17 21:25:43 +00:00
return this;
},
2018-01-22 21:21:47 +00:00
setProgram: function (program)
{
var gl = this.gl;
if (program !== this.currentProgram)
{
2018-01-23 19:29:47 +00:00
this.flush();
2018-01-22 21:21:47 +00:00
gl.useProgram(program);
2018-01-25 05:26:14 +00:00
this.currentProgram = program;
2018-01-22 21:21:47 +00:00
}
return this;
},
2018-01-17 21:25:43 +00:00
setVertexBuffer: function (vertexBuffer)
{
2018-01-17 21:25:43 +00:00
var gl = this.gl;
2018-01-17 21:25:43 +00:00
if (vertexBuffer !== this.currentVertexBuffer)
{
2018-01-23 19:29:47 +00:00
this.flush();
2018-01-17 21:25:43 +00:00
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
2018-01-25 05:26:14 +00:00
this.currentVertexBuffer = vertexBuffer;
}
2018-01-17 21:25:43 +00:00
return this;
},
2018-01-17 21:25:43 +00:00
setIndexBuffer: function (indexBuffer)
2017-05-20 01:16:45 +00:00
{
var gl = this.gl;
2018-01-17 21:25:43 +00:00
if (indexBuffer !== this.currentIndexBuffer)
{
2018-01-23 19:29:47 +00:00
this.flush();
2018-01-17 21:25:43 +00:00
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
2018-01-25 05:26:14 +00:00
this.currentIndexBuffer = indexBuffer;
}
2017-05-20 01:16:45 +00:00
2018-01-17 21:25:43 +00:00
return this;
2017-05-20 01:16:45 +00:00
},
2018-01-17 21:25:43 +00:00
/* Renderer Resource Creation Functions */
2018-01-24 00:40:20 +00:00
createTextureFromSource: function (source, width, height, scaleMode)
2018-01-20 04:05:56 +00:00
{
var gl = this.gl;
var filter = gl.NEAREST;
var wrap = gl.CLAMP_TO_EDGE;
2018-01-24 00:40:20 +00:00
var texture = null;
2018-01-20 04:05:56 +00:00
width = source ? source.width : width;
height = source ? source.height : height;
if (IsSizePowerOfTwo(width, height))
{
wrap = gl.REPEAT;
}
2018-01-24 00:40:20 +00:00
if (scaleMode === CONST.ScaleModes.LINEAR)
2018-01-20 04:05:56 +00:00
{
2018-01-24 00:40:20 +00:00
filter = gl.LINEAR;
}
else if (scaleMode === CONST.ScaleModes.NEAREST || this.config.pixelArt)
2018-01-24 00:40:20 +00:00
{
filter = gl.NEAREST;
}
2018-01-20 04:05:56 +00:00
2018-01-24 00:40:20 +00:00
if (!source && typeof width === 'number' && typeof height === 'number')
{
texture = this.createTexture2D(0, filter, filter, wrap, wrap, gl.RGBA, null, width, height);
}
else
{
texture = this.createTexture2D(0, filter, filter, wrap, wrap, gl.RGBA, source);
2018-01-20 04:05:56 +00:00
}
2018-01-24 00:40:20 +00:00
return texture;
2018-01-20 04:05:56 +00:00
},
2018-01-20 00:37:52 +00:00
createTexture2D: function (mipLevel, minFilter, magFilter, wrapT, wrapS, format, pixels, width, height, pma)
2018-01-17 21:25:43 +00:00
{
2018-01-20 00:37:52 +00:00
var gl = this.gl;
var texture = gl.createTexture();
pma = (pma === undefined || pma === null) ? true : pma;
this.setTexture2D(texture, 0);
2018-01-17 21:25:43 +00:00
2018-01-20 00:37:52 +00:00
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, pma);
if (pixels === null || pixels === undefined)
{
gl.texImage2D(gl.TEXTURE_2D, mipLevel, format, width, height, 0, format, gl.UNSIGNED_BYTE, null);
}
else
{
gl.texImage2D(gl.TEXTURE_2D, mipLevel, format, format, gl.UNSIGNED_BYTE, pixels);
width = pixels.width;
height = pixels.height;
}
this.setTexture2D(null, 0);
texture.isAlphaPremultiplied = pma;
texture.isRenderTexture = false;
texture.width = width;
texture.height = height;
this.nativeTextures.push(texture);
2018-01-20 00:37:52 +00:00
return texture;
2018-01-17 21:25:43 +00:00
},
2018-01-20 00:37:52 +00:00
createFramebuffer: function (width, height, renderTexture, addDepthStencilBuffer)
2018-01-17 21:25:43 +00:00
{
2018-01-20 00:37:52 +00:00
var gl = this.gl;
var framebuffer = gl.createFramebuffer();
var complete = 0;
this.setFramebuffer(framebuffer);
if (addDepthStencilBuffer)
{
var depthStencilBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
}
renderTexture.isRenderTexture = true;
renderTexture.isAlphaPremultiplied = false;
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, renderTexture, 0);
complete = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (complete !== gl.FRAMEBUFFER_COMPLETE)
{
var errors = {
36054: 'Incomplete Attachment',
36055: 'Missing Attachment',
36057: 'Incomplete Dimensions',
36061: 'Framebuffer Unsupported'
};
throw new Error('Framebuffer incomplete. Framebuffer status: ' + errors[complete]);
}
framebuffer.renderTexture = renderTexture;
2018-01-20 00:37:52 +00:00
this.setFramebuffer(null);
return framebuffer;
2018-01-17 21:25:43 +00:00
},
2018-01-20 00:37:52 +00:00
createProgram: function (vertexShader, fragmentShader)
2018-01-17 21:25:43 +00:00
{
2018-01-20 00:37:52 +00:00
var gl = this.gl;
var program = gl.createProgram();
var vs = gl.createShader(gl.VERTEX_SHADER);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vs, vertexShader);
gl.shaderSource(fs, fragmentShader);
gl.compileShader(vs);
gl.compileShader(fs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
{
throw new Error('Failed to compile Vertex Shader:\n' + gl.getShaderInfoLog(vs));
2018-01-20 00:37:52 +00:00
}
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
{
throw new Error('Failed to compile Fragment Shader:\n' + gl.getShaderInfoLog(fs));
2018-01-20 00:37:52 +00:00
}
2017-08-03 20:02:57 +00:00
2018-01-20 00:37:52 +00:00
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
{
throw new Error('Failed to link program:\n' + gl.getProgramInfoLog(program));
2018-01-20 00:37:52 +00:00
}
return program;
2018-01-17 21:25:43 +00:00
},
2018-01-20 00:37:52 +00:00
createVertexBuffer: function (initialDataOrSize, bufferUsage)
2018-01-17 21:25:43 +00:00
{
2018-01-20 00:37:52 +00:00
var gl = this.gl;
var vertexBuffer = gl.createBuffer();
2018-01-20 00:37:52 +00:00
this.setVertexBuffer(vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, initialDataOrSize, bufferUsage);
this.setVertexBuffer(null);
return vertexBuffer;
},
2018-01-25 00:15:51 +00:00
createIndexBuffer: function (initialDataOrSize, bufferUsage)
{
2018-01-20 00:37:52 +00:00
var gl = this.gl;
var indexBuffer = gl.createBuffer();
this.setIndexBuffer(indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, initialDataOrSize, bufferUsage);
this.setIndexBuffer(null);
return indexBuffer;
2018-01-20 04:05:56 +00:00
},
2018-01-25 00:15:51 +00:00
deleteTexture: function (texture)
{
return this;
},
deleteFramebuffer: function (framebuffer)
{
return this;
},
deleteProgram: function (program)
{
return this;
},
deleteBuffer: function (vertexBuffer)
{
return this;
},
2018-01-20 04:05:56 +00:00
/* Rendering Functions */
2018-01-24 03:57:33 +00:00
preRenderCamera: function (camera)
{
2018-01-24 18:55:23 +00:00
this.pushScissor(camera.x, camera.y, camera.width, camera.height);
2018-01-24 03:57:33 +00:00
if (camera.backgroundColor.alphaGL > 0)
{
var color = camera.backgroundColor;
var FlatTintPipeline = this.pipelines.FlatTintPipeline;
FlatTintPipeline.batchFillRect(
0, 0, 1, 1, 0,
camera.x, camera.y, camera.width, camera.height,
Utils.getTintFromFloats(color.redGL, color.greenGL, color.blueGL, 1.0),
color.alphaGL,
1, 0, 0, 1, 0, 0,
[1, 0, 0, 1, 0, 0]
);
FlatTintPipeline.flush();
}
},
postRenderCamera: function (camera)
{
if (camera._fadeAlpha > 0 || camera._flashAlpha > 0)
{
var FlatTintPipeline = this.pipelines.FlatTintPipeline;
// Fade
FlatTintPipeline.batchFillRect(
0, 0, 1, 1, 0,
camera.x, camera.y, camera.width, camera.height,
Utils.getTintFromFloats(camera._fadeRed, camera._fadeGreen, camera._fadeBlue, 1.0),
camera._fadeAlpha,
1, 0, 0, 1, 0, 0,
[1, 0, 0, 1, 0, 0]
);
// Flash
FlatTintPipeline.batchFillRect(
0, 0, 1, 1, 0,
camera.x, camera.y, camera.width, camera.height,
Utils.getTintFromFloats(camera._flashRed, camera._flashGreen, camera._flashBlue, 1.0),
camera._flashAlpha,
1, 0, 0, 1, 0, 0,
[1, 0, 0, 1, 0, 0]
);
FlatTintPipeline.flush();
}
2018-01-24 18:55:23 +00:00
this.popScissor();
2018-01-24 03:57:33 +00:00
},
2018-01-20 04:05:56 +00:00
preRender: function ()
{
if (this.contextLost) return;
2018-01-22 22:51:15 +00:00
var gl = this.gl;
var color = this.config.backgroundColor;
2018-01-26 23:17:11 +00:00
var pipelines = this.pipelines;
2018-01-22 22:51:15 +00:00
// Bind custom framebuffer here
gl.clearColor(color.redGL, color.greenGL, color.blueGL, color.alphaGL);
if (this.config.clearBeforeRender)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
2018-01-26 23:17:11 +00:00
for (var key in pipelines)
{
pipelines[key].onPreRender();
}
2018-01-20 04:05:56 +00:00
},
render: function (scene, children, interpolationPercentage, camera)
{
if (this.contextLost) return;
2018-01-22 21:21:47 +00:00
var gl = this.gl;
var list = children.list;
var childCount = list.length;
2018-01-29 21:46:48 +00:00
var pipelines = this.pipelines;
for (var key in pipelines)
{
pipelines[key].onRender(scene, camera);
}
2018-01-22 21:37:47 +00:00
2018-01-24 03:57:33 +00:00
this.preRenderCamera(camera);
2018-01-22 21:37:47 +00:00
2018-01-22 21:21:47 +00:00
for (var index = 0; index < childCount; ++index)
{
var child = list[index];
if (!child.willRender())
{
continue;
}
2018-01-22 21:37:47 +00:00
if (child.blendMode !== this.currentBlendMode)
{
this.setBlendMode(child.blendMode);
}
if (child.mask)
{
child.mask.preRenderWebGL(this, child, camera);
}
2018-01-22 21:21:47 +00:00
child.renderWebGL(this, child, interpolationPercentage, camera);
2018-01-22 21:37:47 +00:00
if (child.mask)
{
child.mask.postRenderWebGL(this, child);
}
}
this.flush();
2018-01-24 03:57:33 +00:00
this.setBlendMode(CONST.BlendModes.NORMAL);
this.postRenderCamera(camera);
2018-01-20 04:05:56 +00:00
},
postRender: function ()
{
if (this.contextLost) return;
2018-01-22 22:51:15 +00:00
// Unbind custom framebuffer here
2018-01-20 04:05:56 +00:00
if (this.snapshotState.callback)
{
this.snapshotState.callback(WebGLSnapshot(this.canvas, this.snapshotState.type, this.snapshotState.encoder));
this.snapshotState.callback = null;
}
2018-01-26 23:17:11 +00:00
var pipelines = this.pipelines;
for (var key in pipelines)
{
pipelines[key].onPostRender();
}
2018-01-20 04:05:56 +00:00
},
snapshot: function (callback, type, encoderOptions)
{
this.snapshotState.callback = callback;
this.snapshotState.type = type;
this.snapshotState.encoder = encoderOptions;
return this;
},
2018-01-24 00:40:20 +00:00
canvasToTexture: function (srcCanvas, dstTexture, shouldReallocate, scaleMode)
2018-01-20 04:05:56 +00:00
{
var gl = this.gl;
if (!dstTexture)
{
var wrapping = gl.CLAMP_TO_EDGE;
if (IsSizePowerOfTwo(srcCanvas.width, srcCanvas.height))
{
wrapping = gl.REPEAT;
}
dstTexture = this.createTexture2D(0, gl.NEAREST, gl.NEAREST, wrapping, wrapping, gl.RGBA, srcCanvas, srcCanvas.width, srcCanvas.height, true);
2018-01-20 04:05:56 +00:00
}
else
{
2018-01-24 03:03:43 +00:00
this.setTexture2D(dstTexture, 0);
2018-01-20 04:05:56 +00:00
if (!shouldReallocate)
{
gl.texSubImage2D(0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, srcCanvas);
}
else
{
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, srcCanvas);
dstTexture.width = srcCanvas.width;
dstTexture.height = srcCanvas.height;
}
2018-01-24 03:03:43 +00:00
this.setTexture2D(null, 0);
2018-01-20 04:05:56 +00:00
}
return dstTexture;
},
setTextureFilter: function (texture, filter)
{
var gl = this.gl;
var glFilter = [ gl.LINEAR, gl.NEAREST ][filter];
this.setTexture2D(texture, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, glFilter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, glFilter);
this.setTexture2D(null, 0);
2018-01-22 21:21:47 +00:00
return this;
},
setFloat1: function (program, name, x)
{
this.setProgram(program);
this.gl.uniform1f(this.gl.getUniformLocation(program, name), x);
return this;
},
setFloat2: function (program, name, x, y)
{
this.setProgram(program);
this.gl.uniform2f(this.gl.getUniformLocation(program, name), x, y);
return this;
},
setFloat3: function (program, name, x, y, z)
{
this.setProgram(program);
this.gl.uniform3f(this.gl.getUniformLocation(program, name), x, y, z);
return this;
},
setFloat4: function (program, name, x, y, z, w)
{
this.setProgram(program);
this.gl.uniform4f(this.gl.getUniformLocation(program, name), x, y, z, w);
return this;
},
setInt1: function (program, name, x)
{
this.setProgram(program);
this.gl.uniform1i(this.gl.getUniformLocation(program, name), x);
return this;
},
setInt2: function (program, name, x, y)
{
this.setProgram(program);
this.gl.uniform2i(this.gl.getUniformLocation(program, name), x, y);
return this;
},
setInt3: function (program, name, x, y, z)
{
this.setProgram(program);
this.gl.uniform3i(this.gl.getUniformLocation(program, name), x, y, z);
return this;
},
setInt4: function (program, name, x, y, z, w)
{
this.setProgram(program);
this.gl.uniform4i(this.gl.getUniformLocation(program, name), x, y, z, w);
return this;
},
setMatrix2: function (program, name, transpose, matrix)
{
this.setProgram(program);
this.gl.uniformMatrix2fv(this.gl.getUniformLocation(program, name), transpose, matrix);
return this;
},
setMatrix3: function (program, name, transpose, matrix)
{
this.setProgram(program);
this.gl.uniformMatrix3fv(this.gl.getUniformLocation(program, name), transpose, matrix);
return this;
},
setMatrix4: function (program, name, transpose, matrix)
{
this.setProgram(program);
this.gl.uniformMatrix4fv(this.gl.getUniformLocation(program, name), transpose, matrix);
2018-01-20 04:05:56 +00:00
return this;
},
destroy: function ()
{
var gl = this.gl;
// Clear-up anything that should be cleared :)
for (var key in this.pipelines)
{
this.pipelines[key].destroy();
delete this.pipelines[key];
}
for (var index = 0; index < this.nativeTextures.length; ++index)
{
this.deleteTexture(this.nativeTextures[index]);
delete this.nativeTextures[index];
}
if (this.hasExtension('WEBGL_lose_context'))
{
this.getExtension('WEBGL_lose_context').loseContext();
}
delete this.gl;
delete this.game;
this.contextLost = true;
this.extensions = {};
this.nativeTextures.length = 0;
2017-01-23 21:42:47 +00:00
}
});
2016-12-07 02:28:22 +00:00
2018-01-17 21:25:43 +00:00
module.exports = WebGLRenderer;