
var bvFilterLib =
{
	GLBrightnessContrast: {
		name: "Brightn./Contrast",
		webgl: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var brightness = 0, contrast = 0;
			div.innerHTML = "Change brightness and contrast for the selected layer.<br/><br/>";

			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return;
			}
			var texture = glCanvas.texture(tempCanvas);

			var brightnessSlider = new BV.pcSlider({label:"Brightness", w: 300, h: 30, start: 0, end: 100, startval: (brightness+1)*50, func: function(val)
			{
				brightness = val/50 - 1;
				glCanvas.draw(texture).brightnessContrast(brightness, contrast).update();
			}});
			var contrastSlider = new BV.pcSlider({label: "Contrast", w:300, h:30, start:0, end:100, startval:(contrast+1)*50, func:function(val)
			{
				contrast = val/50 - 1;
				glCanvas.draw(texture).brightnessContrast(brightness, contrast).update();
			}});
			div.appendChild(brightnessSlider);
			div.appendChild(contrastSlider);
			
			
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(glCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			
			div.appendChild(previewWrapper);
			glCanvas.draw(texture).brightnessContrast(brightness, contrast).update();
			div.getInput = function() {
				texture.destroy();
				return {
					brightness: brightness,
					contrast: contrast
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var brightness = params.input.brightness;
			var contrast = params.input.contrast;
			if(!context || brightness == null || contrast == null)
				return false;
			
			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return false;
			}
			var texture = glCanvas.texture(context.canvas);
			glCanvas.draw(texture).brightnessContrast(brightness, contrast).update();
			context.clearRect(0,0,context.canvas.width, context.canvas.height);
			context.drawImage(glCanvas,0,0);
			texture.destroy();
			return true;
		}
	
	},
	CropExtend: {
		name: "Crop/Extend",
		webgl: false,
		neededWithWebGL: true,
		updateContext: true,
		updatePos: true,
		getDialog: function(params) {
			var canvas = params.canvas;
			if(!canvas)
				return false;
			var tempCanvas = BV.createCanvas();
			(function() {
				var fit = BV.fitInto(560, 400, canvas.width, canvas.height);
				var w = parseInt(fit.width), h = parseInt(fit.height);
				var previewFactor = w/canvas.width;
				tempCanvas.width = w;
				tempCanvas.height = h;
				tempCanvas.getContext("2d").drawImage(canvas.getCompleteCanvas(previewFactor), 0, 0, w, h);
			})();			
			
			var div = document.createElement("div");
			div.innerHTML = "Crop or extend the image.<br/><br/>";
			var left = 0, right = 0, top = 0, bottom = 0;
			var leftChanged = false, rightChanged = false, topChanged = false, bottomChanged = false;
			var maxWidth = 2048, maxHeight = 2048;
			var offset, scale;
			
			var leftWrapper = document.createElement("div");
			var rightWrapper = document.createElement("div");
			var leftInput = document.createElement("input");
			var rightInput = document.createElement("input");
			leftInput.style.cssFloat = "right";
			leftWrapper.style.width = "220px";
			leftWrapper.style.height = "30px";
			rightInput.style.cssFloat = "right";
			rightWrapper.style.width = "220px";
			rightWrapper.style.height = "30px";
			if(navigator.appName != 'Microsoft Internet Explorer' )
				leftInput.type = "number";
			leftInput.min = -canvas.width;
			leftInput.max = maxWidth;
			if(navigator.appName != 'Microsoft Internet Explorer' )
				rightInput.type = "number";
			rightInput.min = -canvas.width;
			rightInput.max = maxWidth;
			leftInput.value = left;
			rightInput.value = right;
			leftInput.onclick = function() {
				this.focus();
				leftChanged = true;
				updateInput();
			}
			rightInput.onclick = function() {
				this.focus();
				rightChanged = true;
				updateInput();
			}
			leftInput.onchange = function() {
				leftChanged = true;
				updateInput();
			}
			rightInput.onchange = function() {
				rightChanged = true;
				updateInput();
			}
			leftInput.onkeyup = function() {
				leftChanged = true;
				updateInput();
			}
			rightInput.onkeyup = function() {
				rightChanged = true;
				updateInput();
			}
			leftWrapper.appendChild(document.createTextNode("Left: "));
			leftWrapper.appendChild(leftInput);
			rightWrapper.appendChild(document.createTextNode("Right: "));
			rightWrapper.appendChild(rightInput);
			
			div.appendChild(leftWrapper);
			div.appendChild(rightWrapper);
			
			var topWrapper = document.createElement("div");
			var bottomWrapper = document.createElement("div");
			var topInput = document.createElement("input");
			var bottomInput = document.createElement("input");
			topInput.style.cssFloat = "right";
			topWrapper.style.width = "220px";
			topWrapper.style.height = "30px";
			bottomInput.style.cssFloat = "right";
			bottomWrapper.style.width = "220px";
			bottomWrapper.style.height = "30px";
			if(navigator.appName != 'Microsoft Internet Explorer' )
				topInput.type = "number";
			topInput.min = -canvas.height;
			topInput.max = maxHeight;
			if(navigator.appName != 'Microsoft Internet Explorer' )
				bottomInput.type = "number";
			bottomInput.min = -canvas.height;
			bottomInput.max = maxHeight;
			topInput.value = top;
			bottomInput.value = bottom;
			topInput.onclick = function() {
				this.focus();
				topChanged = true;
				updateInput();
			}
			bottomInput.onclick = function() {
				this.focus();
				bottomChanged = true;
				updateInput();
			}
			topInput.onchange = function() {
				topChanged = true;
				updateInput();
			}
			bottomInput.onchange = function() {
				bottomChanged = true;
				updateInput();
			}
			topInput.onkeyup = function() {
				topChanged = true;
				updateInput();
			}
			bottomInput.onkeyup = function() {
				bottomChanged = true;
				updateInput();
			}
			topWrapper.appendChild(document.createTextNode("Top: "));
			topWrapper.appendChild(topInput);
			bottomWrapper.appendChild(document.createTextNode("Bottom: "));
			bottomWrapper.appendChild(bottomInput);
			
			div.appendChild(topWrapper);
			div.appendChild(bottomWrapper);
			
			function updateInput() {
				left = parseInt(leftInput.value);
				right = parseInt(rightInput.value);
				top = parseInt(topInput.value);
				bottom = parseInt(bottomInput.value);
				var newWidth = canvas.width+left+right;
				var newHeight = canvas.height+top+bottom;
				
				if(newWidth <= 0) {
					if(leftChanged) {
						left = -canvas.width-right+1;
						leftInput.value = left;
					}
					if(rightChanged) {
						right = -canvas.width-left+1;
						rightInput.value = right;
					}
					newWidth = 1;
				}
				if(newWidth > maxWidth) {
					if(leftChanged) {
						left = -canvas.width-right+maxWidth;
						leftInput.value = left;
					}
					if(rightChanged) {
						right = -canvas.width-left+maxWidth;
						rightInput.value = right;
					}
					newWidth = maxWidth;
				}
				if(newHeight <= 0) {
					if(topChanged) {
						top = -canvas.height-bottom+1;
						topInput.value = top;
					}
					if(bottomChanged) {
						bottom = -canvas.height-top+1;
						bottomInput.value = bottom;
					}
					newHeight = 1;
				}
				if(newHeight > maxHeight) {
					if(topChanged) {
						top = -canvas.height-bottom+maxHeight;
						topInput.value = top;
					}
					if(bottomChanged) {
						bottom = -canvas.height-top+maxHeight;
						bottomInput.value = bottom;
					}
					newHeight = maxHeight;
				}
				cropper.setTransform( {
					x: -left,
					y: -top,
					width: newWidth,
					height: newHeight					
				});
				
				
				leftChanged = false;
				rightChanged = false;
				topChanged = false;
				bottomChanged = false;
			}
			
			var cbH = document.createElement("input");
			cbH.type = "checkbox";
			cbH.style.cssFloat = "left";
			cbH.checked = true;
			
			cbH.onchange = function() {
				updateGrid();
			};
			var wrapperH = BV.appendTextDiv(div, "");
			wrapperH.onmousedown = function() {
				return false;
			}
			wrapperH.style.height = "30px";
			wrapperH.appendChild(cbH);
			var hLabel = BV.appendTextDiv(wrapperH, "rule of thirds");
			hLabel.onclick = function() {
				cbH.checked = !cbH.checked;
				updateGrid();
			}
			function updateGrid() {
				cropper.showThirds(cbH.checked);
			}
			hLabel.className = "checkLabel";
			
			function update(transform) {
				var fit = BV.fitInto(260, 180, transform.width, transform.height);
				scale = fit.width / transform.width;

				var offset = BV.centerWithin(300, 220, fit.width, fit.height);
				
				tempCanvas.style.width = canvas.width*scale + "px";
				tempCanvas.style.height = canvas.height*scale + "px";
				
				offsetWrapper.style.left = (offset.x - transform.x*scale) + "px";
				offsetWrapper.style.top = (offset.y - transform.y*scale) + "px";
				
				left = parseInt(-transform.x);
				top = parseInt(-transform.y);
				right = parseInt(transform.x + transform.width - canvas.width);
				bottom = parseInt(transform.y + transform.height - canvas.height);
				leftInput.value = left;
				topInput.value = top;
				rightInput.value = right;
				bottomInput.value = bottom;
				
				previewWrapper.style.background = "url(" + BV.createChecker(parseInt(50*scale)) + ")";
				previewWrapper.style.backgroundPosition = (offset.x) + "px " + (offset.y) + "px";
				
				cropper.setScale(scale);
			}
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.backgroundColor = "#aaa";
			previewWrapper.style.position = "relative";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";
			previewWrapper.style.overflow = "hidden";
			
			var offsetWrapper = document.createElement("div");
			offsetWrapper.style.position = "absolute";
			offsetWrapper.style.left = "0px";
			offsetWrapper.style.top = "0px";
			previewWrapper.appendChild(offsetWrapper);
			
			
			var canvasWrapper = BV.appendTextDiv(offsetWrapper, "");
			canvasWrapper.appendChild(tempCanvas);
			//tempCanvas.style.width = w + "px";
			//tempCanvas.style.height = h + "px";
			tempCanvas.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			tempCanvas.style.position = "absolute";
			tempCanvas.style.left = "0px";
			tempCanvas.style.top = "0px";
			
			div.appendChild(previewWrapper);
			var cropper = BV.Cropper( {
				x: 0,
				y: 0,
				width: canvas.width,
				height: canvas.height,
				scale: scale,
				callback: update,
				maxW: maxWidth,
				maxH: maxHeight
			});
			update(cropper.getTransform());
			offsetWrapper.appendChild(cropper);
			
			
			div.getInput = function() {
				return {
					left: left,
					right: right,
					top: top,
					bottom: bottom
				};
			};
			return div;
		},
		apply: function(params) {
			var canvas = params.canvas;
			if(!canvas)
				return false;
			canvas.resizeCanvas(params.input);
			return true;
		}
	},
	Flip: {
		name: "Flip",
		webgl: false,
		neededWithWebGL: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);
			
			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var horizontal = false, vertical = false;
			var flipCanvas = true;
			div.innerHTML = "Flips layer or whole canvas.<br/><br/>";
			
			function update() {
				horizontal = cbH.checked;
				vertical = cbV.checked;
				
				if(flipCanvas) {
					BV.css(layersContainer, {
						transform: "Scale("+(horizontal ? -1 : 1)+", "+(vertical ? -1 : 1)+")"
					});
				} else {
					BV.css(tempCanvas, {
						transform: "Scale("+(horizontal ? -1 : 1)+", "+(vertical ? -1 : 1)+")"
					});
				}
			}
			
			var cbH = document.createElement("input");
			cbH.type = "checkbox";
			cbH.style.cssFloat = "left";
			var cbV = document.createElement("input");
			cbV.type = "checkbox";
			cbV.style.cssFloat = "left";
			
			cbH.onchange = function() {
				update();
			};
			cbV.onchange = function() {
				update();
			};
			
			var wrapperH = BV.appendTextDiv(div, "");
			wrapperH.onmousedown = function() {
				return false;
			}
			wrapperH.style.height = "30px";
			wrapperH.appendChild(cbH);
			var hLabel = BV.appendTextDiv(wrapperH, "Horizontal");
			var wrapperV = BV.appendTextDiv(div, "");
			wrapperV.onmousedown = function() {
				return false;
			}
			wrapperV.style.height = "30px";
			wrapperV.appendChild(cbV);
			var vLabel = BV.appendTextDiv(wrapperV, "Vertical");
			hLabel.onclick = function() {
				cbH.checked = !cbH.checked;
				update();
			}
			vLabel.onclick = function() {
				cbV.checked = !cbV.checked;
				update();
			}
			hLabel.className = "checkLabel";
			vLabel.className = "checkLabel";
			
			var fcOption = document.createElement("div");
			fcOption.onmousedown = function() {
				return false;
			}
			fcOption.innerHTML = "Flip Canvas";
			fcOption.style.width = "150px";
			fcOption.style.height = "30px";
			fcOption.style.paddingTop = "10px";
			fcOption.style.textAlign = "center";
			fcOption.style.cssFloat = "left";
			fcOption.style.paddingBottom = "0px";
			fcOption.style.borderTopLeftRadius = "10px";
			fcOption.style.boxShadow = "inset 0px 5px 10px rgba(0,0,0,0.5)";
			fcOption.style.background = "url(checkmark.png) no-repeat 12px 16px";
			fcOption.style.backgroundColor = "#aaa";
			
			var flOption = document.createElement("div");
			flOption.onmousedown = function() {
				return false;
			}
			flOption.innerHTML = "Flip Layer";
			flOption.style.width = "150px";
			flOption.style.height = "30px";
			flOption.style.paddingTop = "10px";
			flOption.style.textAlign = "center";
			flOption.style.cssFloat = "left";
			flOption.style.paddingBottom = "0px";
			flOption.style.borderTopRightRadius = "10px";
			flOption.style.cursor = "pointer";
			flOption.style.backgroundColor = "#eee";
			
			fcOption.onmouseover = function() {
				if(flipCanvas === false)
					fcOption.style.backgroundColor = "#ccc";
			}
			fcOption.onmouseout = function() {
				if(flipCanvas === false)
					fcOption.style.backgroundColor = "#eee";
			}
			flOption.onmouseover = function() {
				if(flipCanvas === true)
					flOption.style.backgroundColor = "#ccc";
			}
			flOption.onmouseout = function() {
				if(flipCanvas === true)
					flOption.style.backgroundColor = "#eee";
			}
			
			fcOption.onclick = function() {
				flipCanvas = true;
				
				flOption.style.background = "";
				flOption.style.backgroundColor = "#eee";
				flOption.style.boxShadow = "";
				flOption.style.cursor = "pointer";
				
				fcOption.style.background = "url(checkmark.png) no-repeat 12px 16px";
				fcOption.style.backgroundColor = "#aaa";
				fcOption.style.cursor = "default";
				fcOption.style.boxShadow = "inset 0px 5px 10px rgba(0,0,0,0.5)";
				
				BV.css(tempCanvas, {
					transition: ""
				});
				BV.css(layersContainer, {
					transition: "all 0.4s ease-in-out"
				});
				BV.css(layersContainer, {
						transform: "Scale("+(horizontal ? -1 : 1)+", "+(vertical ? -1 : 1)+")"
					});
				BV.css(tempCanvas, {
					transform: "Scale("+1+", "+1+")"
				});
			}
			flOption.onclick = function() {
				flipCanvas = false;
				
				fcOption.style.background = "";
				fcOption.style.backgroundColor = "#eee";
				fcOption.style.boxShadow = "";
				fcOption.style.cursor = "pointer";
				
				flOption.style.background = "url(checkmark.png) no-repeat 12px 16px";
				flOption.style.backgroundColor = "#aaa";
				flOption.style.cursor = "default";
				flOption.style.boxShadow = "inset 0px 5px 10px rgba(0,0,0,0.5)";
				
				BV.css(tempCanvas, {
					transition: "all 0.4s ease-in-out"
				});
				BV.css(layersContainer, {
					transition: ""
				});
				BV.css(tempCanvas, {
						transform: "Scale("+(horizontal ? -1 : 1)+", "+(vertical ? -1 : 1)+")"
					});
				BV.css(layersContainer, {
					transform: "Scale("+1+", "+1+")"
				});
			}
			
			var optionWrapper = document.createElement("div");
			optionWrapper.appendChild(fcOption);
			optionWrapper.appendChild(flOption);
			div.appendChild(optionWrapper);
			
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(tempCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			BV.css(tempCanvas, {
				transition: "all 0.4s ease-in-out"
			});
			BV.css(layersContainer, {
				transition: "all 0.4s ease-in-out"
			});
			
			div.appendChild(previewWrapper);
			update();
			div.getInput = function() {
				return {
					horizontal: horizontal,
					vertical: vertical,
					flipCanvas: flipCanvas
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			var horizontal = params.input.horizontal;
			var vertical = params.input.vertical;
			var flipCanvas = params.input.flipCanvas;
			if(!context || ! canvas)
				return false;
				
			if(flipCanvas) {
				canvas.flip(horizontal, vertical);
			} else {
			
				var w = context.canvas.width;
				var h = context.canvas.height;
				(function () {
					var imdat = context.getImageData(0, 0, w, h);
					var tr, tg, tb, ta;
					var i, e;
					if(vertical) {
						for(i = 0; i < w; i++) {
							for(e = 0; e < h/2; e++) {
								
									tr = imdat.data[i*4+e*w*4];
									tg = imdat.data[i*4+e*w*4+1];
									tb = imdat.data[i*4+e*w*4+2];
									ta = imdat.data[i*4+e*w*4+3];
									
									imdat.data[i*4+e*w*4] = imdat.data[i*4+(h-e-1)*w*4];
									imdat.data[i*4+e*w*4 + 1] = imdat.data[i*4+(h-e-1)*w*4 + 1];
									imdat.data[i*4+e*w*4 + 2] = imdat.data[i*4+(h-e-1)*w*4 + 2];
									imdat.data[i*4+e*w*4 + 3] = imdat.data[i*4+(h-e-1)*w*4 + 3];
									
									imdat.data[i*4+(h-e-1)*w*4] = tr;
									imdat.data[i*4+(h-e-1)*w*4 + 1] = tg;
									imdat.data[i*4+(h-e-1)*w*4 + 2] = tb;
									imdat.data[i*4+(h-e-1)*w*4 + 3] = ta;
								}
							}
						}
					if(horizontal) {
						for(i = 0; i < w/2; i++) {
							for(e = 0; e < h; e++) {
								tr = imdat.data[i*4+e*w*4];
								tg = imdat.data[i*4+e*w*4+1];
								tb = imdat.data[i*4+e*w*4+2];
								ta = imdat.data[i*4+e*w*4+3];
								
								imdat.data[i*4+e*w*4] = imdat.data[(w-i-1)*4+e*w*4];
								imdat.data[i*4+e*w*4 + 1] = imdat.data[(w-i-1)*4+e*w*4 + 1];
								imdat.data[i*4+e*w*4 + 2] = imdat.data[(w-i-1)*4+e*w*4 + 2];
								imdat.data[i*4+e*w*4 + 3] = imdat.data[(w-i-1)*4+e*w*4 + 3];
								
								imdat.data[(w-i-1)*4+e*w*4] = tr;
								imdat.data[(w-i-1)*4+e*w*4 + 1] = tg;
								imdat.data[(w-i-1)*4+e*w*4 + 2] = tb;
								imdat.data[(w-i-1)*4+e*w*4 + 3] = ta;
							}
						}
					}
					context.putImageData(imdat, 0, 0);
				})();
			}
			return true;
		}
	},
	GLHueSaturation: {
		name: "Hue/Saturation",
		webgl: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var hue = 0, Saturation = 0;
			div.innerHTML = "Change hue and saturation for the selected layer.<br/><br/>";

			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return;
			}
			var texture = glCanvas.texture(tempCanvas);

			var hueSlider = new BV.pcSlider({label:"Hue", w:300, h:30, start:-100, end:100, startval:hue*100, func:function(val)
			{
				hue = val/100;
				glCanvas.draw(texture).hueSaturation(hue, Saturation).update();
			}});
			var SaturationSlider = new BV.pcSlider({label:"Saturation", w:300, h:30, start:0, end:100, startval:(Saturation+1)*50, func:function(val)
			{
				Saturation = val/50 - 1;
				glCanvas.draw(texture).hueSaturation(hue, Saturation).update();
			}});
			div.appendChild(hueSlider);
			div.appendChild(SaturationSlider);
			
			
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(glCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			
			div.appendChild(previewWrapper);
			glCanvas.draw(texture).hueSaturation(hue, Saturation).update();
			div.getInput = function() {
				texture.destroy();
				return {
					hue: hue,
					Saturation: Saturation
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var hue = params.input.hue;
			var Saturation = params.input.Saturation;
			if(!context || hue == null || Saturation == null)
				return false;
			
			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return false;
			}
			var texture = glCanvas.texture(context.canvas);
			glCanvas.draw(texture).hueSaturation(hue, Saturation).update();
			context.clearRect(0,0,context.canvas.width, context.canvas.height);
			context.drawImage(glCanvas,0,0);
			texture.destroy();
			return true;
		}
	
	},
	Invert: {
		name: "Invert",
		webgl: false,
		neededWithWebGL: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			//invertieren
			var imdat = tempCanvas.getContext("2d").getImageData(0, 0, w, h);
			for(var i = 0; i < imdat.data.length; i+= 4)
			{
				imdat.data[i] = 255 - imdat.data[i];
				imdat.data[i+1] = 255 - imdat.data[i + 1];
				imdat.data[i+2] = 255 - imdat.data[i + 2];
			}
			tempCanvas.getContext("2d").putImageData(imdat, 0, 0);
			
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var brightness = 0, contrast = 0;
			div.innerHTML = "Inverts the colors of the selected layer.<br/><br/>";
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(tempCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			
			div.appendChild(previewWrapper);
			div.getInput = function() {
				return {
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			if(!context)
				return false;
			
			var imdat = context.getImageData(0, 0, context.canvas.width, context.canvas.height);
			for(var i = 0; i < imdat.data.length; i+= 4)
			{
				imdat.data[i] = 255 - imdat.data[i];
				imdat.data[i+1] = 255 - imdat.data[i + 1];
				imdat.data[i+2] = 255 - imdat.data[i + 2];
			}
			context.putImageData(imdat, 0, 0);
			return true;
		}
	
	},
	GLPerspective: {
		name: "Perspective",
		webgl: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var blur = 0;
			div.innerHTML = "Transforms the selected layer<br/><br/>";

			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return;
			}
			var texture = glCanvas.texture(tempCanvas);
			var ba, bb, bc, bd; //before
			var aa, ab, ac, ad; //after
			function update() {
				glCanvas.draw(texture).perspective([ba.x,ba.y,bb.x,bb.y,bc.x,bc.y,bd.x,bd.y], [aa.x,aa.y,ab.x,ab.y,ac.x,ac.y,ad.x,ad.y]).update();
			}
			function nob(x, y, callback) {
				var div = document.createElement("div");
				div.x = x;
				div.y = y;
				div.style.width = "8px";
				div.style.height = "8px";
				div.style.backgroundColor = "#fff";
				div.style.border = "2px solid #000";
				div.style.borderRadius = "5px";
				div.style.position = "absolute";
				div.style.cursor = "move";
				div.style.left = (x-5)+"px";
				div.style.top = (y-5)+"px";
				BV.attachMouseListener(div, function(v) {
					if(v.dX || v.dY) {
						div.x += v.dX;
						div.y += v.dY;
						div.style.left = (div.x-5)+"px";
						div.style.top = (div.y-5)+"px";
						if(callback != undefined)
							callback();
						update();
					}
						
				});
				div.copy = function(p) {
					div.x = p.x;
					div.y = p.y;
					div.style.left = (div.x-5)+"px";
					div.style.top = (div.y-5)+"px";
				}
				return div;
			}
			function updateAfter() {
				aa.copy(ba);
				ab.copy(bb);
				ac.copy(bc);
				ad.copy(bd);
			};
			ba = nob(0,0, updateAfter);
			bb = nob(w,0, updateAfter);
			bc = nob(w,h, updateAfter);
			bd = nob(0,h, updateAfter);
			aa = nob(0,0);
			ab = nob(w,0);
			ac = nob(w,h);
			ad = nob(0,h);
			
			var before = false;
			var beforeOption = document.createElement("div");
			beforeOption.onmousedown = function() {
				return false;
			}
			beforeOption.innerHTML = "Before";
			beforeOption.style.width = "150px";
			beforeOption.style.height = "30px";
			beforeOption.style.paddingTop = "10px";
			beforeOption.style.textAlign = "center";
			beforeOption.style.cssFloat = "left";
			beforeOption.style.paddingBottom = "0px";
			beforeOption.style.borderTopLeftRadius = "10px";
			beforeOption.style.cursor = "pointer";
			beforeOption.style.backgroundColor = "#eee";
			
			var afterOption = document.createElement("div");
			afterOption.onmousedown = function() {
				return false;
			}
			afterOption.innerHTML = "After";
			afterOption.style.width = "150px";
			afterOption.style.height = "30px";
			afterOption.style.paddingTop = "10px";
			afterOption.style.textAlign = "center";
			afterOption.style.cssFloat = "left";
			afterOption.style.paddingBottom = "0px";
			afterOption.style.borderTopRightRadius = "10px";
			afterOption.style.boxShadow = "inset 0px 5px 10px rgba(0,0,0,0.5)";
			afterOption.style.background = "url(checkmark.png) no-repeat 12px 16px";
			afterOption.style.backgroundColor = "#aaa";
			
			
			beforeOption.onmouseover = function() {
				if(before === false)
					beforeOption.style.backgroundColor = "#ccc";
			}
			beforeOption.onmouseout = function() {
				if(before === false)
					beforeOption.style.backgroundColor = "#eee";
			}
			afterOption.onmouseover = function() {
				if(before === true)
					afterOption.style.backgroundColor = "#ccc";
			}
			afterOption.onmouseout = function() {
				if(before === true)
					afterOption.style.backgroundColor = "#eee";
			}
			
			beforeOption.onclick = function() {
				
				beforeOption.style.background = "url(checkmark.png) no-repeat 12px 16px";
				beforeOption.style.backgroundColor = "#aaa";
				beforeOption.style.boxShadow = "inset 0px 5px 10px rgba(0,0,0,0.5)";
				beforeOption.style.cursor = "default";
				
				afterOption.style.background = "";
				afterOption.style.backgroundColor = "#eee";
				afterOption.style.boxShadow = "";
				afterOption.style.cursor = "pointer";
				
				aa.style.display = "none";
				ab.style.display = "none";
				ac.style.display = "none";
				ad.style.display = "none";
				
				ba.style.display = "block";
				bb.style.display = "block";
				bc.style.display = "block";
				bd.style.display = "block";
				ba.copy(aa);
				bb.copy(ab);
				bc.copy(ac);
				bd.copy(ad);
				before = true;
				update();
			}
			afterOption.onclick = function() {
				before = false;
				
				afterOption.style.background = "url(checkmark.png) no-repeat 12px 16px";
				afterOption.style.backgroundColor = "#aaa";
				afterOption.style.boxShadow = "inset 0px 5px 10px rgba(0,0,0,0.5)";
				afterOption.style.cursor = "default";
				
				beforeOption.style.background = "";
				beforeOption.style.backgroundColor = "#eee";
				beforeOption.style.boxShadow = "";
				beforeOption.style.cursor = "pointer";
				
				ba.style.display = "none";
				bb.style.display = "none";
				bc.style.display = "none";
				bd.style.display = "none";
				
				aa.style.display = "block";
				ab.style.display = "block";
				ac.style.display = "block";
				ad.style.display = "block";
				aa.copy(ba);
				ab.copy(bb);
				ac.copy(bc);
				ad.copy(bd);
			}
			
			var optionWrapper = document.createElement("div");
			optionWrapper.appendChild(beforeOption);
			optionWrapper.appendChild(afterOption);
			div.appendChild(optionWrapper);
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(glCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			layersContainer.appendChild(aa);
			layersContainer.appendChild(ab);
			layersContainer.appendChild(ac);
			layersContainer.appendChild(ad);
			
			ba.style.display = "none";
			bb.style.display = "none";
			bc.style.display = "none";
			bd.style.display = "none";
			layersContainer.appendChild(ba);
			layersContainer.appendChild(bb);
			layersContainer.appendChild(bc);
			layersContainer.appendChild(bd);
			
			
			div.appendChild(previewWrapper);
			update();
			div.getInput = function() {
				texture.destroy();
				return {
					before: [ba.x/previewFactor, ba.y/previewFactor, bb.x/previewFactor, bb.y/previewFactor, bc.x/previewFactor, bc.y/previewFactor, bd.x/previewFactor, bd.y/previewFactor],
					after: [aa.x/previewFactor, aa.y/previewFactor, ab.x/previewFactor, ab.y/previewFactor, ac.x/previewFactor, ac.y/previewFactor, ad.x/previewFactor, ad.y/previewFactor]
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var before = params.input.before;
			var after = params.input.after;
			if(!context || !before || !after)
				return false;
			
			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return false;
			}
			var texture = glCanvas.texture(context.canvas);
			var w = context.canvas.width;
			var h = context.canvas.height;
			glCanvas.draw(texture).perspective(before, after).update();
			context.clearRect(0,0,context.canvas.width, context.canvas.height);
			context.drawImage(glCanvas,0,0);
			texture.destroy();
			return true;
		}
	
	},
	Resize: {
		name: "Resize",
		webgl: false,
		neededWithWebGL: true,
		updateContext: true,
		updatePos: true,
		getDialog: function(params) {
			//BV.centerWithin
			var canvas = params.canvas;
			if(!canvas)
				return false;
			
			var fit = BV.fitInto(280, 200, canvas.width, canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var previewFactor = w/canvas.width;
			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(canvas.getCompleteCanvas(previewFactor), 0, 0, w, h);
				
			
			var div = document.createElement("div");
			var newWidth = canvas.width, newHeight = canvas.height;
			
			div.innerHTML = "Resizes the image.<br/><br/>";
			

			
			var maxWidth = 2048, maxHeight = 2048;
			
			var widthWrapper = document.createElement("div");
			var heightWrapper = document.createElement("div");
			var widthInput = document.createElement("input");
			var heightInput = document.createElement("input");
			widthInput.style.cssFloat = "right";
			widthWrapper.style.width = "220px";
			widthWrapper.style.height = "30px";
			heightInput.style.cssFloat = "right";
			heightWrapper.style.width = "220px";
			heightWrapper.style.height = "30px";
			if(navigator.appName != 'Microsoft Internet Explorer' )
				widthInput.type = "number";
			widthInput.min = 1;
			widthInput.max = maxWidth;
			if(navigator.appName != 'Microsoft Internet Explorer' )
				heightInput.type = "number";
			heightInput.min = 1;
			heightInput.max = maxHeight;
			widthInput.value = canvas.width;
			heightInput.value = canvas.height;
			widthInput.onclick = function() {
				this.focus();
				widthChanged = true;
				update();
			}
			heightInput.onclick = function() {
				this.focus();
				heightChanged = true;
				update();
			}
			widthInput.onchange = function() {
				widthChanged = true;
				update();
			}
			heightInput.onchange = function() {
				heightChanged = true;
				update();
			}
			widthInput.onkeyup = function() {
				widthChanged = true;
				update();
			}
			heightInput.onkeyup = function() {
				heightChanged = true;
				update();
			}
			widthWrapper.appendChild(document.createTextNode("Width: "));
			widthWrapper.appendChild(widthInput);
			heightWrapper.appendChild(document.createTextNode("Height: "));
			heightWrapper.appendChild(heightInput);
			var inputWrapper = document.createElement("div");
			inputWrapper.style.background = "url(constrain.png) no-repeat 220px 0";
			inputWrapper.appendChild(widthWrapper);
			inputWrapper.appendChild(heightWrapper);
			div.appendChild(inputWrapper);
			
			//contrain checkbox
			var heightChanged = false, widthChanged = false;
			var ratio = canvas.width/canvas.height;
			function toggleConstrain() {
				if(cbC.checked) {
					widthInput.value = canvas.width;
					heightInput.value = canvas.height;
					inputWrapper.style.background = "url(constrain.png) no-repeat 220px 0";
					update();
				} else {
					inputWrapper.style.background = "";
				}
			}
			var cbC = document.createElement("input");
			cbC.type = "checkbox";
			cbC.checked = true;
			cbC.style.cssFloat = "left";
			cbC.onchange = function() {
				toggleConstrain();
			};
			var wrapperC = BV.appendTextDiv(div, "");
			wrapperC.onmousedown = function() {
				return false;
			}
			wrapperC.style.height = "30px";
			wrapperC.appendChild(cbC);
			var cLabel = BV.appendTextDiv(wrapperC, "Constrain Proportions");
			cLabel.onclick = function() {
				cbC.checked = !cbC.checked;
				toggleConstrain();
			}
			cLabel.className = "checkLabel";
			
			
			
			
			var previewCanvas = BV.createCanvas();
			previewCanvas.width = tempCanvas.width;
			previewCanvas.height = tempCanvas.height;
			previewCanvas.getContext("2d").drawImage(tempCanvas,0,0,previewCanvas.width, previewCanvas.height);
			
			function update() {
				if(widthInput.value === newWidth && heightInput.value === newHeight) {
					heightChanged = false;
					widthChanged = false;
					return;
				}
				if((widthInput.value.length === 0 && widthChanged) || (heightInput.value.length === 0 && heightChanged)) {
					heightChanged = false;
					widthChanged = false;
					return;
				}
				widthInput.value = Math.max(1, widthInput.value);
				heightInput.value = Math.max(1, heightInput.value);
				if(cbC.checked) {
					if(heightChanged) {
						widthInput.value = parseInt(heightInput.value * ratio);
					}
					if(widthChanged) {
						heightInput.value = parseInt(widthInput.value / ratio);
					}
					
					if(widthInput.value > maxWidth || heightInput.value > maxHeight) {
						var fit = BV.fitInto(maxWidth, maxHeight, widthInput.value, heightInput.value);
						widthInput.value = parseInt(fit.width);
						heightInput.value = parseInt(fit.height);
					}
				}
				
				if(widthInput.value > maxWidth)
					widthInput.value = maxWidth;
				if(heightInput.value > maxHeight)
					heightInput.value = maxHeight;

				heightChanged = false;
				widthChanged = false;
				
				newWidth = widthInput.value;
				newHeight = heightInput.value;
				
				var preview = BV.fitInto(280, 200, newWidth, newHeight);
				var previewW = parseInt(preview.width), previewH = parseInt(preview.height);
				var previewWf = preview.width;
				
				var offset = BV.centerWithin(300,220, previewW, previewH);
				
				if(newWidth < w && newHeight < h) {
					previewCanvas.width = newWidth;
					previewCanvas.height = newHeight;
					previewCanvas.getContext("2d").drawImage(tempCanvas,0,0,previewCanvas.width, previewCanvas.height);
				} else {
					previewCanvas.width = tempCanvas.width;
					previewCanvas.height = tempCanvas.height;
					previewCanvas.getContext("2d").drawImage(tempCanvas,0,0,previewCanvas.width, previewCanvas.height);
				}
				
				previewCanvas.style.width = Math.max(1, previewW)+"px";
				previewCanvas.style.height = Math.max(1, previewH)+"px";
				canvasWrapper.style.left = offset.x+"px";
				canvasWrapper.style.top = offset.y+"px";
				canvasWrapper.style.width = Math.max(1, previewW)+"px";
				canvasWrapper.style.height = Math.max(1, previewH)+"px";
				previewWrapper.style.background = "url(" + BV.createChecker(parseInt(50*(previewWf/newWidth))) + ")";
				previewWrapper.style.backgroundPosition = (offset.x + previewW / 2) + "px " + (offset.y + previewH / 2) + "px";
			}
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.backgroundColor = "#aaa";
			previewWrapper.style.position = "relative";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";


			var canvasWrapper = BV.appendTextDiv(previewWrapper, "");
			canvasWrapper.appendChild(previewCanvas);
			canvasWrapper.style.width = w+"px";
			canvasWrapper.style.height = h+"px";
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.overflow = "hidden";
			canvasWrapper.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			canvasWrapper.style.overflow = "hidden";
			previewWrapper.style.background = "url(" + BV.createChecker(4) + ")";

			div.appendChild(previewWrapper);
			update();
			
			div.getInput = function() {

				return {
					width: newWidth,
					height: newHeight
				};
			};
			return div;
		},
		apply: function(params) {
			var canvas = params.canvas;
			var width = params.input.width;
			var height = params.input.height;
			if(!canvas)
				return false;
			canvas.resize(width, height);
			return true;
		}
	},
	Rotate: {
		name: "Rotate",
		webgl: false,
		neededWithWebGL: true,
		updateContext: true,
		updatePos: true,
		getDialog: function(params) {
			var canvas = params.canvas;
			if(!canvas)
				return false;
			
			var fit = BV.fitInto(280, 200, canvas.width, canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var previewFactor = w/canvas.width;
			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(canvas.getCompleteCanvas(previewFactor), 0, 0, w, h);
				
			
			var div = document.createElement("div");
			var deg = 0;
			div.innerHTML = "Rotates the image.<br/><br/>";
			
			var first = true;
			function update() {
				canvasWrapper.style.WebkitTransform = "rotate("+deg+"deg)";
				canvasWrapper.style.MozTransform = "rotate("+deg+"deg)";
				canvasWrapper.style.OTransform = "rotate("+deg+"deg)";
				canvasWrapper.style.msTransform = "rotate("+deg+"deg)";
				if(Math.abs(deg%180) === 90) {
					//height has to fit width because of rotation
					var fit = BV.fitInto(280, 200, h, w);
					var scale = parseInt(fit.height)/w;
					canvasWrapper.style.WebkitTransform = "rotate("+deg+"deg) scale("+scale+")";
					canvasWrapper.style.MozTransform = "rotate("+deg+"deg) scale("+scale+")";
					canvasWrapper.style.OTransform = "rotate("+deg+"deg) scale("+scale+")";
					canvasWrapper.style.msTransform = "rotate("+deg+"deg) scale("+scale+")";
				}
			}
			
			var btnPlus = document.createElement("button");
			btnPlus.innerHTML = "+90°";
			var btnMinus = document.createElement("button");
			btnMinus.innerHTML = "-90°";
			
			
			btnPlus.onclick = function() {
				deg += 90;
				update();
			};
			btnMinus.onclick = function() {
				deg -= 90;
				update();
			};
			
			div.appendChild(btnMinus);
			div.appendChild(btnPlus);
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";
			previewWrapper.style.overflow = "hidden";;
			
			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(tempCanvas);
			previewWrapper.appendChild(previewcell);
			canvasWrapper.style.width = w+"px";
			canvasWrapper.style.height = h+"px";
			canvasWrapper.style.marginLeft = "auto";
			canvasWrapper.style.marginRight = "auto";
			canvasWrapper.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			canvasWrapper.style.overflow = "hidden";
			canvasWrapper.style.background = "url(" + BV.createChecker(4) + ")";
			canvasWrapper.style.webkitTransition = "all 0.4s ease-in-out";
			canvasWrapper.style.MozTransition = "all 0.4s ease-in-out";
			canvasWrapper.style.OTransition = "all 0.4s ease-in-out";
			canvasWrapper.style.msTransition = "all 0.4s ease-in-out";
			
			div.appendChild(previewWrapper);
			update();
			
			div.getInput = function() {
				return {
					deg: deg
				};
			};
			return div;
		},
		apply: function(params) {
			var canvas = params.canvas;
			var deg = params.input.deg;
			if(!canvas)
				return false;
			canvas.rotate(deg);
			return true;
		}
	},
	GLTiltShift: {
		name: "Tilt Shift",
		webgl: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			var previewFactor = w/context.canvas.width;			
			var div = document.createElement("div");
			var blur = 20, gradient = 200;
			div.innerHTML = "Applies tilt shift on the selected layer.<br/><br/>";

			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return;
			}
			var texture = glCanvas.texture(tempCanvas);
			var fa, fb; // focus line
			function update() {
				glCanvas.draw(texture).tiltShift(fa.x, fa.y, fb.x, fb.y, blur*previewFactor, gradient*previewFactor).update();
			}
			function nob(x, y) {
				var div = document.createElement("div");
				div.x = x;
				div.y = y;
				div.style.width = 6+"px";
				div.style.height = 6+"px";
				div.style.backgroundColor = "#fff";
				div.style.border = "2px solid #000";
				div.style.borderRadius = "5px";
				div.style.position = "absolute";
				div.style.cursor = "move";
				div.style.left = (x-4)+"px";
				div.style.top = (y-4)+"px";
				BV.attachMouseListener(div, function(v) {
					if(v.dX || v.dY) {
						div.x += v.dX;
						div.y += v.dY;
						div.style.left = (div.x-4)+"px";
						div.style.top = (div.y-4)+"px";
						update();
					}
						
				});
				return div;
			}
			fa = nob(parseInt(w/6), parseInt(h/2));
			fb = nob(parseInt(w-w/6), parseInt(h-h/3));
			
			var blurSlider = new BV.pcSlider({label:"Blur Radius", w:300, h:30, start:0, end:100, startval:blur, func:function(val)
			{
				blur = val;
				update();
			}});
			div.appendChild(blurSlider);
			var gradientSlider = new BV.pcSlider({label:"Gradient Radius", w:300, h:30, start:0, end:500, startval:gradient, func:function(val)
			{
				gradient = val;
				update();
			}});
			div.appendChild(gradientSlider);
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(glCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			layersContainer.appendChild(fa);
			layersContainer.appendChild(fb);
			
			
			div.appendChild(previewWrapper);
			update();
			div.getInput = function() {
				texture.destroy();
				return {
					a: {x:fa.x/previewFactor, y:fa.y/previewFactor},
					b: {x:fb.x/previewFactor, y:fb.y/previewFactor},
					blur: blur,
					gradient: gradient
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var a = params.input.a;
			var b = params.input.b;
			var blur = params.input.blur;
			var gradient = params.input.gradient;
			if(!context)
				return false;
			
			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return false;
			}
			var texture = glCanvas.texture(context.canvas);
			var w = context.canvas.width;
			var h = context.canvas.height;
			glCanvas.draw(texture).tiltShift(a.x, a.y, b.x, b.y, blur, gradient).update();
			context.clearRect(0,0,context.canvas.width, context.canvas.height);
			context.drawImage(glCanvas,0,0);
			texture.destroy();
			return true;
		}
	
	},
	Transform: {
		name: "Transform",
		webgl: false,
		neededWithWebGL: true,
		updateContext: true,
		updatePos: false,
		ieFails: true,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);
			var ratio = fit.width/context.canvas.width;
			
			var bounds = {
				x1: context.canvas.width,
				y1: context.canvas.height,
				x2: 0,
				y2: 0
			};
			var imdat = context.getImageData(0, 0, context.canvas.width, context.canvas.height);
			for(var i = 0; i < context.canvas.width; i++) {
				for(var e = 0; e < context.canvas.height; e++) {
					if(imdat.data[i*4 + e*context.canvas.width*4 + 3] > 0) {
						if(i < bounds.x1) {
							bounds.x1 = i;
						}
						if(e < bounds.y1) {
							bounds.y1 = e;
						}
						if(i > bounds.x2) {
							bounds.x2 = i;
						}
						if(e > bounds.y2) {
							bounds.y2 = e;
						}
					}
				}
			}
			if(bounds.x2 === 0 || bounds.y2 === 0)
				return false;
			var tempCanvas = BV.createCanvas();
			tempCanvas.width = (bounds.x2 - bounds.x1)*ratio;
			tempCanvas.height = (bounds.y2 - bounds.y1)*ratio;
			tempCanvas.getContext("2d").drawImage(context.canvas, -bounds.x1*ratio, -bounds.y1*ratio, w, h);
			
			
			
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var brightness = 0, contrast = 0;
			div.innerHTML = "Transform the selected layer.<br/>Press Shift for additional snapping(angle, position).<br/><br/>";
			
			var leftWrapper = document.createElement("div");
			var rightWrapper = document.createElement("div");
			var rotWrapper = document.createElement("div");
			var inputY = document.createElement("input");
			var inputX = document.createElement("input");
			var inputR = document.createElement("input");
			leftWrapper.style.width = "100px";
			leftWrapper.style.height = "30px";
			rightWrapper.style.width = "100px";
			rightWrapper.style.height = "30px";
			rightWrapper.style.display = "inline-block";
			leftWrapper.style.display = "inline-block";
			rotWrapper.style.display = "inline-block";
			rotWrapper.style.width = "100px";
			rotWrapper.style.height = "30px";
			if(navigator.appName != 'Microsoft Internet Explorer' )
				inputY.type = "number";
			if(navigator.appName != 'Microsoft Internet Explorer' )
				inputX.type = "number";
			if(navigator.appName != 'Microsoft Internet Explorer' )
				inputR.type = "number";
			inputX.style.width = 80+"px";
			inputY.style.width = 80+"px";
			inputR.style.width = 80+"px";
			inputY.value = 0;
			inputX.value = 0;
			inputR.value = 0;
			inputY.onclick = function() {
				this.focus();
				update();
			}
			inputX.onclick = function() {
				this.focus();
				update();
			}
			inputR.onclick = function() {
				this.focus();
				update();
			}
			inputY.onchange = function() {
				update();
			}
			inputX.onchange = function() {
				update();
			}
			inputR.onchange = function() {
				update();
			}
			inputY.onkeyup = function() {
				update();
			}
			inputX.onkeyup = function() {
				update();
			}
			inputR.onkeyup = function() {
				update();
			}
			leftWrapper.appendChild(document.createTextNode("X: "));
			leftWrapper.appendChild(inputX);
			rightWrapper.appendChild(document.createTextNode("Y: "));
			rightWrapper.appendChild(inputY);
			rotWrapper.appendChild(document.createTextNode("Rotation: "));
			rotWrapper.appendChild(inputR);
			div.appendChild(leftWrapper);
			div.appendChild(rightWrapper);
			div.appendChild(rotWrapper);
			
			var constrained = false;
			function toggleConstrain() {
				constrained = cbC.checked;
				transform.setConstrained(constrained);
			};
			var cbC = document.createElement("input");
			cbC.type = "checkbox";
			cbC.checked = true;
			cbC.style.cssFloat = "left";
			cbC.onchange = function() {
				toggleConstrain();
			};
			BV.appendTextDiv(div, "<br/>");
			var wrapperC = BV.appendTextDiv(div, "");
			wrapperC.style.display = "inline-block";
			wrapperC.onmousedown = function() {
				return false;
			}
			wrapperC.style.height = "30px";
			wrapperC.appendChild(cbC);
			var cLabel = BV.appendTextDiv(wrapperC, "Constrain Proportions");
			cLabel.style.display = "inline-block";
			cLabel.onclick = function() {
				cbC.checked = !cbC.checked;
				toggleConstrain();
			}
			cLabel.className = "checkLabel";
			
			var snapping = false;
			function toggleSnapping() {
				snapping = cbS.checked;
				transform.setSnapping(snapping);
			};
			var cbS = document.createElement("input");
			cbS.type = "checkbox";
			cbS.checked = true;
			cbS.style.cssFloat = "left";
			cbS.onchange = function() {
				toggleSnapping();
			};
			var wrapperS = BV.appendTextDiv(div, "");
			wrapperS.style.display = "inline-block";
			wrapperS.style.marginLeft = "5px";
			wrapperS.onmousedown = function() {
				return false;
			}
			wrapperS.style.height = "30px";
			wrapperS.appendChild(cbS);
			var sLabel = BV.appendTextDiv(wrapperS, "Snapping");
			sLabel.style.display = "inline-block";
			sLabel.onclick = function() {
				cbS.checked = !cbS.checked;
				toggleSnapping();
			}
			sLabel.className = "checkLabel";
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "260px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";
			previewWrapper.style.overflow = "hidden";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(tempCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			canvasWrapper.style.width = w+"px";
			canvasWrapper.style.height = h+"px";
			canvasWrapper.style.overflow = "hidden";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
				backLayer.style.pointerEvents = "none";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
				frontLayer.style.pointerEvents = "none";
			})();
			
			var transformparams = {
				x: bounds.x1*ratio + (bounds.x2 - bounds.x1 + 1)*ratio/2,
				y: bounds.y1*ratio + (bounds.y2 - bounds.y1 + 1)*ratio/2,
				width: (bounds.x2 - bounds.x1 + 1)*ratio,
				height: (bounds.y2 - bounds.y1 + 1)*ratio,
				angle: 0,
				elem: tempCanvas,
				appendElem: false,
				constrained: true,
				snapX: [0, fit.width],
				snapY: [0, fit.height],
				callback: function(t) {
					inputX.value = Math.round(t.x/ratio);
					inputY.value = Math.round(t.y/ratio);
					inputR.value = Math.round(t.angle);
				},
				scale: ratio
			};
			var transform = new BV.FreeTransform(transformparams);
			function update() {
				//console.log(inputX.value*ratio + " - " + inputY.value*ratio);
				transform.setPos({x:inputX.value*ratio, y:inputY.value*ratio});
				transform.setAngle(inputR.value);
			}
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			layersContainer.appendChild(transform.div);

			div.appendChild(previewWrapper);
			div.getInput = function() {
				var trans = transform.getTransform();
				trans.width /= ratio;
				trans.height /= ratio;
				trans.x /= ratio;
				trans.y /= ratio;
				trans.bounds = bounds;
				return trans;
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			if(!context)
				return false;
			var ratioX = Math.abs(params.input.width) / (params.input.bounds.x2 - params.input.bounds.x1+1);
			var ratioY = Math.abs(params.input.height) / (params.input.bounds.y2 - params.input.bounds.y1+1);
			var tempCanvas = BV.createCanvas();
			tempCanvas.width = (params.input.bounds.x2 - params.input.bounds.x1+1);
			tempCanvas.height = (params.input.bounds.y2 - params.input.bounds.y1+1);
			tempCanvas.getContext("2d").drawImage(context.canvas, -params.input.bounds.x1, -params.input.bounds.y1);
			BV.resizeCanvas(tempCanvas, Math.round(Math.abs(params.input.width)), Math.round(Math.abs(params.input.height)));
			context.save();
			context.clearRect(0,0,context.canvas.width, context.canvas.height);
			context.translate(Math.round(params.input.x),Math.round(params.input.y));
			context.rotate(params.input.angle/180*Math.PI);
			if(params.input.width < 0) {
				context.scale(-1, 1);
			}
			if(params.input.height < 0) {
				context.scale(1, -1);
			}
			context.drawImage(tempCanvas, -Math.round(Math.abs(params.input.width/2)), -Math.round(Math.abs(params.input.height/2)));
			context.restore();
			return true;
		}
	
	},
	GLBlur: {
		name: "Triangle Blur",
		webgl: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var canvas = params.canvas;
			var context = params.context;
			if(!canvas || !context)
				return false;
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var radius = 10;
			div.innerHTML = "Applies triangle blur on the selected layer.<br/><br/>";

			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return;
			}
			var texture = glCanvas.texture(tempCanvas);

			var radiusSlider = new BV.pcSlider({label:"Radius", w:300, h:30, start:1, end:100, startval:radius, func:function(val)
			{
				radius = val;
				glCanvas.draw(texture).triangleBlur(radius*previewFactor).update();
			}});
			div.appendChild(radiusSlider);
			
			
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(glCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			div.appendChild(previewWrapper);
			/*div.appendChild(BV.previewCanvas({
				containerWidth: 260,
				containerHeight: 180
			}));*/
			glCanvas.draw(texture).triangleBlur(radius*previewFactor).update();
			div.getInput = function() {
				return {
					radius: radius
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var radius = params.input.radius;
			if(!context || !radius)
				return false;
			
			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return false;
			}
			var texture = glCanvas.texture(context.canvas);
			glCanvas.draw(texture).triangleBlur(radius).update();
			context.clearRect(0,0,context.canvas.width, context.canvas.height);
			context.drawImage(glCanvas,0,0);
			
			return true;
		}
	
	},
	GLUnsharpMask: {
		name: "Unsharp Mask",
		webgl: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			var canvas = params.canvas;
			if(!context || !canvas)
				return false;
			
			var layer;
			
			var layers = canvas.getLayers();
			context.canvas.funnyname = "dingdong";
			for(var i = 0; i < layers.length; i++)
			{
				if(layers[i].context.canvas.funnyname == "dingdong")
					layer = i;
			}
			context.canvas.funnyname = undefined;
			
			var fit = BV.fitInto(280, 200, context.canvas.width, context.canvas.height);
			var w = parseInt(fit.width), h = parseInt(fit.height);

			var tempCanvas = BV.createCanvas();
			tempCanvas.width = w;
			tempCanvas.height = h;
			tempCanvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);
			var previewFactor = w/context.canvas.width;			
			
			var div = document.createElement("div");
			var radius = 2, strength = 2;
			div.innerHTML = "Sharpens the selected layer by scaling pixels away from the average of their neighbors.<br/><br/>";

			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return;
			}
			var texture = glCanvas.texture(tempCanvas);

			var radiusSlider = new BV.pcSlider({label:"Radius", w:300, h:30, start:0, end:200, startval:0.1, func:function(val)
			{
				radius = val;
				glCanvas.draw(texture).unsharpMask(radius*previewFactor, strength).update();
			}, spline: [[0,0], [0.1, 2],[0.5,50],[1,200]]});
			var strengthSlider = new BV.pcSlider({label:"Strength", w:300, h:30, start:0, end:50, startval:0.1, func:function(val)
			{
				strength = val/10;
				glCanvas.draw(texture).unsharpMask(radius*previewFactor, strength).update();
			}, spline: [[0,0],[0.1,2],[0.5,10],[1,50]]});
			div.appendChild(radiusSlider);
			div.appendChild(strengthSlider);
			
			
			
			var previewWrapper = document.createElement("div");
			previewWrapper.style.width = "300px";
			previewWrapper.style.height = "220px";
			previewWrapper.style.display = "table";
			previewWrapper.style.backgroundColor = "#aaa";
			//previewWrapper.style.padding = "10px";
			previewWrapper.style.marginTop = "10px";
			previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";

			var previewcell = document.createElement("div");
			previewcell.style.display = "table-cell";
			previewcell.style.verticalAlign = "middle";
			var canvasWrapper = document.createElement("div");
			var layersContainer = BV.appendTextDiv(previewcell, "");
			canvasWrapper.appendChild(glCanvas);
			previewWrapper.appendChild(previewcell);
			layersContainer.style.width = w+"px";
			layersContainer.style.height = h+"px";
			layersContainer.style.marginLeft = "auto";
			layersContainer.style.marginRight = "auto";
			layersContainer.style.position = "relative";
			layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
			layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
			
			
			canvasWrapper.style.position = "absolute";
			canvasWrapper.style.left = "0px";
			canvasWrapper.style.top = "0px";
			var backLayer = BV.createCanvas();
			(function() {
				backLayer.width = parseInt(w);
				backLayer.height = parseInt(h);
				var ctx = backLayer.getContext("2d");
				for(var i = 0; i < layer; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, backLayer.width, backLayer.height);
				}
				backLayer.style.position = "absolute";
				backLayer.style.left = "0px";
				backLayer.style.top = "0px";
			})();
			var frontLayer = BV.createCanvas();
			(function() {
				frontLayer.width = parseInt(w);
				frontLayer.height = parseInt(h);
				var ctx = frontLayer.getContext("2d");
				for(var i = layer+1; i < layers.length; i++)
				{
					ctx.globalAlpha = parseFloat(layers[i].opacity);
					ctx.drawImage(layers[i].context.canvas, 0, 0, frontLayer.width, frontLayer.height);
				}
				frontLayer.style.position = "absolute";
				frontLayer.style.left = "0px";
				frontLayer.style.top = "0px";
			})();
			
			
			
			layersContainer.appendChild(backLayer);
			layersContainer.appendChild(canvasWrapper);
			layersContainer.appendChild(frontLayer);
			
			
			div.appendChild(previewWrapper);
			glCanvas.draw(texture).unsharpMask(radius*previewFactor, strength).update();
			div.getInput = function() {
				texture.destroy();
				return {
					radius: radius,
					strength: strength
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var radius = params.input.radius;
			var strength = params.input.strength;
			if(!context || radius == null || strength == null)
				return false;
			
			var glCanvas;
			try {
				glCanvas = fx.canvas();
			} catch (e) {
				return false;
			}
			var texture = glCanvas.texture(context.canvas);
			glCanvas.draw(texture).unsharpMask(radius, strength).update();
			context.clearRect(0,0,context.canvas.width, context.canvas.height);
			context.drawImage(glCanvas,0,0);
			texture.destroy();
			return true;
		}
	
	}
	/*,
	PixelPaint: {
		name: "Pixel Paint",
		webgl: false,
		neededWithWebGL: true,
		updateContext: true,
		updatePos: false,
		getDialog: function(params) {
			var context = params.context;
			if(!context)
				return false;
			var w = context.canvas.width, h = context.canvas.height;
			var canvas = BV.createCanvas();
			canvas.width = w;
			canvas.height = h;
			canvas.getContext("2d").drawImage(context.canvas, 0, 0, w, h);

			var zoom = 10;
			var offsetX = 0, offsetY = 0;
			
			var div = document.createElement("div");
			div.innerHTML = "This module will allow you to draw pixel art.<br/><br/>";

			var preview = BV.createCanvas();
			preview.width = 300;
			preview.height = 220;			
			function updatePreview() {
				var imdat = canvas.getContext("2d").getImageData(offsetX, offsetY, 300, 220);
				var pContext = preview.getContext("2d");
				var i, e, r, g, b, a;
				for(i = 0; i < 300; i++) {
					for(e = 0; e < 220; e++) {
						r = imdat.data[i*4+e*300*4];
						g = imdat.data[i*4+e*300*4+1];
						b = imdat.data[i*4+e*300*4+2];
						a = imdat.data[i*4+e*300*4+3];
						pContext.fillStyle = "rgba("+r+","+g+","+b+","+a+")";
						pContext.fillRect(i*zoom, e*zoom, zoom, zoom);
					}
				}
			};
			updatePreview();
			
			var workspace = document.createElement("div");
			workspace.style.width = "300px";
			workspace.style.height = "220px";
			workspace.style.backgroundColor = "#aaa";
			workspace.onmousedown = function() {
				return false;
			}
			workspace.oncontextmenu = function() {
				return false;
			}
			
			BV.attachMouseListener(workspace, function(val) {
				if(val.dragdone ===false && val.code == 2) {
					offsetX -= val.dX;
					offsetY -= val.dY;
					offsetX = Math.max(0, Math.min(w-300/zoom, offsetX));
					offsetY = Math.max(0, Math.min(h-220/zoom, offsetY));
				}
				if(val.dragdone === true && val.code == 2) {
					updatePreview();
				}
				if(val.down ===true && val.code == 0) {
					var context = canvas.getContext("2d");
					context.fillStyle = "rgba(0,0,0,1)";
					context.fillRect(parseInt(val.absX/zoom+offsetX), parseInt(val.absY/zoom+offsetY), 1, 1);
					
					updatePreview();
				}
			});
			
			workspace.appendChild(preview);
			div.appendChild(workspace);
			
			div.getInput = function() {
				return {
					newCanvas: canvas
				};
			};
			return div;
		},
		apply: function(params) {
			var context = params.context;
			var newCanvas = params.input.newCanvas;
			if(!context || newCanvas == null)
				return false;
			context.drawImage(newCanvas, 0, 0);

			return true;
		}
	
	}*/
};
