summaryrefslogtreecommitdiffstatshomepage
path: root/includes/js/dojox/gfx3d
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dojox/gfx3d')
-rw-r--r--includes/js/dojox/gfx3d/README36
-rw-r--r--includes/js/dojox/gfx3d/_base.js19
-rw-r--r--includes/js/dojox/gfx3d/gradient.js41
-rw-r--r--includes/js/dojox/gfx3d/lighting.js241
-rw-r--r--includes/js/dojox/gfx3d/matrix.js339
-rw-r--r--includes/js/dojox/gfx3d/object.js1092
-rw-r--r--includes/js/dojox/gfx3d/scheduler.js126
-rw-r--r--includes/js/dojox/gfx3d/tests/test_camerarotate.html93
-rw-r--r--includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html97
-rw-r--r--includes/js/dojox/gfx3d/tests/test_cube.html50
-rw-r--r--includes/js/dojox/gfx3d/tests/test_cylinder.html66
-rw-r--r--includes/js/dojox/gfx3d/tests/test_drawer.html92
-rw-r--r--includes/js/dojox/gfx3d/tests/test_edges.html73
-rw-r--r--includes/js/dojox/gfx3d/tests/test_matrix.html89
-rw-r--r--includes/js/dojox/gfx3d/tests/test_orbit.html50
-rw-r--r--includes/js/dojox/gfx3d/tests/test_overlap.html69
-rw-r--r--includes/js/dojox/gfx3d/tests/test_polygon.html44
-rw-r--r--includes/js/dojox/gfx3d/tests/test_quads.html78
-rw-r--r--includes/js/dojox/gfx3d/tests/test_rotate.html123
-rw-r--r--includes/js/dojox/gfx3d/tests/test_scene.html66
-rw-r--r--includes/js/dojox/gfx3d/tests/test_triangles.html82
-rw-r--r--includes/js/dojox/gfx3d/tests/test_vector.html59
-rw-r--r--includes/js/dojox/gfx3d/vector.js110
23 files changed, 3135 insertions, 0 deletions
diff --git a/includes/js/dojox/gfx3d/README b/includes/js/dojox/gfx3d/README
new file mode 100644
index 0000000..bc7ed4e
--- /dev/null
+++ b/includes/js/dojox/gfx3d/README
@@ -0,0 +1,36 @@
+-------------------------------------------------------------------------------
+dojox.gfx3d
+-------------------------------------------------------------------------------
+Version 0.100
+Release date: 10/31/2007
+-------------------------------------------------------------------------------
+Project state:
+beta
+-------------------------------------------------------------------------------
+Credits
+ Kun Xi (bookstack@gmail.com)
+ Eugene Lazutkin (eugene.lazutkin@gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+Implementation of simple portable 3D graphics library.
+-------------------------------------------------------------------------------
+Dependencies:
+
+Dojo Core, dojox.gfx.
+-------------------------------------------------------------------------------
+Documentation
+
+Not ready yet.
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/gfx3d.js
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/gfx3d/*
+
+Install into the following directory structure:
+/dojox/gfx3d/
+
+...which should be at the same level as your Dojo checkout.
+-------------------------------------------------------------------------------
diff --git a/includes/js/dojox/gfx3d/_base.js b/includes/js/dojox/gfx3d/_base.js
new file mode 100644
index 0000000..dbc7748
--- /dev/null
+++ b/includes/js/dojox/gfx3d/_base.js
@@ -0,0 +1,19 @@
+if(!dojo._hasResource["dojox.gfx3d._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.gfx3d._base"] = true;
+dojo.provide("dojox.gfx3d._base");
+
+dojo.mixin(dojox.gfx3d, {
+ // summary: defines constants, prototypes, and utility functions
+
+ // default objects, which are used to fill in missing parameters
+ defaultEdges: {type: "edges", style: null, points: []},
+ defaultTriangles: {type: "triangles", style: null, points: []},
+ defaultQuads: {type: "quads", style: null, points: []},
+ defaultOrbit: {type: "orbit", center: {x: 0, y: 0, z: 0}, radius: 50},
+ defaultPath3d: {type: "path3d", path: []},
+ defaultPolygon: {type: "polygon", path: []},
+ defaultCube: {type: "cube", bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}},
+ defaultCylinder: {type: "cylinder", center: /* center of bottom */ {x: 0, y: 0, z: 0}, height: 100, radius: 50}
+});
+
+}
diff --git a/includes/js/dojox/gfx3d/gradient.js b/includes/js/dojox/gfx3d/gradient.js
new file mode 100644
index 0000000..fa93720
--- /dev/null
+++ b/includes/js/dojox/gfx3d/gradient.js
@@ -0,0 +1,41 @@
+if(!dojo._hasResource["dojox.gfx3d.gradient"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.gfx3d.gradient"] = true;
+dojo.provide("dojox.gfx3d.gradient");
+
+dojo.require("dojox.gfx3d.vector");
+dojo.require("dojox.gfx3d.matrix");
+
+(function(){
+ var dist = function(a, b){ return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)); };
+ var N = 32;
+
+ dojox.gfx3d.gradient = function(model, material, center, radius, from, to, matrix){
+ // summary: calculate a cylindrical gradient
+ // model: dojox.gfx3d.lighting.Model: color model
+ // material: Object: defines visual properties
+ // center: Object: center of the cylinder's bottom
+ // radius: Number: radius of the cylinder
+ // from: Number: from position in radians
+ // to: Number: from position in radians
+ // matrix: dojox.gfx3d.Matrix3D: the cumulative transformation matrix
+ // tolerance: Number: tolerable diffirence in colors between gradient steps
+
+ var m = dojox.gfx3d.matrix, v = dojox.gfx3d.vector, mx = m.normalize(matrix),
+ f = m.multiplyPoint(mx, radius * Math.cos(from) + center.x, radius * Math.sin(from) + center.y, center.z),
+ t = m.multiplyPoint(mx, radius * Math.cos(to) + center.x, radius * Math.sin(to) + center.y, center.z),
+ c = m.multiplyPoint(mx, center.x, center.y, center.z), step = (to - from) / N, r = dist(f, t) / 2,
+ mod = model[material.type], fin = material.finish, pmt = material.color,
+ colors = [{offset: 0, color: mod.call(model, v.substract(f, c), fin, pmt)}];
+
+ for(var a = from + step; a < to; a += step){
+ var p = m.multiplyPoint(mx, radius * Math.cos(a) + center.x, radius * Math.sin(a) + center.y, center.z),
+ df = dist(f, p), dt = dist(t, p);
+ colors.push({offset: df / (df + dt), color: mod.call(model, v.substract(p, c), fin, pmt)});
+ }
+ colors.push({offset: 1, color: mod.call(model, v.substract(t, c), fin, pmt)});
+
+ return {type: "linear", x1: 0, y1: -r, x2: 0, y2: r, colors: colors};
+ };
+})();
+
+}
diff --git a/includes/js/dojox/gfx3d/lighting.js b/includes/js/dojox/gfx3d/lighting.js
new file mode 100644
index 0000000..bbd40de
--- /dev/null
+++ b/includes/js/dojox/gfx3d/lighting.js
@@ -0,0 +1,241 @@
+if(!dojo._hasResource["dojox.gfx3d.lighting"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.gfx3d.lighting"] = true;
+dojo.provide("dojox.gfx3d.lighting");
+dojo.require("dojox.gfx._base");
+
+(function(){
+ var lite = dojox.gfx3d.lighting;
+
+ dojo.mixin(dojox.gfx3d.lighting, {
+ // color utilities
+ black: function(){
+ return {r: 0, g: 0, b: 0, a: 1};
+ },
+ white: function(){
+ return {r: 1, g: 1, b: 1, a: 1};
+ },
+ toStdColor: function(c){
+ c = dojox.gfx.normalizeColor(c);
+ return {r: c.r / 255, g: c.g / 255, b: c.b / 255, a: c.a};
+ },
+ fromStdColor: function(c){
+ return new dojo.Color([Math.round(255 * c.r), Math.round(255 * c.g), Math.round(255 * c.b), c.a]);
+ },
+ scaleColor: function(s, c){
+ return {r: s * c.r, g: s * c.g, b: s * c.b, a: s * c.a};
+ },
+ addColor: function(a, b){
+ return {r: a.r + b.r, g: a.g + b.g, b: a.b + b.b, a: a.a + b.a};
+ },
+ multiplyColor: function(a, b){
+ return {r: a.r * b.r, g: a.g * b.g, b: a.b * b.b, a: a.a * b.a};
+ },
+ saturateColor: function(c){
+ return {
+ r: c.r < 0 ? 0 : c.r > 1 ? 1 : c.r,
+ g: c.g < 0 ? 0 : c.g > 1 ? 1 : c.g,
+ b: c.b < 0 ? 0 : c.b > 1 ? 1 : c.b,
+ a: c.a < 0 ? 0 : c.a > 1 ? 1 : c.a
+ };
+ },
+ mixColor: function(c1, c2, s){
+ return lite.addColor(lite.scaleColor(s, c1), lite.scaleColor(1 - s, c2));
+ },
+ diff2Color: function(c1, c2){
+ var r = c1.r - c2.r;
+ var g = c1.g - c2.g;
+ var b = c1.b - c2.b;
+ var a = c1.a - c2.a;
+ return r * r + g * g + b * b + a * a;
+ },
+ length2Color: function(c){
+ return c.r * c.r + c.g * c.g + c.b * c.b + c.a * c.a;
+ },
+
+ // vector utilities
+ //TODO: move vector utilities from this file to vector.js
+ dot: function(a, b){
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+ },
+ scale: function(s, v){
+ return {x: s * v.x, y: s * v.y, z: s * v.z};
+ },
+ add: function(a, b){
+ return {x: a.x + b.x, y: a.y + b.y, z: a.z + b.z};
+ },
+ saturate: function(v){
+ return Math.min(Math.max(v, 0), 1);
+ },
+ length: function(v){
+ return Math.sqrt(dojox.gfx3d.lighting.dot(v, v));
+ },
+ normalize: function(v){
+ return lite.scale(1 / lite.length(v), v);
+ },
+ faceforward: function(n, i){
+ var p = dojox.gfx3d.lighting;
+ var s = p.dot(i, n) < 0 ? 1 : -1;
+ return p.scale(s, n);
+ },
+ reflect: function(i, n){
+ var p = dojox.gfx3d.lighting;
+ return p.add(i, p.scale(-2 * p.dot(i, n), n));
+ },
+
+ // lighting utilities
+ diffuse: function(normal, lights){
+ var c = lite.black();
+ for(var i = 0; i < lights.length; ++i){
+ var l = lights[i],
+ d = lite.dot(lite.normalize(l.direction), normal);
+ c = lite.addColor(c, lite.scaleColor(d, l.color));
+ }
+ return lite.saturateColor(c);
+ },
+ specular: function(normal, v, roughness, lights){
+ var c = lite.black();
+ for(var i = 0; i < lights.length; ++i){
+ var l = lights[i],
+ h = lite.normalize(lite.add(lite.normalize(l.direction), v)),
+ s = Math.pow(Math.max(0, lite.dot(normal, h)), 1 / roughness);
+ c = lite.addColor(c, lite.scaleColor(s, l.color));
+ }
+ return lite.saturateColor(c);
+ },
+ phong: function(normal, v, size, lights){
+ normal = lite.normalize(normal);
+ var c = lite.black();
+ for(var i = 0; i < lights.length; ++i){
+ var l = lights[i],
+ r = lite.reflect(lite.scale(-1, lite.normalize(v)), normal),
+ s = Math.pow(Math.max(0, lite.dot(r, lite.normalize(l.direction))), size);
+ c = lite.addColor(c, lite.scaleColor(s, l.color));
+ }
+ return lite.saturateColor(c);
+ }
+ });
+
+ // this lighting model is derived from RenderMan Interface Specification Version 3.2
+
+ dojo.declare("dojox.gfx3d.lighting.Model", null, {
+ constructor: function(incident, lights, ambient, specular){
+ this.incident = lite.normalize(incident);
+ this.lights = [];
+ for(var i = 0; i < lights.length; ++i){
+ var l = lights[i];
+ this.lights.push({direction: lite.normalize(l.direction), color: lite.toStdColor(l.color)});
+ }
+ this.ambient = lite.toStdColor(ambient.color ? ambient.color : "white");
+ this.ambient = lite.scaleColor(ambient.intensity, this.ambient);
+ this.ambient = lite.scaleColor(this.ambient.a, this.ambient);
+ this.ambient.a = 1;
+ this.specular = lite.toStdColor(specular ? specular : "white");
+ this.specular = lite.scaleColor(this.specular.a, this.specular);
+ this.specular.a = 1;
+ this.npr_cool = {r: 0, g: 0, b: 0.4, a: 1};
+ this.npr_warm = {r: 0.4, g: 0.4, b: 0.2, a: 1};
+ this.npr_alpha = 0.2;
+ this.npr_beta = 0.6;
+ this.npr_scale = 0.6;
+ },
+ constant: function(normal, finish, pigment){
+ pigment = lite.toStdColor(pigment);
+ var alpha = pigment.a, color = lite.scaleColor(alpha, pigment);
+ color.a = alpha;
+ return lite.fromStdColor(lite.saturateColor(color));
+ },
+ matte: function(normal, finish, pigment){
+ if(typeof finish == "string"){ finish = lite.finish[finish]; }
+ pigment = lite.toStdColor(pigment);
+ normal = lite.faceforward(lite.normalize(normal), this.incident);
+ var ambient = lite.scaleColor(finish.Ka, this.ambient),
+ shadow = lite.saturate(-4 * lite.dot(normal, this.incident)),
+ diffuse = lite.scaleColor(shadow * finish.Kd, lite.diffuse(normal, this.lights)),
+ color = lite.scaleColor(pigment.a, lite.multiplyColor(pigment, lite.addColor(ambient, diffuse)));
+ color.a = pigment.a;
+ return lite.fromStdColor(lite.saturateColor(color));
+ },
+ metal: function(normal, finish, pigment){
+ if(typeof finish == "string"){ finish = lite.finish[finish]; }
+ pigment = lite.toStdColor(pigment);
+ normal = lite.faceforward(lite.normalize(normal), this.incident);
+ var v = lite.scale(-1, this.incident), specular, color,
+ ambient = lite.scaleColor(finish.Ka, this.ambient),
+ shadow = lite.saturate(-4 * lite.dot(normal, this.incident));
+ if("phong" in finish){
+ specular = lite.scaleColor(shadow * finish.Ks * finish.phong, lite.phong(normal, v, finish.phong_size, this.lights));
+ }else{
+ specular = lite.scaleColor(shadow * finish.Ks, lite.specular(normal, v, finish.roughness, this.lights));
+ }
+ color = lite.scaleColor(pigment.a, lite.addColor(lite.multiplyColor(pigment, ambient), lite.multiplyColor(this.specular, specular)));
+ color.a = pigment.a;
+ return lite.fromStdColor(lite.saturateColor(color));
+ },
+ plastic: function(normal, finish, pigment){
+ if(typeof finish == "string"){ finish = lite.finish[finish]; }
+ pigment = lite.toStdColor(pigment);
+ normal = lite.faceforward(lite.normalize(normal), this.incident);
+ var v = lite.scale(-1, this.incident), specular, color,
+ ambient = lite.scaleColor(finish.Ka, this.ambient),
+ shadow = lite.saturate(-4 * lite.dot(normal, this.incident)),
+ diffuse = lite.scaleColor(shadow * finish.Kd, lite.diffuse(normal, this.lights));
+ if("phong" in finish){
+ specular = lite.scaleColor(shadow * finish.Ks * finish.phong, lite.phong(normal, v, finish.phong_size, this.lights));
+ }else{
+ specular = lite.scaleColor(shadow * finish.Ks, lite.specular(normal, v, finish.roughness, this.lights));
+ }
+ color = lite.scaleColor(pigment.a, lite.addColor(lite.multiplyColor(pigment, lite.addColor(ambient, diffuse)), lite.multiplyColor(this.specular, specular)));
+ color.a = pigment.a;
+ return lite.fromStdColor(lite.saturateColor(color));
+ },
+ npr: function(normal, finish, pigment){
+ if(typeof finish == "string"){ finish = lite.finish[finish]; }
+ pigment = lite.toStdColor(pigment);
+ normal = lite.faceforward(lite.normalize(normal), this.incident);
+ var ambient = lite.scaleColor(finish.Ka, this.ambient),
+ shadow = lite.saturate(-4 * lite.dot(normal, this.incident)),
+ diffuse = lite.scaleColor(shadow * finish.Kd, lite.diffuse(normal, this.lights)),
+ color = lite.scaleColor(pigment.a, lite.multiplyColor(pigment, lite.addColor(ambient, diffuse))),
+ cool = lite.addColor(this.npr_cool, lite.scaleColor(this.npr_alpha, color)),
+ warm = lite.addColor(this.npr_warm, lite.scaleColor(this.npr_beta, color)),
+ d = (1 + lite.dot(this.incident, normal)) / 2,
+ color = lite.scaleColor(this.npr_scale, lite.addColor(color, lite.mixColor(cool, warm, d)));
+ color.a = pigment.a;
+ return lite.fromStdColor(lite.saturateColor(color));
+ }
+ });
+})();
+
+// POV-Ray basic finishes
+
+dojox.gfx3d.lighting.finish = {
+
+ // Default
+
+ defaults: {Ka: 0.1, Kd: 0.6, Ks: 0.0, roughness: 0.05},
+
+ dull: {Ka: 0.1, Kd: 0.6, Ks: 0.5, roughness: 0.15},
+ shiny: {Ka: 0.1, Kd: 0.6, Ks: 1.0, roughness: 0.001},
+ glossy: {Ka: 0.1, Kd: 0.6, Ks: 1.0, roughness: 0.0001},
+
+ phong_dull: {Ka: 0.1, Kd: 0.6, Ks: 0.5, phong: 0.5, phong_size: 1},
+ phong_shiny: {Ka: 0.1, Kd: 0.6, Ks: 1.0, phong: 1.0, phong_size: 200},
+ phong_glossy: {Ka: 0.1, Kd: 0.6, Ks: 1.0, phong: 1.0, phong_size: 300},
+
+ luminous: {Ka: 1.0, Kd: 0.0, Ks: 0.0, roughness: 0.05},
+
+ // Metals
+
+ // very soft and dull
+ metalA: {Ka: 0.35, Kd: 0.3, Ks: 0.8, roughness: 1/20},
+ // fairly soft and dull
+ metalB: {Ka: 0.30, Kd: 0.4, Ks: 0.7, roughness: 1/60},
+ // medium reflectivity, holds color well
+ metalC: {Ka: 0.25, Kd: 0.5, Ks: 0.8, roughness: 1/80},
+ // highly hard and polished, high reflectivity
+ metalD: {Ka: 0.15, Kd: 0.6, Ks: 0.8, roughness: 1/100},
+ // very highly polished and reflective
+ metalE: {Ka: 0.10, Kd: 0.7, Ks: 0.8, roughness: 1/120}
+};
+
+}
diff --git a/includes/js/dojox/gfx3d/matrix.js b/includes/js/dojox/gfx3d/matrix.js
new file mode 100644
index 0000000..277b7d5
--- /dev/null
+++ b/includes/js/dojox/gfx3d/matrix.js
@@ -0,0 +1,339 @@
+if(!dojo._hasResource["dojox.gfx3d.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.gfx3d.matrix"] = true;
+dojo.provide("dojox.gfx3d.matrix");
+
+// candidates for dojox.math:
+dojox.gfx3d.matrix._degToRad = function(degree){ return Math.PI * degree / 180; };
+dojox.gfx3d.matrix._radToDeg = function(radian){ return radian / Math.PI * 180; };
+
+dojox.gfx3d.matrix.Matrix3D = function(arg){
+ // summary: a 3D matrix object
+ // description: Normalizes a 3D matrix-like object. If arrays is passed,
+ // all objects of the array are normalized and multiplied sequentially.
+ // arg: Object
+ // a 3D matrix-like object, a number, or an array of such objects
+ if(arg){
+ if(typeof arg == "number"){
+ this.xx = this.yy = this.zz = arg;
+ }else if(arg instanceof Array){
+ if(arg.length > 0){
+ var m = dojox.gfx3d.matrix.normalize(arg[0]);
+ // combine matrices
+ for(var i = 1; i < arg.length; ++i){
+ var l = m;
+ var r = dojox.gfx3d.matrix.normalize(arg[i]);
+ m = new dojox.gfx3d.matrix.Matrix3D();
+ m.xx = l.xx * r.xx + l.xy * r.yx + l.xz * r.zx;
+ m.xy = l.xx * r.xy + l.xy * r.yy + l.xz * r.zy;
+ m.xz = l.xx * r.xz + l.xy * r.yz + l.xz * r.zz;
+ m.yx = l.yx * r.xx + l.yy * r.yx + l.yz * r.zx;
+ m.yy = l.yx * r.xy + l.yy * r.yy + l.yz * r.zy;
+ m.yz = l.yx * r.xz + l.yy * r.yz + l.yz * r.zz;
+ m.zx = l.zx * r.xx + l.zy * r.yx + l.zz * r.zx;
+ m.zy = l.zx * r.xy + l.zy * r.yy + l.zz * r.zy;
+ m.zz = l.zx * r.xz + l.zy * r.yz + l.zz * r.zz;
+ m.dx = l.xx * r.dx + l.xy * r.dy + l.xz * r.dz + l.dx;
+ m.dy = l.yx * r.dx + l.yy * r.dy + l.yz * r.dz + l.dy;
+ m.dz = l.zx * r.dx + l.zy * r.dy + l.zz * r.dz + l.dz;
+ }
+ dojo.mixin(this, m);
+ }
+ }else{
+ dojo.mixin(this, arg);
+ }
+ }
+};
+
+// the default (identity) matrix, which is used to fill in missing values
+dojo.extend(dojox.gfx3d.matrix.Matrix3D, {xx: 1, xy: 0, xz: 0, yx: 0, yy: 1, yz: 0, zx: 0, zy: 0, zz: 1, dx: 0, dy: 0, dz: 0});
+
+dojo.mixin(dojox.gfx3d.matrix, {
+ // summary: class constants, and methods of dojox.gfx3d.matrix
+
+ // matrix constants
+
+ // identity: dojox.gfx3d.matrix.Matrix3D
+ // an identity matrix constant: identity * (x, y, z) == (x, y, z)
+ identity: new dojox.gfx3d.matrix.Matrix3D(),
+
+ // matrix creators
+
+ translate: function(a, b, c){
+ // summary: forms a translation matrix
+ // description: The resulting matrix is used to translate (move) points by specified offsets.
+ // a: Number: an x coordinate value
+ // b: Number: a y coordinate value
+ // c: Number: a z coordinate value
+ if(arguments.length > 1){
+ return new dojox.gfx3d.matrix.Matrix3D({dx: a, dy: b, dz: c}); // dojox.gfx3d.matrix.Matrix3D
+ }
+ // branch
+ // a: Object: a point-like object, which specifies offsets for 3 dimensions
+ // b: null
+ return new dojox.gfx3d.matrix.Matrix3D({dx: a.x, dy: a.y, dz: a.z}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ scale: function(a, b, c){
+ // summary: forms a scaling matrix
+ // description: The resulting matrix is used to scale (magnify) points by specified offsets.
+ // a: Number: a scaling factor used for the x coordinate
+ // b: Number: a scaling factor used for the y coordinate
+ // c: Number: a scaling factor used for the z coordinate
+ if(arguments.length > 1){
+ return new dojox.gfx3d.matrix.Matrix3D({xx: a, yy: b, zz: c}); // dojox.gfx3d.matrix.Matrix3D
+ }
+ if(typeof a == "number"){
+ // branch
+ // a: Number: a uniform scaling factor used for the all coordinates
+ // b: null
+ return new dojox.gfx3d.matrix.Matrix3D({xx: a, yy: a, zz: a}); // dojox.gfx3d.matrix.Matrix3D
+ }
+ // branch
+ // a: Object: a point-like object, which specifies scale factors for 3 dimensions
+ // b: null
+ return new dojox.gfx3d.matrix.Matrix3D({xx: a.x, yy: a.y, zz: a.z}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ rotateX: function(angle){
+ // summary: forms a rotating matrix (about the x axis)
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified angle.
+ // angle: Number: an angle of rotation in radians (>0 for CW)
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+ return new dojox.gfx3d.matrix.Matrix3D({yy: c, yz: -s, zy: s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ rotateXg: function(degree){
+ // summary: forms a rotating matrix (about the x axis)
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified degree.
+ // See dojox.gfx3d.matrix.rotateX() for comparison.
+ // degree: Number: an angle of rotation in degrees (>0 for CW)
+ return dojox.gfx3d.matrix.rotateX(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
+ },
+ rotateY: function(angle){
+ // summary: forms a rotating matrix (about the y axis)
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified angle.
+ // angle: Number: an angle of rotation in radians (>0 for CW)
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+ return new dojox.gfx3d.matrix.Matrix3D({xx: c, xz: s, zx: -s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ rotateYg: function(degree){
+ // summary: forms a rotating matrix (about the y axis)
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified degree.
+ // See dojox.gfx3d.matrix.rotateY() for comparison.
+ // degree: Number: an angle of rotation in degrees (>0 for CW)
+ return dojox.gfx3d.matrix.rotateY(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
+ },
+ rotateZ: function(angle){
+ // summary: forms a rotating matrix (about the z axis)
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified angle.
+ // angle: Number: an angle of rotation in radians (>0 for CW)
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+ return new dojox.gfx3d.matrix.Matrix3D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ rotateZg: function(degree){
+ // summary: forms a rotating matrix (about the z axis)
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified degree.
+ // See dojox.gfx3d.matrix.rotateZ() for comparison.
+ // degree: Number: an angle of rotation in degrees (>0 for CW)
+ return dojox.gfx3d.matrix.rotateZ(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
+ },
+
+ // camera transformation
+ cameraTranslate: function(a, b, c){
+ // summary: forms a translation matrix
+ // description: The resulting matrix is used to translate (move) points by specified offsets.
+ // a: Number: an x coordinate value
+ // b: Number: a y coordinate value
+ // c: Number: a z coordinate value
+ if(arguments.length > 1){
+ return new dojox.gfx3d.matrix.Matrix3D({dx: -a, dy: -b, dz: -c}); // dojox.gfx3d.matrix.Matrix3D
+ }
+ // branch
+ // a: Object: a point-like object, which specifies offsets for 3 dimensions
+ // b: null
+ return new dojox.gfx3d.matrix.Matrix3D({dx: -a.x, dy: -a.y, dz: -a.z}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ cameraRotateX: function(angle){
+ // summary: forms a rotating matrix (about the x axis) in cameraTransform manner
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified angle.
+ // angle: Number: an angle of rotation in radians (>0 for CW)
+ var c = Math.cos(-angle);
+ var s = Math.sin(-angle);
+ return new dojox.gfx3d.matrix.Matrix3D({yy: c, yz: -s, zy: s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ cameraRotateXg: function(degree){
+ // summary: forms a rotating matrix (about the x axis)in cameraTransform manner
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified degree.
+ // See dojox.gfx3d.matrix.rotateX() for comparison.
+ // degree: Number: an angle of rotation in degrees (>0 for CW)
+ return dojox.gfx3d.matrix.rotateX(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
+ },
+ cameraRotateY: function(angle){
+ // summary: forms a rotating matrix (about the y axis) in cameraTransform manner
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified angle.
+ // angle: Number: an angle of rotation in radians (>0 for CW)
+ var c = Math.cos(-angle);
+ var s = Math.sin(-angle);
+ return new dojox.gfx3d.matrix.Matrix3D({xx: c, xz: s, zx: -s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ cameraRotateYg: function(degree){
+ // summary: forms a rotating matrix (about the y axis) in cameraTransform manner
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified degree.
+ // See dojox.gfx3d.matrix.rotateY() for comparison.
+ // degree: Number: an angle of rotation in degrees (>0 for CW)
+ return dojox.gfx3d.matrix.rotateY(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
+ },
+ cameraRotateZ: function(angle){
+ // summary: forms a rotating matrix (about the z axis) in cameraTransform manner
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified angle.
+ // angle: Number: an angle of rotation in radians (>0 for CW)
+ var c = Math.cos(-angle);
+ var s = Math.sin(-angle);
+ return new dojox.gfx3d.matrix.Matrix3D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx3d.matrix.Matrix3D
+ },
+ cameraRotateZg: function(degree){
+ // summary: forms a rotating matrix (about the z axis) in cameraTransform manner
+ // description: The resulting matrix is used to rotate points
+ // around the origin of coordinates (0, 0) by specified degree.
+ // See dojox.gfx3d.matrix.rotateZ() for comparison.
+ // degree: Number: an angle of rotation in degrees (>0 for CW)
+ return dojox.gfx3d.matrix.rotateZ(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
+ },
+
+ // ensure matrix 3D conformance
+ normalize: function(matrix){
+ // summary: converts an object to a matrix, if necessary
+ // description: Converts any 3D matrix-like object or an array of
+ // such objects to a valid dojox.gfx3d.matrix.Matrix3D object.
+ // matrix: Object: an object, which is converted to a matrix, if necessary
+ return (matrix instanceof dojox.gfx3d.matrix.Matrix3D) ? matrix : new dojox.gfx3d.matrix.Matrix3D(matrix); // dojox.gfx3d.matrix.Matrix3D
+ },
+
+ // common operations
+
+ clone: function(matrix){
+ // summary: creates a copy of a 3D matrix
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix-like object to be cloned
+ var obj = new dojox.gfx3d.matrix.Matrix3D();
+ for(var i in matrix){
+ if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
+ }
+ return obj; // dojox.gfx3d.matrix.Matrix3D
+ },
+ invert: function(matrix){
+ // summary: inverts a 2D matrix
+ // matrix: dojox.gfx.matrix.Matrix3D: a 2D matrix-like object to be inverted
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ var D = m.xx * m.yy * m.zz + m.xy * m.yz * m.zx + m.xz * m.yx * m.zy - m.xx * m.yz * m.zy - m.xy * m.yx * m.zz - m.xz * m.yy * m.zx;
+ var M = new dojox.gfx3d.matrix.Matrix3D({
+ xx: (m.yy * m.zz - m.yz * m.zy) / D,
+ xy: (m.xz * m.zy - m.xy * m.zz) / D,
+ xz: (m.xy * m.yz - m.xz * m.yy) / D,
+ yx: (m.yz * m.zx - m.yx * m.zz) / D,
+ yy: (m.xx * m.zz - m.xz * m.zx) / D,
+ yz: (m.xz * m.yx - m.xx * m.yz) / D,
+ zx: (m.yx * m.zy - m.yy * m.zx) / D,
+ zy: (m.xy * m.zx - m.xx * m.zy) / D,
+ zz: (m.xx * m.yy - m.xy * m.yx) / D,
+ dx: -1 * (m.xy * m.yz * m.dz + m.xz * m.dy * m.zy + m.dx * m.yy * m.zz - m.xy * m.dy * m.zz - m.xz * m.yy * m.dz - m.dx * m.yz * m.zy) / D,
+ dy: (m.xx * m.yz * m.dz + m.xz * m.dy * m.zx + m.dx * m.yx * m.zz - m.xx * m.dy * m.zz - m.xz * m.yx * m.dz - m.dx * m.yz * m.zx) / D,
+ dz: -1 * (m.xx * m.yy * m.dz + m.xy * m.dy * m.zx + m.dx * m.yx * m.zy - m.xx * m.dy * m.zy - m.xy * m.yx * m.dz - m.dx * m.yy * m.zx) / D
+ });
+ return M; // dojox.gfx3d.matrix.Matrix3D
+ },
+ _multiplyPoint: function(m, x, y, z){
+ // summary: applies a matrix to a point
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // x: Number: an x coordinate of a point
+ // y: Number: a y coordinate of a point
+ // z: Number: a z coordinate of a point
+ return {x: m.xx * x + m.xy * y + m.xz * z + m.dx, y: m.yx * x + m.yy * y + m.yz * z + m.dy, z: m.zx * x + m.zy * y + m.zz * z + m.dz}; // Object
+ },
+ multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b, /* Number, optional */ c){
+ // summary: applies a matrix to a point
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // a: Number: an x coordinate of a point
+ // b: Number: a y coordinate of a point
+ // c: Number: a z coordinate of a point
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ if(typeof a == "number" && typeof b == "number" && typeof c == "number"){
+ return dojox.gfx3d.matrix._multiplyPoint(m, a, b, c); // Object
+ }
+ // branch
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // a: Object: a point
+ // b: null
+ // c: null
+ return dojox.gfx3d.matrix._multiplyPoint(m, a.x, a.y, a.z); // Object
+ },
+ multiply: function(matrix){
+ // summary: combines matrices by multiplying them sequentially in the given order
+ // matrix: dojox.gfx3d.matrix.Matrix3D...: a 3D matrix-like object,
+ // all subsequent arguments are matrix-like objects too
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ // combine matrices
+ for(var i = 1; i < arguments.length; ++i){
+ var l = m;
+ var r = dojox.gfx3d.matrix.normalize(arguments[i]);
+ m = new dojox.gfx3d.matrix.Matrix3D();
+ m.xx = l.xx * r.xx + l.xy * r.yx + l.xz * r.zx;
+ m.xy = l.xx * r.xy + l.xy * r.yy + l.xz * r.zy;
+ m.xz = l.xx * r.xz + l.xy * r.yz + l.xz * r.zz;
+ m.yx = l.yx * r.xx + l.yy * r.yx + l.yz * r.zx;
+ m.yy = l.yx * r.xy + l.yy * r.yy + l.yz * r.zy;
+ m.yz = l.yx * r.xz + l.yy * r.yz + l.yz * r.zz;
+ m.zx = l.zx * r.xx + l.zy * r.yx + l.zz * r.zx;
+ m.zy = l.zx * r.xy + l.zy * r.yy + l.zz * r.zy;
+ m.zz = l.zx * r.xz + l.zy * r.yz + l.zz * r.zz;
+ m.dx = l.xx * r.dx + l.xy * r.dy + l.xz * r.dz + l.dx;
+ m.dy = l.yx * r.dx + l.yy * r.dy + l.yz * r.dz + l.dy;
+ m.dz = l.zx * r.dx + l.zy * r.dy + l.zz * r.dz + l.dz;
+ }
+ return m; // dojox.gfx3d.matrix.Matrix3D
+ },
+
+ _project: function(m, x, y, z){
+ // summary: applies a matrix to a point
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // x: Number: an x coordinate of a point
+ // y: Number: a y coordinate of a point
+ // z: Number: a z coordinate of a point
+ return { // Object
+ x: m.xx * x + m.xy * y + m.xz * z + m.dx,
+ y: m.yx * x + m.yy * y + m.yz * z + m.dy,
+ z: m.zx * x + m.zy * y + m.zz * z + m.dz};
+ },
+ project: function(matrix, /* Number||Point */ a, /* Number, optional */ b, /* Number, optional */ c){
+ // summary: applies a matrix to a point
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // a: Number: an x coordinate of a point
+ // b: Number: a y coordinate of a point
+ // c: Number: a z coordinate of a point
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ if(typeof a == "number" && typeof b == "number" && typeof c == "number"){
+ return dojox.gfx3d.matrix._project(m, a, b, c); // Object
+ }
+ // branch
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // a: Object: a point
+ // b: null
+ // c: null
+ return dojox.gfx3d.matrix._project(m, a.x, a.y, a.z); // Object
+ }
+});
+
+// propagate matrix up
+dojox.gfx3d.Matrix3D = dojox.gfx3d.matrix.Matrix3D;
+
+}
diff --git a/includes/js/dojox/gfx3d/object.js b/includes/js/dojox/gfx3d/object.js
new file mode 100644
index 0000000..e574c91
--- /dev/null
+++ b/includes/js/dojox/gfx3d/object.js
@@ -0,0 +1,1092 @@
+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()];
+ if(typeof(group) == "number"){
+ if(group){
+ if(args.length >= group){
+ var segment = {action: action, args: args.slice(0, args.length - args.length % group)};
+ this.segments.push(segment);
+ }
+ }else{
+ var 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);
+ 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(var 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(var 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){
+ this.dimension = {
+ width: dojo.isString(dim.width) ? parseInt(dim.width) : dim.width,
+ height: dojo.isString(dim.height) ? parseInt(dim.height) : dim.height
+ };
+ }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;
+ }
+});
+
+}
diff --git a/includes/js/dojox/gfx3d/scheduler.js b/includes/js/dojox/gfx3d/scheduler.js
new file mode 100644
index 0000000..951970c
--- /dev/null
+++ b/includes/js/dojox/gfx3d/scheduler.js
@@ -0,0 +1,126 @@
+if(!dojo._hasResource["dojox.gfx3d.scheduler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.gfx3d.scheduler"] = true;
+dojo.provide("dojox.gfx3d.scheduler");
+dojo.provide("dojox.gfx3d.drawer");
+dojo.require("dojox.gfx3d.vector");
+
+dojo.mixin(dojox.gfx3d.scheduler, {
+ zOrder: function(buffer, order){
+ order = order ? order : dojox.gfx3d.scheduler.order;
+ buffer.sort(function(a, b){
+ return order(b) - order(a);
+ });
+ return buffer;
+ },
+
+ bsp: function(buffer, outline){
+ console.debug("BSP scheduler");
+ outline = outline ? outline : dojox.gfx3d.scheduler.outline;
+ var p = new dojox.gfx3d.scheduler.BinarySearchTree(buffer[0], outline);
+ dojo.forEach(buffer.slice(1), function(item){ p.add(item, outline); });
+ return p.iterate(outline);
+ },
+
+ // default implementation
+ order: function(it){
+ return it.getZOrder();
+ },
+
+ outline: function(it){
+ return it.getOutline();
+ }
+
+});
+
+dojo.declare("dojox.gfx3d.scheduler.BinarySearchTree", null, {
+ constructor: function(obj, outline){
+ // summary: build the binary search tree, using binary space partition algorithm.
+ // The idea is for any polygon, for example, (a, b, c), the space is divided by
+ // the plane into two space: plus and minus.
+ //
+ // for any arbitary vertex p, if(p - a) dotProduct n = 0, p is inside the plane,
+ // > 0, p is in the plus space, vice versa for minus space.
+ // n is the normal vector that is perpendicular the plate, defined as:
+ // n = ( b - a) crossProduct ( c - a )
+ //
+ // in this implementation, n is declared as normal, ,a is declared as orient.
+ //
+ // obj: object: dojox.gfx3d.Object
+ this.plus = null;
+ this.minus = null;
+ this.object = obj;
+
+ var o = outline(obj);
+ this.orient = o[0];
+ this.normal = dojox.gfx3d.vector.normalize(o);
+ },
+
+ add: function(obj, outline){
+ var epsilon = 0.5, o = outline(obj), v = dojox.gfx3d.vector, n = this.normal, a = this.orient;
+
+ if(dojo.every(o, function(item){ return Math.floor(epsilon + v.dotProduct(n, v.substract(item, a))) <= 0; })){
+ if(this.minus){
+ this.minus.add(obj, outline);
+ } else {
+ this.minus = new dojox.gfx3d.scheduler.BinarySearchTree(obj, outline);
+ }
+ } else if(dojo.every(o, function(item){ return Math.floor(epsilon + v.dotProduct(n, v.substract(item, a))) >= 0; })){
+ if(this.plus){
+ this.plus.add(obj, outline);
+ } else {
+ this.plus = new dojox.gfx3d.scheduler.BinarySearchTree(obj, outline);
+ }
+ } else {
+ dojo.forEach(o, function(item){ console.debug(v.dotProduct(n, v.substract(item, a))); });
+ throw "The case: polygon cross siblings' plate is not implemneted yet";
+ }
+ },
+
+ iterate: function(outline){
+ var epsilon = 0.5;
+ var v = dojox.gfx3d.vector;
+ var sorted = [];
+ var subs = null;
+ // FIXME: using Infinity here?
+ var view = {x: 0, y: 0, z: -10000};
+ if(Math.floor( epsilon + v.dotProduct(this.normal, v.substract(view, this.orient))) <= 0){
+ subs = [this.plus, this.minus];
+ } else {
+ subs = [this.minus, this.plus];
+ }
+
+ if(subs[0]){
+ sorted = sorted.concat(subs[0].iterate());
+ }
+ sorted.push(this.object);
+ if(subs[1]){
+ sorted = sorted.concat(subs[1].iterate());
+ }
+ return sorted;
+ }
+
+});
+
+dojo.mixin(dojox.gfx3d.drawer, {
+ conservative: function(todos, objects, viewport){
+ console.debug('conservative draw');
+ dojo.forEach(this.objects, function(item){
+ item.destroy();
+ });
+ dojo.forEach(objects, function(item){
+ item.draw(viewport.lighting);
+ });
+ },
+ chart: function(todos, objects, viewport){
+ // NOTE: ondemand may require the todos' objects to use setShape
+ // to redraw themselves to maintain the z-order.
+ console.debug('chart draw');
+ dojo.forEach(this.todos, function(item){
+ item.draw(viewport.lighting);
+ });
+ }
+ // More aggrasive optimization may re-order the DOM nodes using the order
+ // of objects, and only elements of todos call setShape.
+});
+
+}
diff --git a/includes/js/dojox/gfx3d/tests/test_camerarotate.html b/includes/js/dojox/gfx3d/tests/test_camerarotate.html
new file mode 100644
index 0000000..dcfa1a2
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_camerarotate.html
@@ -0,0 +1,93 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Camera rotate of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "../../../dijit/themes/tundra/tundra.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: false"></script>
+<script type="text/javascript" src="../object.js"></script>
+<script type="text/javascript" src="../scheduler.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+var angles = {x: 30, y: 30, z: 0};
+var cube = null;
+var view = null;
+
+rotate = function() {
+ var m = dojox.gfx3d.matrix;
+
+ if(dojo.byId('rx').checked){
+ angles.x += 1;
+ }
+ if(dojo.byId('ry').checked){
+ angles.y += 1;
+ }
+ if(dojo.byId('rz').checked){
+ angles.z += 1;
+ }
+ var t = m.normalize([
+ m.cameraTranslate(-300, -200, 0),
+ m.cameraRotateXg(angles.x),
+ m.cameraRotateYg(angles.y),
+ m.cameraRotateZg(angles.z)
+ ]);
+ console.debug(t);
+ view.setCameraTransform(t);
+ view.render();
+}
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ view = surface.createViewport();
+
+ var c = {bottom: {x: 0, y: 0, z: 0}, top :{x: 100, y: 100, z: 100}};
+ var xaxis = [{x: 0, y: 0, z: 0}, {x: 200, y: 0, z: 0}];
+ var yaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 200, z: 0}];
+ var zaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 200}];
+
+ var m = dojox.gfx3d.matrix;
+
+ view.createEdges(xaxis).setStroke({color: "red", width: 1});
+ view.createEdges(yaxis).setStroke({color: "green", width: 1});
+ view.createEdges(zaxis).setStroke({color: "blue", width: 1});
+
+ cube = view.createCube(c).setStroke({color: "lime", width: 1});
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraTranslate(-300, -200, 0),
+ m.cameraRotateXg(angles.x),
+ m.cameraRotateYg(angles.y),
+ m.cameraRotateZg(angles.z),
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+ window.setInterval(rotate, 50);
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body class="tundra">
+ <h1>Camera rotate</h1>
+ <p>The cube is in the center (0, 0, 0): The color of X, Y, Z axes are red, green, blue. The view renders all the objects
+ in each frame, the <em>conservative</em> drawer is used.</p>
+<form>
+ <input id="rx" type="checkbox" name="rotateX" checked="true" value="on"/>
+ <label for="rx"> Rotate around X-axis</label> <br/>
+ <input id="ry" type="checkbox" name="rotateY" checked="false" value="off"/>
+ <label for="ry"> Rotate around Y-axis</label> <br/>
+ <input id="rz" type="checkbox" name="rotateZ" checked="false" value="off"/>
+ <label for="rz"> Rotate around Z-axis</label> <br/>
+</form>
+
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html b/includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html
new file mode 100644
index 0000000..e9c0312
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_camerarotate_shaded.html
@@ -0,0 +1,97 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+ <title>Camera rotate of dojox.gfx3d.</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "../../../dijit/themes/tundra/tundra.css";
+ </style>
+ <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: false"></script>
+ <script type="text/javascript" src="../object.js"></script>
+ <script type="text/javascript" src="../scheduler.js"></script>
+ <script type="text/javascript">
+
+ dojo.require("dojox.gfx3d");
+
+ var angles = {x: 30, y: 30, z: 0};
+ var cube = null;
+ var view = null;
+
+ rotate = function() {
+ var m = dojox.gfx3d.matrix;
+
+ if(dojo.byId('rx').checked){
+ angles.x += 1;
+ }
+ if(dojo.byId('ry').checked){
+ angles.y += 1;
+ }
+ if(dojo.byId('rz').checked){
+ angles.z += 1;
+ }
+ var t = m.normalize([
+ m.cameraTranslate(-300, -200, 0),
+ m.cameraRotateXg(angles.x),
+ m.cameraRotateYg(angles.y),
+ m.cameraRotateZg(angles.z)
+ ]);
+ console.debug(t);
+ view.setCameraTransform(t);
+ view.render();
+ }
+
+ makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ view = surface.createViewport();
+
+ view.setLights([{direction: {x: -10, y: -5, z: 5}, color: "white"}],
+ {color:"white", intensity: 2}, "white");
+
+ var c = {bottom: {x: 0, y: 0, z: 0}, top :{x: 100, y: 100, z: 100}};
+ var xaxis = [{x: 0, y: 0, z: 0}, {x: 200, y: 0, z: 0}];
+ var yaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 200, z: 0}];
+ var zaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 200}];
+
+ var m = dojox.gfx3d.matrix;
+
+ view.createEdges(xaxis).setStroke({color: "red", width: 1});
+ view.createEdges(yaxis).setStroke({color: "green", width: 1});
+ view.createEdges(zaxis).setStroke({color: "blue", width: 1});
+
+ // setStroke({color: "lime", width: 1}).
+ cube = view.createCube(c).setFill({ type: "plastic", finish: "dull", color: "lime" });
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraTranslate(-300, -200, 0),
+ m.cameraRotateXg(angles.x),
+ m.cameraRotateYg(angles.y),
+ m.cameraRotateZg(angles.z),
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+ window.setInterval(rotate, 50);
+ };
+
+ dojo.addOnLoad(makeObjects);
+
+ </script>
+</head>
+<body class="tundra">
+ <h1>Camera rotate</h1>
+ <p>The cube is in the center (0, 0, 0): The color of X, Y, Z axes are red, green, blue. The view renders all the objects
+ in each frame, the <em>conservative</em> drawer is used.</p>
+ <form>
+ <input id="rx" type="checkbox" name="rotateX" checked="true" value="on"/>
+ <label for="rx"> Rotate around X-axis</label> <br/>
+ <input id="ry" type="checkbox" name="rotateY" checked="false" value="off"/>
+ <label for="ry"> Rotate around Y-axis</label> <br/>
+ <input id="rz" type="checkbox" name="rotateZ" checked="false" value="off"/>
+ <label for="rz"> Rotate around Z-axis</label> <br/>
+ </form>
+
+ <div id="test" style="width: 500px; height: 500px;"></div>
+ <p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_cube.html b/includes/js/dojox/gfx3d/tests/test_cube.html
new file mode 100644
index 0000000..dcae739
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_cube.html
@@ -0,0 +1,50 @@
+<html>
+<head>
+<title>Cube of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<!--
+The next line should include Microsoft's Silverligth.js, if you plan to use the silverlight backend
+<script type="text/javascript" src="Silverlight.js"></script>
+-->
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+dojo.require("dojox.gfx3d");
+dojo.require("dojox.gfx.utils");
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ var view = surface.createViewport();
+ view.setLights([{direction: {x: -10, y: -5, z: 5}, color: "white"}],
+ {color:"white", intensity: 2}, "white");
+
+ var m = dojox.gfx3d.matrix;
+ var l = view.createCube({bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}})
+ .setFill({type: "plastic", finish: "dull", color: "lime"});
+
+ var camera = [m.cameraRotateXg(20), m.cameraRotateYg(20), m.cameraTranslate(-200, -200, 0)];
+ view.applyCameraTransform(camera);
+ view.render();
+
+ //dojo.byId("out1").value = dojo.byId("test").innerHTML;
+ //dojo.byId("out2").value = dojox.gfx.utils.toJson(surface, true);
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+<h1>Cube Test</h1>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<!--
+<p><button onclick="makeObjects();">Go</button></p>
+<p><textarea id="out1" cols="40" rows="5"></textarea></p>
+<p><textarea id="out2" cols="40" rows="5"></textarea></p>
+-->
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_cylinder.html b/includes/js/dojox/gfx3d/tests/test_cylinder.html
new file mode 100644
index 0000000..cd1d5c1
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_cylinder.html
@@ -0,0 +1,66 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Cylinder test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript" src="../lighting.js"></script>
+<script type="text/javascript" src="../gradient.js"></script>
+<script type="text/javascript" src="../object.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 400);
+ var view = surface.createViewport();
+ view.setLights([
+ {direction: {x: 0, y: 0, z: -10}, color: "white"},
+ {direction: {x: 10, y: 0, z: -10}, color: "#444"}
+ ], {color: "white", intensity: 2}, "white");
+
+ var m = dojox.gfx3d.matrix;
+
+ view.createCylinder({})
+ .setTransform([m.translate(150, 250, 0), m.rotateZg(60), m.rotateXg(-60)])
+ .setStroke("black")
+ .setFill({type: "plastic", finish: "glossy", color: "red"});
+
+ view.createCylinder({})
+ .setTransform([m.translate(150, 100, 0), m.rotateZg(45), m.rotateXg(-135)])
+ .setStroke("black")
+ .setFill({type: "plastic", finish: "shiny", color: "yellow"});
+
+ view.createCylinder({})
+ .setTransform([m.translate(250, 200, 0), m.rotateZg(-30), m.rotateXg(-30)])
+ .setStroke("black")
+ .setFill({type: "plastic", finish: "dull", color: "lime"});
+
+ //var camera = m.normalize([m.cameraRotateXg(15), m.cameraRotateYg(15), m.cameraTranslate(-200, -300, 0)]);
+ //var camera = m.normalize([m.cameraRotateXg(15), m.cameraRotateYg(15)]);
+ var camera = m.normalize({});
+
+ view.applyCameraTransform(camera);
+ view.render();
+};
+
+mdebug = function(matrix){
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ console.debug("xx: " + m.xx + ", xy: " + m.xy + " | xz:" + m.xz + " | dx:" + m.dx);
+ console.debug("yx: " + m.yx + ", yy: " + m.yy + " | yz:" + m.yz + " | dy:" + m.dy);
+ console.debug("zx: " + m.zx + ", zy: " + m.zy + " | zz:" + m.zz + " | dz:" + m.dz);
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+ <h1>Cylinder Test</h1>
+<div id="test" style="width: 500px; height: 400px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_drawer.html b/includes/js/dojox/gfx3d/tests/test_drawer.html
new file mode 100644
index 0000000..3a9af1f
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_drawer.html
@@ -0,0 +1,92 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Pilot test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "../../../dijit/themes/tundra/tundra.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+var angles = {x: 0, y: 0, z: 0};
+var view = null;
+var cube = null;
+
+function moveMe(){
+ var p = dojo.byId("action");
+ var m = dojox.gfx3d.matrix;
+ if(p.value == "Move to Back!"){
+ console.debug(p.value);
+ p.value = "Move to Front!";
+ cube.setTransform(m.translate(20, 0, -120))
+ }else{
+ p.value = "Move to Back!";
+ cube.setTransform(m.translate(50, 0, 150))
+ }
+ cube.invalidate();
+ view.render();
+};
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ view = surface.createViewport();
+ var c = { bottom: {x: 0, y: 0, z: 0}, top :{x: 100, y: 100, z: 100} };
+ var xaxis = [{x: 0, y: 0, z: 0}, {x: 200, y: 0, z: 0}];
+ var yaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 200, z: 0}];
+ var zaxis = [{x: 0, y: 0, z: 0}, {x: 0, y: 0, z: 200}];
+
+ var m = dojox.gfx3d.matrix;
+
+ view.createEdges(xaxis).setStroke({color: "red", width: 1});
+ view.createEdges(yaxis).setStroke({color: "green", width: 1});
+ view.createEdges(zaxis).setStroke({color: "blue", width: 1});
+
+ view.createCube(c)
+ .setFill({type: "plastic", finish: dojox.gfx3d.lighting.finish.dull, color: "blue"})
+ .setStroke({color: "black", width: 1});
+
+ cube = view.createCube(c)
+ .setTransform(m.translate(50, 50, 150))
+ .setFill({type: "plastic", finish: dojox.gfx3d.lighting.finish.dull, color: "lime"})
+ .setStroke({color: "black", width: 1});
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateXg(60),
+ m.cameraRotateYg(30),
+ m.cameraTranslate(-200, -300, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.setLights([{direction: {x: 10, y: 7, z: 5}, color: "white"}],
+ {color:"white", intensity: 2}, "white");
+ view.render();
+
+ // add the click event handler
+ dojo.connect(dojo.byId("action"), "onclick", moveMe);
+};
+
+mdebug = function(matrix){
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ console.debug("xx: " + m.xx + ", xy: " + m.xy + " | xz:" + m.xz + " | dx:" + m.dx);
+ console.debug("yx: " + m.yx + ", yy: " + m.yy + " | yz:" + m.yz + " | dy:" + m.dy);
+ console.debug("zx: " + m.zx + ", zy: " + m.zy + " | zz:" + m.zz + " | dz:" + m.dz);
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body class="tundra">
+ <h1>Pilot Test</h1>
+ <p> The color of X, Y, Z axes are red, green, blue. One cube is in the center (0, 0, 0), click the button to move the other one back
+ and forth, using this to test <em>dojox.gfx3d.drawer.conservative</em></p>
+ <input id="action" type="button" value="Move to Back!"/>
+
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_edges.html b/includes/js/dojox/gfx3d/tests/test_edges.html
new file mode 100644
index 0000000..07b78f0
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_edges.html
@@ -0,0 +1,73 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Edges test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ var view = surface.createViewport();
+ var lines = [
+ {x: 100, y: 10, z: 5},
+ {x: 80, y: 80, z: 55},
+ {x: 120, y: 80, z: 75},
+ {x: 250, y: 92, z: 15},
+ {x: 200, y: 25, z: 5},
+ {x: 156, y: 40, z: 45}
+ ];
+
+ var m = dojox.gfx3d.matrix;
+ var loop = view.createEdges(lines, "loop")
+ .setStroke({color: "blue", width: 1})
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 0, z: 0}));
+
+ var strip = view.createEdges(lines, "strip")
+ .setStroke({color: "red", width: 1})
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 100, z: 0}));
+
+ var normal = view.createEdges(lines)
+ .setStroke({color: "lime", width: 1})
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 200, z: 0}));
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateZg(20),
+ //m.cameraRotateYg(30),
+ //m.cameraRotateXg(50),
+ m.cameraTranslate(0, 0, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+};
+
+mdebug = function(matrix){
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ console.debug("xx: " + m.xx + ", xy: " + m.xy + " | xz:" + m.xz + " | dx:" + m.dx);
+ console.debug("yx: " + m.yx + ", yy: " + m.yy + " | yz:" + m.yz + " | dy:" + m.dy);
+ console.debug("zx: " + m.zx + ", zy: " + m.zy + " | zz:" + m.zz + " | dz:" + m.dz);
+};
+
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+ <h1>Edges Test</h1>
+ <p> Test of the Edges, there are three modes</p>
+ <ul>
+ <li>none, any two vertice pair form one edge, lime</li>
+ <li>strip, vertices are connected by edges. red</li>
+ <li>loop, the same as strip, close the path, blue</li>
+ </ul>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_matrix.html b/includes/js/dojox/gfx3d/tests/test_matrix.html
new file mode 100644
index 0000000..9acf399
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_matrix.html
@@ -0,0 +1,89 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Dojo 3D Matrix</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+mdebug = function(matrix){
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ console.debug("xx: " + m.xx + ", xy: " + m.xy + " | xz:" + m.xz + " | dx:" + m.dx);
+ console.debug("yx: " + m.yx + ", yy: " + m.yy + " | yz:" + m.yz + " | dy:" + m.dy);
+ console.debug("zx: " + m.zx + ", zy: " + m.zy + " | zz:" + m.zz + " | dz:" + m.dz);
+};
+
+pdebug = function(point){
+ console.debug("x: " + point.x + ", y: " + point.y + ", z: " + point.z);
+};
+
+dojo.addOnLoad(function(){
+ var m = dojox.gfx3d.matrix;
+ var a = new m.Matrix3D();
+ console.debug("identity");
+ mdebug(a);
+ a = m.rotateXg(30);
+ console.debug("rotateXg(30);");
+ mdebug(a);
+ a = m.rotateYg(45);
+ console.debug("rotateYg(45);");
+ mdebug(a);
+ a = m.rotateZg(90);
+ console.debug("rotateZg(90);");
+ mdebug(a);
+ a = [new m.Matrix3D(), new m.Matrix3D(), new m.Matrix3D()];
+ console.debug("identity");
+ mdebug(a);
+ a = [m.rotateXg(30), m.rotateXg(-30)];
+ console.debug("identity");
+ mdebug(a);
+ var b = m.multiplyPoint(a, 10, 10, 10);
+ pdebug(b);
+ b = m.multiplyPoint(a, 10, 5, 10);
+ pdebug(b);
+ b = m.multiplyPoint(a, 10, 15, 5);
+ pdebug(b);
+
+ a = [m.scale(1,1,2), m.rotateXg(45)];
+ console.debug("a = [m.scale(1,1,2), m.rotateXg(45)];");
+ mdebug(a);
+ a = [m.rotateXg(45), m.scale(1,1,2)];
+ console.debug("a = [m.rotateXg(45), m.scale(1,1,2)];");
+ mdebug(a);
+
+ a = [m.scale(2,1,2), m.rotateYg(45)];
+ console.debug("a = [m.scale(2,1,2), m.rotateYg(45)];");
+ mdebug(a);
+ a = [m.rotateYg(45), m.scale(2,1,2)];
+ console.debug("a = [m.rotateYg(45), m.scale(2,1,2)];");
+ mdebug(a);
+
+ a = [m.scale(1,2,1), m.invert(m.rotateZg(45))];
+ console.debug("[m.scale(1,2,1), m.invert(m.rotateZg(45))];");
+ mdebug(a);
+ a = [m.invert(m.rotateZg(45)), m.scale(1,2,1)];
+ console.debug("a = [m.invert(m.rotateZg(45)), m.scale(1,2,1)];");
+ mdebug(a);
+
+ a = [a, m.invert(a)];
+ console.debug("identity");
+ mdebug(a);
+
+ a = 5;
+ mdebug(a);
+ a = [2, m.scale(2,1,3)];
+ mdebug(a);
+});
+
+</script>
+</head>
+<body>
+ <h1>dojox.gfx3d.matrix test</h1>
+ <p>Please check the debug console for test results.</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_orbit.html b/includes/js/dojox/gfx3d/tests/test_orbit.html
new file mode 100644
index 0000000..cadc043
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_orbit.html
@@ -0,0 +1,50 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Orbit test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ var view = surface.createViewport();
+ var m = dojox.gfx3d.matrix;
+
+ view.createOrbit({center: {x: 0, y: 0, z: 0}, radius: 80})
+ .setStroke({color: "blue", width: 1});
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateXg(60),
+ m.cameraRotateYg(30),
+ m.cameraRotateZg(0),
+ m.cameraTranslate(-300, -100, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+};
+
+mdebug = function(matrix){
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ console.debug("xx: " + m.xx + ", xy: " + m.xy + " | xz:" + m.xz + " | dx:" + m.dx);
+ console.debug("yx: " + m.yx + ", yy: " + m.yy + " | yz:" + m.yz + " | dy:" + m.dy);
+ console.debug("zx: " + m.zx + ", zy: " + m.zy + " | zz:" + m.zz + " | dz:" + m.dz);
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+ <h1>Orbit Test</h1>
+ <p>Test how orbit looks like in 3D</p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_overlap.html b/includes/js/dojox/gfx3d/tests/test_overlap.html
new file mode 100644
index 0000000..19f63d5
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_overlap.html
@@ -0,0 +1,69 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Test of dojox.gfx3d.scheduler</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+var view = null;
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ view = surface.createViewport();
+ var tas = [
+ [{x: 100, y: 0, z: 0}, {x: 100, y: 100, z: 0}, {x: 50, y: 50, z: 50}],
+ [{x: 100, y: 0, z: 0}, {x: 100, y: 100, z: 0}, {x: 0, y: 70, z: 50}]
+ ];
+ var fills = ["#0cc", "#c0c"];
+
+ var m = dojox.gfx3d.matrix;
+ for(var i = 0; i < tas.length; i++){
+ console.debug(fills[i]);
+ view.createPolygon(tas[i])
+ .setStroke({color: "blue", width: 1})
+ .setFill(fills[i]);
+ }
+ var camera = dojox.gfx3d.matrix.normalize([m.cameraTranslate(0, -300, 0)]);
+
+ view.applyCameraTransform(camera);
+
+ view.render();
+
+ // set up the click handlers.
+ dojo.connect(dojo.byId("bsp"), "onclick", renderWithBSP);
+ dojo.connect(dojo.byId("zorder"), "onclick", renderWithZOrder);
+};
+
+render = function(title, render){
+ dojo.byId("render").innerHTML = title;
+ view.setScheduler(render);
+ view.invalidate();
+ view.render();
+};
+
+renderWithBSP = function(){
+ render("BSP", dojox.gfx3d.scheduler.bsp);
+};
+
+renderWithZOrder = function(){
+ render("ZOrder", dojox.gfx3d.scheduler.zOrder);
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+<h1>Scheduler Test</h1>
+<p>There are two schedulers available in dojox.gfx3d, zOrder and BSP. zOrder is much simpler, and it performs quite well in most cases, it may fail in some rare cases, for example: two triangles share the same two vertice, and have the same Z value of the third vertex, in this case, they have the same z-order. They are rendered in arbitary order. In this case, BSP is the rescure.</p>
+<p>Current render: <strong id="render">default</strong></p>
+<p><button id="bsp">BSP</button>&nbsp;<button id="zorder">zOrder</button></p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_polygon.html b/includes/js/dojox/gfx3d/tests/test_polygon.html
new file mode 100644
index 0000000..ab9f174
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_polygon.html
@@ -0,0 +1,44 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Polygon test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ var view = surface.createViewport();
+ var poly = [{x: 0, y: 0, z: 0}, {x: 0, y: 100, z: 0}, {x: 100, y: 100, z: 0}, {x: 100, y: 0, z: 0}];
+
+ var m = dojox.gfx3d.matrix;
+ t = view.createPolygon(poly)
+ .setStroke({color: "blue", width: 1})
+ .setFill("#cc0");
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateXg(30),
+ m.cameraRotateYg(30),
+ //m.cameraRotateZg(15),
+ m.cameraTranslate(-0, 0, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+<h1>Polygon Test</h1>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_quads.html b/includes/js/dojox/gfx3d/tests/test_quads.html
new file mode 100644
index 0000000..aff3b3b
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_quads.html
@@ -0,0 +1,78 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Quads test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ var view = surface.createViewport();
+ var strip = [
+ {x: 50, y: 0, z: 0},
+ {x: 70, y: 0, z: 60},
+ {x: 0, y: 70, z: 60},
+ {x: 0, y: 50, z: 0},
+ {x: -50, y: 0, z: 0},
+ {x: -70, y: 0, z: 60},
+ {x: 0, y: -70, z: 60},
+ {x: 0, y: -50, z: 0}
+ ];
+
+ var normal = [
+ {x: 50, y: 0, z: 0},
+ {x: 70, y: 0, z: 60},
+ {x: 0, y: 70, z: 60},
+ {x: 0, y: 50, z: 0},
+ {x: 0, y: 70, z: 60},
+ {x: 0, y: 50, z: 0},
+ {x: -50, y: 0, z: 0},
+ {x: -70, y: 0, z: 60}
+ ];
+
+ var m = dojox.gfx3d.matrix;
+ view.createQuads(normal)
+ .setStroke({color: "blue", width: 1})
+ .setFill("#f00")
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 500, z: 10}));
+
+ view.createQuads(strip, "strip")
+ .setStroke({color: "red", width: 1})
+ .setFill("#0f0")
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 200, z: 10}));
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateXg(30),
+ m.cameraRotateYg(30),
+ m.cameraRotateXg(50),
+ m.cameraTranslate(-100, -100, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+};
+
+mdebug = function(matrix){
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ console.debug("xx: " + m.xx + ", xy: " + m.xy + " | xz:" + m.xz + " | dx:" + m.dx);
+ console.debug("yx: " + m.yx + ", yy: " + m.yy + " | yz:" + m.yz + " | dy:" + m.dy);
+ console.debug("zx: " + m.zx + ", zy: " + m.zy + " | zz:" + m.zz + " | dz:" + m.dz);
+};
+
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+<h1>Quads Test</h1>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_rotate.html b/includes/js/dojox/gfx3d/tests/test_rotate.html
new file mode 100644
index 0000000..53c212f
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_rotate.html
@@ -0,0 +1,123 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Rotate test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+ @import "../../../dijit/themes/tundra/tundra.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+var angles = {x: 0, y: 0, z: 0};
+var cube = null;
+var view = null;
+
+rotate = function(){
+ var m = dojox.gfx3d.matrix;
+
+ if(dojo.byId('rx').checked){
+ angles.x += 10;
+ }
+ if(dojo.byId('ry').checked){
+ angles.y += 10;
+ }
+ if(dojo.byId('rz').checked){
+ angles.z += 10;
+ }
+ var t = m.normalize([
+ m.cameraRotateXg(angles.x),
+ m.cameraRotateYg(angles.y),
+ m.cameraRotateZg(angles.z),
+ ]);
+ cube.setTransform(t);
+ cube.invalidate();
+ view.render();
+}
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ view = surface.createViewport();
+ var c = {bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}};
+ var xaxis = [
+ {x: 0, y: 0, z: 0},
+ {x: 200, y: 0, z: 0}
+ ];
+
+ var yaxis = [
+ {x: 0, y: 0, z: 0},
+ {x: 0, y: 200, z: 0}
+ ];
+
+ var zaxis = [
+ {x: 0, y: 0, z: 0},
+ {x: 0, y: 0, z: 200}
+ ];
+
+ var m = dojox.gfx3d.matrix;
+
+ view.createEdges(xaxis).setStroke({color: "red", width: 1});
+ view.createEdges(yaxis).setStroke({color: "green", width: 1});
+ view.createEdges(zaxis).setStroke({color: "blue", width: 1});
+
+ cube = view.createCube(c).setStroke({color: "lime", width: 1});
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateXg(20),
+ m.cameraRotateYg(30),
+ m.cameraTranslate(-100, -100, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+ window.setInterval(rotate, 200);
+
+ // add the click event handler
+ dojo.connect(dojo.byId("conservative"), "onclick", drawWithConservative);
+ dojo.connect(dojo.byId("chart"), "onclick", drawWithChart);
+};
+
+draw = function(title, drawer){
+ dojo.byId("drawer").innerHTML = title;
+ view.setDrawer(drawer);
+};
+
+drawWithConservative = function(){
+ draw("Conservative", dojox.gfx3d.drawer.conservative);
+};
+
+drawWithChart = function(){
+ draw("Chart", dojox.gfx3d.drawer.chart);
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body class="tundra">
+ <h1>Pilot Test</h1>
+ <p>There are two drawers(well, the name is quite misleading, it means draw-er) in dojox.gfx3d, conservative and chart:</p>
+ <ul>
+ <li><em>conservative</em> drawer is a pessimist, it assumes that the movement, transformation of objects would take a big fat impact to the viewport, so it not only render the modified objects, but also reorder all the underlying 2D shapes and redraw them.</li>
+ <li> <em>chart</em> drawer is an optimist, it assumes the change of the objects does not take effect on the z-order, this is most likely true in chart application. It only render and then draw the modified objects.</li>
+ </ul>
+ <p>The cube is in the center (0, 0, 0): The color of X, Y, Z axes are red, green, blue as the reference. The cube would rotate around X, Y, Z or their combination, it is up to you.</p>
+ <p>Current Drawer: <strong id="drawer">Conservative</strong></p>
+<form>
+ <input id="conservative" type="button" value="Draw with conservative"/>
+ <input id="chart" type="button" value="Draw with chart"/><br />
+ <input id="rx" type="checkbox" name="rotateX" checked="true" value="on"/>
+ <label for="rx"> Rotate around X-axis</label> <br/>
+ <input id="ry" type="checkbox" name="rotateY" checked="false" value="off"/>
+ <label for="ry"> Rotate around Y-axis</label> <br/>
+ <input id="rz" type="checkbox" name="rotateZ" checked="false" value="off"/>
+ <label for="rz"> Rotate around Z-axis</label> <br/>
+</form>
+
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_scene.html b/includes/js/dojox/gfx3d/tests/test_scene.html
new file mode 100644
index 0000000..231b289
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_scene.html
@@ -0,0 +1,66 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Scene test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+var view = null;
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ view = surface.createViewport();
+ var c = {bottom: {x: 0, y: 0, z: 0}, top: {x: 100, y: 100, z: 100}};
+ var m = dojox.gfx3d.matrix;
+
+ var sc1 = view.createScene();
+ sc1.createCube(c).setStroke({color: "blue", width: 1});
+
+ var sc2 = view.createScene();
+ sc2.createCube(c).setStroke({color: "red", width: 1}).setFill("lime");
+
+ var poly = [{x: 0, y: 0, z: 0}, {x: 0, y: 100, z: 0}, {x: 100, y: 100, z: 0}, {x: 100, y: 0, z: 0}];
+ sc2.createPolygon(poly)
+ .setStroke({color: "blue", width: 1})
+ .setTransform(dojox.gfx3d.matrix.translate(50, 20, 30))
+ .setFill("yellow");
+
+ sc2.setTransform(dojox.gfx3d.matrix.translate(100, 200, 30))
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateXg(30),
+ m.cameraRotateYg(60),
+ m.cameraTranslate(0, 0, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+
+ // set up the click handlers.
+ dojo.connect(dojo.byId("rotate"), "onclick", rotate);
+};
+
+rotate = function() {
+ view.applyCameraTransform(dojox.gfx3d.matrix.rotateXg(10));
+ view.invalidate();
+ view.render();
+};
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+<h1>Scene Test</h1>
+<p>Test the setTransform of the Scene. the lime cube and yellow polygon are grouped in one Scene, and they are moved in one shot.</p>
+<p>Test Viewport.invalidate with Scene. <input id="rotate" type="button" value="Rotate around Z-Axis"/></p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_triangles.html b/includes/js/dojox/gfx3d/tests/test_triangles.html
new file mode 100644
index 0000000..cc4e65b
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_triangles.html
@@ -0,0 +1,82 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Triangles test of dojox.gfx3d.</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d");
+
+makeObjects = function(){
+ var surface = dojox.gfx.createSurface("test", 500, 500);
+ var view = surface.createViewport();
+ var points = [
+ {x: 0, y: 0, z: 150},
+ {x: 50, y: 0, z: 0},
+ {x: 0, y: 50, z: 0},
+ {x: 0, y: 0, z: 150},
+ {x: 50, y: 0, z: 0},
+ {x: 0, y: -50, z: 0}
+ ];
+ var fan = [
+ {x: 0, y: 0, z: 150},
+ {x: 50, y: 0, z: 0},
+ {x: 0, y: 50, z: 0},
+ {x: -50, y: 0, z: 0},
+ {x: 0, y: -50, z: 0}
+ ];
+ var strip = [
+ {x: 0, y: -50, z: 0},
+ {x: 0, y: 0, z: 150},
+ {x: 50, y: 0, z: 0},
+ {x: 0, y: 50, z: 0}
+ ];
+
+ var m = dojox.gfx3d.matrix;
+ var normal = view.createTriangles(points)
+ .setStroke({color: "blue", width: 1})
+ .setFill("#ccc")
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 0, y: 0, z: 10}));
+
+ view.createTriangles(strip, "strip")
+ .setStroke({color: "red", width: 1})
+ .setFill("#ccc")
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 150, y: 0, z: 10}));
+
+ view.createTriangles(fan, "fan")
+ .setStroke({color: "lime", width: 1})
+ .setFill("#ccc")
+ .applyTransform(dojox.gfx3d.matrix.translate({x: 300, y: 0, z: 10}));
+
+ var camera = dojox.gfx3d.matrix.normalize([
+ m.cameraRotateXg(-30),
+ m.cameraRotateYg(-10),
+ m.cameraTranslate(-50, -100, 0)
+ ]);
+
+ view.applyCameraTransform(camera);
+ view.render();
+};
+
+mdebug = function(matrix){
+ var m = dojox.gfx3d.matrix.normalize(matrix);
+ console.debug("xx: " + m.xx + ", xy: " + m.xy + " | xz:" + m.xz + " | dx:" + m.dx);
+ console.debug("yx: " + m.yx + ", yy: " + m.yy + " | yz:" + m.yz + " | dy:" + m.dy);
+ console.debug("zx: " + m.zx + ", zy: " + m.zy + " | zz:" + m.zz + " | dz:" + m.dz);
+};
+
+
+dojo.addOnLoad(makeObjects);
+
+</script>
+</head>
+<body>
+<h1>Path3d Test</h1>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/tests/test_vector.html b/includes/js/dojox/gfx3d/tests/test_vector.html
new file mode 100644
index 0000000..371d57e
--- /dev/null
+++ b/includes/js/dojox/gfx3d/tests/test_vector.html
@@ -0,0 +1,59 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Dojo 3D Vector</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+ @import "../../../dojo/resources/dojo.css";
+ @import "../../../dijit/tests/css/dijitTests.css";
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx3d.vector");
+
+pdebug = function(point){
+ console.debug("x: " + point.x + ", y: " + point.y + ", z: " + point.z);
+};
+
+dojo.addOnLoad(function(){
+ var m = dojox.gfx3d.vector;
+ console.debug("test crossProduct...");
+ c = m.crossProduct(1, 2, 3, 4, 5, 6);
+ pdebug(c);
+ a = {x: 1, y: 2, z: 3};
+ b = {x: 4, y: 5, z: 6};
+ c = m.crossProduct(a, b);
+ pdebug(c);
+
+ console.debug("test dotProduct...");
+ c = m.dotProduct(1, 2, 3, 4, 5, 6);
+ console.debug(c);
+ a = {x: 1, y: 2, z: 3};
+ b = {x: 4, y: 5, z: 6};
+ c = m.dotProduct(a, b);
+ console.debug(c);
+
+ console.debug("test sum/substract...");
+ a = {x: 10, y: 5, z: 8};
+ b = {x: 1, y: 15, z: 2};
+ console.debug(m.sum(a, b));
+ console.debug(m.substract(a, b));
+
+ console.debug("test normalize...");
+ c = {x: 0, y: 17, z: -2};
+ d = m.normalize(a, b, c);
+ e = m.normalize([a, b, c]);
+ console.debug(d);
+ console.debug( "expecting 0:", m.dotProduct(d, m.substract(b, a)));
+ console.debug(e);
+ console.debug( "expecting 0:", m.dotProduct(e, m.substract(b, a)));
+
+});
+
+</script>
+</head>
+<body>
+ <h1>dojox.gfx3d.vector test</h1>
+ <p>Please check the debug console for test results.</p>
+</body>
+</html>
diff --git a/includes/js/dojox/gfx3d/vector.js b/includes/js/dojox/gfx3d/vector.js
new file mode 100644
index 0000000..7225273
--- /dev/null
+++ b/includes/js/dojox/gfx3d/vector.js
@@ -0,0 +1,110 @@
+if(!dojo._hasResource["dojox.gfx3d.vector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.gfx3d.vector"] = true;
+dojo.provide("dojox.gfx3d.vector");
+
+dojo.mixin(dojox.gfx3d.vector, {
+ sum: function(){
+ // summary: sum of the vectors
+ var v = {x: 0, y: 0, z:0};
+ dojo.forEach(arguments, function(item){ v.x += item.x; v.y += item.y; v.z += item.z; });
+ return v;
+ },
+
+ center: function(){
+ // summary: center of the vectors
+ var l = arguments.length;
+ if(l == 0){
+ return {x: 0, y: 0, z: 0};
+ }
+ var v = dojox.gfx3d.vector.sum(arguments);
+ return {x: v.x/l, y: v.y/l, z: v.z/l};
+ },
+
+ substract: function(/* Pointer */a, /* Pointer */b){
+ return {x: a.x - b.x, y: a.y - b.y, z: a.z - b.z};
+ },
+
+ _crossProduct: function(x, y, z, u, v, w){
+ // summary: applies a cross product of two vectorss, (x, y, z) and (u, v, w)
+ // x: Number: an x coordinate of a point
+ // y: Number: a y coordinate of a point
+ // z: Number: a z coordinate of a point
+ // u: Number: an x coordinate of a point
+ // v: Number: a y coordinate of a point
+ // w: Number: a z coordinate of a point
+ return {x: y * w - z * v, y: z * u - x * w, z: x * v - y * u}; // Object
+ },
+
+ crossProduct: function(/* Number||Point */ a, /* Number||Point */ b, /* Number, optional */ c, /* Number, optional */ d, /* Number, optional */ e, /* Number, optional */ f){
+ // summary: applies a matrix to a point
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // a: Number: an x coordinate of a point
+ // b: Number: a y coordinate of a point
+ // c: Number: a z coordinate of a point
+ // d: Number: an x coordinate of a point
+ // e: Number: a y coordinate of a point
+ // f: Number: a z coordinate of a point
+ if(arguments.length == 6 && dojo.every(arguments, function(item){ return typeof item == "number"; })){
+ return dojox.gfx3d.vector._crossProduct(a, b, c, d, e, f); // Object
+ }
+ // branch
+ // a: Object: a point
+ // b: Object: a point
+ // c: null
+ // d: null
+ // e: null
+ // f: null
+ return dojox.gfx3d.vector._crossProduct(a.x, a.y, a.z, b.x, b.y, b.z); // Object
+ },
+
+ _dotProduct: function(x, y, z, u, v, w){
+ // summary: applies a cross product of two vectorss, (x, y, z) and (u, v, w)
+ // x: Number: an x coordinate of a point
+ // y: Number: a y coordinate of a point
+ // z: Number: a z coordinate of a point
+ // u: Number: an x coordinate of a point
+ // v: Number: a y coordinate of a point
+ // w: Number: a z coordinate of a point
+ return x * u + y * v + z * w; // Number
+ },
+ dotProduct: function(/* Number||Point */ a, /* Number||Point */ b, /* Number, optional */ c, /* Number, optional */ d, /* Number, optional */ e, /* Number, optional */ f){
+ // summary: applies a matrix to a point
+ // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
+ // a: Number: an x coordinate of a point
+ // b: Number: a y coordinate of a point
+ // c: Number: a z coordinate of a point
+ // d: Number: an x coordinate of a point
+ // e: Number: a y coordinate of a point
+ // f: Number: a z coordinate of a point
+ if(arguments.length == 6 && dojo.every(arguments, function(item){ return typeof item == "number"; })){
+ return dojox.gfx3d.vector._dotProduct(a, b, c, d, e, f); // Object
+ }
+ // branch
+ // a: Object: a point
+ // b: Object: a point
+ // c: null
+ // d: null
+ // e: null
+ // f: null
+ return dojox.gfx3d.vector._dotProduct(a.x, a.y, a.z, b.x, b.y, b.z); // Object
+ },
+
+ normalize: function(/* Point||Array*/ a, /* Point */ b, /* Point */ c){
+ // summary: find the normal of the implicit surface
+ // a: Object: a point
+ // b: Object: a point
+ // c: Object: a point
+ var l, m, n;
+ if(a instanceof Array){
+ l = a[0]; m = a[1]; n = a[2];
+ }else{
+ l = a; m = b; n = c;
+ }
+
+ var u = dojox.gfx3d.vector.substract(m, l);
+ var v = dojox.gfx3d.vector.substract(n, l);
+ return dojox.gfx3d.vector.crossProduct(u, v);
+ }
+});
+
+}