Effect Layer

This commit is contained in:
Felipe Alfonso 2017-04-06 22:49:15 -03:00
parent 6fe063b1d2
commit 8c479a56c0
26 changed files with 537 additions and 198 deletions

View file

@ -0,0 +1,7 @@
var RenderTarget = {
renderTarget: null
};
module.exports = RenderTarget;

View file

@ -9,6 +9,7 @@ module.exports = {
Flip: require('./Flip'), Flip: require('./Flip'),
GetBounds: require('./GetBounds'), GetBounds: require('./GetBounds'),
Origin: require('./Origin'), Origin: require('./Origin'),
RenderTarget: require('./RenderTarget'),
ScaleMode: require('./ScaleMode'), ScaleMode: require('./ScaleMode'),
Size: require('./Size'), Size: require('./Size'),
Texture: require('./Texture'), Texture: require('./Texture'),

View file

@ -169,7 +169,7 @@ var DynamicBitmapTextWebGLRenderer = function (renderer, src, interpolationPerce
blitterBatch.flush(); blitterBatch.flush();
} }
renderer.setBatch(blitterBatch, texture); renderer.setRenderer(blitterBatch, texture);
vertexOffset = vertexDataBuffer.allocate(20); vertexOffset = vertexDataBuffer.allocate(20);
blitterBatch.elementCount += 6; blitterBatch.elementCount += 6;

View file

@ -135,7 +135,7 @@ var BitmapTextWebGLRenderer = function (renderer, src, interpolationPercentage,
blitterBatch.flush(); blitterBatch.flush();
} }
renderer.setBatch(blitterBatch, texture); renderer.setRenderer(blitterBatch, texture);
vertexOffset = vertexDataBuffer.allocate(20); vertexOffset = vertexDataBuffer.allocate(20);
blitterBatch.elementCount += 6; blitterBatch.elementCount += 6;

View file

@ -44,7 +44,7 @@ var BlitterWebGLRenderer = function (renderer, src, interpolationPercentage, cam
blitterBatch.flush(); blitterBatch.flush();
} }
renderer.setBatch(blitterBatch, frame.texture.source[frame.sourceIndex].glTexture); renderer.setRenderer(blitterBatch, frame.texture.source[frame.sourceIndex].glTexture);
vertexOffset = vertexDataBuffer.allocate(20); vertexOffset = vertexDataBuffer.allocate(20);
blitterBatch.elementCount += 6; blitterBatch.elementCount += 6;
x += frame.x; x += frame.x;

View file

@ -0,0 +1,75 @@
var Class = require('../../utils/Class');
var GameObject = require('../GameObject');
var Components = require('../../components');
var Render = require('./EffectLayerRender');
var TexturedAndNormalizedTintedShader = require('../../renderer/webgl/shaders/TexturedAndNormalizedTintedShader');
var EffectLayer = new Class({
Extends: GameObject,
Mixins: [
Components.Flip,
Components.Alpha,
Components.Transform,
Components.Visible,
Components.Size,
Components.Origin,
Components.RenderTarget,
Components.BlendMode,
Render
],
initialize:
function EffectLayer(state, x, y, width, height, effectName, fragmentShader)
{
var resourceManager = state.game.renderer.resourceManager;
var gl;
this.dstRenderTarget = null
this.dstRenderTexture = null;
this.dstShader = null;
if (resourceManager !== undefined)
{
gl = state.game.renderer.gl;
this.dstShader = resourceManager.createShader(effectName, {
vert: TexturedAndNormalizedTintedShader.vert,
frag: fragmentShader
});
this.dstRenderTexture = resourceManager.createTexture(
0,
gl.LINEAR, gl.LINEAR,
gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE,
gl.RGBA,
null, width, height
);
this.dstRenderTarget = resourceManager.createRenderTarget(width, height, this.dstRenderTexture, null);
//state.game.renderer.currentTexture = null; // force rebinding of prev texture
}
this.flipY = true;
this.setPosition(x, y);
this.setSize(width, height);
this.setOrigin(0, 0);
},
add: function (gameObject)
{
if (gameObject.renderTarget !== undefined)
{
gameObject.renderTarget = this.dstRenderTarget;
}
},
remove: function (gameObject)
{
if (gameObject.renderTarget !== undefined)
{
gameObject.renderTarget = null;
}
}
});
module.exports = EffectLayer;

View file

@ -0,0 +1,7 @@
var EffectLayerCanvasRenderer = function (renderer, src, interpolationPercentage, camera)
{
};
module.exports = EffectLayerCanvasRenderer;

View file

@ -0,0 +1,20 @@
var EffectLayer = require('./EffectLayer');
var FactoryContainer = require('../../gameobjects/FactoryContainer');
var EffectLayerFactory = {
KEY: 'effectLayer',
add: function (x, y, width, height, effectName, fragmentShader)
{
return this.children.add(new EffectLayer(this.state, x, y, width, height, effectName, fragmentShader));
},
make: function (x, y, width, height, effectName, fragmentShader)
{
return new EffectLayer(this.state, x, y, width, height, effectName, fragmentShader);
}
};
module.exports = FactoryContainer.register(EffectLayerFactory);

View file

@ -0,0 +1,6 @@
module.exports = {
renderCanvas: require('./EffectLayerCanvasRenderer'),
renderWebGL: require('./EffectLayerWebGLRenderer')
};

View file

@ -0,0 +1,11 @@
var EffectLayerWebGLRenderer = function (renderer, src, interpolationPercentage, camera)
{
if (this.renderMask !== this.renderFlags)
{
return;
}
renderer.effectRenderer.renderEffect(src, camera, src.dstRenderTexture, src.width, src.height);
};
module.exports = EffectLayerWebGLRenderer;

View file

@ -95,7 +95,7 @@ var GraphicsWebGLRenderer = function (renderer, src, interpolationPercentage, ca
mve = sre * cma + srf * cmc + cme; mve = sre * cma + srf * cmc + cme;
mvf = sre * cmb + srf * cmd + cmf; mvf = sre * cmb + srf * cmd + cmf;
renderer.setBatch(shapeBatch, null); renderer.setRenderer(shapeBatch, null);
for (var cmdIndex = 0, cmdLength = commandBuffer.length; cmdIndex < cmdLength; ++cmdIndex) for (var cmdIndex = 0, cmdLength = commandBuffer.length; cmdIndex < cmdLength; ++cmdIndex)
{ {

View file

@ -14,6 +14,7 @@ var Image = new Class({
Components.Flip, Components.Flip,
Components.GetBounds, Components.GetBounds,
Components.Origin, Components.Origin,
Components.RenderTarget,
Components.ScaleMode, Components.ScaleMode,
Components.Size, Components.Size,
Components.Texture, Components.Texture,

View file

@ -11,6 +11,7 @@ require('./graphics/GraphicsFactory');
require('./text/static/TextFactory'); require('./text/static/TextFactory');
require('./layer/LayerFactory'); require('./layer/LayerFactory');
require('./zone/ZoneFactory'); require('./zone/ZoneFactory');
require('./effectlayer/EffectLayerFactory');
// Phaser.GameObjects // Phaser.GameObjects
@ -27,6 +28,7 @@ module.exports = {
Layer: require('./layer/Layer'), Layer: require('./layer/Layer'),
Sprite: require('./sprite/Sprite'), Sprite: require('./sprite/Sprite'),
Text: require('./text/static/Text'), Text: require('./text/static/Text'),
Zone: require('./zone/Zone') Zone: require('./zone/Zone'),
EffectLayer: require('./effectlayer/EffectLayer')
}; };

View file

@ -14,6 +14,7 @@ var Sprite = new Class({
Components.Flip, Components.Flip,
Components.GetBounds, Components.GetBounds,
Components.Origin, Components.Origin,
Components.RenderTarget,
Components.ScaleMode, Components.ScaleMode,
Components.Size, Components.Size,
Components.Texture, Components.Texture,

View file

@ -1 +0,0 @@
module.exports = (window.WebGLRenderingContext ? WebGLRenderingContext : {});

View file

@ -1,11 +1,11 @@
var Resources = require('./resources'); var Resources = require('./resources');
var GL = require('./GL');
var ResourceManager = function (gl) var ResourceManager = function (gl)
{ {
this.gl = gl; this.gl = gl;
/* Maybe add pooling here */ /* Maybe add pooling here */
this.shaderCache = {}; this.shaderCache = {};
this.shaderCount = 0;
}; };
ResourceManager.prototype.constructor = ResourceManager; ResourceManager.prototype.constructor = ResourceManager;
@ -20,37 +20,37 @@ ResourceManager.prototype = {
var colorRenderbufferObject = null; var colorRenderbufferObject = null;
var complete = 0; var complete = 0;
gl.bindFramebuffer(GL.FRAMEBUFFER, framebufferObject) gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferObject)
if (depthStencilBuffer !== undefined && depthStencilBuffer !== null) if (depthStencilBuffer !== undefined && depthStencilBuffer !== null)
{ {
depthStencilBuffer.isRenderTexture = true; depthStencilBuffer.isRenderTexture = true;
gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D, depthStencilBuffer.texture, depthStencilBuffer.mipLevel); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilBuffer.texture, depthStencilBuffer.mipLevel);
} }
else else
{ {
depthStencilRenderbufferObject = gl.createRenderbuffer(); depthStencilRenderbufferObject = gl.createRenderbuffer();
gl.bindRenderbuffer(GL.RENDERBUFFER, depthStencilRenderbufferObject); gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilRenderbufferObject);
gl.renderbufferStorage(GL.RENDERBUFFER, GL.DEPTH_STENCIL, width, height); gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
gl.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.RENDERBUFFER, depthStencilRenderbufferObject); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilRenderbufferObject);
} }
if (colorBuffer !== undefined && colorBuffer !== null) if (colorBuffer !== undefined && colorBuffer !== null)
{ {
colorBuffer.isRenderTexture = true; colorBuffer.isRenderTexture = true;
gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, colorBuffer.texture, colorBuffer.mipLevel); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorBuffer.texture, colorBuffer.mipLevel);
} }
else else
{ {
colorRenderbufferObject = gl.createRenderbuffer(); colorRenderbufferObject = gl.createRenderbuffer();
gl.bindRenderbuffer(GL.RENDERBUFFER, colorRenderbufferObject); gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderbufferObject);
gl.renderbufferStorage(GL.RENDERBUFFER, GL.RGBA4, width, height); gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, width, height);
gl.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.RENDERBUFFER, colorRenderbufferObject); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRenderbufferObject);
} }
complete = gl.checkFramebufferStatus(GL.FRAMEBUFFER); complete = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (complete !== GL.FRAMEBUFFER_COMPLETE) if (complete !== gl.FRAMEBUFFER_COMPLETE)
{ {
var errors = { var errors = {
36054: 'Incomplete Attachment', 36054: 'Incomplete Attachment',
@ -58,11 +58,11 @@ ResourceManager.prototype = {
36057: 'Incomplete Dimensions', 36057: 'Incomplete Dimensions',
36061: 'Framebuffer Unsupported' 36061: 'Framebuffer Unsupported'
}; };
alert('Framebuffer incomplete. Framebuffer status: ' + errors[complete]);
throw new Error('Framebuffer incomplete. Framebuffer status: ' + errors[complete]); throw new Error('Framebuffer incomplete. Framebuffer status: ' + errors[complete]);
} }
gl.bindFramebuffer(GL.FRAMEBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return new Resources.RenderTarget( return new Resources.RenderTarget(
framebufferObject, framebufferObject,
@ -81,11 +81,12 @@ ResourceManager.prototype = {
switch (target) switch (target)
{ {
case GL.ARRAY_BUFFER: case gl.ARRAY_BUFFER:
return new Resources.VertexBuffer(gl, bufferObject); return new Resources.VertexBuffer(gl, bufferObject);
case GL.ELEMENT_ARRAY_BUFFER: case gl.ELEMENT_ARRAY_BUFFER:
return new Resources.IndexBuffer(gl, bufferObject); return new Resources.IndexBuffer(gl, bufferObject);
default: default:
alert('Invalid Buffer Target');
throw new Error('Invalid Buffer Target'); throw new Error('Invalid Buffer Target');
} }
@ -97,34 +98,40 @@ ResourceManager.prototype = {
var gl = this.gl; var gl = this.gl;
var texture = gl.createTexture(); var texture = gl.createTexture();
gl.bindTexture(GL.TEXTURE_2D, texture); gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, minFilter); 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_MAG_FILTER, magFilter);
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, wrapT); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
if (pixels === null || pixels === undefined) if (pixels === null || pixels === undefined)
{ {
gl.texImage2D(GL.TEXTURE_2D, mipLevel, format, width, height, 0, format, GL.UNSIGNED_BYTE, null); gl.texImage2D(gl.TEXTURE_2D, mipLevel, format, width, height, 0, format, gl.UNSIGNED_BYTE, null);
} }
else else
{ {
gl.texImage2D(GL.TEXTURE_2D, mipLevel, format, format, GL.UNSIGNED_BYTE, pixels); gl.texImage2D(gl.TEXTURE_2D, mipLevel, format, format, gl.UNSIGNED_BYTE, pixels);
width = pixels.width; width = pixels.width;
height = pixels.height; height = pixels.height;
} }
gl.bindTexture(gl.TEXTURE_2D, null);
return new Resources.Texture(texture, width, height); return new Resources.Texture(texture, width, height);
}, },
createShader: function (shaderName, shaderSources) createShader: function (shaderName, shaderSources)
{ {
if (shaderName === null || shaderName === undefined)
{
shaderName += 'Shader' + this.shaderCount;
this.shaderCount += 1;
}
if (!(shaderName in this.shaderCache)) if (!(shaderName in this.shaderCache))
{ {
var gl = this.gl; var gl = this.gl;
var program = gl.createProgram(); var program = gl.createProgram();
var vertShader = gl.createShader(GL.VERTEX_SHADER); var vertShader = gl.createShader(gl.VERTEX_SHADER);
var fragShader = gl.createShader(GL.FRAGMENT_SHADER); var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
var error; var error;
var shader; var shader;
@ -136,15 +143,17 @@ ResourceManager.prototype = {
error = gl.getShaderInfoLog(vertShader); error = gl.getShaderInfoLog(vertShader);
if (error.length > 0) if (error && error.length > 0)
{ {
alert('Vertex Shader Compilation Error.\n' + error);
throw new Error('Vertex Shader Compilation Error.\n' + error); throw new Error('Vertex Shader Compilation Error.\n' + error);
} }
error = gl.getShaderInfoLog(fragShader); error = gl.getShaderInfoLog(fragShader);
if (error.length > 0) if (error && error.length > 0)
{ {
alert('Fragment Shader Compilation Error.\n' + error);
throw new Error('Fragment Shader Compilation Error.\n' + error); throw new Error('Fragment Shader Compilation Error.\n' + error);
} }
@ -152,12 +161,13 @@ ResourceManager.prototype = {
gl.attachShader(program, fragShader); gl.attachShader(program, fragShader);
gl.linkProgram(program); gl.linkProgram(program);
error = gl.getProgramParameter(program, GL.LINK_STATUS); error = gl.getProgramParameter(program, gl.LINK_STATUS);
if (error === 0) if (error === 0)
{ {
error = gl.getProgramInfoLog(program); error = gl.getProgramInfoLog(program);
alert('Program Linking Error.\n' + error);
throw new Error('Program Linking Error.\n' + error); throw new Error('Program Linking Error.\n' + error);
} }
@ -171,16 +181,6 @@ ResourceManager.prototype = {
} }
}, },
createOutputStage: function ()
{
var outputStage = new Resources.OutputStage();
outputStage.setDefaultDepthStencilState();
outputStage.setNoBlending();
return outputStage;
},
deleteShader: function (shader) deleteShader: function (shader)
{ {
var storedShader = this.shaderCache[shader.name] var storedShader = this.shaderCache[shader.name]

View file

@ -10,6 +10,7 @@ var BlitterBatch = require('./renderers/blitterbatch/BlitterBatch');
var QuadBatch = require('./renderers/quadbatch/QuadBatch'); var QuadBatch = require('./renderers/quadbatch/QuadBatch');
var SpriteBatch = require('./renderers/spritebatch/SpriteBatch'); var SpriteBatch = require('./renderers/spritebatch/SpriteBatch');
var ShapeBatch = require('./renderers/shapebatch/ShapeBatch'); var ShapeBatch = require('./renderers/shapebatch/ShapeBatch');
var EffectRenderer = require('./renderers/effectrenderer/EffectRenderer');
var BlendModes = require('../BlendModes'); var BlendModes = require('../BlendModes');
var ScaleModes = require('../ScaleModes'); var ScaleModes = require('../ScaleModes');
var ResourceManager = require('./ResourceManager'); var ResourceManager = require('./ResourceManager');
@ -51,11 +52,13 @@ var WebGLRenderer = function (game)
this.aaQuadBatch = null; this.aaQuadBatch = null;
this.spriteBatch = null; this.spriteBatch = null;
this.shapeBatch = null; this.shapeBatch = null;
this.effectRenderer = null;
this.currentRenderer = null; this.currentRenderer = null;
this.currentTexture = null; this.currentTexture = null;
this.shaderCache = {}; this.shaderCache = {};
this.currentShader = null; this.currentShader = null;
this.resourceManager = null; this.resourceManager = null;
this.currentRenderTarget = null;
this.init(); this.init();
}; };
@ -108,6 +111,7 @@ WebGLRenderer.prototype = {
this.quadBatch = this.addRenderer(new QuadBatch(this.game, gl, this)); this.quadBatch = this.addRenderer(new QuadBatch(this.game, gl, this));
this.spriteBatch = this.addRenderer(new SpriteBatch(this.game, gl, this)); this.spriteBatch = this.addRenderer(new SpriteBatch(this.game, gl, this));
this.shapeBatch = this.addRenderer(new ShapeBatch(this.game, gl, this)); this.shapeBatch = this.addRenderer(new ShapeBatch(this.game, gl, this));
this.effectRenderer = this.addRenderer(new EffectRenderer(this.game, gl, this));
}, },
createTexture: function (source) createTexture: function (source)
@ -138,7 +142,7 @@ WebGLRenderer.prototype = {
); );
} }
this.currentTexture = source.glTexture; this.currentTexture = null;
}, },
setTexture: function (texture) setTexture: function (texture)
@ -166,19 +170,50 @@ WebGLRenderer.prototype = {
} }
}, },
setBatch: function (batch, texture, camera) setRenderer: function (renderer, texture, camera, renderTarget)
{ {
var gl = this.gl;
this.setTexture(texture); this.setTexture(texture);
this.setRenderTarget(renderTarget);
if (this.currentRenderer !== batch)
if (this.currentRenderer !== renderer)
{ {
if (this.currentRenderer) if (this.currentRenderer)
{ {
this.currentRenderer.flush(); this.currentRenderer.flush();
} }
this.currentRenderer = batch; this.currentRenderer = renderer;
}
},
setRenderTarget: function (renderTarget)
{
var gl = this.gl;
if (this.currentRenderTarget !== renderTarget)
{
if (this.currentRenderer)
{
this.currentRenderer.flush();
}
if (renderTarget !== null)
{
gl.bindFramebuffer(gl.FRAMEBUFFER, renderTarget.framebufferObject);
gl.viewport(0, 0, renderTarget.width, renderTarget.height);
if (renderTarget.shouldClear)
{
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
renderTarget.shouldClear = false;
}
}
else
{
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, this.width, this.height);
}
this.currentRenderTarget = renderTarget;
} }
}, },
@ -245,6 +280,7 @@ WebGLRenderer.prototype = {
// Could move to the State Systems or MainLoop // Could move to the State Systems or MainLoop
var gl = this.gl; var gl = this.gl;
var scissor = (camera.x !== 0 || camera.y !== 0 || camera.width !== gl.canvas.width || camera.height !== gl.canvas.height); var scissor = (camera.x !== 0 || camera.y !== 0 || camera.width !== gl.canvas.width || camera.height !== gl.canvas.height);
this.setRenderTarget(null);
if (scissor) if (scissor)
{ {
@ -252,6 +288,8 @@ WebGLRenderer.prototype = {
gl.scissor(camera.x, (gl.drawingBufferHeight - camera.y - camera.height), camera.width, camera.height); gl.scissor(camera.x, (gl.drawingBufferHeight - camera.y - camera.height), camera.width, camera.height);
} }
// We could either clear color or render a quad // We could either clear color or render a quad
var color = this.game.config.backgroundColor;
gl.clearColor(color.redGL, color.greenGL, color.blueGL, color.alphaGL);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
var list = children.list; var list = children.list;
@ -260,13 +298,13 @@ WebGLRenderer.prototype = {
{ {
var child = list[index]; var child = list[index];
// Setting blend mode if needed // Setting blend mode if needed
var batch = this.currentRenderer; var renderer = this.currentRenderer;
var newBlendMode = child.blendMode; var newBlendMode = child.blendMode;
if (this.blendMode !== newBlendMode) if (this.blendMode !== newBlendMode)
{ {
if (batch) if (renderer)
{ {
batch.flush(); renderer.flush();
} }
var blend = this.blendModes[newBlendMode]; var blend = this.blendModes[newBlendMode];
gl.enable(gl.BLEND); gl.enable(gl.BLEND);
@ -282,10 +320,10 @@ WebGLRenderer.prototype = {
} }
// drawing child // drawing child
child.renderWebGL(this, child, interpolationPercentage, camera); child.renderWebGL(this, child, interpolationPercentage, camera);
batch = this.currentRenderer; renderer = this.currentRenderer;
if (batch && batch.isFull()) if (renderer && renderer.isFull())
{ {
batch.flush(); renderer.flush();
} }
} }
if (this.currentRenderer) if (this.currentRenderer)
@ -343,13 +381,13 @@ WebGLRenderer.prototype = {
setBlendMode: function (newBlendMode) setBlendMode: function (newBlendMode)
{ {
var gl = this.gl; var gl = this.gl;
var batch = this.currentRenderer; var renderer = this.currentRenderer;
var blend = null; var blend = null;
if (this.blendMode !== newBlendMode) if (this.blendMode !== newBlendMode)
{ {
if (batch) if (renderer)
batch.flush(); renderer.flush();
blend = this.blendModes[newBlendMode]; blend = this.blendModes[newBlendMode];
gl.enable(gl.BLEND); gl.enable(gl.BLEND);
if (blend.length > 2) if (blend.length > 2)

View file

@ -0,0 +1,258 @@
var DataBuffer32 = require('../../utils/DataBuffer32');
var DataBuffer16 = require('../../utils/DataBuffer16');
var TransformMatrix = require('../../../../components/TransformMatrix');
var TexturedAndNormalizedTintedShader = require('../../shaders/TexturedAndNormalizedTintedShader');
var PHASER_CONST = require('../../../../const');
var CONST = require('./const');
var EffectRenderer = function (game, gl, manager)
{
this.game = game;
this.type = PHASER_CONST.WEBGL;
this.view = game.canvas;
this.resolution = game.config.resolution;
this.width = game.config.width * game.config.resolution;
this.height = game.config.height * game.config.resolution;
this.glContext = gl;
this.maxSprites = null;
this.shader = null;
this.vertexBufferObject = null;
this.indexBufferObject = null;
this.vertexDataBuffer = null;
this.indexDataBuffer = null;
this.elementCount = 0;
this.currentTexture2D = null;
this.viewMatrixLocation = null;
this.tempMatrix = new TransformMatrix();
// All of these settings will be able to be controlled via the Game Config
this.config = {
clearBeforeRender: true,
transparent: false,
autoResize: false,
preserveDrawingBuffer: false,
WebGLContextOptions: {
alpha: true,
antialias: true,
premultipliedAlpha: true,
stencil: true,
preserveDrawingBuffer: false
}
};
this.manager = manager;
this.dirty = false;
this.init(this.glContext);
};
EffectRenderer.prototype.constructor = EffectRenderer;
EffectRenderer.prototype = {
init: function (gl)
{
var vertexDataBuffer = new DataBuffer32(CONST.VERTEX_SIZE * CONST.QUAD_VERTEX_COUNT * CONST.MAX_QUADS);
var indexDataBuffer = new DataBuffer16(CONST.INDEX_SIZE * CONST.QUAD_INDEX_COUNT * CONST.MAX_QUADS);
var shader = this.manager.resourceManager.createShader('TexturedAndNormalizedTintedShader', TexturedAndNormalizedTintedShader);
var indexBufferObject = this.manager.resourceManager.createBuffer(gl.ELEMENT_ARRAY_BUFFER, indexDataBuffer.getByteCapacity(), gl.STATIC_DRAW);
var vertexBufferObject = this.manager.resourceManager.createBuffer(gl.ARRAY_BUFFER, vertexDataBuffer.getByteCapacity(), gl.STREAM_DRAW);
var viewMatrixLocation = shader.getUniformLocation('u_view_matrix');
var indexBuffer = indexDataBuffer.uintView;
var max = CONST.MAX_QUADS * CONST.QUAD_INDEX_COUNT;
this.vertexDataBuffer = vertexDataBuffer;
this.indexDataBuffer = indexDataBuffer;
this.shader = shader;
this.indexBufferObject = indexBufferObject;
this.vertexBufferObject = vertexBufferObject;
this.viewMatrixLocation = viewMatrixLocation;
vertexBufferObject.addAttribute(0, 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 0);
vertexBufferObject.addAttribute(1, 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 8);
vertexBufferObject.addAttribute(2, 3, gl.UNSIGNED_BYTE, true, CONST.VERTEX_SIZE, 16);
vertexBufferObject.addAttribute(3, 1, gl.FLOAT, false, CONST.VERTEX_SIZE, 20);
// Populate the index buffer only once
for (var indexA = 0, indexB = 0; indexA < max; indexA += CONST.QUAD_INDEX_COUNT, indexB += CONST.QUAD_VERTEX_COUNT)
{
indexBuffer[indexA + 0] = indexB + 0;
indexBuffer[indexA + 1] = indexB + 1;
indexBuffer[indexA + 2] = indexB + 2;
indexBuffer[indexA + 3] = indexB + 0;
indexBuffer[indexA + 4] = indexB + 2;
indexBuffer[indexA + 5] = indexB + 3;
}
indexBufferObject.updateResource(indexBuffer, 0);
this.resize(this.width, this.height, this.game.config.resolution);
},
isFull: function ()
{
return (this.vertexDataBuffer.getByteLength() >= this.vertexDataBuffer.getByteCapacity());
},
bind: function (shader)
{
if (shader === undefined)
{
this.shader.bind();
}
else
{
shader.bind();
this.resize(this.width, this.height, this.game.config.resolution, shader);
}
this.indexBufferObject.bind();
this.vertexBufferObject.bind();
},
flush: function (shader)
{
var gl = this.glContext;
var vertexDataBuffer = this.vertexDataBuffer;
if (this.elementCount === 0)
{
return;
}
this.bind(shader);
this.vertexBufferObject.updateResource(vertexDataBuffer.getUsedBufferAsFloat(), 0);
gl.drawElements(gl.TRIANGLES, this.elementCount, gl.UNSIGNED_SHORT, 0);
vertexDataBuffer.clear();
this.elementCount = 0;
},
resize: function (width, height, resolution, shader)
{
var gl = this.glContext;
var activeShader = shader !== undefined ? shader : this.shader;
this.width = width * resolution;
this.height = height * resolution;
activeShader.setConstantMatrix4x4(
activeShader.getUniformLocation('u_view_matrix'),
new Float32Array([
2 / this.width, 0, 0, 0,
0, -2 / this.height, 0, 0,
0, 0, 1, 1,
-1, 1, 0, 0
])
);
},
destroy: function ()
{
this.manager.resourceManager.deleteShader(this.shader);
this.manager.resourceManager.deleteBuffer(this.indexBufferObject);
this.manager.resourceManager.deleteBuffer(this.vertexBufferObject);
this.shader = null;
this.indexBufferObject = null;
this.vertexBufferObject = null;
},
renderEffect: function (gameObject, camera, texture, textureWidth, textureHeight)
{
var tempMatrix = this.tempMatrix;
var alpha = 16777216;
var vertexDataBuffer = this.vertexDataBuffer;
var vertexBufferObjectF32 = vertexDataBuffer.floatView;
var vertexBufferObjectU32 = vertexDataBuffer.uintView;
var vertexOffset = 0;
var width = textureWidth * (gameObject.flipX ? -1 : 1);
var height = textureHeight * (gameObject.flipY ? -1 : 1);
var translateX = gameObject.x - camera.scrollX;
var translateY = gameObject.y - camera.scrollY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;
var tempMatrixMatrix = tempMatrix.matrix;
var x = -gameObject.displayOriginX + ((textureWidth) * (gameObject.flipX ? 1 : 0.0));
var y = -gameObject.displayOriginY + ((textureHeight) * (gameObject.flipY ? 1 : 0.0));
var xw = x + width;
var yh = y + height;
var cameraMatrix = camera.matrix.matrix;
var mva, mvb, mvc, mvd, mve, mvf, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3;
var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf;
var alpha = gameObject.alpha;
tempMatrix.applyITRS(translateX, translateY, rotation, scaleX, scaleY);
sra = tempMatrixMatrix[0];
srb = tempMatrixMatrix[1];
src = tempMatrixMatrix[2];
srd = tempMatrixMatrix[3];
sre = tempMatrixMatrix[4];
srf = tempMatrixMatrix[5];
cma = cameraMatrix[0];
cmb = cameraMatrix[1];
cmc = cameraMatrix[2];
cmd = cameraMatrix[3];
cme = cameraMatrix[4];
cmf = cameraMatrix[5];
mva = sra * cma + srb * cmc;
mvb = sra * cmb + srb * cmd;
mvc = src * cma + srd * cmc;
mvd = src * cmb + srd * cmd;
mve = sre * cma + srf * cmc + cme;
mvf = sre * cmb + srf * cmd + cmf;
tx0 = x * mva + y * mvc + mve;
ty0 = x * mvb + y * mvd + mvf;
tx1 = x * mva + yh * mvc + mve;
ty1 = x * mvb + yh * mvd + mvf;
tx2 = xw * mva + yh * mvc + mve;
ty2 = xw * mvb + yh * mvd + mvf;
tx3 = xw * mva + y * mvc + mve;
ty3 = xw * mvb + y * mvd + mvf;
this.manager.setRenderer(this, texture, camera, gameObject.renderTarget);
vertexOffset = vertexDataBuffer.allocate(24);
this.elementCount += 6;
vertexBufferObjectF32[vertexOffset++] = tx0;
vertexBufferObjectF32[vertexOffset++] = ty0;
vertexBufferObjectF32[vertexOffset++] = 0;
vertexBufferObjectF32[vertexOffset++] = 0;
vertexBufferObjectU32[vertexOffset++] = 0xFFFFFF;
vertexBufferObjectF32[vertexOffset++] = alpha;
vertexBufferObjectF32[vertexOffset++] = tx1;
vertexBufferObjectF32[vertexOffset++] = ty1;
vertexBufferObjectF32[vertexOffset++] = 0;
vertexBufferObjectF32[vertexOffset++] = 1;
vertexBufferObjectU32[vertexOffset++] = 0xFFFFFF;
vertexBufferObjectF32[vertexOffset++] = alpha;
vertexBufferObjectF32[vertexOffset++] = tx2;
vertexBufferObjectF32[vertexOffset++] = ty2;
vertexBufferObjectF32[vertexOffset++] = 1;
vertexBufferObjectF32[vertexOffset++] = 1;
vertexBufferObjectU32[vertexOffset++] = 0xFFFFFF;
vertexBufferObjectF32[vertexOffset++] = alpha;
vertexBufferObjectF32[vertexOffset++] = tx3;
vertexBufferObjectF32[vertexOffset++] = ty3;
vertexBufferObjectF32[vertexOffset++] = 1;
vertexBufferObjectF32[vertexOffset++] = 0;
vertexBufferObjectU32[vertexOffset++] = 0xFFFFFF;
vertexBufferObjectF32[vertexOffset++] = alpha;
this.flush(gameObject.dstShader);
gameObject.dstRenderTarget.shouldClear = true;
}
};
module.exports = EffectRenderer;

View file

@ -0,0 +1,17 @@
var CONST = {
// VERTEX_SIZE = (sizeof(vec2) * 4) + (sizeof(float) + sizeof(uint32))
VERTEX_SIZE: 24,
INDEX_SIZE: 2,
QUAD_VERTEX_COUNT: 4,
QUAD_INDEX_COUNT: 6,
// How many 32-bit components does the vertex have.
QUAD_VERTEX_COMPONENT_COUNT: 6,
// Can't be bigger since index are 16-bit
MAX_QUADS: 2
};
module.exports = CONST;

View file

@ -158,7 +158,7 @@ SpriteBatch.prototype = {
this.vertexBufferObject = null; this.vertexBufferObject = null;
}, },
addSpriteTexture: function (src, camera, texture, textureWidth, textureHeight) addSpriteTexture: function (gameObject, camera, texture, textureWidth, textureHeight)
{ {
var tempMatrix = this.tempMatrix; var tempMatrix = this.tempMatrix;
var alpha = 16777216; var alpha = 16777216;
@ -166,22 +166,22 @@ SpriteBatch.prototype = {
var vertexBufferObjectF32 = vertexDataBuffer.floatView; var vertexBufferObjectF32 = vertexDataBuffer.floatView;
var vertexBufferObjectU32 = vertexDataBuffer.uintView; var vertexBufferObjectU32 = vertexDataBuffer.uintView;
var vertexOffset = 0; var vertexOffset = 0;
var width = textureWidth * (src.flipX ? -1 : 1); var width = textureWidth * (gameObject.flipX ? -1 : 1);
var height = textureHeight * (src.flipY ? -1 : 1); var height = textureHeight * (gameObject.flipY ? -1 : 1);
var translateX = src.x - camera.scrollX; var translateX = gameObject.x - camera.scrollX;
var translateY = src.y - camera.scrollY; var translateY = gameObject.y - camera.scrollY;
var scaleX = src.scaleX; var scaleX = gameObject.scaleX;
var scaleY = src.scaleY; var scaleY = gameObject.scaleY;
var rotation = -src.rotation; var rotation = -gameObject.rotation;
var tempMatrixMatrix = tempMatrix.matrix; var tempMatrixMatrix = tempMatrix.matrix;
var x = -src.displayOriginX + ((textureWidth) * (src.flipX ? 1 : 0.0)); var x = -gameObject.displayOriginX + ((textureWidth) * (gameObject.flipX ? 1 : 0.0));
var y = -src.displayOriginY + ((textureHeight) * (src.flipY ? 1 : 0.0)); var y = -gameObject.displayOriginY + ((textureHeight) * (gameObject.flipY ? 1 : 0.0));
var xw = x + width; var xw = x + width;
var yh = y + height; var yh = y + height;
var cameraMatrix = camera.matrix.matrix; var cameraMatrix = camera.matrix.matrix;
var mva, mvb, mvc, mvd, mve, mvf, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3; var mva, mvb, mvc, mvd, mve, mvf, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3;
var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf; var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf;
var alpha = src.alpha; var alpha = gameObject.alpha;
tempMatrix.applyITRS(translateX, translateY, rotation, scaleX, scaleY); tempMatrix.applyITRS(translateX, translateY, rotation, scaleX, scaleY);
@ -215,7 +215,7 @@ SpriteBatch.prototype = {
tx3 = xw * mva + y * mvc + mve; tx3 = xw * mva + y * mvc + mve;
ty3 = xw * mvb + y * mvd + mvf; ty3 = xw * mvb + y * mvd + mvf;
this.manager.setBatch(this, texture, camera); this.manager.setRenderer(this, texture, camera, gameObject.renderTarget);
vertexOffset = vertexDataBuffer.allocate(24); vertexOffset = vertexDataBuffer.allocate(24);
this.elementCount += 6; this.elementCount += 6;
@ -248,32 +248,32 @@ SpriteBatch.prototype = {
vertexBufferObjectF32[vertexOffset++] = alpha; vertexBufferObjectF32[vertexOffset++] = alpha;
}, },
addSprite: function (src, camera) addSprite: function (gameObject, camera)
{ {
var tempMatrix = this.tempMatrix; var tempMatrix = this.tempMatrix;
var frame = src.frame; var frame = gameObject.frame;
var alpha = 16777216; var alpha = 16777216;
var vertexDataBuffer = this.vertexDataBuffer; var vertexDataBuffer = this.vertexDataBuffer;
var vertexBufferObjectF32 = vertexDataBuffer.floatView; var vertexBufferObjectF32 = vertexDataBuffer.floatView;
var vertexBufferObjectU32 = vertexDataBuffer.uintView; var vertexBufferObjectU32 = vertexDataBuffer.uintView;
var vertexOffset = 0; var vertexOffset = 0;
var uvs = frame.uvs; var uvs = frame.uvs;
var width = frame.width * (src.flipX ? -1 : 1); var width = frame.width * (gameObject.flipX ? -1 : 1);
var height = frame.height * (src.flipY ? -1 : 1); var height = frame.height * (gameObject.flipY ? -1 : 1);
var translateX = src.x - camera.scrollX; var translateX = gameObject.x - camera.scrollX;
var translateY = src.y - camera.scrollY; var translateY = gameObject.y - camera.scrollY;
var scaleX = src.scaleX; var scaleX = gameObject.scaleX;
var scaleY = src.scaleY; var scaleY = gameObject.scaleY;
var rotation = -src.rotation; var rotation = -gameObject.rotation;
var tempMatrixMatrix = tempMatrix.matrix; var tempMatrixMatrix = tempMatrix.matrix;
var x = -src.displayOriginX + frame.x + ((frame.width) * (src.flipX ? 1 : 0.0)); var x = -gameObject.displayOriginX + frame.x + ((frame.width) * (gameObject.flipX ? 1 : 0.0));
var y = -src.displayOriginY + frame.y + ((frame.height) * (src.flipY ? 1 : 0.0)); var y = -gameObject.displayOriginY + frame.y + ((frame.height) * (gameObject.flipY ? 1 : 0.0));
var xw = x + width; var xw = x + width;
var yh = y + height; var yh = y + height;
var cameraMatrix = camera.matrix.matrix; var cameraMatrix = camera.matrix.matrix;
var mva, mvb, mvc, mvd, mve, mvf, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3; var mva, mvb, mvc, mvd, mve, mvf, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3;
var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf; var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf;
var alpha = src.alpha; var alpha = gameObject.alpha;
tempMatrix.applyITRS(translateX, translateY, rotation, scaleX, scaleY); tempMatrix.applyITRS(translateX, translateY, rotation, scaleX, scaleY);
@ -307,7 +307,7 @@ SpriteBatch.prototype = {
tx3 = xw * mva + y * mvc + mve; tx3 = xw * mva + y * mvc + mve;
ty3 = xw * mvb + y * mvd + mvf; ty3 = xw * mvb + y * mvd + mvf;
this.manager.setBatch(this, frame.texture.source[frame.sourceIndex].glTexture, camera); this.manager.setRenderer(this, frame.texture.source[frame.sourceIndex].glTexture, camera, gameObject.renderTarget);
vertexOffset = vertexDataBuffer.allocate(24); vertexOffset = vertexDataBuffer.allocate(24);
this.elementCount += 6; this.elementCount += 6;

View file

@ -1,9 +1,8 @@
var GL = require('../GL');
var IndexBuffer = function (gl, bufferObject) var IndexBuffer = function (gl, bufferObject)
{ {
this.gl = gl; this.gl = gl;
this.bufferTarget = GL.ELEMENT_ARRAY_BUFFER; this.bufferTarget = gl.ELEMENT_ARRAY_BUFFER;
this.bufferObject = bufferObject; this.bufferObject = bufferObject;
}; };
@ -21,8 +20,8 @@ IndexBuffer.prototype = {
updateResource: function (bufferData, offset) updateResource: function (bufferData, offset)
{ {
var gl = this.gl; var gl = this.gl;
gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, this.bufferObject); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.bufferObject);
gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, offset, bufferData); gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, offset, bufferData);
return this; return this;
} }

View file

@ -1,102 +0,0 @@
var GL = require('../GL');
var OutputStage = function ()
{
this.renderTarget = null;
this.enableDepthTest = false;
this.enableStencilTest = false;
this.enableBlending = false;
/* Blend State */
this.blendLogicOp = 0;
this.blendSrcRgb = 0;
this.blendDstRgb = 0;
this.blendSrcAlpha = 0;
this.blendDstAlpha = 0;
this.blendEqRgb = 0;
this.blendEqAlpha = 0;
this.blendRed = 0;
this.blendGreen = 0;
this.blendBlue = 0;
this.blendAlpha = 0;
/* Depth-Stencil State */
this.depthFunc = 0;
this.depthMask = 0;
this.stencilFunc = 0;
this.stencilFail = 0;
this.stencilZFail = 0;
this.stencilZPass = 0;
};
OutputStage.prototype.constructor = OutputStage;
OutputStage.prototype = {
setRenderTarget: function (renderTarget)
{
this.renderTarget = renderTarget;
return this;
},
setDefaultDepthStencilState: function ()
{
this.depthEnabled = false;
this.stencilEnabled = false;
this.depthMask = true;
this.depthFunc = GL.LESS;
this.stencilFunc = GL.NEVER;
this.stencilZFail = GL.KEEP;
this.stencilZPass = GL.KEEP;
return this;
},
setBlendColor: function (r, g, b, a)
{
this.blendRed = r;
this.blendGreen = g;
this.blendBlue = b;
this.blendAlpha = a;
},
setBlendFunc: function (src, dst, eq)
{
this.blendSrcRgb = this.blendSrcAlpha = src;
this.blendDstRgb = this.blendDstAlpha = dst;
this.blendEqRgb = this.blendEqAlpha = eq;
return this;
},
setBlendFuncSeparate: function (srcRgb, dstRgb, srcAlpha, dstAlpha, eqRgb, eqAlpha)
{
this.blendSrcRgb = srcRgb;
this.blendSrcAlpha = srcAlpha;
this.blendDstRgb = dstRgb;
this.blendDstAlpha = dstAlpha;
this.blendEqRgb = eqRgb;
this.blendEqAlpha = eqAlpha;
return this;
},
setDefaultBlending: function ()
{
this.setBlendFuncSeparate(
GL.SRC_ALPHA,
GL.ONE_MINUS_SRC_ALPHA,
GL.ONE,
GL.ONE_MINUS_SRC_ALPHA,
GL.FUNC_ADD,
GL.FUNC_ADD
);
return this;
},
setNoBlending: function ()
{
this.setBlendFunc(GL.ONE, GL.ZERO, GL.FUNC_ADD);
return this;
}
};
module.exports = OutputStage;

View file

@ -5,6 +5,7 @@ var RenderTarget = function (framebufferObject, width, height, colorBuffer, dept
this.height = height; this.height = height;
this.colorBuffer = colorBuffer; this.colorBuffer = colorBuffer;
this.depthStencilBuffer = depthStencilBuffer; this.depthStencilBuffer = depthStencilBuffer;
this.shouldClear = false;
}; };
module.exports = RenderTarget; module.exports = RenderTarget;

View file

@ -1,9 +1,7 @@
var GL = require('../GL');
var VertexBuffer = function (gl, bufferObject) var VertexBuffer = function (gl, bufferObject)
{ {
this.gl = gl; this.gl = gl;
this.bufferTarget = GL.ARRAY_BUFFER; this.bufferTarget = gl.ARRAY_BUFFER;
this.bufferObject = bufferObject; this.bufferObject = bufferObject;
this.attributes = []; this.attributes = [];
}; };
@ -28,8 +26,8 @@ VertexBuffer.prototype = {
updateResource: function (bufferData, offset) updateResource: function (bufferData, offset)
{ {
var gl = this.gl; var gl = this.gl;
gl.bindBuffer(GL.ARRAY_BUFFER, this.bufferObject); gl.bindBuffer(gl.ARRAY_BUFFER, this.bufferObject);
gl.bufferSubData(GL.ARRAY_BUFFER, offset, bufferData); gl.bufferSubData(gl.ARRAY_BUFFER, offset, bufferData);
return this; return this;
}, },
@ -40,7 +38,7 @@ VertexBuffer.prototype = {
var attributes = this.attributes; var attributes = this.attributes;
var attributesLength = attributes.length; var attributesLength = attributes.length;
gl.bindBuffer(GL.ARRAY_BUFFER, bufferObject); gl.bindBuffer(gl.ARRAY_BUFFER, bufferObject);
for (var index = 0; index < attributesLength; ++index) for (var index = 0; index < attributesLength; ++index)
{ {
var element = attributes[index]; var element = attributes[index];

View file

@ -1,7 +1,6 @@
module.exports = { module.exports = {
IndexBuffer: require('./IndexBuffer'), IndexBuffer: require('./IndexBuffer'),
OutputStage: require('./OutputStage'),
RenderTarget: require('./RenderTarget'), RenderTarget: require('./RenderTarget'),
Shader: require('./Shader'), Shader: require('./Shader'),
Texture: require('./Texture'), Texture: require('./Texture'),

View file

@ -1,10 +1,11 @@
module.exports = { module.exports = {
vert: [ vert: [
'uniform mat4 u_view_matrix;',
'attribute vec2 a_position;', 'attribute vec2 a_position;',
'attribute vec2 a_tex_coord;', 'attribute vec2 a_tex_coord;',
'varying vec2 v_tex_coord;', 'varying vec2 v_tex_coord;',
'void main(void) {', 'void main(void) {',
' gl_Position = vec4(a_position, 0.0, 1.0);', ' gl_Position = u_view_matrix * vec4(a_position, 0.0, 1.0);',
' v_tex_coord = a_tex_coord;', ' v_tex_coord = a_tex_coord;',
'}' '}'
].join('\n'), ].join('\n'),