<commit_before>define(["put-selector/put", "dojo/_base/declare", "dojo/on", "dojo/aspect", "dojo/has", "dojo/has!touch?./TouchScroll", "xstyle/has-class", "dojo/_base/sniff", "xstyle/css!./css/dgrid.css?dgrid-css-loaded"],
function(put, declare, listen, aspect, has, TouchScroll, hasClass){
	// Add user agent/feature CSS classes
	hasClass("mozilla", "opera", "ie-6", "ie-6-7", "quirks", "no-quirks");

	var scrollbarWidth;
	var byId = function(id){
		return document.getElementById(id);
	};
	function Row(id, object, element){
		this.id = id;
		this.data = object;
		this.element = element;
	}
	Row.prototype = {
		remove: function(){
			var rowElement = this.element;
			var contentNode = rowElement.parentNode;
			contentNode.removeChild(rowElement);
			var connected = rowElement.connected;
			if(connected){
				// if it has a connected node, remove that as well
				contentNode.removeChild(connected);
			}
		}
	};
	function move(item, steps, targetClass){
		var nextSibling, current, element = current = item.element;
		steps = steps || 1;
		do{
			// move in the correct direction
			if(nextSibling = current[steps < 0 ? 'previousSibling' : 'nextSibling']){
				do{
					current = nextSibling;
					var className = current && current.className;
					if(className && className.indexOf(targetClass) > -1){
						// it's an element with the correct class name, counts as a real move
						element = current;
						steps += steps < 0 ? 1 : -1;
						break;
					}
					// if the next sibling isn't a match, drill down to search
				}while(nextSibling = current[steps < 0 ? 'lastChild' : 'firstChild']);
			}else if((current = current.parentNode) == this.domNode){ // intentional assignment
				// we stepped all the way out of the grid, given up now
				break;
			}
		}while(steps);
		return element;
	}

	// var and function for autogenerating ID when one isn't provided
	var autogen = 0;
	function generateId(){
		return "dgrid_" + autogen++;
	}

	return declare(TouchScroll ? [TouchScroll] : [], {
		constructor: function(params, srcNodeRef){
		var self = this;
		// summary:
		//		The set of observers for the data
	/* TODO: Implement this to hide (detach from DOM) out-of-sight nodes to improve performance
	 * clearTop = function(){
		var scrollNode = self.bodyNode;
		var transform = self.contentNode.style.webkitTransform;
		var visibleTop = scrollNode.scrollTop + (transform ? -transform.match(/translate[\w]*\(.*?,(.*?)px/)[1] : 0);

		var elements = self.contentNode.childNodes;
		for(var i = 0; i < elements.length; i++){
			if(elements[i].offsetTop > visibleTop){
				break;
			}
		}
		self.otherNode = create("div", {
		});
		var last = elements[i];
		for(; i > 0; i--){
			self.otherNode.appendChild(elements[i -1]);
		}
		var node = create("div", {
			style: {
				height: visibleTop + "px"
			}
		});
		self.contentNode.insertBefore(node, last);
	};*/
		},
		postscript: function(params, srcNodeRef){
			// invoke create in postScript to allow descendants to
			// perform logic before create/postCreate happen (a la dijit/_WidgetBase)

			if(srcNodeRef){
				// normalize srcNodeRef and store on instance during create process.
				// Doing this in postscript is a bit earlier than dijit would do it,
				// but allows subclasses to access it pre-normalized during create.
				this.srcNodeRef = srcNodeRef =
					srcNodeRef.nodeType ? srcNodeRef : byId(srcNodeRef);
			}
			this.create(params, srcNodeRef);
		},
		getCSSClass: function(shortName){
			return "dgrid-" + shortName;
		},
		listType: "list",
		create: function(params, srcNodeRef){
			// mix in params now, but wait until postScript to create
			if(params){
				this.params = params;
				declare.safeMixin(this, params);
			}
			this.domNode = srcNodeRef || put("div");

			this.postMixInProperties();
			// apply id to widget and domNode,
			// from incoming node, widget params, or autogenerated.
			this.buildRendering();
			this.postCreate && this.postCreate();
			// remove srcNodeRef instance property post-create
			delete this.srcNodeRef;
		},
		postMixInProperties: function(){
			this.observers = [];
			this._listeners = [];
			this._rowIdToObject = {};
		},
		tabableHeader: false,
		buildRendering: function(){
			var domNode = this.domNode;
			this.id = domNode.id = domNode.id || this.id || generateId();
			put(domNode, "[role=grid].ui-widget.dgrid.dgrid-" + this.listType);
			var headerNode = this.headerNode = put(domNode,
				"div.dgrid-header.dgrid-header-row.ui-widget-header");
			if(has("quirks") || has("ie") < 8){
				var spacerNode = put(domNode, "div.dgrid-spacer");
			}
			var bodyNode = this.bodyNode = put(domNode, "div.dgrid-scroller");
			this.headerScrollNode = put(domNode, "div.dgrid-header-scroll.dgrid-scrollbar-width.ui-widget-header");
			listen(bodyNode, "scroll", function(event){
				// keep the header aligned with the body
				headerNode.scrollLeft = bodyNode.scrollLeft;
				event.stopPropagation(); // we will refire, since browsers are not consistent about propagation here
				listen.emit(domNode, "scroll", {scrollTarget: bodyNode});
			});
			this.configStructure();
			this.renderHeader(headerNode);
			this.resize();
			this.refresh();
			aspect.after(this, "scrollTo", function(){
				listen.emit(bodyNode, "scroll", {});
			});
			var grid = this;
			listen(window, "resize", function(){
				grid.resize();
			});
		},
		configStructure: function(){
			// does nothing in List, this is more of a hook for the Grid
		},
		resize: function(){
			var bodyNode = this.bodyNode;
			var headerNode = this.headerNode;
			this.headerScrollNode.style.height = bodyNode.style.marginTop = headerNode.offsetHeight + "px";
			if(has("quirks") || has("ie") < 7){
				// in quirks mode, the "bottom" CSS property is ignored, so do this to fix it
				// We might want to use a CSS expression or the xstyle package to fix this.
				// We guard against negative values in case of issues with external CSS.
				bodyNode.style.height =
					Math.max((this.domNode.offsetHeight - headerNode.offsetHeight), 0) + "px";
			}
			if(!scrollbarWidth){
				// we haven't computed the scroll bar width yet, do so now, and add a new rule if need be
				scrollbarWidth = 1 + bodyNode.offsetWidth - bodyNode.clientWidth;

				// add rules that can be used where scrollbar width/height is needed
				this.addCssRule(".dgrid-scrollbar-width", "width: " + scrollbarWidth + "px");
				this.addCssRule(".dgrid-scrollbar-height", "height: " + scrollbarWidth + "px");

				if(scrollbarWidth != 17){
					this.addCssRule(".dgrid-header", "right: " + scrollbarWidth + "px");
					this.addCssRule(".dgrid-header-scroll", "width: " + scrollbarWidth + "px");
				}
			}
		},
		addCssRule: function(selector, css){
			var styleSheets = document.styleSheets;
			var styleSheet = styleSheets[styleSheets.length - 1];
			var index = (styleSheet.cssRules || styleSheet.rules).length;
			styleSheet.addRule ?
				styleSheet.addRule(selector, css) :
				styleSheet.insertRule(selector + '{' + css + '}', index);
			return {
				remove: function(){
					styleSheet.deleteRule(index);
				}
			}
		},
		on: function(eventType, listener){
			// delegate events to the domNode
			var signal = listen(this.domNode, eventType, listener);
			if(!has("dom-addeventlistener")){
				this._listeners.push(signal);
			}
		},
		destroy: function(){
			// cleanup listeners
			for(var i = 0; i < this._listeners.length; i++){
				this._listeners.remove();
			}
		},
		refresh: function(){
			// summary:
			//		refreshes the contents of the grid
			this._rowIdToObject = {};
			this._autoId = 0;
			if(this.contentNode){
				// remove the content so it can be recreated
				this.contentNode.innerHTML = "";
				// remove any listeners
				for(var i = 0;i < this.observers.length; i++){
					this.observers[i].cancel();
				}
				this.observers = [];
			}else{
				this.contentNode = put(this.bodyNode, "div.dgrid-content.ui-widget-content");
			}
			if(this.init){
				this.init({
					domNode: this.bodyNode,
					containerNode: this.contentNode
				});
			}
			this.preloadNode = null;
		},
		renderArray: function(results, beforeNode, options){
			// summary:
			//		This renders an array or collection of objects as rows in the grid, before the
			//		given node. This will listen for changes in the collection if an observe method
			//		is available (as it should be if it comes from an Observable data store).
			options = options || {};
			var start = options.start || 0;
			var self = this;
			if(!beforeNode){
				this.lastCollection = results;
			}
			if(results.observe){
				// observe the results for changes
				this.observers.push(results.observe(function(object, from, to){
					// a change in the data took place
					if(from > -1){
						// remove from old slot
						self.row(rows.splice(from, 1)[0]).remove();
					}
					if(to > -1){
						// add to new slot
						var before = rows[to] || beforeNode;
						var row = self.insertRow(object, before.parentNode, before, (options.start + to), options);
						put(row, ".ui-state-highlight");
						setTimeout(function(){
							put(row, "!ui-state-highlight");
						}, 250);
						rows.splice(to, 0, row);
					}
				}, true));
			}
			var rowsFragment = document.createDocumentFragment();
			// now render the results
			if(results.map){
				var rows = results.map(mapEach, console.error);
				if(rows.then){
					return rows.then(whenDone);
				}
			}else{
				var rows = [];
				for(var i = 0, l = results.length; i < l; i++){
					rows[i] = mapEach(results[i]);
				}
			}
			var lastRow;
			function mapEach(object){
				return lastRow = self.insertRow(object, rowsFragment, null, start++, options);
			}
			function whenDone(rows){
				(beforeNode && beforeNode.parentNode || self.contentNode).insertBefore(rowsFragment, beforeNode || null);
				if(!beforeNode){
					put(lastRow, ".dgrid-last-row");
				}
				return rows;
			}
			return whenDone(rows);
		},
		_autoId: 0,
		renderHeader: function(){
			// no-op in a place list
		},
		insertRow: function(object, parent, beforeNode, i, options){
			// summary:
			//		Renders a single row in the grid
			var row = this.renderRow(object, options);
			row.className = (row.className || "") + " ui-state-default dgrid-row " + (i% 2 == 1 ? "dgrid-row-odd" : "dgrid-row-even");
			// get the row id for easy retrieval
			this._rowIdToObject[row.id = this.id + "-row-" + ((this.store && this.store.getIdentity) ? this.store.getIdentity(object) : this._autoId++)] = object;
			parent.insertBefore(row, beforeNode);
			return row;
		},
		renderRow: function(value, options){
			return put("div", value);
		},
		row: function(target){
			// summary:
			//		Get the row object by id, object, node, or event
			if(target.target && target.target.nodeType){
				// event
				target = target.target;
			}
			if(target.nodeType){
				var object;
				do{
					var rowId = target.id;
					if(object = this._rowIdToObject[rowId]){
						return new Row(rowId.substring(this.id.length + 5), object, target);
					}
					target = target.parentNode;
				}while(target && target != this.domNode);
				return;
			}
			if(typeof target == "object"){
				// assume target represents a store item
				var id = this.store.getIdentity(target);
			}else{
				// assume target is a row ID
				var id = target;
				target = this._rowIdToObject[this.id + "-row-" + id];
			}
			return new Row(id, target, byId(this.id + "-row-" + id));
		},
		cell: function(target){
			// this doesn't do much in a plain list
			return {
				row: this.row(target)
			};
		},
		_move: move,
		up: function(row, steps){
			return this.row(move(row, -(steps || 1), "dgrid-row"));
		},
		down: function(row, steps){
			return this.row(move(row, steps || 1, "dgrid-row"));
		},
		sort: function(property, descending){
			// summary:
			//		Sort the content
			this.sortOrder = [{attribute: property, descending: descending}];
			this.refresh();
			if(this.lastCollection){
				this.lastCollection.sort(function(a,b){
					return a[property] > b[property] == !descending ? 1 : -1;
				})
				this.renderArray(this.lastCollection);
			}
		}
	});
});<commit_msg>Make non-store sort logic more predictable for undefined values<commit_after>define(["put-selector/put", "dojo/_base/declare", "dojo/on", "dojo/aspect", "dojo/has", "dojo/has!touch?./TouchScroll", "xstyle/has-class", "dojo/_base/sniff", "xstyle/css!./css/dgrid.css?dgrid-css-loaded"],
function(put, declare, listen, aspect, has, TouchScroll, hasClass){
	// Add user agent/feature CSS classes
	hasClass("mozilla", "opera", "ie-6", "ie-6-7", "quirks", "no-quirks");

	var scrollbarWidth;
	var byId = function(id){
		return document.getElementById(id);
	};
	function Row(id, object, element){
		this.id = id;
		this.data = object;
		this.element = element;
	}
	Row.prototype = {
		remove: function(){
			var rowElement = this.element;
			var contentNode = rowElement.parentNode;
			contentNode.removeChild(rowElement);
			var connected = rowElement.connected;
			if(connected){
				// if it has a connected node, remove that as well
				contentNode.removeChild(connected);
			}
		}
	};
	function move(item, steps, targetClass){
		var nextSibling, current, element = current = item.element;
		steps = steps || 1;
		do{
			// move in the correct direction
			if(nextSibling = current[steps < 0 ? 'previousSibling' : 'nextSibling']){
				do{
					current = nextSibling;
					var className = current && current.className;
					if(className && className.indexOf(targetClass) > -1){
						// it's an element with the correct class name, counts as a real move
						element = current;
						steps += steps < 0 ? 1 : -1;
						break;
					}
					// if the next sibling isn't a match, drill down to search
				}while(nextSibling = current[steps < 0 ? 'lastChild' : 'firstChild']);
			}else if((current = current.parentNode) == this.domNode){ // intentional assignment
				// we stepped all the way out of the grid, given up now
				break;
			}
		}while(steps);
		return element;
	}

	// var and function for autogenerating ID when one isn't provided
	var autogen = 0;
	function generateId(){
		return "dgrid_" + autogen++;
	}

	return declare(TouchScroll ? [TouchScroll] : [], {
		constructor: function(params, srcNodeRef){
		var self = this;
		// summary:
		//		The set of observers for the data
	/* TODO: Implement this to hide (detach from DOM) out-of-sight nodes to improve performance
	 * clearTop = function(){
		var scrollNode = self.bodyNode;
		var transform = self.contentNode.style.webkitTransform;
		var visibleTop = scrollNode.scrollTop + (transform ? -transform.match(/translate[\w]*\(.*?,(.*?)px/)[1] : 0);

		var elements = self.contentNode.childNodes;
		for(var i = 0; i < elements.length; i++){
			if(elements[i].offsetTop > visibleTop){
				break;
			}
		}
		self.otherNode = create("div", {
		});
		var last = elements[i];
		for(; i > 0; i--){
			self.otherNode.appendChild(elements[i -1]);
		}
		var node = create("div", {
			style: {
				height: visibleTop + "px"
			}
		});
		self.contentNode.insertBefore(node, last);
	};*/
		},
		postscript: function(params, srcNodeRef){
			// invoke create in postScript to allow descendants to
			// perform logic before create/postCreate happen (a la dijit/_WidgetBase)

			if(srcNodeRef){
				// normalize srcNodeRef and store on instance during create process.
				// Doing this in postscript is a bit earlier than dijit would do it,
				// but allows subclasses to access it pre-normalized during create.
				this.srcNodeRef = srcNodeRef =
					srcNodeRef.nodeType ? srcNodeRef : byId(srcNodeRef);
			}
			this.create(params, srcNodeRef);
		},
		getCSSClass: function(shortName){
			return "dgrid-" + shortName;
		},
		listType: "list",
		create: function(params, srcNodeRef){
			// mix in params now, but wait until postScript to create
			if(params){
				this.params = params;
				declare.safeMixin(this, params);
			}
			this.domNode = srcNodeRef || put("div");

			this.postMixInProperties();
			// apply id to widget and domNode,
			// from incoming node, widget params, or autogenerated.
			this.buildRendering();
			this.postCreate && this.postCreate();
			// remove srcNodeRef instance property post-create
			delete this.srcNodeRef;
		},
		postMixInProperties: function(){
			this.observers = [];
			this._listeners = [];
			this._rowIdToObject = {};
		},
		tabableHeader: false,
		buildRendering: function(){
			var domNode = this.domNode;
			this.id = domNode.id = domNode.id || this.id || generateId();
			put(domNode, "[role=grid].ui-widget.dgrid.dgrid-" + this.listType);
			var headerNode = this.headerNode = put(domNode,
				"div.dgrid-header.dgrid-header-row.ui-widget-header");
			if(has("quirks") || has("ie") < 8){
				var spacerNode = put(domNode, "div.dgrid-spacer");
			}
			var bodyNode = this.bodyNode = put(domNode, "div.dgrid-scroller");
			this.headerScrollNode = put(domNode, "div.dgrid-header-scroll.dgrid-scrollbar-width.ui-widget-header");
			listen(bodyNode, "scroll", function(event){
				// keep the header aligned with the body
				headerNode.scrollLeft = bodyNode.scrollLeft;
				event.stopPropagation(); // we will refire, since browsers are not consistent about propagation here
				listen.emit(domNode, "scroll", {scrollTarget: bodyNode});
			});
			this.configStructure();
			this.renderHeader(headerNode);
			this.resize();
			this.refresh();
			aspect.after(this, "scrollTo", function(){
				listen.emit(bodyNode, "scroll", {});
			});
			var grid = this;
			listen(window, "resize", function(){
				grid.resize();
			});
		},
		configStructure: function(){
			// does nothing in List, this is more of a hook for the Grid
		},
		resize: function(){
			var bodyNode = this.bodyNode;
			var headerNode = this.headerNode;
			this.headerScrollNode.style.height = bodyNode.style.marginTop = headerNode.offsetHeight + "px";
			if(has("quirks") || has("ie") < 7){
				// in quirks mode, the "bottom" CSS property is ignored, so do this to fix it
				// We might want to use a CSS expression or the xstyle package to fix this.
				// We guard against negative values in case of issues with external CSS.
				bodyNode.style.height =
					Math.max((this.domNode.offsetHeight - headerNode.offsetHeight), 0) + "px";
			}
			if(!scrollbarWidth){
				// we haven't computed the scroll bar width yet, do so now, and add a new rule if need be
				scrollbarWidth = 1 + bodyNode.offsetWidth - bodyNode.clientWidth;

				// add rules that can be used where scrollbar width/height is needed
				this.addCssRule(".dgrid-scrollbar-width", "width: " + scrollbarWidth + "px");
				this.addCssRule(".dgrid-scrollbar-height", "height: " + scrollbarWidth + "px");

				if(scrollbarWidth != 17){
					this.addCssRule(".dgrid-header", "right: " + scrollbarWidth + "px");
					this.addCssRule(".dgrid-header-scroll", "width: " + scrollbarWidth + "px");
				}
			}
		},
		addCssRule: function(selector, css){
			var styleSheets = document.styleSheets;
			var styleSheet = styleSheets[styleSheets.length - 1];
			var index = (styleSheet.cssRules || styleSheet.rules).length;
			styleSheet.addRule ?
				styleSheet.addRule(selector, css) :
				styleSheet.insertRule(selector + '{' + css + '}', index);
			return {
				remove: function(){
					styleSheet.deleteRule(index);
				}
			}
		},
		on: function(eventType, listener){
			// delegate events to the domNode
			var signal = listen(this.domNode, eventType, listener);
			if(!has("dom-addeventlistener")){
				this._listeners.push(signal);
			}
		},
		destroy: function(){
			// cleanup listeners
			for(var i = 0; i < this._listeners.length; i++){
				this._listeners.remove();
			}
		},
		refresh: function(){
			// summary:
			//		refreshes the contents of the grid
			this._rowIdToObject = {};
			this._autoId = 0;
			if(this.contentNode){
				// remove the content so it can be recreated
				this.contentNode.innerHTML = "";
				// remove any listeners
				for(var i = 0;i < this.observers.length; i++){
					this.observers[i].cancel();
				}
				this.observers = [];
			}else{
				this.contentNode = put(this.bodyNode, "div.dgrid-content.ui-widget-content");
			}
			if(this.init){
				this.init({
					domNode: this.bodyNode,
					containerNode: this.contentNode
				});
			}
			this.preloadNode = null;
		},
		renderArray: function(results, beforeNode, options){
			// summary:
			//		This renders an array or collection of objects as rows in the grid, before the
			//		given node. This will listen for changes in the collection if an observe method
			//		is available (as it should be if it comes from an Observable data store).
			options = options || {};
			var start = options.start || 0;
			var self = this;
			if(!beforeNode){
				this.lastCollection = results;
			}
			if(results.observe){
				// observe the results for changes
				this.observers.push(results.observe(function(object, from, to){
					// a change in the data took place
					if(from > -1){
						// remove from old slot
						self.row(rows.splice(from, 1)[0]).remove();
					}
					if(to > -1){
						// add to new slot
						var before = rows[to] || beforeNode;
						var row = self.insertRow(object, before.parentNode, before, (options.start + to), options);
						put(row, ".ui-state-highlight");
						setTimeout(function(){
							put(row, "!ui-state-highlight");
						}, 250);
						rows.splice(to, 0, row);
					}
				}, true));
			}
			var rowsFragment = document.createDocumentFragment();
			// now render the results
			if(results.map){
				var rows = results.map(mapEach, console.error);
				if(rows.then){
					return rows.then(whenDone);
				}
			}else{
				var rows = [];
				for(var i = 0, l = results.length; i < l; i++){
					rows[i] = mapEach(results[i]);
				}
			}
			var lastRow;
			function mapEach(object){
				return lastRow = self.insertRow(object, rowsFragment, null, start++, options);
			}
			function whenDone(rows){
				(beforeNode && beforeNode.parentNode || self.contentNode).insertBefore(rowsFragment, beforeNode || null);
				if(!beforeNode){
					put(lastRow, ".dgrid-last-row");
				}
				return rows;
			}
			return whenDone(rows);
		},
		_autoId: 0,
		renderHeader: function(){
			// no-op in a place list
		},
		insertRow: function(object, parent, beforeNode, i, options){
			// summary:
			//		Renders a single row in the grid
			var row = this.renderRow(object, options);
			row.className = (row.className || "") + " ui-state-default dgrid-row " + (i% 2 == 1 ? "dgrid-row-odd" : "dgrid-row-even");
			// get the row id for easy retrieval
			this._rowIdToObject[row.id = this.id + "-row-" + ((this.store && this.store.getIdentity) ? this.store.getIdentity(object) : this._autoId++)] = object;
			parent.insertBefore(row, beforeNode);
			return row;
		},
		renderRow: function(value, options){
			return put("div", value);
		},
		row: function(target){
			// summary:
			//		Get the row object by id, object, node, or event
			if(target.target && target.target.nodeType){
				// event
				target = target.target;
			}
			if(target.nodeType){
				var object;
				do{
					var rowId = target.id;
					if(object = this._rowIdToObject[rowId]){
						return new Row(rowId.substring(this.id.length + 5), object, target);
					}
					target = target.parentNode;
				}while(target && target != this.domNode);
				return;
			}
			if(typeof target == "object"){
				// assume target represents a store item
				var id = this.store.getIdentity(target);
			}else{
				// assume target is a row ID
				var id = target;
				target = this._rowIdToObject[this.id + "-row-" + id];
			}
			return new Row(id, target, byId(this.id + "-row-" + id));
		},
		cell: function(target){
			// this doesn't do much in a plain list
			return {
				row: this.row(target)
			};
		},
		_move: move,
		up: function(row, steps){
			return this.row(move(row, -(steps || 1), "dgrid-row"));
		},
		down: function(row, steps){
			return this.row(move(row, steps || 1, "dgrid-row"));
		},
		sort: function(property, descending){
			// summary:
			//		Sort the content
			this.sortOrder = [{attribute: property, descending: descending}];
			this.refresh();
			if(this.lastCollection){
				this.lastCollection.sort(function(a,b){
					// fall back undefined values to "" for more consistent behavior
					return (typeof a[property] == "undefined" ? "" : a[property]) >
						(typeof b[property] == "undefined" ? "" : b[property]) == !descending ? 1 : -1;
				});
				this.renderArray(this.lastCollection);
			}
		}
	});
});<|endoftext|>


<commit_before>/**
 * Created with JetBrains WebStorm.
 * User: alxlu
 * Date: 10/15/13
 * Time: 11:40 PM
 */
(function () {

    var container, bricks, paddle, boundingBox, ball, Signal = signals.Signal, views;
    var shared = {
        width: window.innerHeight-5,
        height: window.innerHeight-5,
        mouseX: 0,
        mouseY: 0,
        pressedKeys: [0, 0, 0, 0],
        pressedKeys2: [0, 0, 0, 0],
        collidableMeshList: [],
        parameters: {
            ballsize: 2,
            ballspeed: {
                x: (Math.random() - 0.5),
                y: (Math.random() + 0.5),
                z: (Math.random() - 0.5)
            },
            bounding: {
                width: 60,
                height: 60,
                depth: 60,
                x: 0,
                y: 5,
                z: 6,
                sx: 3,
                sy: 3,
                sz: 3
            },
            bricksize: {
                width: 20,
                height: 10,
                depth: 20
            },
            brickspacing: {
                x: 0,
                y: 0,
                z: 0
            },
            bricklayout: {
                x: 3,
                y: 1,
                z: 3
            },
            brickoffsets: {
                x: 10,
                y: 30,
                z: -14
            },
            paddlesize: {
                width: 20,
                height: 2,
                depth: 20
            },
            paddlespeed: 0.6
        },
        signals: {
            blockHit: new Signal()
        },
        util: {
            combine: function (rule) {
                return rule.apply(this, [].slice.call(arguments, 1));
            },
            idToIdx: function (id) {
                return (id.x*100 +id.y*10+id.z);
            },
            brickbounce: (function () {
                var x, y, z;
                x = y = z = false;
                return function (c1, c2, c3) {
                    var result = void 0;
                    if (x && c1) {
                        result = "x";
                    } else if (y && c2) {
                        result = "y";
                    } else if (z && c3) {
                        result = "z";
                    }
                    if (result == void 0) {
                        z = c1 && c2 ? true : false;
                        y = c1 && c3 ? true : false;
                        x = c2 && c3 ? true : false;
                    } else {
                        x = y = z = false;
                    }
                    return result;
                };
            }()),
            maybe: function (fn) {
                return function () {
                    var i;
                    if (arguments.length == 0) {
                        return;
                    } else {
                        for (i = 0; i < arguments.length; i++) {
                            if (arguments[i] == null) return;
                        }
                        return fn.apply(this, arguments);
                    }
                };
            }
        }
    };

    init();
    anim();

    function init() {
        //create container and append to scene.
        container = document.createElement('div');
        container.id = "webgl";
        document.body.appendChild(container);

        //setup scene and camera
        shared.renderer = new THREE.WebGLRenderer();

        views = [
            {
                left: 1,
                bottom: 2,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.2, 0.5, 0.7 ),
                eye: [0, 5, -80 ],
                up: [ 0, 1, 0 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {
                    camera.lookAt(new THREE.Vector3(0, this.eye[1], 0));
                }
            },
            {
                left: 0,
                bottom: 1,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.5, 0.5, 0.7 ),
                eye: [ 85, 5, 5.7 ],
                up: [ 0, 0, -1 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {

                    camera.lookAt(new THREE.Vector3(0, this.eye[1], this.eye[2]));
                }
            },
            {
                left: 1,
                bottom: 0,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.7, 0.5, 0.5 ),
                eye: [ 0, 5, 90 ],
                up: [ 0, -1, 0 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {
                    camera.lookAt(new THREE.Vector3(0, this.eye[1], this.eye[2]));
                }
            },
            {
                left: 2,
                bottom: 1,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.5, 0.7, 0.7 ),
                eye: [ -85, 5.3, 6.3 ],
                up: [ 0, 0, -1 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {
                    camera.lookAt(new THREE.Vector3(0, this.eye[1], this.eye[2]));
                }
            }
        ];

        for (var ii =  0; ii < views.length; ++ii ) {

            var view = views[ii];
            var camera = new THREE.PerspectiveCamera( view.fov, 1, 0.1, 10000 );
            camera.position.x = view.eye[ 0 ];
            camera.position.y = view.eye[ 1 ];
            camera.position.z = view.eye[ 2 ];
            camera.up.x = view.up[ 0 ];
            camera.up.y = view.up[ 1 ];
            camera.up.z = view.up[ 2 ];
            view.camera = camera;
        }

        shared.camera = new THREE.PerspectiveCamera(45, shared.width / shared.height, 0.1, 1000);
        shared.scene = new THREE.Scene();
        shared.renderer.setClearColor(0x000000);
        shared.camera.position.z = 100;
        shared.scene.add(shared.camera);
        shared.renderer.setSize(shared.width, shared.height, void 0);

        container.appendChild(shared.renderer.domElement);

        boundingBox = new BoundingBox(shared);

        shared.scene.add(boundingBox.geometry);
        shared.scene.add(boundingBox.floorGeometry);

        shared.collidableMeshList.push(boundingBox.floorGeometry);

        bricks = new Bricks(shared);

        bricks.update(function (b) {
            shared.scene.add(b.mesh);
            shared.collidableMeshList.push(b.mesh);
        });

        //console.log(bricks.brickList[3].getBounding());
        bricks.setSignal(shared.signals, shared.scene, shared);

        paddle = new Paddles(shared, 0x00ff00);
        paddle2 = new Paddles(shared, 0xff0000);

        Balls.prototype.bounce = shared.util.maybe(Balls.prototype.bounce);
        ball = new Balls(shared);

        shared.scene.add(paddle.geometry);
        shared.scene.add(paddle2.geometry);
        shared.scene.add(ball.geometry);
        shared.scene.add(ball.helperGeometry);

        window.addEventListener('mousemove', onMouseMove, false);
        window.addEventListener('click', onClick, false);
        window.addEventListener('keydown', handleKeyPresses(shared.parameters.paddlespeed), false);
        window.addEventListener('keyup', handleKeyPresses(0), false);

    }

    function anim() {
        requestAnimationFrame(anim);

        computePaddle(paddle, shared.pressedKeys);
        computePaddle(paddle2, shared.pressedKeys2);
        ball.update(shared.parameters.bounding);
        var origin = ball.geometry.position.clone();
        for (var vtxIdx = 0; vtxIdx < ball.geometry.geometry.vertices.length ; vtxIdx++) {
            var lvtx = ball.geometry.geometry.vertices[vtxIdx].clone();
            var gvtx = lvtx.applyMatrix4(ball.geometry.matrix);
            var direction = gvtx.sub(ball.geometry.position);

            var ray = new THREE.Raycaster(origin, direction.clone().normalize());
            var results = ray.intersectObjects(shared.collidableMeshList);
            var paddleHit = ray.intersectObjects([paddle.geometry,paddle2.geometry]);
            if (results.length > 0 && results[0].distance < direction.length()) {
                if(results[0].object.name == "floor"){
                    shared.scene.remove(ball.geometry);
                    setTimeout(function(){
                        var p = shared.parameters;
                        ball.geometry.position = new THREE.Vector3(0,0,0);
                        shared.scene.add(ball.geometry);
                    }, 500)
                }
                else{
                    ball.bounce(direction.clone().normalize().multiplyScalar(0.9));
                    var hit = results[0].object.idx;
                    var temp = shared.collidableMeshList[hit];
                    shared.signals.blockHit.dispatch(hit);
                    delete shared.collidableMeshList[hit];
                    setTimeout(function(){shared.collidableMeshList[hit] = temp; }, 40)
                }

            }
            if (paddleHit.length > 0 && paddleHit[0].distance < direction.length()) {
                ball.bounce(direction.clone ().normalize().multiplyScalar(0.9));
            }
        }

        //shared.renderer.render(shared.scene, shared.camera);
        for ( var ii = 0; ii < views.length; ++ii ) {

            var view = views[ii];
            shared.camera = view.camera;

            view.updateCamera( shared.camera, shared.scene, shared.mouseX, shared.mouseY );

            var left   = Math.floor( window.innerHeight  /3 * view.left);
            var bottom = Math.floor( window.innerHeight / 3 * view.bottom );
            var width  = Math.floor( window.innerHeight / 3 );
            var height = Math.floor( window.innerHeight / 3 );
            shared.renderer.setViewport( left+view.offsetX, bottom+view.offsetY, width, height );
            shared.renderer.setScissor( left, bottom, width, height );
            shared.renderer.enableScissorTest ( true );
            shared.renderer.setClearColor( view.background );

            shared.camera.aspect =1;
            shared.camera.updateProjectionMatrix();

            shared.renderer.render( shared.scene, shared.camera );
        }
    }

    function BoundingBox(shared) {
        this.width = shared.parameters.bounding.width;
        this.height = shared.parameters.bounding.height;
        this.depth = shared.parameters.bounding.depth;
        var geometry = new THREE.CubeGeometry(this.width, this.height, this.depth,
            shared.parameters.bounding.sx, shared.parameters.bounding.sy, shared.parameters.bounding.sz);
        var material = new THREE.MeshBasicMaterial({wireframe: true, opacity: 0, transparency: true});
        var boundingBox = new THREE.Mesh(geometry, material);
        boundingBox.position = new THREE.Vector3(shared.parameters.bounding.x, shared.parameters.bounding.y,
            shared.parameters.bounding.z);
        this.geometry = boundingBox.clone();

        var floorGeometry = new THREE.PlaneGeometry(shared.parameters.bounding.width, shared.parameters.bounding.height);

        var floorMaterial = new THREE.MeshBasicMaterial({wireframe: true, color: 0x13bee9});

        var floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);

        floorMesh.rotation.x = Math.PI / 2;
        floorMesh.position.y = -22.5;
        floorMesh.position.z = 5;

        this.floorGeometry = floorMesh.clone();
        this.floorGeometry.name = "floor";

    }

    function computePaddle(paddle, pressedKeys) {
        var movement = {x: pressedKeys[3] - pressedKeys[1], z: pressedKeys[2] - pressedKeys[0]};
        paddle.incrementPos(movement, shared.parameters.bounding);
    }

    function onMouseMove(event) {
        shared.mouseX = event.clientX;
        shared.mouseY = event.clientY;
    }

    function onClick(event) {
        console.log(shared.pressedKeys);
    }

    function handleKeyPresses(speed) {
        return function (event) {
            console.log(String.fromCharCode(event.keyCode));
            var key = String.fromCharCode(event.keyCode);
            if (key == 'W') {
                shared.pressedKeys[0] = speed;
                shared.pressedKeys[2] = 0;
            }
            if (key == 'A') {
                shared.pressedKeys[1] = speed;
                shared.pressedKeys[3] = 0;
            }
            if (key == 'S') {
                shared.pressedKeys[2] = speed;
                shared.pressedKeys[0] = 0;
            }
            if (key == 'D') {
                shared.pressedKeys[3] = speed;
                shared.pressedKeys[1] = 0;
            }
//
            if (key == '&') {
                shared.pressedKeys2[0] = speed;
                shared.pressedKeys2[2] = 0;
            }
            if (key == '%') {
                shared.pressedKeys2[1] = speed;
                shared.pressedKeys2[3] = 0;
            }
            if (key == '(') {
                shared.pressedKeys2[2] = speed;
                shared.pressedKeys2[0] = 0;
            }
            if (key == '\'') {
                shared.pressedKeys2[3] = speed;
                shared.pressedKeys2[1] = 0;
            }

            if (key == 'T') {
                shared.signals.blockHit.dispatch(2);
            }
        };
    }

}());<commit_msg>ball changes color based on paddle hit<commit_after>/**
 * Created with JetBrains WebStorm.
 * User: alxlu
 * Date: 10/15/13
 * Time: 11:40 PM
 */
(function () {

    var container, bricks, paddle, boundingBox, ball, Signal = signals.Signal, views;
    var shared = {
        width: window.innerHeight-5,
        height: window.innerHeight-5,
        mouseX: 0,
        mouseY: 0,
        pressedKeys: [0, 0, 0, 0],
        pressedKeys2: [0, 0, 0, 0],
        collidableMeshList: [],
        parameters: {
            ballsize: 2,
            ballspeed: {
                x: (Math.random() - 0.5),
                y: (Math.random() + 0.5),
                z: (Math.random() - 0.5)
            },
            bounding: {
                width: 60,
                height: 60,
                depth: 60,
                x: 0,
                y: 5,
                z: 6,
                sx: 3,
                sy: 3,
                sz: 3
            },
            bricksize: {
                width: 20,
                height: 10,
                depth: 20
            },
            brickspacing: {
                x: 0,
                y: 0,
                z: 0
            },
            bricklayout: {
                x: 3,
                y: 1,
                z: 3
            },
            brickoffsets: {
                x: 10,
                y: 30,
                z: -14
            },
            paddlesize: {
                width: 20,
                height: 2,
                depth: 20
            },
            paddlespeed: 0.6
        },
        signals: {
            blockHit: new Signal()
        },
        util: {
            combine: function (rule) {
                return rule.apply(this, [].slice.call(arguments, 1));
            },
            idToIdx: function (id) {
                return (id.x*100 +id.y*10+id.z);
            },
            brickbounce: (function () {
                var x, y, z;
                x = y = z = false;
                return function (c1, c2, c3) {
                    var result = void 0;
                    if (x && c1) {
                        result = "x";
                    } else if (y && c2) {
                        result = "y";
                    } else if (z && c3) {
                        result = "z";
                    }
                    if (result == void 0) {
                        z = c1 && c2 ? true : false;
                        y = c1 && c3 ? true : false;
                        x = c2 && c3 ? true : false;
                    } else {
                        x = y = z = false;
                    }
                    return result;
                };
            }()),
            maybe: function (fn) {
                return function () {
                    var i;
                    if (arguments.length == 0) {
                        return;
                    } else {
                        for (i = 0; i < arguments.length; i++) {
                            if (arguments[i] == null) return;
                        }
                        return fn.apply(this, arguments);
                    }
                };
            }
        }
    };

    init();
    anim();

    function init() {
        //create container and append to scene.
        container = document.createElement('div');
        container.id = "webgl";
        document.body.appendChild(container);

        //setup scene and camera
        shared.renderer = new THREE.WebGLRenderer();

        views = [
            {
                left: 1,
                bottom: 2,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.2, 0.5, 0.7 ),
                eye: [0, 5, -80 ],
                up: [ 0, 1, 0 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {
                    camera.lookAt(new THREE.Vector3(0, this.eye[1], 0));
                }
            },
            {
                left: 0,
                bottom: 1,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.5, 0.5, 0.7 ),
                eye: [ 85, 5, 5.7 ],
                up: [ 0, 0, -1 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {

                    camera.lookAt(new THREE.Vector3(0, this.eye[1], this.eye[2]));
                }
            },
            {
                left: 1,
                bottom: 0,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.7, 0.5, 0.5 ),
                eye: [ 0, 5, 90 ],
                up: [ 0, -1, 0 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {
                    camera.lookAt(new THREE.Vector3(0, this.eye[1], this.eye[2]));
                }
            },
            {
                left: 2,
                bottom: 1,
                width: 0.5,
                height: 0.5,
                offsetX: 0,
                offsetY: 0,
                background: new THREE.Color().setRGB( 0.5, 0.7, 0.7 ),
                eye: [ -85, 5.3, 6.3 ],
                up: [ 0, 0, -1 ],
                fov: 60,
                updateCamera: function ( camera, scene, mouseX, mouseY ) {
                    camera.lookAt(new THREE.Vector3(0, this.eye[1], this.eye[2]));
                }
            }
        ];

        for (var ii =  0; ii < views.length; ++ii ) {

            var view = views[ii];
            var camera = new THREE.PerspectiveCamera( view.fov, 1, 0.1, 10000 );
            camera.position.x = view.eye[ 0 ];
            camera.position.y = view.eye[ 1 ];
            camera.position.z = view.eye[ 2 ];
            camera.up.x = view.up[ 0 ];
            camera.up.y = view.up[ 1 ];
            camera.up.z = view.up[ 2 ];
            view.camera = camera;
        }

        shared.camera = new THREE.PerspectiveCamera(45, shared.width / shared.height, 0.1, 1000);
        shared.scene = new THREE.Scene();
        shared.renderer.setClearColor(0x000000);
        shared.camera.position.z = 100;
        shared.scene.add(shared.camera);
        shared.renderer.setSize(shared.width, shared.height, void 0);

        container.appendChild(shared.renderer.domElement);

        boundingBox = new BoundingBox(shared);

        shared.scene.add(boundingBox.geometry);
        shared.scene.add(boundingBox.floorGeometry);

        shared.collidableMeshList.push(boundingBox.floorGeometry);

        bricks = new Bricks(shared);

        bricks.update(function (b) {
            shared.scene.add(b.mesh);
            shared.collidableMeshList.push(b.mesh);
        });

        //console.log(bricks.brickList[3].getBounding());
        bricks.setSignal(shared.signals, shared.scene, shared);

        paddle = new Paddles(shared, 0x00ff00);
        paddle2 = new Paddles(shared, 0xff0000);

        Balls.prototype.bounce = shared.util.maybe(Balls.prototype.bounce);
        ball = new Balls(shared);

        shared.scene.add(paddle.geometry);
        shared.scene.add(paddle2.geometry);
        shared.scene.add(ball.geometry);
        shared.scene.add(ball.helperGeometry);

        window.addEventListener('mousemove', onMouseMove, false);
        window.addEventListener('click', onClick, false);
        window.addEventListener('keydown', handleKeyPresses(shared.parameters.paddlespeed), false);
        window.addEventListener('keyup', handleKeyPresses(0), false);

    }

    function anim() {
        requestAnimationFrame(anim);

        computePaddle(paddle, shared.pressedKeys);
        computePaddle(paddle2, shared.pressedKeys2);
        ball.update(shared.parameters.bounding);
        var origin = ball.geometry.position.clone();
        for (var vtxIdx = 0; vtxIdx < ball.geometry.geometry.vertices.length ; vtxIdx++) {
            var lvtx = ball.geometry.geometry.vertices[vtxIdx].clone();
            var gvtx = lvtx.applyMatrix4(ball.geometry.matrix);
            var direction = gvtx.sub(ball.geometry.position);

            var ray = new THREE.Raycaster(origin, direction.clone().normalize());
            var results = ray.intersectObjects(shared.collidableMeshList);
            var paddleHit = ray.intersectObjects([paddle.geometry,paddle2.geometry]);
            if (results.length > 0 && results[0].distance < direction.length()) {
                if(results[0].object.name == "floor"){
                    shared.scene.remove(ball.geometry);
                    setTimeout(function(){
                        var p = shared.parameters;
                        ball.geometry.position = new THREE.Vector3(0,0,0);
                        shared.scene.add(ball.geometry);
                    }, 500)
                }
                else{
                    ball.bounce(direction.clone().normalize().multiplyScalar(0.9));
                    var hit = results[0].object.idx;
                    var temp = shared.collidableMeshList[hit];
                    shared.signals.blockHit.dispatch(hit);
                    delete shared.collidableMeshList[hit];
                    setTimeout(function(){shared.collidableMeshList[hit] = temp; }, 40)
                }

            }
            if (paddleHit.length > 0 && paddleHit[0].distance < direction.length()) {
                console.log(paddleHit[0].object.material.color);
                ball.geometry.material.color = paddleHit[0].object.material.color;
                ball.bounce(direction.clone ().normalize().multiplyScalar(0.9));
            }
        }

        //shared.renderer.render(shared.scene, shared.camera);
        for ( var ii = 0; ii < views.length; ++ii ) {

            var view = views[ii];
            shared.camera = view.camera;

            view.updateCamera( shared.camera, shared.scene, shared.mouseX, shared.mouseY );

            var left   = Math.floor( window.innerHeight  /3 * view.left);
            var bottom = Math.floor( window.innerHeight / 3 * view.bottom );
            var width  = Math.floor( window.innerHeight / 3 );
            var height = Math.floor( window.innerHeight / 3 );
            shared.renderer.setViewport( left+view.offsetX, bottom+view.offsetY, width, height );
            shared.renderer.setScissor( left, bottom, width, height );
            shared.renderer.enableScissorTest ( true );
            shared.renderer.setClearColor( view.background );

            shared.camera.aspect =1;
            shared.camera.updateProjectionMatrix();

            shared.renderer.render( shared.scene, shared.camera );
        }
    }

    function BoundingBox(shared) {
        this.width = shared.parameters.bounding.width;
        this.height = shared.parameters.bounding.height;
        this.depth = shared.parameters.bounding.depth;
        var geometry = new THREE.CubeGeometry(this.width, this.height, this.depth,
            shared.parameters.bounding.sx, shared.parameters.bounding.sy, shared.parameters.bounding.sz);
        var material = new THREE.MeshBasicMaterial({wireframe: true, opacity: 0, transparency: true});
        var boundingBox = new THREE.Mesh(geometry, material);
        boundingBox.position = new THREE.Vector3(shared.parameters.bounding.x, shared.parameters.bounding.y,
            shared.parameters.bounding.z);
        this.geometry = boundingBox.clone();

        var floorGeometry = new THREE.PlaneGeometry(shared.parameters.bounding.width, shared.parameters.bounding.height);

        var floorMaterial = new THREE.MeshBasicMaterial({wireframe: true, color: 0x13bee9});

        var floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);

        floorMesh.rotation.x = Math.PI / 2;
        floorMesh.position.y = -22.5;
        floorMesh.position.z = 5;

        this.floorGeometry = floorMesh.clone();
        this.floorGeometry.name = "floor";

    }

    function computePaddle(paddle, pressedKeys) {
        var movement = {x: pressedKeys[3] - pressedKeys[1], z: pressedKeys[2] - pressedKeys[0]};
        paddle.incrementPos(movement, shared.parameters.bounding);
    }

    function onMouseMove(event) {
        shared.mouseX = event.clientX;
        shared.mouseY = event.clientY;
    }

    function onClick(event) {
        console.log(shared.pressedKeys);
    }

    function handleKeyPresses(speed) {
        return function (event) {
            console.log(String.fromCharCode(event.keyCode));
            var key = String.fromCharCode(event.keyCode);
            if (key == 'W') {
                shared.pressedKeys[0] = speed;
                shared.pressedKeys[2] = 0;
            }
            if (key == 'A') {
                shared.pressedKeys[1] = speed;
                shared.pressedKeys[3] = 0;
            }
            if (key == 'S') {
                shared.pressedKeys[2] = speed;
                shared.pressedKeys[0] = 0;
            }
            if (key == 'D') {
                shared.pressedKeys[3] = speed;
                shared.pressedKeys[1] = 0;
            }
//
            if (key == '&') {
                shared.pressedKeys2[0] = speed;
                shared.pressedKeys2[2] = 0;
            }
            if (key == '%') {
                shared.pressedKeys2[1] = speed;
                shared.pressedKeys2[3] = 0;
            }
            if (key == '(') {
                shared.pressedKeys2[2] = speed;
                shared.pressedKeys2[0] = 0;
            }
            if (key == '\'') {
                shared.pressedKeys2[3] = speed;
                shared.pressedKeys2[1] = 0;
            }

            if (key == 'T') {
                shared.signals.blockHit.dispatch(2);
            }
        };
    }

}());<|endoftext|>


<commit_before>Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    layout: {
        type: 'fit'
    },

    launch: function() {

        this._loadBuildDefs();

        /*  // Creates a table using Rally ui
            Rally.data.ModelFactory.getModel({
                    type:'Build Definition',
                    scope:this,
                    success: function(model){

                        var myGrid = Ext.create('Rally.ui.grid.Grid',{
                            model: model,
                            columnCfgs: [
                                'Name',
                                'Description',
                                'LastStatus'
                                ]
                        });
                        this.add(myGrid);

                    },
                    context: {
                        workspace: "/workspace/4365660833"
                    }

                });
        */

    },

    // Creates a query for specific build definitions
    _createQuery: function(buildDefRecords) {

        // get first entry
        var q = Ext.create('Rally.data.QueryFilter', {
            property: 'BuildDefinition',
            operator: '=',
            value: buildDefRecords[0].get('_ref')
            //            value: '/slm/webservice/1.37/builddefinition/6035424766' //PacSystems Mainline Build Definition
        });

        // remove teh first entry
        Ext.Array.remove(buildDefRecords, buildDefRecords[0]);

        // cycle through the remaineder in the array
        Ext.Array.forEach(buildDefRecords, function(item, index, allItems) {
            q = q.or(Ext.create('Rally.data.QueryFilter', {
                property: 'BuildDefinition',
                operator: '=',
                value: item.get('_ref')
            }));
        });

        console.log("query = ", q.toString());

        return q;

    },

    _getBuilds: function(buildDefRecords) {
        var query = this._createQuery(buildDefRecords);

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Fetched %d builds", records.length);
                    Ext.Array.forEach(records, function(item) {
                        //                        console.log("Name: %s, Def: %s, Status %s", item.get("Number"), item.get("BuildDefinition")._ref, item.get("Status"));
                    });
                    this._siftBuilds(records);
                },
                scope: this
            },
            sorters: [{
                property: 'CreationDate',
                direction: 'DESC'
            }],
            filters: query,
            autoLoad: true,
            pageSize: 100
        });
    },

    _loadBuildDefs: function() {

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build Definition',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Loaded %d Build Definitions.", records.length);

                    this.buildDefinitions = [];
                    Ext.Array.forEach(records, function(item) {
                        Ext.Array.push(this.buildDefinitions, item.get("_ref"));

                    }, this);
                    console.log("Build definitions array ", this.buildDefinitions);

                    this._getBuilds(records);
                },
                scope: this
            },
            autoLoad: true
        });

    },

    // creates the build def/ build record data struct
    _siftBuilds: function(buildDefBuildRecords) {

        var buildStructure = {};

        // Create a build structure
        Ext.Array.forEach(buildDefBuildRecords, function(item) {
            build = item;
            buildDef = item.get("BuildDefinition")._ref;
            //console.log(item.get("BuildDefinition"));

            if (!buildStructure.hasOwnProperty(buildDef)) {
                buildStructure[buildDef] = {
                    buildDefName: item.get("BuildDefinition")._refObjectName,
                    builds: [build],
                    lastBuild: null,
                    failCount: 0
                };
                //                console.log("Added new build def %s",buildDef);

            }
            else {
                Ext.Array.push(buildStructure[buildDef].builds, build);
                //                console.log("Pushed build  %s",item.get("Number"));
            }

        });

        //Now update the lastGoodBuild and failCount fields

        // for each build ref
        //    for each build
        //      if build failed
        //          increment failCount
        //      else
        //          set lastGoodBuild
        //          break;
        Ext.Array.forEach(this.buildDefinitions, function(item) {

            var buildDef = item;
            buildStructure[buildDef].failCount = 0;

            //            console.log("Working on %s",buildDef);

            Ext.Array.forEach(buildStructure[item].builds, function(item) {

                var build = item;

                if (build.get("Status") === "FAILURE") {
                    if (buildStructure[buildDef].lastGoodBuild == undefined) {
                        buildStructure[buildDef].failCount = buildStructure[buildDef].failCount + 1;
                        //                        console.log("%s failed, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    }
                    else {
                        return;
                    }
                }
                else {
                    //                    console.log("%s succeeded, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    buildStructure[buildDef].lastGoodBuild = build;
                    return;
                }

            });

            console.log("Build %s Fails %d", buildDef, buildStructure[buildDef].failCount);

        });
        console.log(buildStructure);

        gridFormattedBuilds = [];
        var count = 0;
        //format data into a new grid-freindly array
        Ext.Array.forEach(this.buildDefinitions, function(item) {
            var buildDef = item;

            gridFormattedBuilds[count] = {};
            gridFormattedBuilds[count].Name = buildStructure[buildDef].buildDefName; //i.e : "PACSystems Mainline CI Builds"

            //todo: make sure a build exists
            gridFormattedBuilds[count].Status = buildStructure[buildDef].builds[0].get("Status");
            gridFormattedBuilds[count].CurrentBuild = buildStructure[buildDef].builds[0].get("Number");
            gridFormattedBuilds[count].LastGoodBuild = buildStructure[buildDef].lastGoodBuild.get("Number");
            gridFormattedBuilds[count].NumFailedBuilds = buildStructure[buildDef].failCount;

            count++;
        });
        console.log("Grid Array:");
        //console.log(gridFormattedBuilds);

        //pipe it into a store
        Ext.create('Ext.data.Store', {
            storeId: 'ciBuildStore',
            fields: ['Name', 'Status', 'CurrentBuild', 'LastGoodBuild', 'NumFailedBuilds'],
            data: gridFormattedBuilds

        });

        // Color
        var statusTpl = new Ext.XTemplate(
            "<tpl switch='Status'>",
                "<tpl case='SUCCESS'>",
                    "
 {Status};
",
                "<tpl default>",
                    "
 {Status};
",
            "</tpl>");

        //{
        //    text: 'Verdict', dataIndex: 'Verdict', width: 95,
        //    renderer: function(value){
        //        if((value === "Fail") || (value === "Error") || (value === "Blocked")){
        //            return Ext.String.format("
{0}
", value);
        //        } else if ( value === "Inconclusive" ) {
        //            return Ext.String.format("
{0}
", value);
        //        }else{
        //            return Ext.String.format("
{0}
", value);
        //        }
        //    }
        //}

        var myGrid = Ext.create('Ext.grid.Panel', {
            title: 'Build Status',
            store: Ext.data.StoreManager.lookup('ciBuildStore'),
            columns: [
                { text: 'Name', dataIndex: 'Name', width: 205 },
                { text: 'Status', dataIndex: 'Status', flex: 1, xtype: 'templatecolumn', tpl: statusTpl},
                { text: 'Current Build', dataIndex: 'CurrentBuild', width: 165},
                { text: 'Last Good Build', dataIndex: 'LastGoodBuild', width: 165 },
                { text: 'Failed Builds', dataIndex: 'NumFailedBuilds', width: 50, tooltip: 'Number of failed builds since the last success', tooltipType: "qtip"},
                { menuDisabled: true, sortable: false, xtype: 'actioncolumn',items: [{
                    icon: 'https://raw.github.com/skandl/BuildActionBoard/master/button_got_it.jpg',
                    iconCls: 'gotItButton',
                    tooltip: 'I got it',
                    handler: function(grid, rowIndex, colIndex) {
                        console.log("Selected row %d", rowIndex);
                    }}],
                },
                {text: ' Savior', dataIndex: 'Owner', flex: 1}
            ],
            height: 200
            //            plugins: [{
            //                ptype: 'rowexpander',
            //                rowBodyTpl: new Ext.XTemplate('foo')
            //            }],
            //            collapsible: true,
            //            animCollapse: false
        });

        this.add(myGrid);

    }

});
<commit_msg>adds color coded build ids<commit_after>Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    layout: {
        type: 'fit'
    },

    launch: function() {

        this._loadBuildDefs();

        /*  // Creates a table using Rally ui
            Rally.data.ModelFactory.getModel({
                    type:'Build Definition',
                    scope:this,
                    success: function(model){

                        var myGrid = Ext.create('Rally.ui.grid.Grid',{
                            model: model,
                            columnCfgs: [
                                'Name',
                                'Description',
                                'LastStatus'
                                ]
                        });
                        this.add(myGrid);

                    },
                    context: {
                        workspace: "/workspace/4365660833"
                    }

                });
        */

    },

    // Creates a query for specific build definitions
    _createQuery: function(buildDefRecords) {

        // get first entry
        var q = Ext.create('Rally.data.QueryFilter', {
            property: 'BuildDefinition',
            operator: '=',
            value: buildDefRecords[0].get('_ref')
            //            value: '/slm/webservice/1.37/builddefinition/6035424766' //PacSystems Mainline Build Definition
        });

        // remove teh first entry
        Ext.Array.remove(buildDefRecords, buildDefRecords[0]);

        // cycle through the remaineder in the array
        Ext.Array.forEach(buildDefRecords, function(item, index, allItems) {
            q = q.or(Ext.create('Rally.data.QueryFilter', {
                property: 'BuildDefinition',
                operator: '=',
                value: item.get('_ref')
            }));
        });

        console.log("query = ", q.toString());

        return q;

    },

    _getBuilds: function(buildDefRecords) {
        var query = this._createQuery(buildDefRecords);

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Fetched %d builds", records.length);
                    Ext.Array.forEach(records, function(item) {
                        //                        console.log("Name: %s, Def: %s, Status %s", item.get("Number"), item.get("BuildDefinition")._ref, item.get("Status"));
                    });
                    this._siftBuilds(records);
                },
                scope: this
            },
            sorters: [{
                property: 'CreationDate',
                direction: 'DESC'
            }],
            filters: query,
            autoLoad: true,
            pageSize: 100
        });
    },

    _loadBuildDefs: function() {

        Ext.create('Rally.data.WsapiDataStore', {
            model: 'Build Definition',
            fetch: true,
            listeners: {
                load: function(store, records, success) {
                    console.log("Loaded %d Build Definitions.", records.length);

                    this.buildDefinitions = [];
                    Ext.Array.forEach(records, function(item) {
                        Ext.Array.push(this.buildDefinitions, item.get("_ref"));

                    }, this);
                    console.log("Build definitions array ", this.buildDefinitions);

                    this._getBuilds(records);
                },
                scope: this
            },
            autoLoad: true
        });

    },

    // creates the build def/ build record data struct
    _siftBuilds: function(buildDefBuildRecords) {

        var buildStructure = {};

        // Create a build structure
        Ext.Array.forEach(buildDefBuildRecords, function(item) {
            build = item;
            buildDef = item.get("BuildDefinition")._ref;
            //console.log(item.get("BuildDefinition"));

            if (!buildStructure.hasOwnProperty(buildDef)) {
                buildStructure[buildDef] = {
                    buildDefName: item.get("BuildDefinition")._refObjectName,
                    builds: [build],
                    lastBuild: null,
                    failCount: 0
                };
                //                console.log("Added new build def %s",buildDef);

            }
            else {
                Ext.Array.push(buildStructure[buildDef].builds, build);
                //                console.log("Pushed build  %s",item.get("Number"));
            }

        });

        //Now update the lastGoodBuild and failCount fields

        // for each build ref
        //    for each build
        //      if build failed
        //          increment failCount
        //      else
        //          set lastGoodBuild
        //          break;
        Ext.Array.forEach(this.buildDefinitions, function(item) {

            var buildDef = item;
            buildStructure[buildDef].failCount = 0;

            //            console.log("Working on %s",buildDef);

            Ext.Array.forEach(buildStructure[item].builds, function(item) {

                var build = item;

                if (build.get("Status") === "FAILURE") {
                    if (buildStructure[buildDef].lastGoodBuild == undefined) {
                        buildStructure[buildDef].failCount = buildStructure[buildDef].failCount + 1;
                        //                        console.log("%s failed, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    }
                    else {
                        return;
                    }
                }
                else {
                    //                    console.log("%s succeeded, failCount %d",build.get("Number"), buildStructure[buildDef].failCount);
                    buildStructure[buildDef].lastGoodBuild = build;
                    return;
                }

            });

            console.log("Build %s Fails %d", buildDef, buildStructure[buildDef].failCount);

        });
        console.log(buildStructure);

        gridFormattedBuilds = [];
        var count = 0;
        //format data into a new grid-freindly array
        Ext.Array.forEach(this.buildDefinitions, function(item) {
            var buildDef = item;

            gridFormattedBuilds[count] = {};
            gridFormattedBuilds[count].Name = buildStructure[buildDef].buildDefName; //i.e : "PACSystems Mainline CI Builds"

            //todo: make sure a build exists
            gridFormattedBuilds[count].Status = buildStructure[buildDef].builds[0].get("Status");
            gridFormattedBuilds[count].CurrentBuild = buildStructure[buildDef].builds[0].get("Number");
            gridFormattedBuilds[count].LastGoodBuild = buildStructure[buildDef].lastGoodBuild.get("Number");
            gridFormattedBuilds[count].NumFailedBuilds = buildStructure[buildDef].failCount;

            count++;
        });
        console.log("Grid Array:");
        //console.log(gridFormattedBuilds);

        //pipe it into a store
        Ext.create('Ext.data.Store', {
            storeId: 'ciBuildStore',
            fields: ['Name', 'Status', 'CurrentBuild', 'LastGoodBuild', 'NumFailedBuilds'],
            data: gridFormattedBuilds

        });

        // Color
        var statusTpl = new Ext.XTemplate(
            "<tpl switch='Status'>",
                "<tpl case='SUCCESS'>",
                    "
 {Status};
",
                "<tpl default>",
                    "
 {Status};
",
            "</tpl>");
        var currentBuildTpl = new Ext.XTemplate(
            "<tpl switch='Status'>",
                "<tpl case='SUCCESS'>",
                    "
 {CurrentBuild}
",
                "<tpl default>",
                    "
 {CurrentBuild}
",
            "</tpl>");

        var lastGoodBuildTpl = new Ext.XTemplate(
            "<tpl>",
                    "
 {LastGoodBuild}
",
            "</tpl>");

        //{
        //    text: 'Verdict', dataIndex: 'Verdict', width: 95,
        //    renderer: function(value){
        //        if((value === "Fail") || (value === "Error") || (value === "Blocked")){
        //            return Ext.String.format("
{0}
", value);
        //        } else if ( value === "Inconclusive" ) {
        //            return Ext.String.format("
{0}
", value);
        //        }else{
        //            return Ext.String.format("
{0}
", value);
        //        }
        //    }
        //}

        var myGrid = Ext.create('Ext.grid.Panel', {
            title: 'Build Status',
            store: Ext.data.StoreManager.lookup('ciBuildStore'),
            columns: [
                { text: 'Name', dataIndex: 'Name', width: 205 },
//                { text: 'Status', dataIndex: 'Status', flex: 1, xtype: 'templatecolumn', tpl: statusTpl},
                { text: 'Current Build', dataIndex: 'CurrentBuild', width: 175, xtype: 'templatecolumn', tpl: currentBuildTpl},
                { text: 'Last Good Build', dataIndex: 'LastGoodBuild', width: 175, xtype: 'templatecolumn', tpl: lastGoodBuildTpl },
                { text: 'Failed Builds', dataIndex: 'NumFailedBuilds', width: 50, tooltip: 'Number of failed builds since the last success', tooltipType: "qtip"},
                { menuDisabled: true, sortable: false, xtype: 'actioncolumn',items: [{
                    icon: 'https://raw.github.com/skandl/BuildActionBoard/master/button_got_it.jpg',
                    iconCls: 'gotItButton',
                    tooltip: 'I got it',
                    handler: function(grid, rowIndex, colIndex) {
                        console.log("Selected row %d", rowIndex);
                    }}],
                },
                {text: ' Savior', dataIndex: 'Owner', flex: 1}
            ],
            height: 200
            //            plugins: [{
            //                ptype: 'rowexpander',
            //                rowBodyTpl: new Ext.XTemplate('foo')
            //            }],
            //            collapsible: true,
            //            animCollapse: false
        });

        this.add(myGrid);

    }

});
<|endoftext|>


<commit_before>Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
	myGrid: undefined,
	defectStore: undefined,

	launch: function() {
		console.log('Our Second App woot');

		this.pulldownContainer = Ext.create('Ext.container.Container', {
			layout: {
				type: 'hbox',
				align: 'stretch'
			}
		});

		this.add(this.pulldownContainer);

		this._loadIterations();
	},

	_loadIterations: function() {
		this.iterComboBox = Ext.create('Rally.ui.combobox.IterationComboBox', {
			fieldLabel: 'Iteration',
			labelAlign: 'right',
			width: 300,
			listeners: {
				ready: function(combobox) {
					//var selectedIterRef = combobox.getRecord().get('_ref');
					//this._loadData();
					this._loadSeverities();
				},
				select: function(combobox, records) {
					this._loadData();
				},
				scope: this
			}
		});

		this.pulldownContainer.add(this.iterComboBox);
	},

	_loadSeverities: function() {
		this.severityPicker = Ext.create('Rally.ui.combobox.FieldValueComboBox', {
			model: 'Defect',
			field: 'Severity',
			fieldLabel: 'Severity',
			labelAlign: 'right',
			listeners: {
				ready: function(combobox) {
					this._loadData();
				},
				select: function(combobox, records) {
					this._loadData();
				},
				scope: this
			}
		});

		this.pulldownContainer.add(this.severityPicker);
	},

	// Get data from Rally
	_loadData: function() {
		var selectedIterRef = this.iterComboBox.getRecord().get('_ref'); // selected iteration
		var selectedSeverityValue = this.severityPicker.getRecord().get('value'); // selected severity

		var myFilters = [
			{
				property: 'Iteration',
				operation: '=',
				value: selectedIterRef
			},
			{
				property: 'Severity',
				operation: '=',
				value: selectedSeverityValue
			}
		];

		// if store exists, just load new data
		if (this.defectStore) {
			console.log('store exists');
			this.defectStore.setFilter(myFilters);
			this.defectStore.load();
		} else {
			console.log('creating store');
			//create store
			this.defectStore = Ext.create('Rally.data.wsapi.Store', {
				model: 'Defect',
				autoLoad: true,
				filters: myFilters,
				listeners: {
					load: function(store, data, success) {
						//console.log('got data!', store, data, success);
						if (!this.myGrid) {
							this._createGrid(this.defectStore);
						}
					},
					scope: this
				},
				fetch: ['Name', 'formattedID', 'Severity', 'Iteration']
			});
		}
	},

	// Create Grid
	_createGrid: function(myStoryStore) {
		this.myGrid = Ext.create('Rally.ui.grid.Grid', {
			store: myStoryStore,
			columnCfgs: [
				'FormattedID',
				'Name',
				'Severity',
				'Iteration'
			]
		});

		this.add(this.myGrid);
	}
});
<commit_msg>Completed Refactored Grid<commit_after>Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',

	items: [
		{
			xtype: 'container',
			itemId: 'pulldown-container',
			layout: {
				type: 'hbox',
				align: 'stretch'
			}
		}
	],

	myGrid: undefined,
	defectStore: undefined,

	launch: function() {
		console.log('Our Second App woot');

		this._loadIterations();
	},

	_loadIterations: function() {
		var me = this;

		var iterComboBox = Ext.create('Rally.ui.combobox.IterationComboBox', {
			itemId: 'iteration-combobox',
			fieldLabel: 'Iteration',
			labelAlign: 'right',
			width: 300,
			listeners: {
				ready: me._loadSeverities,
				select: me._loadData,
				scope: me
			}
		});

		//this.pulldownContainer.add(this.iterComboBox);
		this.down('#pulldown-container').add(iterComboBox);
	},

	_loadSeverities: function() {
		var me = this;

		var severityPicker = Ext.create('Rally.ui.combobox.FieldValueComboBox', {
			itemId: 'severity-combobox',
			model: 'Defect',
			field: 'Severity',
			fieldLabel: 'Severity',
			labelAlign: 'right',
			listeners: {
				ready: me._loadData,
				select: me._loadData,
				scope: me
			}
		});

		this.down('#pulldown-container').add(severityPicker);
	},

	_getFilters: function(iterationValue, severityValue) {
		var iterationFilter = Ext.create('Rally.data.wsapi.Filter', {
			property: 'Iteration',
			operation: '=',
			value: iterationValue
		});

		var severityFilter = Ext.create('Rally.data.wsapi.Filter', {
			property: 'Severity',
			operation: '=',
			value: severityValue
		});

		return iterationFilter.and(severityFilter);
	},

	// Get data from Rally
	_loadData: function() {
		var me = this;

		var selectedIterRef = me.down('#iteration-combobox').getRecord().get('_ref'); // selected iteration
		var selectedSeverityValue = me.down('#severity-combobox').getRecord().get('value'); // selected severity

		var myFilters = me._getFilters(selectedIterRef, selectedSeverityValue);

		// if store exists, just load new data
		if (me.defectStore) {
			console.log('store exists');
			me.defectStore.setFilter(myFilters);
			me.defectStore.load();
		} else {
			console.log('creating store');
			//create store
			me.defectStore = Ext.create('Rally.data.wsapi.Store', {
				model: 'Defect',
				autoLoad: true,
				filters: myFilters,
				listeners: {
					load: function(store, data, success) {
						//console.log('got data!', store, data, success);
						if (!me.myGrid) {
							me._createGrid(me.defectStore);
						}
					},
					scope: me
				},
				fetch: ['Name', 'formattedID', 'Severity', 'Iteration']
			});
		}
	},

	// Create Grid
	_createGrid: function(myStoryStore) {
		var me = this;

		me.myGrid = Ext.create('Rally.ui.grid.Grid', {
			store: myStoryStore,
			columnCfgs: [
				'FormattedID',
				'Name',
				'Severity',
				'Iteration'
			]
		});

		me.add(me.myGrid);
	}
});
<|endoftext|>


<commit_before>function unpack(src, out, elemSize) {
    for(var i=0, len=src.length; i<len; i++) {
        for(var j=0; j<elemSize; j++) {
            out[i * elemSize + j] = src[i][j];
        }
    }
}

function isFlatArray(a) {
    return (a.length == 0) || (a[0].length === undefined);
}

//TODO: add divisor support for attributes
/**
 * [Mesh description]
 * @param {[type]} ctx              Context
 * @param {[type]} attributes       Array of { data: Array(flat or list of verts), location: Int, size: Int or guess, usage: Int or guess}
 * @param {[type]} indicesInfo      { data : Array(flat or list faces), usage: Int or guess }
 * @param {[type]} primitiveType    PrimitiveType (default guesses from indices: no indices = POINTS, list of edges = LINES, list of faces = TRIANGLES)
 */
function Mesh(ctx, attributes, indicesInfo, primitiveType) {
    this._ctx = ctx;

    var attributesDesc = [];

    this._attributes = [];
    this._attributesMap = [];

    var vertexCount = 0;

    for(var i=0, len=attributes.length; i<len; i++) {
        var attributeInfo = attributes[i];
        var data = attributeInfo.data;
        var location = attributeInfo.location;
        var elementSize = data[0].length || attributeInfo.size || -1;
        //TODO: this can be done with !isNaN(data[0])

        //TODO: are we allowing empty attributes e.g. data=[] ?
        if (!data.length) {
            throw new Error('Mesh: Empty attribute data is not supported');
        }

        if (location === undefined) {
            throw new Error('Mesh: Unknown attribute location at index ' + i);
        }

        if (elementSize === -1) {
            throw new Error('Mesh: Missing attribute size at index ' + i);
        }

        var dataArray = new Float32Array(data.length * elementSize);
        if (isFlatArray(data)) {
            dataArray.set(data);
        }
        else {
            unpack(data, dataArray, elementSize);
        }

        var usage = attributeInfo.usage || ctx.STATIC_DRAW;

        var buffer = ctx.createBuffer(ctx.ARRAY_BUFFER, dataArray, usage);

        var attributeDesc = {
            buffer: buffer,
            location : location,
            size: attributeInfo.size || elementSize
        }

        var attribute = {
            data: data,
            dataArray: dataArray,
            buffer: buffer,
            location : location,
            size: attributeInfo.size || elementSize
        }

        attributesDesc.push(attributeDesc);
        this._attributes.push(attribute);
        this._attributesMap[location] = attribute;

        if (location == ctx.ATTRIB_POSITION) {
            vertexCount = data.length;
        }
    }

    var indicesCount = 0;

    if (indicesInfo) {
        var indicesData = indicesInfo.data;
        var indicesDataElementSize = indicesData[0].length || 1;
        var indicesDataType = indicesInfo.type;
        if (!indicesDataType) {
            if (ctx.isSupported(ctx.CAPS_ELEMENT_INDEX_UINT)) {
                indicesDataType = ctx.UNSIGNED_INT;
            }
            else {
                indicesDataType = ctx.UNSIGNED_SHORT;
            }
        }
        var indicesDataArrayType = (indicesDataType === ctx.UNSIGNED_INT) ? Uint32Array : Uint16Array;
        var indicesDataArray = new indicesDataArrayType(indicesData.length * indicesDataElementSize);

        if (isFlatArray(indicesData)) {
            indicesDataArray.set(indicesDataElementSize);
        }
        else {
            unpack(indicesData, indicesDataArray, indicesDataElementSize)
        }

        var usage = indicesInfo.usage || ctx.STATIC_DRAW;

        var indicesBuffer  = ctx.createBuffer(ctx.ELEMENT_ARRAY_BUFFER, indicesDataArray, usage);

        if (!primitiveType) {
            if (indicesDataElementSize == 1) primitiveType = ctx.POINTS;
            if (indicesDataElementSize == 2) primitiveType = ctx.LINES;
            if (indicesDataElementSize == 3) primitiveType = ctx.TRIANGLES;
        }

        this._indices = {
            data: indicesData,
            dataArray: indicesDataArray,
            buffer: indicesBuffer,
            size: indicesDataElementSize
        };

        indicesCount = indicesData.length * indicesDataElementSize;
    }
    else {
        this._indices = null;
    }

    this._primiviteType = primitiveType || ctx.TRIANGLES;
    this._count = indicesCount || vertexCount;
    this._offset = 0;
    this._vao = ctx.createVertexArray(attributesDesc, this._indices ? this._indices.buffer : null);
}

Mesh.prototype.draw = function() {
    this._ctx.bindVertexArray(this._vao);
    this._ctx.drawElements(this._primiviteType, this._count, this._offset);
}

Mesh.prototype.getAttribute = function(location) {
    return this._attributesMap[location];
}

Mesh.prototype.updateAttribute = function(location, data) {
    var ctx = this._ctx;
    var attribute = this._attributesMap[location];

    if (!attribute) {
        throw new Error('Mesh.updateAttribute: invalid attribute loaction');
    }

    if (data.length != attribute.data.length) {
        attribute.dataArray = new Float32Array(data.length);
    }

    if (isFlatArray(data)) {
        attribute.dataArray.set(data);
    }
    else {
        //ASSUMING we don't suddently change Vec2 into Vec3, so size is the same
        unpack(data, attribute.dataArray, attribute.size);
    }

    attribute.data = data;

    //TODO: test this
    if (location == ctx.ATTRIB_POSITION && this._indices === null) {
        this._count = data.length;
    }

    attribute.buffer.bufferData(attribute.dataArray);
}

Mesh.prototype.getIndices = function() {
    return this._indices;
}

//TODO: test this
//TODO: update count
//TODO: copy data ref
/**
 * Updates index buffer
 * @param  {Array of Int or Array or Arrays} data must have length > 0
 */
Mesh.prototype.updateIndices = function(data) {
    var indices = this._indices;

    if (!indices) {
        throw new Error('Mesh.updateIndices: mesh has no indices to update');
    }
    if (data.length != indices.data.length) {
        indices.dataArray = new Float32Array(data.length);
    }

    if (isFlatArray(data)) {
        indices.dataArray.set(data);
    }
    else {
        //ASSUMING we don't suddently change face3 into face2 or flat, so size is the same
        unpack(data, indices.dataArray, indices.size);
    }

    indices.data = data;

    //ASSUMING we don't suddently change face3 into face2 or flat, so size is the same
    //TODO: test this
    this._count = data.length * indices.size;

    indices.buffer.bufferData(indices.dataArray);
}

module.exports = Mesh;
<commit_msg>Mesh fixed typed array length and type bugs<commit_after>function unpack(src, out, elemSize) {
    for(var i=0, len=src.length; i<len; i++) {
        for(var j=0; j<elemSize; j++) {
            out[i * elemSize + j] = src[i][j];
        }
    }
}

function isFlatArray(a) {
    return (a.length == 0) || (a[0].length === undefined);
}

//TODO: add divisor support for attributes
/**
 * [Mesh description]
 * @param {[type]} ctx              Context
 * @param {[type]} attributes       Array of { data: Array(flat or list of verts), location: Int, size: Int or guess, usage: Int or guess}
 * @param {[type]} indicesInfo      { data : Array(flat or list faces), usage: Int or guess }
 * @param {[type]} primitiveType    PrimitiveType (default guesses from indices: no indices = POINTS, list of edges = LINES, list of faces = TRIANGLES)
 */
function Mesh(ctx, attributes, indicesInfo, primitiveType) {
    this._ctx = ctx;

    var attributesDesc = [];

    this._attributes = [];
    this._attributesMap = [];

    var vertexCount = 0;

    for(var i=0, len=attributes.length; i<len; i++) {
        var attributeInfo = attributes[i];
        var data = attributeInfo.data;
        var location = attributeInfo.location;
        var elementSize = data[0].length || attributeInfo.size || -1;
        //TODO: this can be done with !isNaN(data[0])

        //TODO: are we allowing empty attributes e.g. data=[] ?
        if (!data.length) {
            throw new Error('Mesh: Empty attribute data is not supported');
        }

        if (location === undefined) {
            throw new Error('Mesh: Unknown attribute location at index ' + i);
        }

        if (elementSize === -1) {
            throw new Error('Mesh: Missing attribute size at index ' + i);
        }

        var dataArray = new Float32Array(data.length * elementSize);
        if (isFlatArray(data)) {
            dataArray.set(data);
        }
        else {
            unpack(data, dataArray, elementSize);
        }

        var usage = attributeInfo.usage || ctx.STATIC_DRAW;

        var buffer = ctx.createBuffer(ctx.ARRAY_BUFFER, dataArray, usage);

        var attributeDesc = {
            buffer: buffer,
            location : location,
            size: attributeInfo.size || elementSize
        }

        var attribute = {
            data: data,
            dataArray: dataArray,
            buffer: buffer,
            location : location,
            size: attributeInfo.size || elementSize
        }

        attributesDesc.push(attributeDesc);
        this._attributes.push(attribute);
        this._attributesMap[location] = attribute;

        if (location == ctx.ATTRIB_POSITION) {
            vertexCount = data.length;
        }
    }

    var indicesCount = 0;

    if (indicesInfo) {
        var indicesData = indicesInfo.data;
        var indicesDataElementSize = indicesData[0].length || 1;
        var indicesDataType = indicesInfo.type;
        if (!indicesDataType) {
            if (ctx.isSupported(ctx.CAPS_ELEMENT_INDEX_UINT)) {
                indicesDataType = ctx.UNSIGNED_INT;
            }
            else {
                indicesDataType = ctx.UNSIGNED_SHORT;
            }
        }
        var indicesDataArrayType = (indicesDataType === ctx.UNSIGNED_INT) ? Uint32Array : Uint16Array;
        var indicesDataArray = new indicesDataArrayType(indicesData.length * indicesDataElementSize);

        if (isFlatArray(indicesData)) {
            indicesDataArray.set(indicesDataElementSize);
        }
        else {
            unpack(indicesData, indicesDataArray, indicesDataElementSize)
        }

        var usage = indicesInfo.usage || ctx.STATIC_DRAW;

        var indicesBuffer  = ctx.createBuffer(ctx.ELEMENT_ARRAY_BUFFER, indicesDataArray, usage);

        if (!primitiveType) {
            if (indicesDataElementSize == 1) primitiveType = ctx.POINTS;
            if (indicesDataElementSize == 2) primitiveType = ctx.LINES;
            if (indicesDataElementSize == 3) primitiveType = ctx.TRIANGLES;
        }

        this._indices = {
            data: indicesData,
            dataArray: indicesDataArray,
            buffer: indicesBuffer,
            size: indicesDataElementSize
        };

        indicesCount = indicesData.length * indicesDataElementSize;
    }
    else {
        this._indices = null;
    }

    this._primiviteType = primitiveType || ctx.TRIANGLES;
    this._count = indicesCount || vertexCount;
    this._offset = 0;
    this._vao = ctx.createVertexArray(attributesDesc, this._indices ? this._indices.buffer : null);
}

Mesh.prototype.draw = function() {
    this._ctx.bindVertexArray(this._vao);
    this._ctx.drawElements(this._primiviteType, this._count, this._offset);
}

Mesh.prototype.getAttribute = function(location) {
    return this._attributesMap[location];
}

Mesh.prototype.updateAttribute = function(location, data) {
    var ctx = this._ctx;
    var attribute = this._attributesMap[location];

    if (!attribute) {
        throw new Error('Mesh.updateAttribute: invalid attribute loaction');
    }

    if (data.length != attribute.data.length) {
        attribute.dataArray = new Float32Array(data.length * attribute.size);
    }

    if (isFlatArray(data)) {
        attribute.dataArray.set(data);
    }
    else {
        //ASSUMING we don't suddently change Vec2 into Vec3, so size is the same
        unpack(data, attribute.dataArray, attribute.size);
    }

    attribute.data = data;

    //TODO: test this
    if (location == ctx.ATTRIB_POSITION && this._indices === null) {
        this._count = data.length;
    }

    attribute.buffer.bufferData(attribute.dataArray);
}

Mesh.prototype.getIndices = function() {
    return this._indices;
}

//TODO: test this
//TODO: update count
//TODO: copy data ref
/**
 * Updates index buffer
 * @param  {Array of Int or Array or Arrays} data must have length > 0
 */
Mesh.prototype.updateIndices = function(data) {
    var indices = this._indices;

    if (!indices) {
        throw new Error('Mesh.updateIndices: mesh has no indices to update');
    }
    if (data.length != indices.data.length) {
        if (indices.dataArray instanceof Uint32Array) {
            indices.dataArray = new Uint32Array(data.length * indices.size);
        }
        else {
            indices.dataArray = new Uint16Array(data.length * indices.size);
        }
    }

    if (isFlatArray(data)) {
        indices.dataArray.set(data);
    }
    else {
        //ASSUMING we don't suddently change face3 into face2 or flat, so size is the same
        unpack(data, indices.dataArray, indices.size);
    }

    indices.data = data;

    //ASSUMING we don't suddently change face3 into face2 or flat, so size is the same
    //TODO: test this
    this._count = data.length * indices.size;

    indices.buffer.bufferData(indices.dataArray);
}

module.exports = Mesh;
<|endoftext|>


<commit_before>const Gpio = require('pigpio').Gpio;

/**
 *
 *
 * @class Led
 */
class Led {
    /**
     * Creates an instance of Led.
     * @param {number} pin
     * @memberof Led
     */
    constructor(pin) {
        this.led = new Gpio(pin, {
            mode: Gpio.OUTPUT
        });
        this.pwmWrites = 0;
    }
    on() {
        this.led.digitalWrite(0);
    }
    off() {
        this.led.digitalWrite(1);
    }
    /**
     *
     *
     * @param {number} value
     * @memberof Led
     */
    rgb(value) {
        value = parseInt(255 - value);
        if (value > 255) value = 255;
        else if (value < 0) value = 0;
        this.led.pwmWrite(value)
        if (this.pwmWrites == 0) {
            this.led.pwmWrite(value)
        }
        this.pwmWrites++
    }
}

module.exports = Led;<commit_msg>pwm bugfix<commit_after>const Gpio = require('pigpio').Gpio;

/**
 *
 *
 * @class Led
 */
class Led {
    /**
     * Creates an instance of Led.
     * @param {number} pin
     * @memberof Led
     */
    constructor(pin) {
        this.led = new Gpio(pin, {
            mode: Gpio.OUTPUT
        });
        this.pwmWrites = 0;
    }
    on() {
        this.led.digitalWrite(0);
    }
    off() {
        this.led.digitalWrite(1);
    }
    /**
     *
     *
     * @param {number} value
     * @memberof Led
     */
    rgb(value) {
        value = parseInt(255 - value);
        if (value > 255) value = 255;
        else if (value < 0) value = 0;
        this.led.pwmWrite(value)
        if (this.pwmWrites == 0) {
            setTimeout( () =>{
                this.led.pwmWrite(value)
            },200)
        }
        this.pwmWrites++
    }
}

module.exports = Led;<|endoftext|>