videocontext
Version:
A WebGL & HTML5 graph based video composition library
254 lines (211 loc) • 10.5 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: ProcessingNodes/processingnode.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: ProcessingNodes/processingnode.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>//Matthew Shotton, R&D User Experience,© BBC 2015
import GraphNode from "../graphnode";
import { createShaderProgram, createElementTexutre, updateTexture } from "../utils.js";
import { RenderException } from "../exceptions.js";
class ProcessingNode extends GraphNode{
/**
* Initialise an instance of a ProcessingNode.
*
* This class is not used directly, but is extended to create CompositingNodes, TransitionNodes, and EffectNodes.
*/
constructor(gl, renderGraph, definition, inputNames, limitConnections){
super(gl, renderGraph, inputNames, limitConnections);
this._vertexShader = definition.vertexShader;
this._fragmentShader = definition.fragmentShader;
this._definition = definition;
this._properties = {};//definition.properties;
//copy definition properties
for(let propertyName in definition.properties){
let propertyValue = definition.properties[propertyName].value;
//if an array then shallow copy it
if(Object.prototype.toString.call(propertyValue) === "[object Array]"){
propertyValue = definition.properties[propertyName].value.slice();
}
let propertyType = definition.properties[propertyName].type;
this._properties[propertyName] = {type:propertyType, value:propertyValue};
}
this._inputTextureUnitMapping =[];
this._maxTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
this._boundTextureUnits = 0;
this._parameterTextureCount = 0;
this._inputTextureCount = 0;
this._texture = createElementTexutre(gl);
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.canvas.width, gl.canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
//compile the shader
this._program = createShaderProgram(gl, this._vertexShader, this._fragmentShader);
//create and setup the framebuffer
this._framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._texture,0);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
//create properties on this object for the passed properties
for (let propertyName in this._properties){
Object.defineProperty(this, propertyName, {
get:function(){return this._properties[propertyName].value;},
set:function(passedValue){this._properties[propertyName].value = passedValue;}
});
}
//create texutres for any texture properties
for (let propertyName in this._properties){
let propertyValue = this._properties[propertyName].value;
if (propertyValue instanceof Image){
this._properties[propertyName].texture = createElementTexutre(gl);
this._properties[propertyName].texutreUnit = gl.TEXTURE0 + this._boundTextureUnits;
this._boundTextureUnits += 1;
this._parameterTextureCount +=1;
if (this._boundTextureUnits > this._maxTextureUnits){
throw new RenderException("Trying to bind more than available textures units to shader");
}
}
}
//calculate texutre units for input textures
for(let inputName of definition.inputs){
this._inputTextureUnitMapping.push({name:inputName, textureUnit:gl.TEXTURE0 + this._boundTextureUnits});
this._boundTextureUnits += 1;
this._inputTextureCount += 1;
if (this._boundTextureUnits > this._maxTextureUnits){
throw new RenderException("Trying to bind more than available textures units to shader");
}
}
//find the locations of the properties in the compiled shader
for (let propertyName in this._properties){
if (this._properties[propertyName].type === "uniform"){
this._properties[propertyName].location = this._gl.getUniformLocation(this._program, propertyName);
}
}
this._currentTimeLocation = this._gl.getUniformLocation(this._program, "currentTime");
this._currentTime = 0;
//Other setup
let positionLocation = gl.getAttribLocation(this._program, "a_position");
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
1.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 0.0]),
gl.STATIC_DRAW);
let texCoordLocation = gl.getAttribLocation(this._program, "a_texCoord");
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
this._displayName = "ProcessingNode";
}
/**
* Sets the passed processing node property to the passed value.
* @param {string} name - The name of the processing node parameter to modify.
* @param {Object} value - The value to set it to.
*
* @example
* var ctx = new VideoContext();
* var monoNode = ctx.effect(VideoContext.DEFINITIONS.MONOCHROME);
* monoNode.setProperty("inputMix", [1.0,0.0,0.0]); //Just use red channel
*/
setProperty(name, value){
this._properties[name].value = value;
}
/**
* Sets the passed processing node property to the passed value.
* @param {string} name - The name of the processing node parameter to get.
*
* @example
* var ctx = new VideoContext();
* var monoNode = ctx.effect(VideoContext.DEFINITIONS.MONOCHROME);
* console.log(monoNode.getProperty("inputMix")); //Will output [0.4,0.6,0.2], the default value from the effect definition.
*
*/
getProperty(name){
return this._properties[name].value;
}
_update(currentTime){
this._currentTime = currentTime;
}
_seek(currentTime){
this._currentTime = currentTime;
}
_render(){
this._rendered = true;
let gl = this._gl;
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(this._program);
//upload the default uniforms
gl.uniform1f(this._currentTimeLocation, parseFloat(this._currentTime));
//upload/update the custom uniforms
let textureOffset = 0;
for (let propertyName in this._properties){
let propertyValue = this._properties[propertyName].value;
let propertyType = this._properties[propertyName].type;
let propertyLocation = this._properties[propertyName].location;
if (propertyType !== "uniform") continue;
if (typeof propertyValue === "number"){
gl.uniform1f(propertyLocation, propertyValue);
}
else if( Object.prototype.toString.call(propertyValue) === "[object Array]"){
if(propertyValue.length === 1){
gl.uniform1fv(propertyLocation, propertyValue);
} else if(propertyValue.length === 2){
gl.uniform2fv(propertyLocation, propertyValue);
} else if(propertyValue.length === 3){
gl.uniform3fv(propertyLocation, propertyValue);
} else if(propertyValue.length === 4){
gl.uniform4fv(propertyLocation, propertyValue);
} else{
console.debug("Shader parameter", propertyName, "is too long an array:", propertyValue);
}
} else if(propertyValue instanceof Image){
let texture = this._properties[propertyName].texture;
let textureUnit = this._properties[propertyName].texutreUnit;
updateTexture(gl, texture, propertyValue);
gl.activeTexture(textureUnit);
gl.uniform1i(propertyLocation, textureOffset);
textureOffset += 1;
gl.bindTexture(gl.TEXTURE_2D, texture);
}
else{
//TODO - add tests for textures
/*gl.activeTexture(gl.TEXTURE0 + textureOffset);
gl.uniform1i(parameterLoctation, textureOffset);
gl.bindTexture(gl.TEXTURE_2D, textures[textureOffset-1]);*/
}
}
}
}
export default ProcessingNode;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-VideoContext.html">VideoContext</a></li></ul><h3>Classes</h3><ul><li><a href="CanvasNode.html">CanvasNode</a></li><li><a href="CompositingNode.html">CompositingNode</a></li><li><a href="DestinationNode.html">DestinationNode</a></li><li><a href="EffectNode.html">EffectNode</a></li><li><a href="GraphNode.html">GraphNode</a></li><li><a href="ImageNode.html">ImageNode</a></li><li><a href="module-VideoContext.html">VideoContext</a></li><li><a href="ProcessingNode.html">ProcessingNode</a></li><li><a href="RenderGraph.html">RenderGraph</a></li><li><a href="SourceNode.html">SourceNode</a></li><li><a href="TransitionNode.html">TransitionNode</a></li><li><a href="VideoNode.html">VideoNode</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>