import Base from '../core/Base';
import OrthoCamera from '../camera/Orthographic';
import Plane from '../geometry/Plane';
import Shader from '../Shader';
import Material from '../Material';
import Mesh from '../Mesh';
import glenum from '../core/glenum';
import vertexGlsl from '../shader/source/compositor/vertex.glsl.js';
Shader['import'](vertexGlsl);
var planeGeo = new Plane();
var mesh = new Mesh({
geometry: planeGeo,
frustumCulling: false
});
var camera = new OrthoCamera();
/**
* @constructor clay.compositor.Pass
* @extends clay.core.Base
*/
var Pass = Base.extend(function () {
return /** @lends clay.compositor.Pass# */ {
/**
* Fragment shader string
* @type {string}
*/
// PENDING shader or fragment ?
fragment: '',
/**
* @type {Object}
*/
outputs: null,
/**
* @type {clay.Material}
*/
material: null,
/**
* @type {Boolean}
*/
blendWithPrevious: false,
/**
* @type {Boolean}
*/
clearColor: false,
/**
* @type {Boolean}
*/
clearDepth: true
};
}, function() {
var shader = new Shader(Shader.source('clay.compositor.vertex'), this.fragment);
var material = new Material({
shader: shader
});
material.enableTexturesAll();
this.material = material;
},
/** @lends clay.compositor.Pass.prototype */
{
/**
* @param {string} name
* @param {} value
*/
setUniform: function(name, value) {
this.material.setUniform(name, value);
},
/**
* @param {string} name
* @return {}
*/
getUniform: function(name) {
var uniform = this.material.uniforms[name];
if (uniform) {
return uniform.value;
}
},
/**
* @param {clay.Texture} texture
* @param {number} attachment
*/
attachOutput: function(texture, attachment) {
if (!this.outputs) {
this.outputs = {};
}
attachment = attachment || glenum.COLOR_ATTACHMENT0;
this.outputs[attachment] = texture;
},
/**
* @param {clay.Texture} texture
*/
detachOutput: function(texture) {
for (var attachment in this.outputs) {
if (this.outputs[attachment] === texture) {
this.outputs[attachment] = null;
}
}
},
bind: function(renderer, frameBuffer) {
if (this.outputs) {
for (var attachment in this.outputs) {
var texture = this.outputs[attachment];
if (texture) {
frameBuffer.attach(texture, attachment);
}
}
}
if (frameBuffer) {
frameBuffer.bind(renderer);
}
},
unbind: function(renderer, frameBuffer) {
frameBuffer.unbind(renderer);
},
/**
* @param {clay.Renderer} renderer
* @param {clay.FrameBuffer} [frameBuffer]
*/
render: function(renderer, frameBuffer) {
var _gl = renderer.gl;
if (frameBuffer) {
this.bind(renderer, frameBuffer);
// MRT Support in chrome
// https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/ext-draw-buffers.html
var ext = renderer.getGLExtension('EXT_draw_buffers');
if (ext && this.outputs) {
var bufs = [];
for (var attachment in this.outputs) {
attachment = +attachment;
if (attachment >= _gl.COLOR_ATTACHMENT0 && attachment <= _gl.COLOR_ATTACHMENT0 + 8) {
bufs.push(attachment);
}
}
ext.drawBuffersEXT(bufs);
}
}
this.trigger('beforerender', this, renderer);
// FIXME Don't clear in each pass in default, let the color overwrite the buffer
// FIXME pixels may be discard
var clearBit = this.clearDepth ? _gl.DEPTH_BUFFER_BIT : 0;
_gl.depthMask(true);
if (this.clearColor) {
clearBit = clearBit | _gl.COLOR_BUFFER_BIT;
_gl.colorMask(true, true, true, true);
var cc = this.clearColor;
if (Array.isArray(cc)) {
_gl.clearColor(cc[0], cc[1], cc[2], cc[3]);
}
}
_gl.clear(clearBit);
if (this.blendWithPrevious) {
// Blend with previous rendered scene in the final output
// FIXME Configure blend.
// FIXME It will cause screen blink?
_gl.enable(_gl.BLEND);
this.material.transparent = true;
}
else {
_gl.disable(_gl.BLEND);
this.material.transparent = false;
}
this.renderQuad(renderer);
this.trigger('afterrender', this, renderer);
if (frameBuffer) {
this.unbind(renderer, frameBuffer);
}
},
/**
* Simply do quad rendering
*/
renderQuad: function (renderer) {
mesh.material = this.material;
renderer.renderPass([mesh], camera);
},
/**
* @param {clay.Renderer} renderer
*/
dispose: function (renderer) {}
});
export default Pass;