| Index: samples/openglui/src/openglui_canvas_tests.dart
|
| diff --git a/samples/openglui/src/openglui_canvas_tests.dart b/samples/openglui/src/openglui_canvas_tests.dart
|
| deleted file mode 100644
|
| index b9b394704b5abc4a7c08630624e7e5cae7353b89..0000000000000000000000000000000000000000
|
| --- a/samples/openglui/src/openglui_canvas_tests.dart
|
| +++ /dev/null
|
| @@ -1,1047 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -//
|
| -// Canvas API tests. Some of these are adapted from:
|
| -//
|
| -// http://www.html5canvastutorials.com/
|
| -
|
| -library openglui_canvas_tests;
|
| -
|
| -import 'gl.dart';
|
| -import 'dart:math' as Math;
|
| -
|
| -var ctx;
|
| -var width, height;
|
| -bool isDirty = true;
|
| -var canvas;
|
| -
|
| -void resize(int w, int h) {
|
| - width = w;
|
| - height = h;
|
| -}
|
| -
|
| -void setup(canvasp, int w, int h, int f) {
|
| - if (canvasp == null) {
|
| - log("Allocating canvas");
|
| - canvas = new CanvasElement(width: w, height: h);
|
| - document.body.nodes.add(canvas);
|
| - } else {
|
| - log("Using parent canvas");
|
| - canvas = canvasp;
|
| - }
|
| - canvas.onMouseDown.listen((e) {
|
| - ++testnum;
|
| - isDirty = true;
|
| - });
|
| - canvas.onKeyDown.listen((e) {
|
| - ++testnum;
|
| - isDirty = true;
|
| - });
|
| - ctx = canvas.getContext("2d");
|
| - if (ctx == null) {
|
| - throw "Failed to get 2D context";
|
| - }
|
| - resize(w, h);
|
| - window.requestAnimationFrame(update);
|
| - log("Done setup");
|
| -}
|
| -
|
| -resetCanvas() {
|
| - ctx.globalCompositeOperation = "source-over";
|
| - ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| - ctx.fillStyle = "#FFFFFF";
|
| - ctx.clearRect(0, 0, width, height);
|
| - ctx.shadowOffsetX = ctx.shadowOffsetY = ctx.shadowBlur = 0.0;
|
| - ctx.beginPath();
|
| -}
|
| -
|
| -initTest(title) {
|
| - resetCanvas();
|
| - ctx.font = "15px Courier";
|
| - ctx.textAlign = 'left';
|
| - ctx.fillStyle = "black";
|
| - ctx.fillText(title, 20, 20);
|
| -}
|
| -
|
| -helloWorld() {
|
| - initTest("Hello world");
|
| - ctx.font = "30px Courier";
|
| - ctx.strokeStyle = "#7F7F7F";
|
| - ctx.fillStyle = "#7F7F7F";
|
| - ctx.textAlign = "center";
|
| - ctx.lineWidth = 2;
|
| - ctx.strokeText("Align Center", width / 2, height / 4);
|
| - ctx.textAlign = "left";
|
| - ctx.fillText("Align Left", width / 2, height / 2);
|
| - ctx.textAlign = "right";
|
| - ctx.fillText("Align Right", width / 2, 3 * height / 4);
|
| -}
|
| -
|
| -blocks() {
|
| - initTest("fillRect/strokeRect");
|
| - ctx.fillStyle = "#FF0000";
|
| - ctx.fillRect(width / 10, height / 10, width / 2, height / 25);
|
| - ctx.fillStyle = "#00FF00";
|
| - ctx.fillRect(width / 4, height / 5, width / 20, height / 8);
|
| - //ctx.fillStyle = "rgba(0,0,255,0.8)";
|
| - ctx.strokeStyle = "rgba(128,128,128, 0.5)";
|
| - //ctx.fillStyle = "#7F7F7F";
|
| - ctx.strokeRect(width / 5, height / 10, width / 2, height / 8);
|
| -}
|
| -
|
| -square(left, top, width, height) {
|
| - ctx.beginPath();
|
| - ctx.moveTo(left, top);
|
| - ctx.lineTo(left + width, top);
|
| - ctx.lineTo(left + width, top + height);
|
| - ctx.lineTo(left, top + height);
|
| - ctx.closePath(); //lineTo(left, top);
|
| -}
|
| -
|
| -squares() {
|
| - initTest("fill/stroke paths");
|
| - ctx.strokeStyle = "black";
|
| - ctx.fillStyle = "#FF0000";
|
| - ctx.lineWidth = 4;
|
| - square(width / 10, height / 10, width / 2, height / 25);
|
| - ctx.fill();
|
| - ctx.stroke();
|
| - ctx.fillStyle = "#00FF00";
|
| - square(width / 4, height / 5, width / 20, height / 8);
|
| - ctx.fill();
|
| - ctx.stroke();
|
| - ctx.fillStyle = "rgba(128,128,128, 0.5)";
|
| - square(width / 5, height / 10, width / 2, height / 8);
|
| - ctx.fill();
|
| - ctx.stroke();
|
| -}
|
| -
|
| -lineJoin() {
|
| - initTest("Line joins");
|
| - ctx.strokeStyle = "black";
|
| - ctx.fillStyle = "#FF0000";
|
| - ctx.lineWidth = 8;
|
| - ctx.lineJoin = "round";
|
| - square(width / 10, height / 10, width / 2, height / 25);
|
| - ctx.stroke();
|
| - ctx.fillStyle = "#00FF00";
|
| - ctx.lineJoin = "bevel";
|
| - square(width / 4, height / 5, width / 20, height / 8);
|
| - ctx.stroke();
|
| - ctx.fillStyle = "rgba(128,128,128, 0.5)";
|
| - ctx.lineJoin = "miter";
|
| - square(width / 5, height / 10, width / 2, height / 8);
|
| - ctx.stroke();
|
| -}
|
| -
|
| -grid() {
|
| - initTest("line strokes");
|
| - ctx.lineWidth = 1;
|
| - for (var x = 0.5; x < width; x += 10) {
|
| - ctx.moveTo(x, 0);
|
| - ctx.lineTo(x, height);
|
| - }
|
| - for (var y = 0.5; y < height; y += 10) {
|
| - ctx.moveTo(0, y);
|
| - ctx.lineTo(width, y);
|
| - }
|
| - ctx.strokeStyle = "#eee";
|
| - ctx.stroke();
|
| -}
|
| -
|
| -line(x1, y1, x2, y2) {
|
| - ctx.beginPath();
|
| - ctx.moveTo(x1, y1);
|
| - ctx.lineTo(x2, y2);
|
| -}
|
| -
|
| -strokeLines() {
|
| - initTest("line caps");
|
| - ctx.lineWidth = height / 40;
|
| - ctx.strokeStyle = '#0000ff';
|
| - // butt line cap (top line)
|
| - line(width / 4, height / 4, 3 * width / 4, height / 4);
|
| - ctx.lineCap = 'butt';
|
| - ctx.stroke();
|
| -
|
| - // round line cap (middle line)
|
| - line(width / 4, height / 2, 3 * width / 4, height / 2);
|
| - ctx.lineCap = 'round';
|
| - ctx.stroke();
|
| -
|
| - // square line cap (bottom line)
|
| - line(width / 4, 3 * height / 4, 3 * width / 4, 3 * height / 4);
|
| - ctx.lineCap = 'square';
|
| - ctx.stroke();
|
| -}
|
| -
|
| -colors() {
|
| - initTest("Colors");
|
| - var colors = [
|
| - "maroon",
|
| - "red",
|
| - "orange",
|
| - "yellow",
|
| - "olive",
|
| - "purple",
|
| - "fuschia",
|
| - "white",
|
| - "lime",
|
| - "green",
|
| - "navy",
|
| - "blue",
|
| - "aqua",
|
| - "teal",
|
| - "silver",
|
| - "gray",
|
| - "black"
|
| - ];
|
| -
|
| - var i = 1;
|
| - var yinc = height / (2 * colors.length + 1);
|
| -
|
| - ctx.textAlign = "center";
|
| - ctx.font = "${yinc}px Courier";
|
| -
|
| - for (var color in colors) {
|
| - ctx.fillStyle = color;
|
| - ctx.fillRect(width / 4, i * 2 * yinc, width / 2, 3 * yinc / 2);
|
| - ctx.fillStyle = (color == "gray") ? "white" : "gray";
|
| - ctx.fillText(color, width / 2, i * 2 * yinc + 7 * yinc / 8);
|
| - ++i;
|
| - }
|
| -}
|
| -
|
| -smiley() {
|
| - initTest("arcs");
|
| - ctx.translate(width / 2 - 80, height / 2 - 75);
|
| -
|
| - ctx.beginPath();
|
| - ctx.arc(100,80,75,0,Math.PI*2,true);
|
| - ctx.fillStyle = "rgb(255,255,204)";
|
| - ctx.fill();
|
| - ctx.stroke();
|
| -
|
| - ctx.fillStyle = "black";
|
| - ctx.beginPath();
|
| - ctx.arc(80,55,8,0,Math.PI*2,true);
|
| - ctx.fill();
|
| -
|
| - ctx.beginPath();
|
| - ctx.arc(120,55,8,0,Math.PI*2,true);
|
| - ctx.fill();
|
| -
|
| - ctx.beginPath();
|
| - ctx.arc(100,85,10,4,Math.PI*2,true);
|
| - ctx.stroke();
|
| -
|
| - ctx.beginPath();
|
| - ctx.arc(100,95,30,0,Math.PI,false);
|
| - ctx.stroke();
|
| -
|
| - ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| -}
|
| -
|
| -rot(txt1, [txt2, sx = 1.0, sy = 1.0]) {
|
| - if (txt2 == null) txt2 = txt1;
|
| - ctx.font = "50px sans serif";
|
| - ctx.translate(width / 2, height / 2);
|
| - ctx.textAlign = "right";
|
| - ctx.fillStyle = "red";
|
| - ctx.fillText(txt1, 0, 0);
|
| - ctx.rotate(Math.PI / 2);
|
| - ctx.scale(sx, sy);
|
| - ctx.fillStyle = "green";
|
| - ctx.fillText(txt2, 0, 0);
|
| - ctx.scale(sx, sy);
|
| - ctx.rotate(Math.PI / 2);
|
| - ctx.fillStyle = "blue";
|
| - ctx.fillText(txt1, 0, 0);
|
| - ctx.scale(sx, sy);
|
| - ctx.rotate(Math.PI / 2);
|
| - ctx.fillStyle = "yellow";
|
| - ctx.fillText(txt2, 0, 0);
|
| - ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| -}
|
| -
|
| -rotate() {
|
| - initTest("Rotation");
|
| - rot("Dart");
|
| -}
|
| -
|
| -alpha() {
|
| - initTest("Global alpha");
|
| - ctx.fillStyle = "gray";
|
| - ctx.fillRect(0, 0, width, height);
|
| - grid();
|
| - ctx.globalAlpha = 0.5;
|
| - rot("Global", "Alpha");
|
| - ctx.globalAlpha = 1.0;
|
| -}
|
| -
|
| -scale() {
|
| - initTest("Scale");
|
| - rot("Scale", "Test", 0.8, 0.5);
|
| -}
|
| -
|
| -curves() {
|
| - initTest("Curves");
|
| - ctx.beginPath();
|
| - ctx.moveTo(188, 150);
|
| - ctx.quadraticCurveTo(288, 0, 388, 150);
|
| - ctx.lineWidth = 2;
|
| - ctx.strokeStyle = 'red';
|
| - ctx.stroke();
|
| - ctx.beginPath();
|
| - ctx.moveTo(188, 130);
|
| - ctx.bezierCurveTo(140, 10, 388, 10, 388, 170);
|
| - ctx.lineWidth = 5;
|
| - ctx.strokeStyle = 'blue';
|
| - ctx.stroke();
|
| - var x1, x2, y1, y2, ex, ey;
|
| - ctx.beginPath();
|
| - x1 = width / 4;
|
| - y1 = height / 2;
|
| - x2 = width / 2;
|
| - y2 = height / 4;
|
| - ex = 3 * width / 4;
|
| - ey = y1;
|
| - ctx.moveTo(x1, x2);
|
| - ctx.quadraticCurveTo(x2, y2, ex, ey);
|
| - ctx.lineWidth = 10;
|
| - ctx.strokeStyle = 'green';
|
| - ctx.stroke();
|
| -
|
| - ctx.beginPath();
|
| - ctx.moveTo(188, 130);
|
| - x1 = width / 8;
|
| - x2 = 7 * width / 8;
|
| - y1 = height / 50;
|
| - y2 = y1;
|
| - ex = x2;
|
| - ey = height / 2;
|
| - ctx.bezierCurveTo(x1, y1, x2, y2, ex, ey);
|
| - ctx.lineWidth = 7;
|
| - ctx.strokeStyle = 'black';
|
| - ctx.stroke();
|
| -
|
| - // Draw a cloud
|
| - ctx.beginPath();
|
| - var wscale = width / 578;
|
| - var hscale = height / 800;
|
| - ctx.translate(0, height / 2);
|
| - ctx.moveTo(170 * wscale, 80 * hscale);
|
| - ctx.bezierCurveTo(130 * wscale, 100 * hscale,
|
| - 130 * wscale, 150 * hscale,
|
| - 230 * wscale, 150 * hscale);
|
| - ctx.bezierCurveTo(250 * wscale, 180 * hscale,
|
| - 320 * wscale, 180 * hscale,
|
| - 340 * wscale, 150 * hscale);
|
| - ctx.bezierCurveTo(420 * wscale, 150 * hscale,
|
| - 420 * wscale, 120 * hscale,
|
| - 390 * wscale, 100 * hscale);
|
| - ctx.bezierCurveTo(430 * wscale, 40 * hscale,
|
| - 370 * wscale, 30 * hscale,
|
| - 340 * wscale, 50 * hscale);
|
| - ctx.bezierCurveTo(320 * wscale, 5 * hscale,
|
| - 250 * wscale, 20 * hscale,
|
| - 250 * wscale, 50 * hscale);
|
| - ctx.bezierCurveTo(200 * wscale, 5 * hscale,
|
| - 150 * wscale, 20 * hscale,
|
| - 170 * wscale, 80 * hscale);
|
| - ctx.closePath();
|
| - ctx.lineWidth = 5;
|
| - ctx.fillStyle = 'gray';
|
| - ctx.fill();
|
| -}
|
| -
|
| -void shadows() {
|
| - initTest("Shadows");
|
| - ctx.shadowBlur=20;
|
| - ctx.shadowColor="black";
|
| - ctx.fillStyle="red";
|
| - var w = width / 2;
|
| - if (w > height / 2) w = height / 2;
|
| - ctx.fillRect(width / 2 - w / 2, height / 4 - w / 2, w, w);
|
| - ctx.shadowOffsetX = 10;
|
| - ctx.shadowOffsetY = 10;
|
| - ctx.shadowColor="green";
|
| - ctx.fillRect(width / 2 - w / 2, 3 * height / 4 - w / 2, w, w);
|
| -}
|
| -
|
| -void lineJoins() {
|
| - initTest("Line joins");
|
| - ctx.lineWidth=10;
|
| - ctx.lineJoin="miter";
|
| - ctx.moveTo(width / 2 - 25, height / 4 - 10);
|
| - ctx.lineTo(width /2 + 25, height / 4);
|
| - ctx.lineTo(width / 2 - 25, height / 4 + 10);
|
| - ctx.stroke();
|
| - ctx.lineJoin="round";
|
| - ctx.moveTo(width / 2 - 25, height / 2 - 10);
|
| - ctx.lineTo(width /2 + 25, height / 2);
|
| - ctx.lineTo(width / 2 - 25, height / 2 + 10);
|
| - ctx.stroke();
|
| - ctx.lineJoin="bevel";
|
| - ctx.moveTo(width / 2 - 25, 3 * height / 4 - 10);
|
| - ctx.lineTo(width /2 + 25, 3 * height / 4);
|
| - ctx.lineTo(width / 2 - 25, 3 * height / 4 + 10);
|
| - ctx.stroke();
|
| -}
|
| -
|
| -void saveRestore() {
|
| - initTest("Save/restore state");
|
| - ctx.font = "30px courier";
|
| - ctx.fillStyle = "red";
|
| - ctx.strokeStyle = "black";
|
| - ctx.shadowBlur = 5;
|
| - ctx.shadowColor = "green";
|
| - ctx.lineWidth = 1;
|
| - ctx.textAlign = "left";
|
| - ctx.rotate(Math.PI / 30);
|
| - ctx.fillText("State 1", width /2, height / 6);
|
| - ctx.strokeText("State 1", width /2, height / 6);
|
| - ctx.save();
|
| -
|
| - ctx.font = "40px sans serif";
|
| - ctx.fillStyle = "blue";
|
| - ctx.strokeStyle = "orange";
|
| - ctx.shadowBlur = 8;
|
| - ctx.shadowOffsetX = 5;
|
| - ctx.shadowColor = "black";
|
| - ctx.lineWidth = 2;
|
| - ctx.textAlign = "right";
|
| - ctx.rotate(Math.PI / 30);
|
| - ctx.fillText("State 2", width /2, 2 * height / 6);
|
| - ctx.strokeText("State 2", width /2, 2 * height / 6);
|
| - ctx.save();
|
| -
|
| - ctx.font = "50px times roman";
|
| - ctx.fillStyle = "yellow";
|
| - ctx.strokeStyle = "gray";
|
| - ctx.shadowBlur = 8;
|
| - ctx.shadowOffsetX = 5;
|
| - ctx.shadowColor = "red";
|
| - ctx.lineWidth = 3;
|
| - ctx.textAlign = "center";
|
| - ctx.rotate(-Math.PI / 15);
|
| - ctx.fillText("State 3", width /2, 3 * height / 6);
|
| - ctx.strokeText("State 3", width /2, 3 * height / 6);
|
| -
|
| - ctx.restore();
|
| - ctx.fillText("State 2", width /2, 4 * height / 6);
|
| - ctx.strokeText("State 2", width /2, 4 * height / 6);
|
| -
|
| - ctx.restore();
|
| - ctx.fillText("State 1", width /2, 5 * height / 6);
|
| - ctx.strokeText("State 1", width /2, 5 * height / 6);
|
| -}
|
| -
|
| -void mirror() {
|
| - initTest("Mirror");
|
| - // translate context to center of canvas
|
| - ctx.translate(width / 2, height / 2);
|
| -
|
| - // flip context horizontally
|
| - ctx.scale(-1, 1);
|
| -
|
| - ctx.font = '30pt Calibri';
|
| - ctx.textAlign = 'center';
|
| - ctx.fillStyle = 'blue';
|
| - ctx.fillText('Magic Mirror', 0, 0);
|
| -}
|
| -
|
| -void oval() {
|
| - initTest("Path - pop state - stroke");
|
| - var centerX = 0;
|
| - var centerY = 0;
|
| - var radius = 50;
|
| -
|
| - // save state
|
| - ctx.save();
|
| -
|
| - // translate context
|
| - ctx.translate(width / 2, height / 2);
|
| -
|
| - // scale context horizontally
|
| - ctx.scale(2, 1);
|
| -
|
| - // draw circle which will be stretched into an oval
|
| - ctx.beginPath();
|
| - ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
|
| -
|
| - // restore to original state
|
| - ctx.restore();
|
| -
|
| - // apply styling
|
| - ctx.fillStyle = '#8ED6FF';
|
| - ctx.fill();
|
| - ctx.lineWidth = 5;
|
| - ctx.strokeStyle = 'black';
|
| - ctx.stroke();
|
| -}
|
| -
|
| -void lineDash() {
|
| - initTest("Line dash");
|
| - ctx.setLineDash([ 5, 8, 3 ]);
|
| - ctx.strokeStyle = "#FF0000";
|
| - ctx.strokeRect(width / 10, height / 10, width / 2, height / 25);
|
| - ctx.lineDashOffset = 1;
|
| - ctx.strokeStyle = "#00FF00";
|
| - ctx.strokeRect(width / 4, height / 5, width / 20, height / 8);
|
| - ctx.setLineDash([]);
|
| - ctx.strokeStyle = "#0000FF";
|
| - ctx.strokeStyle = "rgba(128,128,128, 0.5)";
|
| - ctx.strokeRect(width / 5, height / 10, width / 2, height / 8);
|
| - log("Width = $width");
|
| -}
|
| -
|
| -void loadImage() {
|
| - initTest("Image loading");
|
| - var imageObj = new ImageElement();
|
| - // Setting src before onLoad is a more interesting test.
|
| - imageObj.src = 'chrome.png';
|
| - imageObj.onLoad.listen((e) {
|
| - ctx.drawImage(e.target, 0, 0, width, height, 0, 0, width, height);
|
| - });
|
| -}
|
| -
|
| -void clip() {
|
| - initTest("Clipping");
|
| - var x = width / 2;
|
| - var y = height / 2;
|
| - var radius = height / 4;
|
| - var offset = 2 * radius / 3;
|
| -
|
| - ctx.save();
|
| - ctx.beginPath();
|
| - ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
|
| - ctx.clip();
|
| -
|
| - // draw blue circle inside clipping region
|
| - ctx.beginPath();
|
| - ctx.arc(x - offset, y - offset, radius, 0, 2 * Math.PI, false);
|
| - ctx.fillStyle = 'blue';
|
| - ctx.fill();
|
| -
|
| - // draw yellow circle inside clipping region
|
| - ctx.beginPath();
|
| - ctx.arc(x + offset, y, radius, 0, 2 * Math.PI, false);
|
| - ctx.fillStyle = 'yellow';
|
| - ctx.fill();
|
| -
|
| - // draw red circle inside clipping region
|
| - ctx.beginPath();
|
| - ctx.arc(x, y + offset, radius, 0, 2 * Math.PI, false);
|
| - ctx.fillStyle = 'red';
|
| - ctx.fill();
|
| -
|
| - // Restore the canvas context to its original state
|
| - // before we defined the clipping region
|
| - ctx.restore();
|
| - ctx.beginPath();
|
| - ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
|
| - ctx.lineWidth = 10;
|
| - ctx.strokeStyle = 'blue';
|
| - ctx.stroke();
|
| -}
|
| -
|
| -void shear() {
|
| - initTest("Transform");
|
| - var rectWidth = width / 4;
|
| - var rectHeight = height / 8;
|
| -
|
| - // shear matrix:
|
| - // 1 sx 0
|
| - // sy 1 0
|
| - // 0 0 1
|
| -
|
| - var sx = 0.75;
|
| - // .75 horizontal shear
|
| - var sy = 0;
|
| - // no vertical shear
|
| -
|
| - // translate context to center of canvas
|
| - ctx.translate(width / 2, height / 2);
|
| -
|
| - // apply custom transform
|
| - ctx.transform(1, sy, sx, 1, 0, 0);
|
| -
|
| - ctx.fillStyle = 'blue';
|
| - ctx.fillRect(-rectWidth / 2, rectHeight / -2, rectWidth, rectHeight);
|
| -}
|
| -
|
| -void composite() {
|
| - initTest("Composition");
|
| - var num = 0;
|
| - var numPerRow = width ~/ 150;
|
| - var tempCanvas = new CanvasElement(width: width, height:height);
|
| - var tempContext = tempCanvas.getContext("2d");
|
| - log("Width = $width, numPerRow = $numPerRow\n");
|
| - for (var mode in [ 'source-atop', 'source-in',
|
| - 'source-out', 'source-over',
|
| - 'destination-atop', 'destination-in',
|
| - 'destination-out', 'destination-over',
|
| - 'lighter', 'darker',
|
| - 'xor', 'copy']) {
|
| - tempContext.save();
|
| - tempContext.clearRect(0, 0, width, height);
|
| - tempContext.beginPath();
|
| - tempContext.rect(0, 0, 55, 55);
|
| - tempContext.fillStyle = 'blue';
|
| - tempContext.fill();
|
| -
|
| - tempContext.globalCompositeOperation = mode;
|
| - tempContext.beginPath();
|
| - tempContext.arc(50, 50, 35, 0, 2 * Math.PI, false);
|
| - tempContext.fillStyle = 'red';
|
| - tempContext.fill();
|
| - tempContext.restore();
|
| - tempContext.font = '10pt Verdana';
|
| - tempContext.fillStyle = 'black';
|
| - tempContext.fillText(mode, 0, 100);
|
| - if (num > 0) {
|
| - if ((num % numPerRow) == 0) {
|
| - ctx.translate(-150 * (numPerRow-1), 150);
|
| - } else {
|
| - ctx.translate(150, 0);
|
| - }
|
| - }
|
| - ctx.drawImage(tempCanvas, 0, 0);
|
| - ++num;
|
| - }
|
| -}
|
| -
|
| -class Rectangle {
|
| - num x, y, width, height, borderWidth;
|
| -}
|
| -
|
| -var startTime = 0;
|
| -var myRectangle = null;
|
| -
|
| -void anim() {
|
| - if (myRectangle == null) {
|
| - myRectangle = new Rectangle();
|
| - myRectangle.x = 250;
|
| - myRectangle.y = 70;
|
| - myRectangle.width = 100;
|
| - myRectangle.height = 50;
|
| - myRectangle.borderWidth = 5;
|
| - startTime = (new DateTime.now()).millisecondsSinceEpoch;
|
| - }
|
| -
|
| - var now = (new DateTime.now()).millisecondsSinceEpoch;
|
| - var time = now - startTime;
|
| - var amplitude = 150;
|
| -
|
| - // in ms
|
| - var period = 2000;
|
| - var centerX = width / 2 - myRectangle.width / 2;
|
| - var nextX = amplitude * Math.sin(time * 2 * Math.PI / period) + centerX;
|
| - myRectangle.x = nextX;
|
| -
|
| - // clear
|
| - ctx.clearRect(0, 0, width, height);
|
| -
|
| - // draw
|
| -
|
| - ctx.beginPath();
|
| - ctx.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
|
| - ctx.fillStyle = '#8ED6FF';
|
| - ctx.fill();
|
| - ctx.lineWidth = myRectangle.borderWidth;
|
| - ctx.strokeStyle = 'black';
|
| - ctx.stroke();
|
| -}
|
| -
|
| -void linearGradient() {
|
| - initTest("Linear Gradient");
|
| - ctx.rect(0, 0, width, height);
|
| - var grd = ctx.createLinearGradient(0, 0, width, height);
|
| - // light blue
|
| - grd.addColorStop(0, '#8ED6FF');
|
| - // dark blue
|
| - grd.addColorStop(1, '#004CB3');
|
| - ctx.fillStyle = grd;
|
| - ctx.fill();
|
| -}
|
| -
|
| -void radialGradient() {
|
| - initTest("Radial Gradient");
|
| - ctx.rect(0, 0, width, height);
|
| - var grd = ctx.createRadialGradient(238, 50, 10, 238, 50, 300);
|
| - // light blue
|
| - grd.addColorStop(0, '#8ED6FF');
|
| - // dark blue
|
| - grd.addColorStop(1, '#004CB3');
|
| - ctx.fillStyle = grd;
|
| - ctx.fill();
|
| -}
|
| -
|
| -int testnum = 0; // Set this to -1 to start with last test.
|
| -
|
| -double x, y, z;
|
| -
|
| -onAccelerometer(double xx, double yy, double zz) {
|
| - x = xx;
|
| - y = yy;
|
| - z = zz;
|
| -}
|
| -
|
| -void update(num when) {
|
| - window.requestAnimationFrame(update);
|
| - if (testnum == 0) {
|
| - anim();
|
| - return;
|
| - }
|
| - if (!isDirty) return;
|
| - switch(testnum) {
|
| - case 1:
|
| - helloWorld();
|
| - break;
|
| - case 2:
|
| - blocks();
|
| - break;
|
| - case 3:
|
| - squares();
|
| - break;
|
| - case 4:
|
| - grid();
|
| - break;
|
| - case 5:
|
| - strokeLines();
|
| - break;
|
| - case 6:
|
| - lineJoin();
|
| - break;
|
| - case 7:
|
| - colors();
|
| - break;
|
| - case 8:
|
| - rotate();
|
| - break;
|
| - case 9:
|
| - alpha();
|
| - break;
|
| - case 10:
|
| - scale();
|
| - break;
|
| - case 11:
|
| - curves();
|
| - break;
|
| - case 12:
|
| - shadows();
|
| - break;
|
| - case 13:
|
| - lineJoins();
|
| - break;
|
| - case 14:
|
| - saveRestore();
|
| - break;
|
| - case 15:
|
| - mirror();
|
| - break;
|
| - case 16:
|
| - oval();
|
| - break;
|
| - case 17:
|
| - lineDash();
|
| - break;
|
| - case 18:
|
| - loadImage();
|
| - break;
|
| - case 19:
|
| - clip();
|
| - break;
|
| - case 20:
|
| - shear();
|
| - break;
|
| - case 21:
|
| - composite();
|
| - break;
|
| - case 22:
|
| - smiley();
|
| - break;
|
| - case 23:
|
| - linearGradient();
|
| - break;
|
| - case 24:
|
| - radialGradient();
|
| - break;
|
| - case 25:
|
| - break; // Skip for now; this is really slow.
|
| - var rayTracer = new RayTracer();
|
| - rayTracer.render(defaultScene(), ctx, width, height);
|
| - break;
|
| - default:
|
| - if (testnum < 0) {
|
| - testnum = 24;
|
| - } else {
|
| - testnum = 0;
|
| - }
|
| - return;
|
| - }
|
| -
|
| - isDirty = false;
|
| -}
|
| -
|
| -// Raytracer adapted from https://gist.github.com/mythz/3817303.
|
| -
|
| -Scene defaultScene() =>
|
| - new Scene(
|
| - [new Plane(new Vector(0.0, 1.0, 0.0), 0.0, Surfaces.checkerboard),
|
| - new Sphere(new Vector(0.0, 1.0, -0.25), 1.0, Surfaces.shiny),
|
| - new Sphere(new Vector(-1.0, 0.5, 1.5), 0.5, Surfaces.shiny)],
|
| - [new Light(new Vector(-2.0, 2.5, 0.0), new Color(0.49, 0.07, 0.07) ),
|
| - new Light(new Vector(1.5, 2.5, 1.5), new Color(0.07, 0.07, 0.49) ),
|
| - new Light(new Vector(1.5, 2.5, -1.5), new Color(0.07, 0.49, 0.071) ),
|
| - new Light(new Vector(0.0, 3.5, 0.0), new Color(0.21, 0.21, 0.35) )],
|
| - new Camera(new Vector(3.0, 2.0, 4.0), new Vector(-1.0, 0.5, 0.0))
|
| - );
|
| -
|
| -
|
| -class Vector {
|
| - num x, y, z;
|
| - Vector(this.x, this.y, this.z);
|
| -
|
| - operator -(Vector v) => new Vector(x - v.x, y - v.y, z - v.z);
|
| - operator +(Vector v) => new Vector(x + v.x, y + v.y, z + v.z);
|
| - static times(num k, Vector v) => new Vector(k * v.x, k * v.y, k * v.z);
|
| - static num dot(Vector v1, Vector v2) =>
|
| - v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
|
| - static num mag(Vector v) => Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
| - static Vector norm(Vector v) {
|
| - var _mag = mag(v);
|
| - var div = _mag == 0 ? double.INFINITY : 1.0 / _mag;
|
| - return times(div, v);
|
| - }
|
| - static Vector cross(Vector v1, Vector v2) {
|
| - return new Vector(v1.y * v2.z - v1.z * v2.y,
|
| - v1.z * v2.x - v1.x * v2.z,
|
| - v1.x * v2.y - v1.y * v2.x);
|
| - }
|
| -}
|
| -
|
| -class Color {
|
| - num r, g, b;
|
| - static final white = new Color(1.0, 1.0, 1.0);
|
| - static final grey = new Color(0.5, 0.5, 0.5);
|
| - static final black = new Color(0.0, 0.0, 0.0);
|
| - static final background = Color.black;
|
| - static final defaultColor = Color.black;
|
| -
|
| - Color(this.r,this.g,this.b);
|
| - static scale(num k, Color v) => new Color(k * v.r, k * v.g, k * v.b);
|
| - operator +(Color v) => new Color(r + v.r, g + v.g, b + v.b);
|
| - operator *(Color v) => new Color(r * v.r, g * v.g, b * v.b);
|
| - static _intColor(num d) => ((d > 1 ? 1 : d) * 255).toInt();
|
| - static String toDrawingRGB(Color c) =>
|
| - "rgb(${_intColor(c.r)}, ${_intColor(c.g)}, ${_intColor(c.b)})";
|
| -}
|
| -
|
| -class Camera {
|
| - Vector pos, forward, right, up;
|
| - Camera (this.pos, Vector lookAt) {
|
| - var down = new Vector(0.0, -1.0, 0.0);
|
| - forward = Vector.norm(lookAt - pos);
|
| - right = Vector.times(1.5, Vector.norm(Vector.cross(forward, down)));
|
| - up = Vector.times(1.5, Vector.norm(Vector.cross(forward, right)));
|
| - }
|
| -}
|
| -
|
| -class Ray {
|
| - Vector start, dir;
|
| - Ray([this.start, this.dir]);
|
| -}
|
| -
|
| -class Intersection {
|
| - Thing thing;
|
| - Ray ray;
|
| - num dist;
|
| - Intersection(this.thing, this.ray, this.dist);
|
| -}
|
| -
|
| -class Light {
|
| - Vector pos;
|
| - Color color;
|
| - Light(this.pos, this.color);
|
| -}
|
| -
|
| -abstract class Surface {
|
| - int roughness;
|
| - Color diffuse(Vector pos);
|
| - Color specular(Vector pos);
|
| - num reflect(Vector pos);
|
| -}
|
| -
|
| -abstract class Thing {
|
| - Intersection intersect(Ray ray);
|
| - Vector normal(Vector pos);
|
| - Surface surface;
|
| -}
|
| -
|
| -class Scene {
|
| - List<Thing> things;
|
| - List<Light> lights;
|
| - Camera camera;
|
| - Scene([this.things,this.lights,this.camera]);
|
| -}
|
| -
|
| -class Sphere implements Thing {
|
| - num radius2, radius;
|
| - Vector center;
|
| - Surface surface;
|
| -
|
| - Sphere (this.center, this.radius, this.surface) {
|
| - this.radius2 = radius * radius;
|
| - }
|
| - normal(Vector pos) => Vector.norm(pos - center);
|
| - intersect(Ray ray) {
|
| - var eo = this.center - ray.start;
|
| - var v = Vector.dot(eo, ray.dir);
|
| - var dist = 0;
|
| - if (v >= 0) {
|
| - var disc = this.radius2 - (Vector.dot(eo, eo) - v * v);
|
| - if (disc >= 0) {
|
| - dist = v - Math.sqrt(disc);
|
| - }
|
| - }
|
| - return dist == 0 ? null : new Intersection(this, ray, dist);
|
| - }
|
| -}
|
| -
|
| -class Plane implements Thing {
|
| - Vector norm;
|
| - num offset;
|
| - Surface surface;
|
| - Plane(this.norm, this.offset, this.surface);
|
| - Vector normal(Vector pos) => norm;
|
| - Intersection intersect(Ray ray) {
|
| - var denom = Vector.dot(norm, ray.dir);
|
| - if (denom > 0) {
|
| - return null;
|
| - } else {
|
| - var dist = (Vector.dot(norm, ray.start) + offset) / (-denom);
|
| - return new Intersection(this, ray, dist);
|
| - }
|
| - }
|
| -}
|
| -
|
| -class CustomSurface implements Surface {
|
| - Color diffuseColor, specularColor;
|
| - int roughness;
|
| - num reflectPos;
|
| - CustomSurface(this.diffuseColor, this.specularColor,
|
| - this.reflectPos, this.roughness);
|
| - diffuse(pos) => diffuseColor;
|
| - specular(pos) => specularColor;
|
| - reflect(pos) => reflectPos;
|
| -}
|
| -
|
| -class CheckerBoardSurface implements Surface {
|
| - int roughness;
|
| - CheckerBoardSurface([this.roughness=150]);
|
| - diffuse(pos) => (pos.z.floor() + pos.x.floor()) % 2 != 0
|
| - ? Color.white
|
| - : Color.black;
|
| - specular(pos) => Color.white;
|
| - reflect(pos) => (pos.z.floor() + pos.x.floor()) % 2 != 0 ? 0.1 : 0.7;
|
| -}
|
| -
|
| -class Surfaces {
|
| - static final shiny = new CustomSurface(Color.white, Color.grey, 0.7, 250);
|
| - static final checkerboard = new CheckerBoardSurface();
|
| -}
|
| -
|
| -class RayTracer {
|
| - num _maxDepth = 5;
|
| -
|
| - Intersection _intersections(Ray ray, Scene scene) {
|
| - var closest = double.INFINITY;
|
| - Intersection closestInter = null;
|
| - for (Thing thing in scene.things) {
|
| - var inter = thing.intersect(ray);
|
| - if (inter != null && inter.dist < closest) {
|
| - closestInter = inter;
|
| - closest = inter.dist;
|
| - }
|
| - }
|
| - return closestInter;
|
| - }
|
| -
|
| - _testRay(Ray ray, Scene scene) {
|
| - var isect = _intersections(ray, scene);
|
| - return isect != null ? isect.dist : null;
|
| - }
|
| -
|
| - _traceRay(Ray ray, Scene scene, num depth) {
|
| - var isect = _intersections(ray, scene);
|
| - return isect == null ? Color.background : _shade(isect, scene, depth);
|
| - }
|
| -
|
| - _shade(Intersection isect, Scene scene, num depth) {
|
| - var d = isect.ray.dir;
|
| - var pos = Vector.times(isect.dist, d) + isect.ray.start;
|
| - var normal = isect.thing.normal(pos);
|
| - var reflectDir = d -
|
| - Vector.times(2, Vector.times(Vector.dot(normal, d), normal));
|
| - var naturalColor = Color.background +
|
| - _getNaturalColor(isect.thing, pos, normal, reflectDir, scene);
|
| - var reflectedColor = (depth >= _maxDepth) ? Color.grey :
|
| - _getReflectionColor(isect.thing, pos, normal, reflectDir,
|
| - scene, depth);
|
| - return naturalColor + reflectedColor;
|
| - }
|
| -
|
| - _getReflectionColor(Thing thing, Vector pos, Vector normal, Vector rd,
|
| - Scene scene, num depth) =>
|
| - Color.scale(thing.surface.reflect(pos),
|
| - _traceRay(new Ray(pos, rd), scene, depth + 1));
|
| -
|
| - _getNaturalColor(Thing thing, Vector pos, Vector norm, Vector rd,
|
| - Scene scene) {
|
| - var addLight = (col, light) {
|
| - var ldis = light.pos - pos;
|
| - var livec = Vector.norm(ldis);
|
| - var neatIsect = _testRay(new Ray(pos, livec), scene);
|
| - var isInShadow = neatIsect == null ? false :
|
| - (neatIsect <= Vector.mag(ldis));
|
| - if (isInShadow) {
|
| - return col;
|
| - } else {
|
| - var illum = Vector.dot(livec, norm);
|
| - var lcolor = (illum > 0) ? Color.scale(illum, light.color)
|
| - : Color.defaultColor;
|
| - var specular = Vector.dot(livec, Vector.norm(rd));
|
| - var scolor = (specular > 0)
|
| - ? Color.scale(Math.pow(specular, thing.surface.roughness),
|
| - light.color)
|
| - : Color.defaultColor;
|
| - return col + (thing.surface.diffuse(pos) * lcolor)
|
| - + (thing.surface.specular(pos) * scolor);
|
| - }
|
| - };
|
| - return scene.lights.fold(Color.defaultColor, addLight);
|
| - }
|
| -
|
| - render(Scene scene, CanvasRenderingContext2D ctx, num screenWidth,
|
| - num screenHeight) {
|
| - var getPoint = (x, y, camera) {
|
| - var recenterX = (x) => (x - (screenWidth / 2.0)) / 2.0 / screenWidth;
|
| - var recenterY = (y) => - (y - (screenHeight / 2.0)) / 2.0 / screenHeight;
|
| - return Vector.norm(camera.forward
|
| - + Vector.times(recenterX(x), camera.right)
|
| - + Vector.times(recenterY(y), camera.up));
|
| - };
|
| - for (int y = 0; y < screenHeight; y++) {
|
| - for (int x = 0; x < screenWidth; x++) {
|
| - var color = _traceRay(new Ray(scene.camera.pos,
|
| - getPoint(x, y, scene.camera) ), scene, 0);
|
| - ctx.fillStyle = Color.toDrawingRGB(color);
|
| - ctx.fillRect(x, y, x + 1, y + 1);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
|
|