Mercurial > hg > extraction-interface
diff geotemco/lib/excanvas/examples/example2.html @ 0:b12c99b7c3f0
commit for previous development
author | Zoe Hong <zhong@mpiwg-berlin.mpg.de> |
---|---|
date | Mon, 19 Jan 2015 17:13:49 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geotemco/lib/excanvas/examples/example2.html Mon Jan 19 17:13:49 2015 +0100 @@ -0,0 +1,513 @@ +<!-- + Copyright 2006 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<html> +<head> + <title>ExplorerCanvas Example 1</title> + <!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]--> + <script type="text/javascript"> + /* -------------------------------------------------------------------- */ + + var canvas, ctx; + var canvasWidth, halfCanvasWidth; + var canvasHeight, halfCanvasHeight; + + var space; // 3D Engine + var scene; // 3D Scene + + /* -------------------------------------------------------------------- */ + + /** + * Space is a simple 3D system. + * + * Y+ = up + * Z+ = into screen + * X+ = right + */ + function Space() { + this.m = this.createMatrixIdentity(); + this.mStack = []; + } + + Space.prototype.createMatrixIdentity = function() { + return [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1] + ]; + } + + /** + * Multiplies two 4x4 matricies together. + */ + Space.prototype.matrixMultiply = function(m1, m2) { + var result = this.createMatrixIdentity(); + + var width = m1[0].length; + var height = m1.length; + + if (width != m2.length) { + // error + } + + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + var sum = 0; + + for (var z = 0; z < width; z++) { + sum += m1[y][z] * m2[z][x]; + } + + result[y][x] = sum; + } + } + + return result; + } + + /** + * Transforms a coordinate using the current transformation + * matrix, then flattens it using the projection matrix. + */ + Space.prototype.flatten = function(point) { + var p = [[point.x, point.y, point.z, 1]]; + var pm = this.matrixMultiply(p, this.m); + + point.tx = pm[0][0]; + point.ty = pm[0][1]; + point.tz = pm[0][2]; + + // lazy projection + point.fx = halfCanvasWidth + (canvasWidth * point.tx / point.tz); + point.fy = halfCanvasHeight -(canvasWidth * point.ty / point.tz); + } + + /** + * Translate (move) the current transformation matrix + */ + Space.prototype.translate = function(x, y, z) { + var m = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [x, y, z, 1] + ]; + + this.m = this.matrixMultiply(m, this.m); + } + + /** + * Rotate the current transformation matrix. Rotations are + * world-oriented, and occur in y,x,z order. + */ + Space.prototype.rotate = function(x, y, z) { + if (y) { + var cosY = Math.cos(y); + var sinY = Math.sin(y); + var rotY = [ + [cosY, 0, sinY, 0], + [0, 1, 0, 0], + [-sinY, 0, cosY, 0], + [0, 0, 0, 1] + ]; + + this.m = this.matrixMultiply(this.m, rotY); + } + + if (x) { + var cosX = Math.cos(x); + var sinX = Math.sin(x); + var rotX = [ + [1, 0, 0, 0], + [0, cosX, -sinX, 0], + [0, sinX, cosX,0], + [0, 0, 0, 1] + ]; + this.m = this.matrixMultiply(this.m, rotX); + } + + if (z) { + var cosZ = Math.cos(z); + var sinZ = Math.sin(z); + var rotZ = [ + [cosZ, -sinZ, 0, 0], + [sinZ, cosZ, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1] + ]; + + this.m = this.matrixMultiply(this.m, rotZ); + } + } + + /** + * Pushes the current transformation onto the stack + */ + Space.prototype.push = function() { + this.mStack.push(this.m); + this.m = [ + [this.m[0][0], this.m[0][1], this.m[0][2], this.m[0][3]], + [this.m[1][0], this.m[1][1], this.m[1][2], this.m[1][3]], + [this.m[2][0], this.m[2][1], this.m[2][2], this.m[2][3]], + [this.m[3][0], this.m[3][1], this.m[3][2], this.m[3][3]] + ]; + } + + /** + * Pops the end off the transformation stack + */ + Space.prototype.pop = function() { + this.m = this.mStack.pop(); + } + + /* -------------------------------------------------------------------- */ + + /** + * A 3d coordinate + */ + function Point(x, y, z) { + this.x = x; + this.y = y; + this.z = z; + + // Relative to camera coordinates + this.tx; + this.ty; + this.tz; + + // Flattened coordinates + this.fx; + this.fy; + } + + /** + * A Shape is made up of polygons + */ + function Shape() { + this.points = []; + this.polygons = []; + } + + /** + * Draws the shape + */ + Shape.prototype.draw = function(drawlist) { + for (var i = 0; i< this.points.length; i++) { + space.flatten(this.points[i]); + } + + for (var i = 0; i< this.polygons.length; i++) { + var poly = this.polygons[i]; // convenience + + space.flatten(poly.origin); + + // lazy backface culling + if (poly.normal && this.backface) { + space.flatten(poly.normal); + + var originDist = Math.pow(poly.origin.tx, 2) + + Math.pow(poly.origin.ty, 2) + + Math.pow(poly.origin.tz, 2); + + var normalDist = Math.pow(poly.normal.tx, 2) + + Math.pow(poly.normal.ty, 2) + + Math.pow(poly.normal.tz, 2); + + if(originDist > normalDist) { + drawlist.push(poly); + } + } else { + drawlist.push(poly); + } + } + } + + /** + * A polygon is a connection of points in the shape object. You + * should probably try to make them coplanar. + */ + function Polygon(points, normal, backface, type, color) { + this.points = points; + + this.origin = new Point(0, 0, 0); + for(var i = 0; i < this.points.length; i++) { + this.origin.x += this.points[i].x; + this.origin.y += this.points[i].y; + this.origin.z += this.points[i].z; + } + + this.origin.x /= this.points.length; + this.origin.y /= this.points.length; + this.origin.z /= this.points.length; + + if (normal) { + this.normal = new Point(this.origin.x + normal.x, + this.origin.y + normal.y, + this.origin.z + normal.z); + } else { + this.normal = null; + } + + this.backface = backface; + this.type = type; + this.color = color; + } + + Polygon.SOLID = 0; + Polygon.WIRE = 1; + + /** + * Draws the polygon. Assumes that the points have already been + * flattened. + */ + Polygon.prototype.draw = function() { + ctx.beginPath(); + ctx.moveTo(this.points[0].fx, this.points[0].fy); + + for(var i = 0; i < this.points.length; i++) { + ctx.lineTo(this.points[i].fx, this.points[i].fy); + } + + ctx.closePath(); + + var color = this.color; + + /* + // Do lighting here + lightvector = Math.abs(this.normal.x + this.normal.y); + if(lightvector > 1) { + lightvector = 1; + } + + color[0] = (color[0] * lightvector).toString(); + color[1] = (color[1] * lightvector).toString(); + color[2] = (color[2] * lightvector).toString(); + */ + + if (color.length > 3) { + var style = ["rgba(", + color[0], ",", + color[1], ",", + color[2], ",", + color[3], ")"].join(""); + } else { + var style = ["rgb(", + color[0], ",", + color[1], ",", + color[2], ")"].join(""); + } + + if (this.type == Polygon.SOLID) { + ctx.fillStyle = style; + ctx.fill(); + } else if (this.type == Polygon.WIRE) { + ctx.strokeStyle = style; + ctx.stroke(); + } + } + + /* -------------------------------------------------------------------- */ + + /** + * Scene describes the 3D environment + */ + function Scene() { + this.shapes = {}; + this.camera = new Point(0, 0, 0); + this.cameraTarget = new Point(0, 0, 0); + this.cameraRotation = 0; + + this.drawlist = []; + } + + /** + * Draw the world + */ + Scene.prototype.draw = function() { + space.push(); + + // Camera transformation + space.translate( + -this.camera.x, + -this.camera.y, + -this.camera.z + ); + + // Camera rotation + var xdiff = this.cameraTarget.x - this.camera.x; + var ydiff = this.cameraTarget.y - this.camera.y; + var zdiff = this.cameraTarget.z - this.camera.z; + + var xzdist = Math.sqrt(Math.pow(xdiff, 2) + Math.pow(zdiff, 2)); + + var xrot = -Math.atan2(ydiff, xzdist); // up/down rotation + var yrot = Math.atan2(xdiff, zdiff); // left/right rotation + + space.rotate(xrot, yrot, this.cameraRotation); + + // Drawing + this.drawlist = []; + + for(var i in this.shapes) { + this.shapes[i].draw(this.drawlist); + } + + // Depth sorting (warning: this is only enough to drive this demo - feel + // free to contribute a better system). + this.drawlist.sort(function (poly1, poly2) { + return poly2.origin.tz - poly1.origin.tz; + }); + + for (var i = 0; i < this.drawlist.length; i++) { + this.drawlist[i].draw(); + } + + space.pop(); + } + + /* -------------------------------------------------------------------- */ + + var count = 0; + + function loop() { + ctx.clearRect(0, 0, canvasWidth, canvasHeight); + + scene.camera.x = 70*Math.sin(count); + scene.camera.y = 70; + scene.camera.z = 70*Math.cos(count); + scene.cameraRotation = count / 10; + + count += 0.01; + scene.draw(); + } + + function load() { + // Init drawing system + canvas = document.getElementById("cv"); + ctx = canvas.getContext("2d"); + + canvasWidth = canvas.width; + canvasHeight = canvas.height; + halfCanvasWidth = canvasWidth * 0.5; + halfCanvasHeight = canvasHeight * 0.5; + + // Init 3D components + space = new Space(); + scene = new Scene(); + + // Create a box shape and add it to the scene + scene.shapes['box'] = new Shape(); + var p = scene.shapes['box'].points; // for convenience + + p[0] = new Point(-10, -10, -10); // left bottom front + p[1] = new Point(10, -10, -10); // right bottom front + p[2] = new Point(10, 10, -10); // right top front + p[3] = new Point(-10, 10, -10); // left top front + + p[4] = new Point(-10, -10, 10); // left bottom back + p[5] = new Point(10, -10, 10); // right bottom back + p[6] = new Point(10, 10, 10); // right top back + p[7] = new Point(-10, 10, 10); // left top back + + // Back + scene.shapes['box'].polygons.push(new Polygon( + [ p[0], p[1], p[2], p[3] ], + new Point(0, 0, -1), + true /* double-sided */, + Polygon.SOLID, + [255, 0, 0] + )); + + // Front + scene.shapes['box'].polygons.push(new Polygon( + [ p[4], p[5], p[6], p[7] ], + new Point(0, 0, 1), + true /* double-sided */, + Polygon.SOLID, + [0, 0, 255] + )); + + // Top + scene.shapes['box'].polygons.push(new Polygon( + [ p[2], p[3], p[7], p[6] ], + new Point(0, 1, 0), + false /* single-sided */, + Polygon.WIRE, + [0, 255, 0] + )); + + // Transparent Top + scene.shapes['box'].polygons.push(new Polygon( + [ p[2], p[3], p[7], p[6] ], + new Point(0, 1, 0), + false /* single-sided */, + Polygon.SOLID, + [0, 255, 0, 0.4] + )); + + // Left + scene.shapes['box'].polygons.push(new Polygon( + [ p[0], p[4], p[7], p[3] ], + new Point(-1, 0, 0), + true /* double-sided */, + Polygon.SOLID, + [255, 255, 0] + )); + + // Right + scene.shapes['box'].polygons.push(new Polygon( + [ p[1], p[5], p[6], p[2] ], + new Point(1, 0, 0), + true /* double-sided */, + Polygon.SOLID, + [0, 255, 255] + )); + + // Create a floor shape and add it to the scene + scene.shapes['floor'] = new Shape(); + var p = scene.shapes['floor'].points; // for convenience + + p[0] = new Point(-40, -10, -40); + p[1] = new Point(-40, -10, 40); + p[2] = new Point( 40, -10, 40); + p[3] = new Point( 40, -10, -40); + + // Floor + scene.shapes['floor'].polygons.push(new Polygon( + [ p[0], p[1], p[2], p[3] ], + new Point(0, 1, 0), + false /* single-sided */, + Polygon.SOLID, + [45, 45, 45] + )); + + setInterval('loop()', 20); + } + + /* -------------------------------------------------------------------- */ + </script> + <style> + body { + background-color:black; + margin:50px; + text-align:center; + } + </style> +</head> +<body onload="load();"> + <canvas id="cv" width="400" height="300"></canvas> +</body> +</html> \ No newline at end of file