function getShaderNodeVarName( node, name )
	{
		return "VAR_" + (name || "TEMP") + "_" + node.id;
	}
********************************
	function LGraphCubemapToTexture2D() {
		this.addInput("in", "texture");
		this.addInput("yaw", "number");
		this.addOutput("out", "texture");
		this.properties = { yaw: 0 };
	}

	LGraphCubemapToTexture2D.title = "CubemapToTexture2D";
	LGraphCubemapToTexture2D.desc = "Transforms a CUBEMAP texture into a TEXTURE2D in Polar Representation";

	LGraphCubemapToTexture2D.prototype.onExecute = function() {
		if (!this.isOutputConnected(0))
			return;

		var tex = this.getInputData(0);
		if ( !tex || tex.texture_type != GL.TEXTURE_CUBE_MAP )
			return;
		if( this._last_tex && ( this._last_tex.height != tex.height || this._last_tex.type != tex.type ))
			this._last_tex = null;
		var yaw = this.getInputOrProperty("yaw");
		this._last_tex = GL.Texture.cubemapToTexture2D( tex, tex.height, this._last_tex, true, yaw );
		this.setOutputData( 0, this._last_tex );
	};

	LiteGraph.registerNodeType( "texture/cubemapToTexture2D", LGraphCubemapToTexture2D );
})(this);

(function(global) {

    if (typeof GL == "undefined")
		return;

    var LiteGraph = global.LiteGraph;
	var LGraphCanvas = global.LGraphCanvas;

	var SHADERNODES_COLOR = "#345";

	var LGShaders = LiteGraph.Shaders = {};

	var GLSL_types = LGShaders.GLSL_types = ["float","vec2","vec3","vec4","mat3","mat4","sampler2D","samplerCube"];
	var GLSL_types_const = LGShaders.GLSL_types_const = ["float","vec2","vec3","vec4"];

	var GLSL_functions_desc = {
		"radians": "T radians(T degrees)",
		"degrees": "T degrees(T radians)",
		"sin": "T sin(T angle)",
		"cos": "T cos(T angle)",
		"tan": "T tan(T angle)",
		"asin": "T asin(T x)",
		"acos": "T acos(T x)",
		"atan": "T atan(T x)",
		"atan2": "T atan(T x,T y)",
		"pow": "T pow(T x,T y)",
		"exp": "T exp(T x)",
		"log": "T log(T x)",
		"exp2": "T exp2(T x)",
		"log2": "T log2(T x)",
		"sqrt": "T sqrt(T x)",
		"inversesqrt": "T inversesqrt(T x)",
		"abs": "T abs(T x)",
		"sign": "T sign(T x)",
		"floor": "T floor(T x)",
		"round": "T round(T x)",
		"ceil": "T ceil(T x)",
		"fract": "T fract(T x)",
		"mod": "T mod(T x,T y)", //"T mod(T x,float y)"
		"min": "T min(T x,T y)",
		"max": "T max(T x,T y)",
		"clamp": "T clamp(T x,T minVal = 0.0,T maxVal = 1.0)",
		"mix": "T mix(T x,T y,T a)", //"T mix(T x,T y,float a)"
		"step": "T step(T edge, T edge2, T x)", //"T step(float edge, T x)"
		"smoothstep": "T smoothstep(T edge, T edge2, T x)", //"T smoothstep(float edge, T x)"
		"length":"float length(T x)",
		"distance":"float distance(T p0, T p1)",
		"normalize":"T normalize(T x)",
		"dot": "float dot(T x,T y)",
		"cross": "vec3 cross(vec3 x,vec3 y)",
		"reflect": "vec3 reflect(vec3 V,vec3 N)",
		"refract": "vec3 refract(vec3 V,vec3 N, float IOR)"
	};

	//parse them
	var GLSL_functions = {};
	var GLSL_functions_name = [];
	parseGLSLDescriptions();

	LGShaders.ALL_TYPES = "float,vec2,vec3,vec4";

	function parseGLSLDescriptions()
	{
		GLSL_functions_name.length = 0;

		for(var i in GLSL_functions_desc)
		{
			var op = GLSL_functions_desc[i];
			var index = op.indexOf(" ");
			var return_type = op.substr(0,index);
			var index2 = op.indexOf("(",index);
			var func_name = op.substr(index,index2-index).trim();
			var params = op.substr(index2 + 1, op.length - index2 - 2).split(",");
			for(var j in params)
			{
				var p = params[j].split(" ").filter(function(a){ return a; });
				params[j] = { type: p[0].trim(), name: p[1].trim() };
				if(p[2] == "=")
					params[j].value = p[3].trim();
			}
			GLSL_functions[i] = { return_type: return_type, func: func_name, params: params };
			GLSL_functions_name.push( func_name );
			//console.log( GLSL_functions[i] );
		}
	}

	//common actions to all shader node classes
	function registerShaderNode( type, node_ctor )
	{
		//static attributes
		node_ctor.color = SHADERNODES_COLOR;
		node_ctor.filter = "shader";

		//common methods
		node_ctor.prototype.clearDestination = function(){ this.shader_destination = {};  }
		node_ctor.prototype.propagateDestination = function propagateDestination( dest_name )
		{
			this.shader_destination[ dest_name ] = true;
			if(this.inputs)
			for(var i = 0; i < this.inputs.length; ++i)
			{
				var origin_node = this.getInputNode(i);
				if(origin_node)
					origin_node.propagateDestination( dest_name );
			}
		}
		if(!node_ctor.prototype.onPropertyChanged)
			node_ctor.prototype.onPropertyChanged = function()
			{
				if(this.graph)
					 this.graph._version++;
			}

		/*
		if(!node_ctor.prototype.onGetCode)
			node_ctor.prototype.onGetCode = function()
			{
				//check destination to avoid lonely nodes
				if(!this.shader_destination)
					return;
				//grab inputs with types
				var inputs = [];
				if(this.inputs)
				for(var i = 0; i < this.inputs.length; ++i)
					inputs.push({ type: this.getInputData(i), name: getInputLinkID(this,i) });
				var outputs = [];
				if(this.outputs)
				for(var i = 0; i < this.outputs.length; ++i)
					outputs.push({ name: getOutputLinkID(this,i) });
				//pass to code func
				var results = this.extractCode(inputs);
				//grab output, pass to next
				if(results)
				for(var i = 0; i < results.length; ++i)
				{
					var r = results[i];
					if(!r)
						continue;
					this.setOutputData(i,r.value);
				}
			}