in seriously.js [1947:2443]
get: makeGetter(name),
set: makeSetter(name)
});
}
} else {
//todo: this is temporary. get rid of it.
throw new Error('Cannot overwrite Seriously.' + name);
}
}
}
Object.defineProperties(this, {
effect: {
enumerable: true,
configurable: true,
get: function () {
return me.hook;
}
},
title: {
enumerable: true,
configurable: true,
get: function () {
return me.effect.title || me.hook;
}
},
width: {
enumerable: true,
configurable: true,
get: function () {
return me.width;
}
},
height: {
enumerable: true,
configurable: true,
get: function () {
return me.height;
}
},
id: {
enumerable: true,
configurable: true,
get: function () {
return me.id;
}
}
});
this.render = function () {
me.render();
return this;
};
this.readPixels = function (x, y, width, height, dest) {
return me.readPixels(x, y, width, height, dest);
};
this.on = function (eventName, callback) {
me.on(eventName, callback);
};
this.off = function (eventName, callback) {
me.off(eventName, callback);
};
this.inputs = function (name) {
var result,
input,
inputs,
i,
key;
inputs = me.effect.inputs;
if (name) {
input = inputs[name];
if (!input) {
return null;
}
result = {
type: input.type,
defaultValue: input.defaultValue,
title: input.title || name
};
if (input.type === 'number') {
result.min = input.min;
result.max = input.max;
result.step = input.step;
} else if (input.type === 'enum') {
//make a copy
result.options = extend({}, input.options);
} else if (input.type === 'vector') {
result.dimensions = input.dimensions;
}
if (input.description) {
result.description = input.description;
}
return result;
}
result = {};
for (key in inputs) {
if (inputs.hasOwnProperty(key)) {
result[key] = this.inputs(key);
}
}
return result;
};
this.alias = function (inputName, aliasName) {
me.alias(inputName, aliasName);
return this;
};
this.matte = function (polygons) {
me.matte(polygons);
};
this.destroy = function () {
var i,
descriptor;
me.destroy();
for (i in this) {
if (this.hasOwnProperty(i) && i !== 'isDestroyed' && i !== 'id') {
descriptor = Object.getOwnPropertyDescriptor(this, i);
if (descriptor.get || descriptor.set ||
typeof this[i] !== 'function') {
delete this[i];
} else {
this[i] = nop;
}
}
}
};
this.isDestroyed = function () {
return me.isDestroyed;
};
this.isReady = function () {
return me.ready;
};
};
EffectNode = function (hook, options) {
var key, name, input,
defaultValue,
defaults,
defaultSources = {};
Node.call(this, options);
this.gl = gl;
this.effectRef = seriousEffects[hook];
this.sources = {};
this.targets = [];
this.inputElements = {};
this.dirty = true;
this.shaderDirty = true;
this.hook = hook;
this.options = options;
this.transform = null;
this.effect = extend({}, this.effectRef);
if (this.effectRef.definition) {
/*
todo: copy over inputs object separately in case some are specified
in advance and some are specified in definition function
*/
extend(this.effect, this.effectRef.definition.call(this, options));
}
validateInputSpecs(this.effect);
this.uniforms.transform = identity;
this.inputs = {};
defaults = defaultInputs[hook];
for (name in this.effect.inputs) {
if (this.effect.inputs.hasOwnProperty(name)) {
input = this.effect.inputs[name];
if (input.defaultValue === undefined || input.defaultValue === null) {
if (input.type === 'number') {
input.defaultValue = Math.min(Math.max(0, input.min), input.max);
} else if (input.type === 'color') {
input.defaultValue = [0, 0, 0, 0];
} else if (input.type === 'boolean') {
input.defaultValue = false;
} else if (input.type === 'string') {
input.defaultValue = '';
} else if (input.type === 'enum') {
input.defaultValue = input.firstValue;
}
}
defaultValue = input.validate.call(this, input.defaultValue, input);
if (defaults && defaults[name] !== undefined) {
defaultValue = input.validate.call(this, defaults[name], input, input.defaultValue, defaultValue);
defaults[name] = defaultValue;
if (input.type === 'image') {
defaultSources[name] = defaultValue;
}
}
this.inputs[name] = defaultValue;
if (input.uniform) {
this.uniforms[input.uniform] = input.defaultValue;
}
}
}
if (gl) {
this.initialize();
if (this.effect.commonShader) {
/*
this effect is unlikely to need to be modified again
by changing parameters, so build it now to avoid jank later
*/
this.buildShader();
}
}
this.updateReady();
this.inPlace = this.effect.inPlace;
this.pub = new Effect(this);
nodes.push(this);
nodesById[this.id] = this;
effects.push(this);
allEffectsByHook[hook].push(this);
for (name in defaultSources) {
if (defaultSources.hasOwnProperty(name)) {
this.setInput(name, defaultSources[name]);
}
}
};
extend(EffectNode, Node);
EffectNode.prototype.initialize = function () {
if (!this.initialized) {
var that = this;
this.baseShader = baseShader;
if (this.shape) {
this.model = makeGlModel(this.shape, this.gl);
} else {
this.model = rectangleModel;
}
if (typeof this.effect.initialize === 'function') {
this.effect.initialize.call(this, function () {
that.initFrameBuffer(true);
}, gl);
} else {
this.initFrameBuffer(true);
}
if (this.frameBuffer) {
this.texture = this.frameBuffer.texture;
}
this.initialized = true;
}
};
EffectNode.prototype.resize = function () {
var i;
Node.prototype.resize.call(this);
if (this.effect.resize) {
this.effect.resize.call(this);
}
for (i = 0; i < this.targets.length; i++) {
this.targets[i].resize();
}
};
EffectNode.prototype.updateReady = function () {
var i,
input,
key,
effect,
ready = true,
method;
effect = this.effect;
for (key in effect.inputs) {
if (effect.inputs.hasOwnProperty(key)) {
input = this.effect.inputs[key];
if (input.type === 'image' &&
(!this.sources[key] || !this.sources[key].ready) &&
(!effect.requires || effect.requires.call(this, key, this.inputs))
) {
ready = false;
break;
}
}
}
if (this.ready !== ready) {
this.ready = ready;
this.emit(ready ? 'ready' : 'unready');
method = ready ? 'setReady' : 'setUnready';
if (this.targets) {
for (i = 0; i < this.targets.length; i++) {
this.targets[i][method]();
}
}
}
};
EffectNode.prototype.setReady = EffectNode.prototype.updateReady;
EffectNode.prototype.setUnready = EffectNode.prototype.updateReady;
EffectNode.prototype.addTarget = function (target) {
var i;
for (i = 0; i < this.targets.length; i++) {
if (this.targets[i] === target) {
return;
}
}
this.targets.push(target);
};
EffectNode.prototype.removeTarget = function (target) {
var i = this.targets && this.targets.indexOf(target);
if (i >= 0) {
this.targets.splice(i, 1);
}
};
EffectNode.prototype.removeSource = function (source) {
var i, pub = source && source.pub;
for (i in this.inputs) {
if (this.inputs.hasOwnProperty(i) &&
(this.inputs[i] === source || this.inputs[i] === pub)) {
this.inputs[i] = null;
}
}
for (i in this.sources) {
if (this.sources.hasOwnProperty(i) &&
(this.sources[i] === source || this.sources[i] === pub)) {
this.sources[i] = null;
}
}
};
EffectNode.prototype.buildShader = function () {
var shader, effect = this.effect;
if (this.shaderDirty) {
if (effect.commonShader && commonShaders[this.hook]) {
if (!this.shader) {
commonShaders[this.hook].count++;
}
this.shader = commonShaders[this.hook].shader;
} else if (effect.shader) {
if (this.shader && !effect.commonShader) {
this.shader.destroy();
}
shader = effect.shader.call(this, this.inputs, {
vertex: baseVertexShader,
fragment: baseFragmentShader
}, Seriously.util);
if (shader instanceof ShaderProgram) {
this.shader = shader;
} else if (shader && shader.vertex && shader.fragment) {
this.shader = new ShaderProgram(gl, shader.vertex, shader.fragment);
} else {
this.shader = baseShader;
}
if (effect.commonShader) {
commonShaders[this.hook] = {
count: 1,
shader: this.shader
};
}
} else {
this.shader = baseShader;
}
this.shaderDirty = false;
}
};
EffectNode.prototype.render = function () {
var key,
frameBuffer,
effect = this.effect,
that = this,
inPlace;
function drawFn(shader, model, uniforms, frameBuffer, node, options) {
draw(shader, model, uniforms, frameBuffer, node || that, options);
}
if (!gl) {
return;
}
if (!this.initialized) {
this.initialize();
}
if (this.shaderDirty) {
this.buildShader();
}
if (this.dirty && this.ready) {
for (key in this.sources) {
if (this.sources.hasOwnProperty(key) &&
(!effect.requires || effect.requires.call(this, key, this.inputs))) {
//todo: set source texture in case it changes?
//sourcetexture = this.sources[i].render() || this.sources[i].texture
inPlace = typeof this.inPlace === 'function' ? this.inPlace(key) : this.inPlace;
this.sources[key].render(!inPlace);
}
}
if (this.frameBuffer) {
frameBuffer = this.frameBuffer.frameBuffer;
}
if (typeof effect.draw === 'function') {
effect.draw.call(this, this.shader, this.model, this.uniforms, frameBuffer, drawFn);
this.emit('render');
} else if (frameBuffer) {
draw(this.shader, this.model, this.uniforms, frameBuffer, this);
this.emit('render');
}
this.dirty = false;
}
return this.texture;
};
EffectNode.prototype.setInput = function (name, value) {
var input, uniform,
sourceKeys,
source,
me = this,
defaultValue;
function disconnectSource() {
var previousSource = me.sources[name],
key;
/*
remove this node from targets of previously connected source node,
but only if the source node is not being used as another input
*/
if (previousSource) {
for (key in me.sources) {
if (key !== name &&
me.sources.hasOwnProperty(key) &&
me.sources[key] === previousSource) {
return;
}
}
previousSource.removeTarget(me);
}
}
if (this.effect.inputs.hasOwnProperty(name)) {
input = this.effect.inputs[name];
if (input.type === 'image') {
//&& !(value instanceof Effect) && !(value instanceof Source)) {
if (value) {
value = findInputNode(value);
if (value !== this.sources[name]) {
disconnectSource();
if (traceSources(value, this)) {