Source: Sketch/Driver.js

/* global Sketch */
/**
 * @classdesc The driver class for the sketch module. Initialise via Sketch.createSketch(...) for default configs.
 * @class Sketch.Driver
 * @param {HTMLCanvasElement} canvas - The canvas element that sketch will be targeting.
 * @author FelixMcFelix (Kyle S.)
 */
Sketch.Driver = function(canvas){
	/**
	 * Internal counter used to block execution calls while shaders are still being added.
	 * @name Sketch.Driver#readyLock
	 * @type int
	 * @private
	 */
	this.readyLock = 0;

	//Canvas-y stuff;
	/**
	 * The module's attached canvas.
	 * @name Sketch.Driver#canvas
	 * @type HTMLCanvasElement
	 * @protected
	 * @readonly
	 */
	this.canvas = canvas;
	/**
	 * The module's attached context.
	 * @name Sketch.Driver#context
	 * @type WebGLRenderingContext
	 * @protected
	 * @readonly
	 */
	this.context = canvas.getContext("webgl", {preserveDrawingBuffer: true});

	//Modules.
	/**
	 * A reference to the parser.
	 * @name Sketch.Driver#parser
	 * @type Parser
	 * @protected
	 * @readonly
	 */
	this.parser = sketchParse;
	/**
	 * The module's reference to the code generator.
	 * @name Sketch.Driver#codeGen
	 * @type Object
	 * @protected
	 * @readonly
	 */
	this.codeGen = null;
	/**
	 * The module's reference to the shader manager.
	 * @name Sketch.Driver#shaderManager
	 * @type Palette.Manager
	 * @protected
	 * @readonly
	 */
	this.shaderManager = new Palette.Manager(this.context);
	/**
	 * The module's reference to the VM.
	 * @name Sketch.Driver#vm
	 * @type MVM
	 * @protected
	 * @readonly
	 */
	this.vm = null;
};

Sketch.Driver.prototype = {
	/**
	 * Add a shader from an already-resolved JSON String.
	 * @method Sketch.Driver#addShader
	 * @param {String} text - the JSON string for a shader object.
	 * @public
	 */
	addShader: function(text){
		this.readyLock++;
		this.addShaderInternal(text);
	},

	/**
	 * Add a shader from a URL.
	 * @method Sketch.Driver#addShaderURL
	 * @param {String} url - the URL string leading to a shader object.
	 * @async
	 * @public
	 */
	addShaderURL: function(url){
		this.readyLock++;
		var that = this;
		var x = new XMLHttpRequest();
		x.open("GET", url, true);
		x.onload = function(){
			that.addShaderInternal(x.responseText);
		};
		x.send();
	},

	/**
	 * Final phase of shader addition. Frees up the lock to allow execution.
	 * @method Sketch.Driver#addShaderInternal
	 * @param {String} text - the JSON string for a shader object.
	 * @private
	 */
	addShaderInternal: function(text){
		this.shaderManager.addShader(text);
		this.readyLock--;
	},

	/**
	 * Compile and execute a Sketch program.
	 * @method Sketch.Driver#compile
	 * @param {String} text - the source code for a Sketch program.
	 * @returns boolean - will fail either on error, or if shaders are still being added.
	 * @public
	 */
	compile: function(text){
		if(this.readyLock>0){
			alert("Sketch driver is still loading shaders - be patient!" +
			" If it's been excessively long then you may have tried to add a malformed shader.");
			return false;
		}
		if(this.vm){
			this.vm.kill();
		}
		this.vm = null;
		this.codeGen = null;
		try{
			this.codeGen = new Sketch.SketchGen();
			var ast = this.parser.parse(text);

			var prog = this.codeGen.interpret(ast);

			var vm = new MVM.VM(this.context, this.shaderManager, prog.code, false);

			this.vm = vm;
			var d = this.vm.interpret();

			if(prog.initAddr !== null){
				this.vm.call(prog.initAddr, []);
			}

			var initTime = Date.now();
			if(prog.renderAddr !== null){
				var t = this;

				var fn = function(){
					if(!vm.dead){
						vm.call(prog.renderAddr, [Date.now()-initTime]);
						var k = window.requestAnimationFrame(fn, t.canvas);
					}
				}

				window.requestAnimationFrame(fn, this.canvas);
				
			}
			// alert("The final values of global scope variables are (in order of definition):\n"+d.variables);
			//Since the code generator is not capable of outputting graphical operations
			//we shall simply print the stack's top value to demonstrate our wonderful
			//calculator.
			// alert("The Virtual Machine's final state is in the console.");
			console.log(d);
		} catch (e){
			alert("Error detected while rendering! See console for stack trace.");
			console.log(e);
			return false;
		}
		return true;
	}
};