/*
 * Water Canvas by Almer Thie (http://code.almeros.com).
 * Description: A realtime water ripple effect on an HTML5 canvas. 
 * Copyright 2010 Almer Thie. All rights reserved.
 *
 * Example: http://code.almeros.com/code-examples/water-effect-canvas/
 * Tutorial: http://code.almeros.com/water-ripple-canvas-and-javascript
 */

 
////////////////////////////////////////////////////////////////////////////////
//                              WaterCanvas object                            //
////////////////////////////////////////////////////////////////////////////////

/**
 * This view object is responsible for applying the water ripple data state to an image and therefor 
 * is also responsible for the refraction effect of the light through the water.
 * 
 * @param {Number} width The width in pixels this canvas should be.
 * @param {Number} hight The hight in pixels this canvas should be.
 * @param {String} documentElement The div element ID to insert the canvas into.
 * @param {Object} waterModel A reference to a WaterModel object previously created.
 * @param {Object} props A key/value object which may contain the following properties:
 * 				backgroundImageUrl: 
 *						A relative URL to an image on your webserver. This cannot be a URL to an 
 *						image on another domain. The HTML5 Canvas element follows the Same Origin Policy.
 *				lightRefraction: 
 *						Sets how many pixels the refraction of light uses.
 * 				lightReflection: 
 *						Sets the amount of color highlighting.
 * 				maxFps: 
 *						Maximum Frames Per Second; The maximum reachable FPS highly depends on the system and 
 *						browser the water canvas is running on. You can't control that, but you can control the maximum 
 * 						FPS to keep systems from overloading, trying to reach the highest FPS.
 * 				showStats: 
 *						When set to true, it shows "FPS Canvas: " plus the current FPS of this view on the canvas.
 *
 * @constructor
 */
WaterCanvas = function(width, height, documentElement, waterModel, props) {
	// If a certain property is not set, use a default value
	props = props || {};
	this.backgroundImageUrl	= props.backgroundImageUrl	|| null;
	this.lightRefraction 	= props.lightRefraction 	|| 9.0;
	this.lightReflection	= props.lightReflection 	|| 0.1;
	this.maxFps 			= props.maxFps 				|| 20;
	this.showStats			= props.showStats 			|| false;

	this.width = width;
	this.height = height;
	this.documentElement = document.getElementById(documentElement);
	this.waterModel = waterModel;

	
	
    this.canvas = document.createElement('canvas');  
    this.canvasHelp = document.createElement('canvas'); 

	if(!this.canvas.getContext || !this.canvasHelp.getContext){ 
		alert("You need a browser that supports the HTML5 canvas tag.");
		return; // No point to continue
	}

	this.ctx = this.canvas.getContext('2d');  
	this.ctxHelp = this.canvasHelp.getContext('2d');  	

	this.setSize(width, height);
    this.documentElement.appendChild(this.canvas);  
	
	this.setMaxFps(this.maxFps);
	

	
	// Find out the FPS at certain intervals
	this.fps = -1;
	if(this.showStats){	
		this.fpsCounter = 0;
		this.prevMs = 0;
			
		var self = this; 
		setInterval(function(){
			self.findFps.apply(self);
		}, 1000);
	}
}

/**
 * Sets the size of the canvas.
 *
 * @param {Number} width The width in pixels this canvas should be.
 * @param {Number} hight The hight in pixels this canvas should be.
 */
WaterCanvas.prototype.setSize = function(width, height){
	this.width = width;
	this.height = height;
	
    this.canvas.setAttribute('width', this.width);  
    this.canvas.setAttribute('height', this.height); 
	
    this.canvasHelp.setAttribute('width', this.width);  
    this.canvasHelp.setAttribute('height', this.height);  	

	this.setBackground(this.backgroundImageUrl);	
}

/**
 * Sets the image to perform the water rippling effect on. 
 *
 * Use an image from the same server as where this script lives. This is needed since browsers use the 
 * Same Origin Policy for savety reasons. If an empty URL is given, a standard canvas will be shown.
 *
 * @param {String} backgroundImageUrl (Relative) URL to an image on the same webserver as this script.						
 */
WaterCanvas.prototype.setBackground = function(backgroundImageUrl){
	this.backgroundImageUrl = backgroundImageUrl=="" ? null : backgroundImageUrl;
	this.pixelsIn = null;
	
	if(this.backgroundImageUrl!=null){
	
		// Background image loading
		this.backgroundImg = new Image();  
		
		var self = this; 	
		this.backgroundImg.onload = function(){  
			self.ctxHelp.drawImage(self.backgroundImg, 0, 0, self.width, self.height); 
			
			// Get the canvas pixel data
			var imgDataIn = self.ctxHelp.getImageData(0, 0, self.width, self.height);
			self.pixelsIn = imgDataIn.data;
			
			// Also paint it on the output canvas
			self.ctx.putImageData(imgDataIn, 0, 0);
		}
		this.backgroundImg.src = this.backgroundImageUrl;
		
	} else {
	
		var radgrad = pointerCtx.createRadialGradient(this.width/2,this.height/2,0,	 this.width/2,this.height/2,this.height/2);
		radgrad.addColorStop(0, '#4af');
		radgrad.addColorStop(1, '#000');

		this.ctxHelp.fillStyle = radgrad;
		this.ctxHelp.fillRect(0,0,this.width,this.height);	
		
		this.ctxHelp.shadowColor = "white";
		this.ctxHelp.shadowOffsetX = 0;
		this.ctxHelp.shadowOffsetY = 0;
		this.ctxHelp.shadowBlur = 10;
		
		this.ctxHelp.textBaseline = "top";
		this.ctxHelp.font = 'normal 200 45px verdana';
		this.ctxHelp.fillStyle = "white";  
		this.ctxHelp.fillText("Water Canvas", 10, (this.height/2)-40);  	
		this.ctxHelp.font = 'normal 200 12px verdana';
		this.ctxHelp.fillText("Move your mouse over this canvas to move the water.", 10, (this.height/2)+10); 
		this.ctxHelp.fillText("By Almeros 2010, See http://code.almeros.com", 10, (this.height/2)+30);  	

		// Get the canvas pixel data
		var imgDataIn = this.ctxHelp.getImageData(0, 0, this.width, this.height);
		this.pixelsIn = imgDataIn.data;			
		
		// Also paint it on the output canvas
		this.ctx.putImageData(imgDataIn, 0, 0);
		
	}
}

/**
 * Renders the next frame and draws it on the canvas. 
 * Called at regular intervals by an internal setInterval.
 *
 * @private
 */
WaterCanvas.prototype.drawNextFrame = function(){
	if(this.pixelsIn==null || !this.waterModel.isEvolving())
		return;
		
	
	// Make the canvas give us a CanvasDataArray. 
	// Creating an array ourselves is slow!!!
	// https://developer.mozilla.org/en/HTML/Canvas/Pixel_manipulation_with_canvas
	var imgDataOut = this.ctx.getImageData(0, 0, this.width, this.height);
	var pixelsOut = imgDataOut.data;
	for (var i = 0; n = pixelsOut.length, i < n; i += 4) {
		var pixel = i/4;
		var x = pixel % this.width;
		var y = (pixel-x) / this.width;
		
		var strength = this.waterModel.getWater(x,y);
		

		// Refraction of light in water
		var refraction = Math.round(strength * this.lightRefraction);
		
		var xPix = x + refraction;
		var yPix = y + refraction;     
		
		if(xPix < 0) xPix = 0;
		if(yPix < 0) yPix = 0;					
		if(xPix > this.width-1) xPix = this.width-1;
		if(yPix > this.height-1) yPix = this.height-1;			
		
		
		
		// Get the pixel from input
		var iPix = ((yPix * this.width) + xPix) * 4;
		var red 	= this.pixelsIn[iPix  ];
		var green 	= this.pixelsIn[iPix+1];
		var blue 	= this.pixelsIn[iPix+2];
		
		
		// Set the pixel to output
		strength *= this.lightReflection;
		strength += 1.0;

		pixelsOut[i  ] = red *= strength;
		pixelsOut[i+1] = green *= strength;
		pixelsOut[i+2] = blue *= strength;
		pixelsOut[i+3] = 255; // alpha 
	}

	this.ctx.putImageData(imgDataOut, 0,0);
	
	
	if(this.showStats){
		this.fpsCounter++;
		
	
		this.ctx.textBaseline = "top";
		this.ctx.font = 'normal 200 10px arial';
		
		this.ctx.fillStyle = "white";  
		this.ctx.fillText  ("FPS Canvas: " + this.getFps(), 10, 10);  
		this.ctx.fillText  ("FPS Water: " + this.waterModel.getFps(), 10, 20);  		

		this.ctx.shadowColor = "black";
		this.ctx.shadowOffsetX = 0;
		this.ctx.shadowOffsetY = 0;
		this.ctx.shadowBlur = 2;
	}
}

/**
 * Determine the Frames Per Second. 
 * Called at regular intervals by an internal setInterval.
 *
 * @private
 */
WaterCanvas.prototype.findFps = function(){
	if(!this.showStats)
		return;
	
	var nowMs = new Date().getTime();
	var diffMs = nowMs - this.prevMs;

	this.fps = Math.round( ((this.fpsCounter*1000) / diffMs) * 10.0 ) / 10.0;
	
	this.prevMs = nowMs;
	this.fpsCounter = 0;
}

/**
 * @returns The Frames Per Second that was last rendered.
 */
WaterCanvas.prototype.getFps = function(){
	return this.fps;
}

/**
 * Sets the maximum frames per second to render. Use this to set a limit and release resources for other processes.
 *
 * @param {Number} maxFps The maximum frames per second to render.
 */
WaterCanvas.prototype.setMaxFps = function(maxFps){
	this.maxFps = maxFps;
	
	clearInterval(this.maxFpsInterval);

	var self = this; // For referencing 'this' in internal eventListeners
	
	// Updating of the animation
	if(this.maxFps>0){
		this.maxFpsInterval = setInterval(function(){
			self.drawNextFrame.apply(self);
		}, 1000/this.maxFps); 	
	}
}

/**
 * Sets the a amount of refraction of light through the water.
 *
 * @param {Number} lightRefraction The a amount of refraction of light.
 */
WaterCanvas.prototype.setLightRefraction = function(lightRefraction){
	this.lightRefraction = lightRefraction;	
}

/**
 * Sets the a amount of reflection of light on the water.
 *
 * @param {Number} lightRefraction The a amount of reflection of light.
 */
WaterCanvas.prototype.setLightReflection = function(lightReflection){
	this.lightReflection = lightReflection;	
}





////////////////////////////////////////////////////////////////////////////////
//                              WaterModel object                             //
////////////////////////////////////////////////////////////////////////////////

/**
 * Model object that is responsible for holding, manipulating and updating the water ripple data.
 * 
 * @param {Number} width The width in pixels this model should work with.
 * @param {Number} hight The hight in pixels this model should work with.
 * @param {Object} props A key/value object which may contain the following properties:
 * 				resolution:  
 *						Sets the pixelsize to use in the model. The higher hte better the performance, but 
 *						you may want to use interpolation to prefent visible block artifacts.
 *				interpolate: 
 *						When the resolution is set higher then 1.0, you can set this to true to use interpolation.
 *				damping: 
 *						Effectively sets how long water ripples travel.
 *				clipping: 
 *						Multiple waves add up. This may create a wave that's to high or low. The clipping value sets 
 *						the absolute maximum a water pixel value may have in the model.
 *				evolveThreshold: 
 *						To prevent this  script from always taking up CPU cycles, even when no water rippling 
 *						is going on in the model (your website is on a non visible tab) you can set a threshold. When 
 *						no water pixel is above this absolute value, the WaterModel and the WaterCanvas will both stop 
 *						rendering until new waves are created by the user.
 *				maxFps: 
 *						Maximum Frames Per Second; The maximum reachable FPS highly depends on the system and browser 
 *						the water canvas is running on. You can't control that, but you can control the maximum FPS to 
 *						keep systems from overloading, trying to reach the highest FPS.
 *				showStats: 
 *						When set to true, it shows "FPS Water: " plus the current FPS of this model on the canvas.
 *
 * @constructor
 */
WaterModel = function(width, height, props) {
	// If a certain property is not set, use a default value
	props = props || {};
	this.resolution 		= props.resolution 		|| 2.0;
	this.interpolate 		= props.interpolate 	|| false;
	this.damping 			= props.damping 		|| 0.985;
	this.clipping 			= props.clipping 		|| 5;	
	this.maxFps 			= props.maxFps 			|| 30;
	this.showStats 			= props.showStats 		|| false;
	this.evolveThreshold 	= props.evolveThreshold	|| 0.05;
	
	this.width = Math.ceil(width/this.resolution);
	this.height = Math.ceil(height/this.resolution);

	
	
	// Create water model 2D arrays
	this.resetSizeAndResolution(width, height, this.resolution)
	this.swapMap;

	this.setMaxFps(this.maxFps);
	
	this.evolving = false; // Holds whether it's needed to render frames
	
	

	// Find out the FPS at certain intervals
	this.fps = -1;
	if(this.showStats){	
		this.fpsCounter = 0;
		this.prevMs = 0;
			
		var self = this; 
		setInterval(function(){
			self.findFps.apply(self);
		}, 1000);
	}
}

/**
 * Gets the (interpolated) water value of an coordinate.
 *
 * @param {Number} x The X position.
 * @param {Number} y The Y position.
 *
 * @returns A float value representing the hight of the water.
 */
WaterModel.prototype.getWater = function(x, y){
	xTrans = x/this.resolution;
	yTrans = y/this.resolution;

	if(!this.interpolate || this.resolution==1.0){
		xF = Math.floor(xTrans); 
		yF = Math.floor(yTrans);	

		if(xF>this.width-1 || yF>this.height-1)
			return 0.0;
		
		return this.depthMap1[xF][yF];
	}
	
	
	// Else use Bilinear Interpolation
	xF = Math.floor(xTrans); 
	yF = Math.floor(yTrans);
	xC = Math.ceil(xTrans); 
	yC = Math.ceil(yTrans);	

	if(xC>this.width-1 || yC>this.height-1)
		return 0.0;
		
	// Now get 4 points from the array
	var br = this.depthMap1[xF][yF];
	var bl = this.depthMap1[xC][yF];
	var tr = this.depthMap1[xF][yC];
	var tl = this.depthMap1[xC][yC];
	
	// http://tech-algorithm.com/articles/bilinear-image-scaling/
	//	D   C
	//	  Y
	//	B	A
	// Y = A(1-w)(1-h) + B(w)(1-h) + C(h)(1-w) + Dwh

	var xChange = xC - xTrans;
	var yChange = yC - yTrans;
	var intpVal =
			tl*(1-xChange)	*	(1-yChange) +  
			tr*(xChange)	*	(1-yChange) +
			bl*(yChange)	*	(1-xChange) +  
			br*xChange		*	yChange;

	return intpVal;
}

/**
 * Sets bilinear interpolation on or off. Interpolation will give a more smooth effect
 * when a higher resolution is used, but needs CPU resources for that.
 *
 * @param {Boolean} interpolate Whether to use interpolation or not
 */
WaterModel.prototype.setInterpolation = function(interpolate){
	this.interpolate = interpolate;
}

/**
 * Gets the (interpolated) water value of an coordinate.
 *
 * @param {Number} x The X position. The center of where the array2d will be placed.
 * @param {Number} y The Y position. The center of where the array2d will be placed.
 * @param {Number} pressure The factor to multiply the array2d values with while adding the array2d to the model.
 * @param {Array} array2d A 2D array containing float values between -1.0 and 1.0 in a pattern.
 */
WaterModel.prototype.touchWater = function(x, y, pressure, array2d){
	this.evolving = true;

	x = Math.floor(x/this.resolution); 
	y = Math.floor(y/this.resolution);
	
	// Place the array2d in the center of the mouse position
	if(array2d.length>4 || array2d[0].length>4){
		x-=array2d.length/2;
		y-=array2d[0].length/2;
	}
	
	if(x<0) x = 0;
	if(y<0) y = 0;
	if(x>this.width) x = this.width;
	if(y>this.height) y = this.height;

	// Big pixel block
	for(var i = 0; i < array2d.length; i++){
		for(var j = 0; j < array2d[0].length; j++){

			if(x+i>=0 && y+j>=0 && x+i<=this.width-1 && y+j<=this.height-1) {
				this.depthMap1[x+i][y+j] -= array2d[i][j] * pressure;
			}
			
		}
	}
}

/**
 * Renders the next frame in the model. The water ripples will be evolved one step.
 * Called at regular intervals by an internal setInterval.
 *
 * @private
 */
WaterModel.prototype.renderNextFrame = function() {
	if(!this.evolving)
		return;

	this.evolving = false;
	
	for (var x = 0; x < this.width; x++) {
		for (var y = 0; y < this.height; y++) {

			// Handle borders correctly
			var val = 	(x==0 				? 0 : this.depthMap1[x - 1][y]) +
						(x==this.width-1 	? 0 : this.depthMap1[x + 1][y]) +
						(y==0 				? 0 : this.depthMap1[x][y - 1]) +
						(y==this.height-1 	? 0 : this.depthMap1[x][y + 1]);

			// Damping
			val = ((val / 2.0) - this.depthMap2[x][y]) * this.damping;
			
			// Clipping prevention
			if(val>this.clipping) val = this.clipping;
			if(val<-this.clipping) val = -this.clipping;
			
			// Evolve check
			if(Math.abs(val)>this.evolveThreshold) 
				this.evolving = true; 

			
			this.depthMap2[x][y] = val;
		}
	}

	// Swap buffer references
	this.swapMap 	= this.depthMap1;
	this.depthMap1 	= this.depthMap2;
	this.depthMap2 	= this.swapMap;
	
	this.fpsCounter++;
}

/**
 * Tells if the WaterModel is currently evolving. When all postions in the model are below a threshold 
 * (evolveThreshold), evolving will be set to false. This saves resources, especially when the canvas 
 * is not visible on screen.
 *
 * @returns A boolean that tells if the WaterModel is currently in evolving state.
 */
WaterModel.prototype.isEvolving = function() {
	return this.evolving;
}

/**
 * Determine the Frames Per Second. 
 * Called at regular intervals by an internal setInterval.
 *
 * @private
 */
WaterModel.prototype.findFps = function(){
	if(!this.showStats)
		return;
	
	var nowMs = new Date().getTime();
	var diffMs = nowMs - this.prevMs;

	this.fps = Math.round( ((this.fpsCounter*1000) / diffMs) * 10.0 ) / 10.0;
	
	this.prevMs = nowMs;
	this.fpsCounter = 0;
}

/**
 * @returns The Frames Per Second that was last rendered.
 */
WaterModel.prototype.getFps = function(){
	return this.fps;
}

/**
 * Sets the maximum frames per second to render. Use this to set a limit and release resources for other processes.
 *
 * @param {Number} maxFps The maximum frames per second to render.
 */
WaterModel.prototype.setMaxFps = function(maxFps){
	this.maxFps = maxFps;
	
	clearInterval(this.maxFpsInterval);

	// Updating of the animation
	var self = this; // For referencing 'this' in internal eventListeners	
	
	if(this.maxFps>0){
		this.maxFpsInterval = setInterval(function(){
			self.renderNextFrame.apply(self);
		}, 1000/this.maxFps); 	
	}
}

/**
 * Effectively sets how long water ripples travel.
 *
 * @param {Number} damping The amount of strength to pass on from postion to surrounding positions.
 */
WaterModel.prototype.setDamping = function(damping){
	this.damping = damping;
}

/**
 * Effectively sets how long water ripples travel.
 * 
 * @param {Number} width The width in pixels this model should work with.
 * @param {Number} hight The hight in pixels this model should work with.
 * @param {Number} resolution The pixel size of a models position. The higher the resolution, the less positions to render, the faster. 
 */
WaterModel.prototype.resetSizeAndResolution = function(width, height, resolution){
	this.width = Math.ceil(width/resolution);
	this.height = Math.ceil(height/resolution);
	this.resolution = resolution;
	
	this.depthMap1 = new Array(this.width); 
	this.depthMap2 = new Array(this.width);
	for(var x = 0; x < this.width; x++){
		this.depthMap1[x] = new Array(this.height);
		this.depthMap2[x] = new Array(this.height);
		
		for (var y = 0; y < this.height; y++) {
			this.depthMap1[x][y] = 0.0;
			this.depthMap2[x][y] = 0.0;
		}
	}
}






////////////////////////////////////////////////////////////////////////////////
//                                 Util functions                             //
////////////////////////////////////////////////////////////////////////////////

/**
 * A class to mimic rain on the given waterModel with raindrop2dArray's as raindrops.
 */
RainMaker = function(width, height, waterModel, raindrop2dArray) {
	this.width = width;
	this.height = height;
	this.waterModel = waterModel;
	this.raindrop2dArray = raindrop2dArray;

	this.rainMinPressure = 1;
	this.rainMaxPressure = 3;
}

RainMaker.prototype.raindrop = function(){
	var x = Math.floor(Math.random() * this.width);
	var y = Math.floor(Math.random() * this.height);
	this.waterModel.touchWater(x, y, this.rainMinPressure + Math.random() * this.rainMaxPressure, this.raindrop2dArray);		
}	

RainMaker.prototype.setRaindropsPerSecond = function(rps){
	this.rps = rps;
	
	clearInterval(this.rainInterval);

	if(this.rps>0) {
		var self = this; 
		this.rainInterval = setInterval(function(){
			self.raindrop.apply(self);
		}, 1000/this.rps); 	
	}
}

RainMaker.prototype.setRainMinPressure = function(rainMinPressure){
	this.rainMinPressure = rainMinPressure;
}

RainMaker.prototype.setRainMaxPressure = function(rainMaxPressure){
	this.rainMaxPressure = rainMaxPressure;
}

/**
 * Enables mouse interactivity by adding event listeners to the given documentElement and
 * using the mouse coordinates to 'touch' the water.
 */
function enableMouseInteraction(waterModel, documentElement){		
	var mouseDown = false;
	
	var canvasHolder = document.getElementById(documentElement);
	
	canvasHolder.addEventListener("mousedown", function(e){
		mouseDown = true;
		var x = (e.clientX - canvasHolder.offsetLeft) + document.body.scrollLeft + document.documentElement.scrollLeft;
		var y = (e.clientY - canvasHolder.offsetTop) + document.body.scrollTop + document.documentElement.scrollTop;
		waterModel.touchWater(x, y, 1.5, mouseDown ? finger : pixel);
	}, false);
	
	canvasHolder.addEventListener("mouseup", function(e){
		mouseDown = false;
	}, false);
	
	canvasHolder.addEventListener("mousemove", function(e){
		var x = (e.clientX - canvasHolder.offsetLeft) + document.body.scrollLeft + document.documentElement.scrollLeft;
		var y = (e.clientY - canvasHolder.offsetTop) + document.body.scrollTop + document.documentElement.scrollTop;
		// mozPressure: https://developer.mozilla.org/en/DOM/Event/UIEvent/MouseEvent
		waterModel.touchWater(x, y, 1.5, mouseDown ? finger : pixel);
	}, false);
}

/**
 * Creates a canvas with a radial gradient from white in the center to black on the outside.
 */
function createRadialCanvas(width, height){
	// Create a canvas
	var pointerCanvas = document.createElement('canvas');  
	pointerCanvas.setAttribute('width', width);  
	pointerCanvas.setAttribute('height', height);  
	pointerCtx = pointerCanvas.getContext('2d'); 
	
	// Create a drawing on the canvas
	var radgrad = pointerCtx.createRadialGradient(width/2,height/2,0,  width/2,height/2,height/2);
	radgrad.addColorStop(0, '#fff');
	radgrad.addColorStop(1, '#000');

	pointerCtx.fillStyle = radgrad;
	pointerCtx.fillRect(0,0,width,height);	
	
	return pointerCanvas;
}

/**	
 * Creates a 2D pointer array from a given canvas with a grayscale image on it. 
 * This canvas image is then converted to a 2D array with values between -1.0 and 0.0.
 * 
 * Example:
 * 	var array2d = [
 * 		[0.5, 1.0, 0.5], 
 * 		[1.0, 1.0, 1.0], 
 * 		[0.5, 1.0, 0.5]
 * 	];
 */
function create2DArray(canvas){
	var width = canvas.width;
	var height = canvas.height;

	// Create an empty 2D  array
	var pointerArray = new Array(width); 
	for(var x = 0; x < width; x++){
		pointerArray[x] = new Array(height);
		for (var y = 0; y < height; y++) {
			pointerArray[x][y] = 0.0;
		}
	}

	// Convert gray scale canvas to 2D array
	var pointerCtx = canvas.getContext('2d'); 
	var imgData = pointerCtx.getImageData(0, 0, width, height);
	var pixels = imgData.data;	

	for (var i = 0; n = pixels.length, i < n; i += 4) {				
		// Get the pixel from input
		var pixVal 	= pixels[i];// only use red
		var arrVal = pixVal/255.0;

		var pixel = i/4;
		var x = pixel % width;
		var y = (pixel-x) / width;					

		pointerArray[x][y] = arrVal;
	}				
	
	return pointerArray;			
}
