| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107 | 
							- /*
 
- 	Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
 
- 	Available via Academic Free License >= 2.1 OR the modified BSD license.
 
- 	see: http://dojotoolkit.org/license for details
 
- */
 
- if(!dojo._hasResource["dojox.gfx3d.object"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 
- dojo._hasResource["dojox.gfx3d.object"] = true;
 
- dojo.provide("dojox.gfx3d.object");
 
- dojo.require("dojox.gfx");
 
- dojo.require("dojox.gfx3d.lighting");
 
- dojo.require("dojox.gfx3d.scheduler");
 
- dojo.require("dojox.gfx3d.vector");
 
- dojo.require("dojox.gfx3d.gradient");
 
- // FIXME: why the global "out" var here?
 
- var out = function(o, x){
 
- 	if(arguments.length > 1){
 
- 		// console.debug("debug:", o);
 
- 		o = x;
 
- 	}
 
- 	var e = {};
 
- 	for(var i in o){
 
- 		if(i in e){ continue; }
 
- 		// console.debug("debug:", i, typeof o[i], o[i]);
 
- 	}
 
- };
 
- dojo.declare("dojox.gfx3d.Object", null, {
 
- 	constructor: function(){
 
- 		// summary: a Object object, which knows how to map
 
- 		// 3D objects to 2D shapes.
 
- 		// object: Object: an abstract Object object
 
- 		// (see dojox.gfx3d.defaultEdges,
 
- 		// dojox.gfx3d.defaultTriangles,
 
- 		// dojox.gfx3d.defaultQuads
 
- 		// dojox.gfx3d.defaultOrbit
 
- 		// dojox.gfx3d.defaultCube
 
- 		// or dojox.gfx3d.defaultCylinder)
 
- 		this.object = null;
 
- 		// matrix: dojox.gfx3d.matrix: world transform
 
- 		this.matrix = null;
 
- 		// cache: buffer for intermediate result, used late for draw()
 
- 		this.cache = null;
 
- 		// renderer: a reference for the Viewport
 
- 		this.renderer = null;
 
- 		// parent: a reference for parent, Scene or Viewport object
 
- 		this.parent = null;
 
- 		// strokeStyle: Object: a stroke object
 
- 		this.strokeStyle = null;
 
- 		// fillStyle: Object: a fill object or texture object
 
- 		this.fillStyle = null;
 
- 		// shape: dojox.gfx.Shape: an underlying 2D shape
 
- 		this.shape = null;
 
- 	},
 
- 	setObject: function(newObject){
 
- 		// summary: sets a Object object
 
- 		// object: Object: an abstract Object object
 
- 		// (see dojox.gfx3d.defaultEdges,
 
- 		// dojox.gfx3d.defaultTriangles,
 
- 		// dojox.gfx3d.defaultQuads
 
- 		// dojox.gfx3d.defaultOrbit
 
- 		// dojox.gfx3d.defaultCube
 
- 		// or dojox.gfx3d.defaultCylinder)
 
- 		this.object = dojox.gfx.makeParameters(this.object, newObject);
 
- 		return this;
 
- 	},
 
- 	setTransform: function(matrix){
 
- 		// summary: sets a transformation matrix
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx3d.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		this.matrix = dojox.gfx3d.matrix.clone(matrix ? dojox.gfx3d.matrix.normalize(matrix) : dojox.gfx3d.identity, true);
 
- 		return this;	// self
 
- 	},
 
- 	// apply left & right transformation
 
- 	
 
- 	applyRightTransform: function(matrix){
 
- 		// summary: multiplies the existing matrix with an argument on right side
 
- 		//	(this.matrix * matrix)
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		return matrix ? this.setTransform([this.matrix, matrix]) : this;	// self
 
- 	},
 
- 	applyLeftTransform: function(matrix){
 
- 		// summary: multiplies the existing matrix with an argument on left side
 
- 		//	(matrix * this.matrix)
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		return matrix ? this.setTransform([matrix, this.matrix]) : this;	// self
 
- 	},
 
- 	applyTransform: function(matrix){
 
- 		// summary: a shortcut for dojox.gfx.Shape.applyRightTransform
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		return matrix ? this.setTransform([this.matrix, matrix]) : this;	// self
 
- 	},
 
- 	
 
- 	setFill: function(fill){
 
- 		// summary: sets a fill object
 
- 		// (the default implementation is to delegate to
 
- 		// the underlying 2D shape).
 
- 		// fill: Object: a fill object
 
- 		//	(see dojox.gfx.defaultLinearGradient,
 
- 		//	dojox.gfx.defaultRadialGradient,
 
- 		//	dojox.gfx.defaultPattern,
 
- 		//	dojo.Color
 
- 		//	or dojox.gfx.MODEL)
 
- 		this.fillStyle = fill;
 
- 		return this;
 
- 	},
 
- 	setStroke: function(stroke){
 
- 		// summary: sets a stroke object
 
- 		//	(the default implementation simply ignores it)
 
- 		// stroke: Object: a stroke object
 
- 		//	(see dojox.gfx.defaultStroke)
 
- 		this.strokeStyle = stroke;
 
- 		return this;
 
- 	},
 
- 	toStdFill: function(lighting, normal){
 
- 		return (this.fillStyle && typeof this.fillStyle['type'] != "undefined") ? lighting[this.fillStyle.type](normal, this.fillStyle.finish, this.fillStyle.color) : this.fillStyle;
 
- 	},
 
- 	invalidate: function(){
 
- 		this.renderer.addTodo(this);
 
- 	},
 
- 	
 
- 	destroy: function(){
 
- 		if(this.shape){
 
- 			var p = this.shape.getParent();
 
- 			if(p){
 
- 				p.remove(this.shape);
 
- 			}
 
- 			this.shape = null;
 
- 		}
 
- 	},
 
- 	// All the 3D objects need to override the following virtual functions:
 
- 	// render, getZOrder, getOutline, draw, redraw if necessary.
 
- 	render: function(camera){
 
- 		throw "Pure virtual function, not implemented";
 
- 	},
 
- 	draw: function(lighting){
 
- 		throw "Pure virtual function, not implemented";
 
- 	},
 
- 	getZOrder: function(){
 
- 		return 0;
 
- 	},
 
- 	getOutline: function(){
 
- 		return null;
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Scene", dojox.gfx3d.Object, {
 
- 	// summary: the Scene is just a containter.
 
- 	// note: we have the following assumption:
 
- 	// all objects in the Scene are not overlapped with other objects
 
- 	// outside of the scene.
 
- 	constructor: function(){
 
- 		// summary: a containter of other 3D objects
 
- 		this.objects= [];
 
- 		this.todos = [];
 
- 		this.schedule = dojox.gfx3d.scheduler.zOrder;
 
- 		this._draw = dojox.gfx3d.drawer.conservative;
 
- 	},
 
- 	setFill: function(fill){
 
- 		this.fillStyle = fill;
 
- 		dojo.forEach(this.objects, function(item){
 
- 			item.setFill(fill);
 
- 		});
 
- 		return this;
 
- 	},
 
- 	setStroke: function(stroke){
 
- 		this.strokeStyle = stroke;
 
- 		dojo.forEach(this.objects, function(item){
 
- 			item.setStroke(stroke);
 
- 		});
 
- 		return this;
 
- 	},
 
- 	render: function(camera, deep){
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		if(deep){
 
- 			this.todos = this.objects;
 
- 		}
 
- 		dojo.forEach(this.todos, function(item){ item.render(m, deep); });
 
- 	},
 
- 	draw: function(lighting){
 
- 		this.objects = this.schedule(this.objects);
 
- 		this._draw(this.todos, this.objects, this.renderer);
 
- 	},
 
- 	addTodo: function(newObject){
 
- 		// FIXME: use indexOf?
 
- 		if(dojo.every(this.todos, function(item){ return item != newObject; })){
 
- 			this.todos.push(newObject);
 
- 			this.invalidate();
 
- 		}
 
- 	},
 
- 	invalidate: function(){
 
- 		this.parent.addTodo(this);
 
- 	},
 
- 	getZOrder: function(){
 
- 		var zOrder = 0;
 
- 		dojo.forEach(this.objects, function(item){ zOrder += item.getZOrder(); });
 
- 		return (this.objects.length > 1) ?  zOrder / this.objects.length : 0;
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Edges", dojox.gfx3d.Object, {
 
- 	constructor: function(){
 
- 		// summary: a generic edge in 3D viewport
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultEdges);
 
- 	},
 
- 	setObject: function(newObject, /* String, optional */ style){
 
- 		// summary: setup the object
 
- 		// newObject: Array of points || Object
 
- 		// style: String, optional
 
- 		this.object = dojox.gfx.makeParameters(this.object, (newObject instanceof Array) ? { points: newObject, style: style } : newObject);
 
- 		return this;
 
- 	},
 
- 	getZOrder: function(){
 
- 		var zOrder = 0;
 
- 		dojo.forEach(this.cache, function(item){ zOrder += item.z;} );
 
- 		return (this.cache.length > 1) ?  zOrder / this.cache.length : 0;
 
- 	},
 
- 	render: function(camera){
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		this.cache = dojo.map(this.object.points, function(item){
 
- 			return dojox.gfx3d.matrix.multiplyPoint(m, item);
 
- 		});
 
- 	},
 
- 	draw: function(){
 
- 		var c = this.cache;
 
- 		if(this.shape){
 
- 			this.shape.setShape("")
 
- 		}else{
 
- 			this.shape = this.renderer.createPath();
 
- 		}
 
- 		var p = this.shape.setAbsoluteMode("absolute");
 
- 		if(this.object.style == "strip" || this.object.style == "loop"){
 
- 			p.moveTo(c[0].x, c[0].y);
 
- 			dojo.forEach(c.slice(1), function(item){
 
- 				p.lineTo(item.x, item.y);
 
- 			});
 
- 			if(this.object.style == "loop"){
 
- 				p.closePath();
 
- 			}
 
- 		}else{
 
- 			for(var i = 0; i < this.cache.length; ){
 
- 				p.moveTo(c[i].x, c[i].y);
 
- 				i ++;
 
- 				p.lineTo(c[i].x, c[i].y);
 
- 				i ++;
 
- 			}
 
- 		}
 
- 		// FIXME: doe setFill make sense here?
 
- 		p.setStroke(this.strokeStyle);
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Orbit", dojox.gfx3d.Object, {
 
- 	constructor: function(){
 
- 		// summary: a generic edge in 3D viewport
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultOrbit);
 
- 	},
 
- 	render: function(camera){
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		var angles = [0, Math.PI/4, Math.PI/3];
 
- 		var center = dojox.gfx3d.matrix.multiplyPoint(m, this.object.center);
 
- 		var marks = dojo.map(angles, function(item){
 
- 			return {x: this.center.x + this.radius * Math.cos(item),
 
- 				y: this.center.y + this.radius * Math.sin(item), z: this.center.z};
 
- 			}, this.object);
 
- 		marks = dojo.map(marks, function(item){
 
- 			return dojox.gfx3d.matrix.multiplyPoint(m, item);
 
- 		});
 
- 		var normal = dojox.gfx3d.vector.normalize(marks);
 
- 		marks = dojo.map(marks, function(item){
 
- 			return dojox.gfx3d.vector.substract(item, center);
 
- 		});
 
- 		// Use the algorithm here:
 
- 		// http://www.3dsoftware.com/Math/PlaneCurves/EllipseAlgebra/
 
- 		// After we normalize the marks, the equation is:
 
- 		// a x^2 + 2b xy + cy^2 + f = 0: let a = 1
 
- 		//  so the final equation is:
 
- 		//  [ xy, y^2, 1] * [2b, c, f]' = [ -x^2 ]'
 
- 		var A = {
 
- 			xx: marks[0].x * marks[0].y, xy: marks[0].y * marks[0].y, xz: 1,
 
- 			yx: marks[1].x * marks[1].y, yy: marks[1].y * marks[1].y, yz: 1,
 
- 			zx: marks[2].x * marks[2].y, zy: marks[2].y * marks[2].y, zz: 1,
 
- 			dx: 0, dy: 0, dz: 0
 
- 		};
 
- 		var B = dojo.map(marks, function(item){
 
- 			return -Math.pow(item.x, 2);
 
- 		});
 
- 		// X is 2b, c, f
 
- 		var X = dojox.gfx3d.matrix.multiplyPoint(dojox.gfx3d.matrix.invert(A),B[0], B[1], B[2]);
 
- 		var theta = Math.atan2(X.x, 1 - X.y) / 2;
 
- 		// rotate the marks back to the canonical form
 
- 		var probes = dojo.map(marks, function(item){
 
- 			return dojox.gfx.matrix.multiplyPoint(dojox.gfx.matrix.rotate(-theta), item.x, item.y);
 
- 		});
 
- 		// we are solving the equation: Ax = b
 
- 		// A = [x^2, y^2] X = [1/a^2, 1/b^2]', b = [1, 1]'
 
- 		// so rx = Math.sqrt(1/ ( inv(A)[1:] * b ) );
 
- 		// so ry = Math.sqrt(1/ ( inv(A)[2:] * b ) );
 
- 		var a = Math.pow(probes[0].x, 2);
 
- 		var b = Math.pow(probes[0].y, 2);
 
- 		var c = Math.pow(probes[1].x, 2);
 
- 		var d = Math.pow(probes[1].y, 2);
 
- 		// the invert matrix is
 
- 		// 1/(ad -bc) [ d, -b; -c, a];
 
- 		var rx = Math.sqrt( (a*d - b*c)/ (d-b) );
 
- 		var ry  = Math.sqrt( (a*d - b*c)/ (a-c) );
 
- 		this.cache = {cx: center.x, cy: center.y, rx: rx, ry: ry, theta: theta, normal: normal};
 
- 	},
 
- 	draw: function(lighting){
 
- 		if(this.shape){
 
- 			this.shape.setShape(this.cache);
 
- 		} else {
 
- 			this.shape = this.renderer.createEllipse(this.cache);
 
- 		}
 
- 		this.shape.applyTransform(dojox.gfx.matrix.rotateAt(this.cache.theta, this.cache.cx, this.cache.cy))
 
- 			.setStroke(this.strokeStyle)
 
- 			.setFill(this.toStdFill(lighting, this.cache.normal));
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Path3d", dojox.gfx3d.Object, {
 
- 	// This object is still very immature !
 
- 	constructor: function(){
 
- 		// summary: a generic line
 
- 		//	(this is a helper object, which is defined for convenience)
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultPath3d);
 
- 		this.segments = [];
 
- 		this.absolute = true;
 
- 		this.last = {};
 
- 		this.path = "";
 
- 	},
 
- 	_collectArgs: function(array, args){
 
- 		// summary: converts an array of arguments to plain numeric values
 
- 		// array: Array: an output argument (array of numbers)
 
- 		// args: Array: an input argument (can be values of Boolean, Number, dojox.gfx.Point, or an embedded array of them)
 
- 		for(var i = 0; i < args.length; ++i){
 
- 			var t = args[i];
 
- 			if(typeof(t) == "boolean"){
 
- 				array.push(t ? 1 : 0);
 
- 			}else if(typeof(t) == "number"){
 
- 				array.push(t);
 
- 			}else if(t instanceof Array){
 
- 				this._collectArgs(array, t);
 
- 			}else if("x" in t && "y" in t){
 
- 				array.push(t.x);
 
- 				array.push(t.y);
 
- 			}
 
- 		}
 
- 	},
 
- 	// a dictionary, which maps segment type codes to a number of their argemnts
 
- 	_validSegments: {m: 3, l: 3,  z: 0},
 
- 	_pushSegment: function(action, args){
 
- 		// summary: adds a segment
 
- 		// action: String: valid SVG code for a segment's type
 
- 		// args: Array: a list of parameters for this segment
 
- 		var group = this._validSegments[action.toLowerCase()], segment;
 
- 		if(typeof(group) == "number"){
 
- 			if(group){
 
- 				if(args.length >= group){
 
- 					segment = {action: action, args: args.slice(0, args.length - args.length % group)};
 
- 					this.segments.push(segment);
 
- 				}
 
- 			}else{
 
- 				segment = {action: action, args: []};
 
- 				this.segments.push(segment);
 
- 			}
 
- 		}
 
- 	},
 
- 	moveTo: function(){
 
- 		// summary: formes a move segment
 
- 		var args = [];
 
- 		this._collectArgs(args, arguments);
 
- 		this._pushSegment(this.absolute ? "M" : "m", args);
 
- 		return this; // self
 
- 	},
 
- 	lineTo: function(){
 
- 		// summary: formes a line segment
 
- 		var args = [];
 
- 		this._collectArgs(args, arguments);
 
- 		this._pushSegment(this.absolute ? "L" : "l", args);
 
- 		return this; // self
 
- 	},
 
- 	closePath: function(){
 
- 		// summary: closes a path
 
- 		this._pushSegment("Z", []);
 
- 		return this; // self
 
- 	},
 
- 	render: function(camera){
 
- 		// TODO: we need to get the ancestors' matrix
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		// iterate all the segments and convert them to 2D canvas
 
- 		// TODO consider the relative mode
 
- 		var path = ""
 
- 		var _validSegments = this._validSegments;
 
- 		dojo.forEach(this.segments, function(item){
 
- 			path += item.action;
 
- 			for(var i = 0; i < item.args.length; i+= _validSegments[item.action.toLowerCase()] ){
 
- 				var pt = dojox.gfx3d.matrix.multiplyPoint(m, item.args[i], item.args[i+1], item.args[i+2])
 
- 				path += " " + pt.x + " " + pt.y;
 
- 			}
 
- 		});
 
- 		this.cache =  path;
 
- 	},
 
- 	_draw: function(){
 
- 		return this.parent.createPath(this.cache);
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Triangles", dojox.gfx3d.Object, {
 
- 	constructor: function(){
 
- 		// summary: a generic triangle
 
- 		//	(this is a helper object, which is defined for convenience)
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultTriangles);
 
- 	},
 
- 	setObject: function(newObject, /* String, optional */ style){
 
- 		// summary: setup the object
 
- 		// newObject: Array of points || Object
 
- 		// style: String, optional
 
- 		if(newObject instanceof Array){
 
- 			this.object = dojox.gfx.makeParameters(this.object, { points: newObject, style: style } );
 
- 		} else {
 
- 			this.object = dojox.gfx.makeParameters(this.object, newObject);
 
- 		}
 
- 		return this;
 
- 	},
 
- 	render: function(camera){
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		var c = dojo.map(this.object.points, function(item){
 
- 			return dojox.gfx3d.matrix.multiplyPoint(m, item);
 
- 		});
 
- 		this.cache = [];
 
- 		var pool = c.slice(0, 2);
 
- 		var center = c[0];
 
- 		if(this.object.style == "strip"){
 
- 			dojo.forEach(c.slice(2), function(item){
 
- 				pool.push(item);
 
- 				pool.push(pool[0]);
 
- 				this.cache.push(pool);
 
- 				pool = pool.slice(1, 3);
 
- 			}, this);
 
- 		} else if(this.object.style == "fan"){
 
- 			dojo.forEach(c.slice(2), function(item){
 
- 				pool.push(item);
 
- 				pool.push(center);
 
- 				this.cache.push(pool);
 
- 				pool = [center, item];
 
- 			}, this);
 
- 		} else {
 
- 			for(var i = 0; i < c.length; ){
 
- 				this.cache.push( [ c[i], c[i+1], c[i+2], c[i] ]);
 
- 				i += 3;
 
- 			}
 
- 		}
 
- 	},
 
- 	draw: function(lighting){
 
- 		// use the BSP to schedule
 
- 		this.cache = dojox.gfx3d.scheduler.bsp(this.cache, function(it){  return it; });
 
- 		if(this.shape){
 
- 			this.shape.clear();
 
- 		} else {
 
- 			this.shape = this.renderer.createGroup();
 
- 		}
 
- 		dojo.forEach(this.cache, function(item){
 
- 			this.shape.createPolyline(item)
 
- 				.setStroke(this.strokeStyle)
 
- 				.setFill(this.toStdFill(lighting, dojox.gfx3d.vector.normalize(item)));
 
- 		}, this);
 
- 	},
 
- 	getZOrder: function(){
 
- 		var zOrder = 0;
 
- 		dojo.forEach(this.cache, function(item){
 
- 				zOrder += (item[0].z + item[1].z + item[2].z) / 3; });
 
- 		return (this.cache.length > 1) ?  zOrder / this.cache.length : 0;
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Quads", dojox.gfx3d.Object, {
 
- 	constructor: function(){
 
- 		// summary: a generic triangle
 
- 		//	(this is a helper object, which is defined for convenience)
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultQuads);
 
- 	},
 
- 	setObject: function(newObject, /* String, optional */ style){
 
- 		// summary: setup the object
 
- 		// newObject: Array of points || Object
 
- 		// style: String, optional
 
- 		this.object = dojox.gfx.makeParameters(this.object, (newObject instanceof Array) ? { points: newObject, style: style } : newObject );
 
- 		return this;
 
- 	},
 
- 	render: function(camera){
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix), i;
 
- 		var c = dojo.map(this.object.points, function(item){
 
- 			return dojox.gfx3d.matrix.multiplyPoint(m, item);
 
- 		});
 
- 		this.cache = [];
 
- 		if(this.object.style == "strip"){
 
- 			var pool = c.slice(0, 2);
 
- 			for(i = 2; i < c.length; ){
 
- 				pool = pool.concat( [ c[i], c[i+1], pool[0] ] );
 
- 				this.cache.push(pool);
 
- 				pool = pool.slice(2,4);
 
- 				i += 2;
 
- 			}
 
- 		}else{
 
- 			for(i = 0; i < c.length; ){
 
- 				this.cache.push( [c[i], c[i+1], c[i+2], c[i+3], c[i] ] );
 
- 				i += 4;
 
- 			}
 
- 		}
 
- 	},
 
- 	draw: function(lighting){
 
- 		// use the BSP to schedule
 
- 		this.cache = dojox.gfx3d.scheduler.bsp(this.cache, function(it){  return it; });
 
- 		if(this.shape){
 
- 			this.shape.clear();
 
- 		}else{
 
- 			this.shape = this.renderer.createGroup();
 
- 		}
 
- 		// using naive iteration to speed things up a bit by avoiding function call overhead
 
- 		for(var x=0; x<this.cache.length; x++){
 
- 			this.shape.createPolyline(this.cache[x])
 
- 				.setStroke(this.strokeStyle)
 
- 				.setFill(this.toStdFill(lighting, dojox.gfx3d.vector.normalize(this.cache[x])));
 
- 		}
 
- 		/*
 
- 		dojo.forEach(this.cache, function(item){
 
- 			this.shape.createPolyline(item)
 
- 				.setStroke(this.strokeStyle)
 
- 				.setFill(this.toStdFill(lighting, dojox.gfx3d.vector.normalize(item)));
 
- 		}, this);
 
- 		*/
 
- 	},
 
- 	getZOrder: function(){
 
- 		var zOrder = 0;
 
- 		// using naive iteration to speed things up a bit by avoiding function call overhead
 
- 		for(var x=0; x<this.cache.length; x++){
 
- 			var i = this.cache[x];
 
- 			zOrder += (i[0].z + i[1].z + i[2].z + i[3].z) / 4;
 
- 		}
 
- 		/*
 
- 		dojo.forEach(this.cache, function(item){
 
- 				zOrder += (item[0].z + item[1].z + item[2].z + item[3].z) / 4; });
 
- 		*/
 
- 		return (this.cache.length > 1) ?  zOrder / this.cache.length : 0;
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Polygon", dojox.gfx3d.Object, {
 
- 	constructor: function(){
 
- 		// summary: a generic triangle
 
- 		//	(this is a helper object, which is defined for convenience)
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultPolygon);
 
- 	},
 
- 	setObject: function(newObject){
 
- 		// summary: setup the object
 
- 		// newObject: Array of points || Object
 
- 		this.object = dojox.gfx.makeParameters(this.object, (newObject instanceof Array) ? {path: newObject} : newObject)
 
- 		return this;
 
- 	},
 
- 	render: function(camera){
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		this.cache = dojo.map(this.object.path, function(item){
 
- 			return dojox.gfx3d.matrix.multiplyPoint(m, item);
 
- 		});
 
- 		// add the first point to close the polyline
 
- 		this.cache.push(this.cache[0]);
 
- 	},
 
- 	draw: function(lighting){
 
- 		if(this.shape){
 
- 			this.shape.setShape({points: this.cache});
 
- 		}else{
 
- 			this.shape = this.renderer.createPolyline({points: this.cache});
 
- 		}
 
- 		this.shape.setStroke(this.strokeStyle)
 
- 			.setFill(this.toStdFill(lighting, dojox.gfx3d.matrix.normalize(this.cache)));
 
- 	},
 
- 	getZOrder: function(){
 
- 		var zOrder = 0;
 
- 		// using naive iteration to speed things up a bit by avoiding function call overhead
 
- 		for(var x=0; x<this.cache.length; x++){
 
- 			zOrder += this.cache[x].z;
 
- 		}
 
- 		return (this.cache.length > 1) ?  zOrder / this.cache.length : 0;
 
- 	},
 
- 	getOutline: function(){
 
- 		return this.cache.slice(0, 3);
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Cube", dojox.gfx3d.Object, {
 
- 	constructor: function(){
 
- 		// summary: a generic triangle
 
- 		//	(this is a helper object, which is defined for convenience)
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultCube);
 
- 		this.polygons = [];
 
- 	},
 
- 	setObject: function(newObject){
 
- 		// summary: setup the object
 
- 		// newObject: Array of points || Object
 
- 		this.object = dojox.gfx.makeParameters(this.object, newObject);
 
- 	},
 
- 	render: function(camera){
 
- 		// parse the top, bottom to get 6 polygons:
 
- 		var a = this.object.top;
 
- 		var g = this.object.bottom;
 
- 		var b = {x: g.x, y: a.y, z: a.z};
 
- 		var c = {x: g.x, y: g.y, z: a.z};
 
- 		var d = {x: a.x, y: g.y, z: a.z};
 
- 		var e = {x: a.x, y: a.y, z: g.z};
 
- 		var f = {x: g.x, y: a.y, z: g.z};
 
- 		var h = {x: a.x, y: g.y, z: g.z};
 
- 		var polygons = [a, b, c, d, e, f, g, h];
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		var p = dojo.map(polygons, function(item){
 
- 			return dojox.gfx3d.matrix.multiplyPoint(m, item);
 
- 		});
 
- 		a = p[0]; b = p[1]; c = p[2]; d = p[3]; e = p[4]; f = p[5]; g = p[6]; h = p[7];
 
- 		this.cache = [[a, b, c, d, a], [e, f, g, h, e], [a, d, h, e, a], [d, c, g, h, d], [c, b, f, g, c], [b, a, e, f, b]];
 
- 	},
 
- 	draw: function(lighting){
 
- 		// use bsp to sort.
 
- 		this.cache = dojox.gfx3d.scheduler.bsp(this.cache, function(it){ return it; });
 
- 		// only the last 3 polys are visible.
 
- 		var cache = this.cache.slice(3);
 
- 		if(this.shape){
 
- 			this.shape.clear();
 
- 		}else{
 
- 			this.shape = this.renderer.createGroup();
 
- 		}
 
- 		for(var x=0; x<cache.length; x++){
 
- 			this.shape.createPolyline(cache[x])
 
- 				.setStroke(this.strokeStyle)
 
- 				.setFill(this.toStdFill(lighting, dojox.gfx3d.vector.normalize(cache[x])));
 
- 		}
 
- 		/*
 
- 		dojo.forEach(cache, function(item){
 
- 			this.shape.createPolyline(item)
 
- 				.setStroke(this.strokeStyle)
 
- 				.setFill(this.toStdFill(lighting, dojox.gfx3d.vector.normalize(item)));
 
- 		}, this);
 
- 		*/
 
- 	},
 
- 	getZOrder: function(){
 
- 		var top = this.cache[0][0];
 
- 		var bottom = this.cache[1][2];
 
- 		return (top.z + bottom.z) / 2;
 
- 	}
 
- });
 
- dojo.declare("dojox.gfx3d.Cylinder", dojox.gfx3d.Object, {
 
- 	constructor: function(){
 
- 		this.object = dojo.clone(dojox.gfx3d.defaultCylinder);
 
- 	},
 
- 	render: function(camera){
 
- 		// get the bottom surface first
 
- 		var m = dojox.gfx3d.matrix.multiply(camera, this.matrix);
 
- 		var angles = [0, Math.PI/4, Math.PI/3];
 
- 		var center = dojox.gfx3d.matrix.multiplyPoint(m, this.object.center);
 
- 		var marks = dojo.map(angles, function(item){
 
- 			return {x: this.center.x + this.radius * Math.cos(item),
 
- 				y: this.center.y + this.radius * Math.sin(item), z: this.center.z};
 
- 			}, this.object);
 
- 		marks = dojo.map(marks, function(item){
 
- 			return dojox.gfx3d.vector.substract(dojox.gfx3d.matrix.multiplyPoint(m, item), center);
 
- 		});
 
- 		// Use the algorithm here:
 
- 		// http://www.3dsoftware.com/Math/PlaneCurves/EllipseAlgebra/
 
- 		// After we normalize the marks, the equation is:
 
- 		// a x^2 + 2b xy + cy^2 + f = 0: let a = 1
 
- 		//  so the final equation is:
 
- 		//  [ xy, y^2, 1] * [2b, c, f]' = [ -x^2 ]'
 
- 		var A = {
 
- 			xx: marks[0].x * marks[0].y, xy: marks[0].y * marks[0].y, xz: 1,
 
- 			yx: marks[1].x * marks[1].y, yy: marks[1].y * marks[1].y, yz: 1,
 
- 			zx: marks[2].x * marks[2].y, zy: marks[2].y * marks[2].y, zz: 1,
 
- 			dx: 0, dy: 0, dz: 0
 
- 		};
 
- 		var B = dojo.map(marks, function(item){
 
- 			return -Math.pow(item.x, 2);
 
- 		});
 
- 		// X is 2b, c, f
 
- 		var X = dojox.gfx3d.matrix.multiplyPoint(dojox.gfx3d.matrix.invert(A), B[0], B[1], B[2]);
 
- 		var theta = Math.atan2(X.x, 1 - X.y) / 2;
 
- 		// rotate the marks back to the canonical form
 
- 		var probes = dojo.map(marks, function(item){
 
- 			return dojox.gfx.matrix.multiplyPoint(dojox.gfx.matrix.rotate(-theta), item.x, item.y);
 
- 		});
 
- 		// we are solving the equation: Ax = b
 
- 		// A = [x^2, y^2] X = [1/a^2, 1/b^2]', b = [1, 1]'
 
- 		// so rx = Math.sqrt(1/ ( inv(A)[1:] * b ) );
 
- 		// so ry = Math.sqrt(1/ ( inv(A)[2:] * b ) );
 
- 		var a = Math.pow(probes[0].x, 2);
 
- 		var b = Math.pow(probes[0].y, 2);
 
- 		var c = Math.pow(probes[1].x, 2);
 
- 		var d = Math.pow(probes[1].y, 2);
 
- 		// the invert matrix is
 
- 		// 1/(ad - bc) [ d, -b; -c, a];
 
- 		var rx = Math.sqrt((a * d - b * c) / (d - b));
 
- 		var ry = Math.sqrt((a * d - b * c) / (a - c));
 
- 		if(rx < ry){
 
- 			var t = rx;
 
- 			rx = ry;
 
- 			ry = t;
 
- 			theta -= Math.PI/2;
 
- 		}
 
- 		var top = dojox.gfx3d.matrix.multiplyPoint(m,
 
- 			dojox.gfx3d.vector.sum(this.object.center, {x: 0, y:0, z: this.object.height}));
 
- 		var gradient = this.fillStyle.type == "constant" ? this.fillStyle.color
 
- 			: dojox.gfx3d.gradient(this.renderer.lighting, this.fillStyle, this.object.center, this.object.radius, Math.PI, 2 * Math.PI, m);
 
- 		if(isNaN(rx) || isNaN(ry) || isNaN(theta)){
 
- 			// in case the cap is invisible (parallel to the incident vector)
 
- 			rx = this.object.radius, ry = 0, theta = 0;
 
- 		}
 
- 		this.cache = {center: center, top: top, rx: rx, ry: ry, theta: theta, gradient: gradient};
 
- 	},
 
- 	draw: function(){
 
- 		var c = this.cache, v = dojox.gfx3d.vector, m = dojox.gfx.matrix,
 
- 			centers = [c.center, c.top], normal = v.substract(c.top, c.center);
 
- 		if(v.dotProduct(normal, this.renderer.lighting.incident) > 0){
 
- 			centers = [c.top, c.center];
 
- 			normal = v.substract(c.center, c.top);
 
- 		}
 
- 		var color = this.renderer.lighting[this.fillStyle.type](normal, this.fillStyle.finish, this.fillStyle.color),
 
- 			d = Math.sqrt( Math.pow(c.center.x - c.top.x, 2) + Math.pow(c.center.y - c.top.y, 2) );
 
- 		if(this.shape){
 
- 			this.shape.clear();
 
- 		}else{
 
- 			this.shape = this.renderer.createGroup();
 
- 		}
 
- 		
 
- 		this.shape.createPath("")
 
- 			.moveTo(0, -c.rx)
 
- 			.lineTo(d, -c.rx)
 
- 			.lineTo(d, c.rx)
 
- 			.lineTo(0, c.rx)
 
- 			.arcTo(c.ry, c.rx, 0, true, true, 0, -c.rx)
 
- 			.setFill(c.gradient).setStroke(this.strokeStyle)
 
- 			.setTransform([m.translate(centers[0]),
 
- 				m.rotate(Math.atan2(centers[1].y - centers[0].y, centers[1].x - centers[0].x))]);
 
- 		if(c.rx > 0 && c.ry > 0){
 
- 			this.shape.createEllipse({cx: centers[1].x, cy: centers[1].y, rx: c.rx, ry: c.ry})
 
- 				.setFill(color).setStroke(this.strokeStyle)
 
- 				.applyTransform(m.rotateAt(c.theta, centers[1]));
 
- 		}
 
- 	}
 
- });
 
- // the ultimate container of 3D world
 
- dojo.declare("dojox.gfx3d.Viewport", dojox.gfx.Group, {
 
- 	constructor: function(){
 
- 		// summary: a viewport/container for 3D objects, which knows
 
- 		// the camera and lightings
 
- 		// matrix: dojox.gfx3d.matrix: world transform
 
- 		// dimension: Object: the dimension of the canvas
 
- 		this.dimension = null;
 
- 		// objects: Array: all 3d Objects
 
- 		this.objects = [];
 
- 		// todos: Array: all 3d Objects that needs to redraw
 
- 		this.todos = [];
 
- 		// FIXME: memory leak?
 
- 		this.renderer = this;
 
- 		// Using zOrder as the default scheduler
 
- 		this.schedule = dojox.gfx3d.scheduler.zOrder;
 
- 		this.draw = dojox.gfx3d.drawer.conservative;
 
- 		// deep: boolean, true means the whole viewport needs to re-render, redraw
 
- 		this.deep = false;
 
- 		// lights: Array: an array of light objects
 
- 		this.lights = [];
 
- 		this.lighting = null;
 
- 	},
 
- 	setCameraTransform: function(matrix){
 
- 		// summary: sets a transformation matrix
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		this.camera = dojox.gfx3d.matrix.clone(matrix ? dojox.gfx3d.matrix.normalize(matrix) : dojox.gfx3d.identity, true);
 
- 		this.invalidate();
 
- 		return this;	// self
 
- 	},
 
- 	applyCameraRightTransform: function(matrix){
 
- 		// summary: multiplies the existing matrix with an argument on right side
 
- 		//	(this.matrix * matrix)
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx3d.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		return matrix ? this.setCameraTransform([this.camera, matrix]) : this;	// self
 
- 	},
 
- 	applyCameraLeftTransform: function(matrix){
 
- 		// summary: multiplies the existing matrix with an argument on left side
 
- 		//	(matrix * this.matrix)
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx3d.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		return matrix ? this.setCameraTransform([matrix, this.camera]) : this;	// self
 
- 	},
 
- 	applyCameraTransform: function(matrix){
 
- 		// summary: a shortcut for dojox.gfx3d.Object.applyRightTransform
 
- 		// matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object
 
- 		//	(see an argument of dojox.gfx3d.matrix.Matrix
 
- 		//	constructor for a list of acceptable arguments)
 
- 		return this.applyCameraRightTransform(matrix); // self
 
- 	},
 
- 	setLights: function(/* Array || Object */lights, /* Color, optional */ ambient,
 
- 		/* Color, optional */ specular){
 
- 		// summary: set the lights
 
- 		// lights: Array: an array of light object
 
- 		// or lights object
 
- 		// ambient: Color: an ambient object
 
- 		// specular: Color: an specular object
 
- 		this.lights = (lights instanceof Array) ? {sources: lights, ambient: ambient, specular: specular} : lights;
 
- 		var view = {x: 0, y: 0, z: 1};
 
- 		this.lighting = new dojox.gfx3d.lighting.Model(view, this.lights.sources,
 
- 				this.lights.ambient, this.lights.specular);
 
- 		this.invalidate();
 
- 		return this;
 
- 	},
 
- 	addLights: function(lights){
 
- 		// summary: add new light/lights to the viewport.
 
- 		// lights: Array || light object: light object(s)
 
- 		return this.setLights(this.lights.sources.concat(lights));
 
- 	},
 
- 	addTodo: function(newObject){
 
- 		// NOTE: Viewport implements almost the same addTodo,
 
- 		// except calling invalidate, since invalidate is used as
 
- 		// any modification needs to redraw the object itself, call invalidate.
 
- 		// then call render.
 
- 		if(dojo.every(this.todos,
 
- 			function(item){
 
- 				return item != newObject;
 
- 			}
 
- 		)){
 
- 			this.todos.push(newObject);
 
- 		}
 
- 	},
 
- 	invalidate: function(){
 
- 		this.deep = true;
 
- 		this.todos = this.objects;
 
- 	},
 
- 	setDimensions: function(dim){
 
- 		if(dim){
 
- 			var w = dojo.isString(dim.width) ? parseInt(dim.width)  : dim.width;
 
- 			var h = dojo.isString(dim.height) ? parseInt(dim.height) : dim.height;
 
- 			// there is no rawNode in canvas GFX implementation
 
- 			if(this.rawNode){
 
- 				var trs = this.rawNode.style;
 
- 				trs.height = h;
 
- 				trs.width = w;
 
- 			}
 
- 			this.dimension = {
 
- 				width:  w,
 
- 				height: h
 
- 			};
 
- 		}else{
 
- 			this.dimension = null;
 
- 		}
 
- 	},
 
- 	render: function(){
 
- 		// summary: iterate all children and call their render callback function.
 
- 		if(!this.todos.length){ return; }
 
- 		// console.debug("Viewport::render");
 
- 		var m = dojox.gfx3d.matrix;
 
- 		
 
- 		// Iterate the todos and call render to prepare the rendering:
 
- 		for(var x=0; x<this.todos.length; x++){
 
- 			this.todos[x].render(dojox.gfx3d.matrix.normalize([
 
- 				m.cameraRotateXg(180),
 
- 				m.cameraTranslate(0, this.dimension.height, 0),
 
- 				this.camera
 
- 			]), this.deep);
 
- 		}
 
- 		this.objects = this.schedule(this.objects);
 
- 		this.draw(this.todos, this.objects, this);
 
- 		this.todos = [];
 
- 		this.deep = false;
 
- 	}
 
- });
 
- //FIXME: Viewport cannot masquerade as a Group
 
- dojox.gfx3d.Viewport.nodeType = dojox.gfx.Group.nodeType;
 
- dojox.gfx3d._creators = {
 
- 	// summary: object creators
 
- 	createEdges: function(edges, style){
 
- 		// summary: creates an edge object
 
- 		// line: Object: a edge object (see dojox.gfx3d.defaultPath)
 
- 		return this.create3DObject(dojox.gfx3d.Edges, edges, style);	// dojox.gfx3d.Edge
 
- 	},
 
- 	createTriangles: function(tris, style){
 
- 		// summary: creates an edge object
 
- 		// line: Object: a edge object (see dojox.gfx3d.defaultPath)
 
- 		return this.create3DObject(dojox.gfx3d.Triangles, tris, style);	// dojox.gfx3d.Edge
 
- 	},
 
- 	createQuads: function(quads, style){
 
- 		// summary: creates an edge object
 
- 		// line: Object: a edge object (see dojox.gfx3d.defaultPath)
 
- 		return this.create3DObject(dojox.gfx3d.Quads, quads, style);	// dojox.gfx3d.Edge
 
- 	},
 
- 	createPolygon: function(points){
 
- 		// summary: creates an triangle object
 
- 		// points: Array of points || Object
 
- 		return this.create3DObject(dojox.gfx3d.Polygon, points);	// dojox.gfx3d.Polygon
 
- 	},
 
- 	createOrbit: function(orbit){
 
- 		// summary: creates an triangle object
 
- 		// points: Array of points || Object
 
- 		return this.create3DObject(dojox.gfx3d.Orbit, orbit);	// dojox.gfx3d.Cube
 
- 	},
 
- 	createCube: function(cube){
 
- 		// summary: creates an triangle object
 
- 		// points: Array of points || Object
 
- 		return this.create3DObject(dojox.gfx3d.Cube, cube);	// dojox.gfx3d.Cube
 
- 	},
 
- 	createCylinder: function(cylinder){
 
- 		// summary: creates an triangle object
 
- 		// points: Array of points || Object
 
- 		return this.create3DObject(dojox.gfx3d.Cylinder, cylinder);	// dojox.gfx3d.Cube
 
- 	},
 
- 	createPath3d: function(path){
 
- 		// summary: creates an edge object
 
- 		// line: Object: a edge object (see dojox.gfx3d.defaultPath)
 
- 		return this.create3DObject(dojox.gfx3d.Path3d, path);	// dojox.gfx3d.Edge
 
- 	},
 
- 	createScene: function(){
 
- 		// summary: creates an triangle object
 
- 		// line: Object: a triangle object (see dojox.gfx3d.defaultPath)
 
- 		return this.create3DObject(dojox.gfx3d.Scene);	// dojox.gfx3d.Scene
 
- 	},
 
- 	create3DObject: function(objectType, rawObject, style){
 
- 		// summary: creates an instance of the passed shapeType class
 
- 		// shapeType: Function: a class constructor to create an instance of
 
- 		// rawShape: Object: properties to be passed in to the classes "setShape" method
 
- 		var obj = new objectType();
 
- 		this.adopt(obj);
 
- 		if(rawObject){ obj.setObject(rawObject, style); }
 
- 		return obj;	// dojox.gfx3d.Object
 
- 	},
 
- 	// todo : override the add/remove if necessary
 
- 	adopt: function(obj){
 
- 		// summary: adds a shape to the list
 
- 		// shape: dojox.gfx.Shape: a shape
 
- 		obj.renderer = this.renderer; // obj._setParent(this, null); more TODOs HERER?
 
- 		obj.parent = this;
 
- 		this.objects.push(obj);
 
- 		this.addTodo(obj);
 
- 		return this;
 
- 	},
 
- 	abandon: function(obj, silently){
 
- 		// summary: removes a shape from the list
 
- 		// silently: Boolean?: if true, do not redraw a picture yet
 
- 		for(var i = 0; i < this.objects.length; ++i){
 
- 			if(this.objects[i] == obj){
 
- 				this.objects.splice(i, 1);
 
- 			}
 
- 		}
 
- 		// if(this.rawNode == shape.rawNode.parentNode){
 
- 		//	this.rawNode.removeChild(shape.rawNode);
 
- 		// }
 
- 		// obj._setParent(null, null);
 
- 		obj.parent = null;
 
- 		return this;	// self
 
- 	},
 
- 	setScheduler: function(scheduler){
 
- 		this.schedule = scheduler;
 
- 	},
 
- 	setDrawer: function(drawer){
 
- 		this.draw = drawer;
 
- 	}
 
- };
 
- dojo.extend(dojox.gfx3d.Viewport, dojox.gfx3d._creators);
 
- dojo.extend(dojox.gfx3d.Scene, dojox.gfx3d._creators);
 
- delete dojox.gfx3d._creators;
 
- //FIXME: extending dojox.gfx.Surface and masquerading Viewport as Group is hacky!
 
- // Add createViewport to dojox.gfx.Surface
 
- dojo.extend(dojox.gfx.Surface, {
 
- 	createViewport: function(){
 
- 		//FIXME: createObject is non-public method!
 
- 		var viewport = this.createObject(dojox.gfx3d.Viewport, null, true);
 
- 		//FIXME: this may not work with dojox.gfx.Group !!
 
- 		viewport.setDimensions(this.getDimensions());
 
- 		return viewport;
 
- 	}
 
- });
 
- }
 
 
  |