diff --git a/doodle.html b/doodle.html
index 57eeac0..0f5f4e4 100644
--- a/doodle.html
+++ b/doodle.html
@@ -4,7 +4,6 @@
Doedel Drie Dee
-
diff --git a/library/cal.js b/library/cal.js
deleted file mode 100644
index dbe3a06..0000000
--- a/library/cal.js
+++ /dev/null
@@ -1,2329 +0,0 @@
-//canvas cheat sheet
-//http://cheatsheetworld.com/programming/html5-canvas-cheat-sheet/
-
-//TODO
-//Global Composite Operation
-//Linear Gradient
-//Radial Gradient
-//Bezier Curve
-//Circle
-//Touch support
-
-"use strict";
-var CAL = {
- name: "Canvas Abstraction Layer",
- version: "1.0",
- author: "Casper Lamboo",
- contact: "casperlamboo@gmail.com"
-};
-
-CAL.Math = {
- clamb: function (value, min, max) {
- return (value > min) ? ((value < max) ? value : max) : min;
- },
- randomInt: function (min, max) {
- return Math.round(CAL.Math.random(min, max));
- },
- random: function (min, max) {
- min = min || 0;
- max = max === undefined ? 1 : max;
-
- return Math.random()*(max - min) + min;
- },
- sign: function (value) {
- return (value > 0) ? 1 : ((value < 0) ? -1 : 0);
- },
- lineCollision: function (v1, v2, v3, v4) {
- //bron: http://mathworld.wolfram.com/Line-LineIntersection.html
- var intersection = new CAL.Vector(
- ((v1.x*v2.y-v1.y*v2.x)*(v3.x-v4.x)-(v1.x-v2.x)*(v3.x*v4.y-v3.y*v4.x)) / ((v1.x-v2.x)*(v3.y-v4.y)-(v1.y-v2.y)*(v3.x-v4.x)),
- ((v1.x*v2.y-v1.y*v2.x)*(v3.y-v4.y)-(v1.y-v2.y)*(v3.x*v4.y-v3.y*v4.x)) / ((v1.x-v2.x)*(v3.y-v4.y)-(v1.y-v2.y)*(v3.x-v4.x))
- );
-
- var line1 = v1.subtract(v2).length();
- var line2 = v3.subtract(v4).length();
-
- var a = line1 >= v1.subtract(intersection).length();
- var b = line1 >= v2.subtract(intersection).length();
- var c = line2 >= v3.subtract(intersection).length();
- var d = line2 >= v4.subtract(intersection).length();
-
- return (a && b && c && d) ? intersection : false;
- }
-};
-
-CAL.Easings = {
- bounceEaseOut: function (dt, b, c, d) {
- if ((dt /= d) < (1 / 2.75)) {
- return c * (7.5625 * dt * dt) + b;
- }
- else if (dt < (2 / 2.75)) {
- return c * (7.5625 * (dt -= (1.5 / 2.75)) * dt + 0.75) + b;
- }
- else if (dt < (2.5 / 2.75)) {
- return c * (7.5625 * (dt -= (2.25 / 2.75)) * dt + 0.9375) + b;
- }
- else {
- return c * (7.5625 * (dt -= (2.625 / 2.75)) * dt + 0.984375) + b;
- }
- },
- easeIn: function (dt, b, c, d) {
- return c * (dt /= d) * dt + b;
- },
- easeOut: function (dt, b, c, d) {
- return -c * (dt /= d) * (dt - 2) + b;
- },
- easeInOut: function (dt, b, c, d) {
- if ((dt /= d / 2) < 1) {
- return c / 2 * dt * dt + b;
- }
- return -c / 2 * ((--dt) * (dt - 2) - 1) + b;
- },
- strongEaseIn: function (dt, b, c, d) {
- return c * (dt /= d) * dt * dt * dt * dt + b;
- },
- strongEaseOut: function (dt, b, c, d) {
- return c * (( dt = dt / d - 1) * dt * dt * dt * dt + 1) + b;
- },
- strongEaseInOut: function (dt, b, c, d) {
- if ((dt /= d / 2) < 1) {
- return c / 2 * dt * dt * dt * dt * dt + b;
- }
- return c / 2 * ((dt -= 2) * dt * dt * dt * dt + 2) + b;
- },
- linear: function (dt, b, c, d) {
- return c * dt / d + b;
- }
-};
-
-
-//this doesn't work, everything is an instance of Object in JavaScript
-/*Object.prototype.clone = function () {
- var object = {};
- for (var i in this) {
- var element = this[i];
-
- object[i] = element.clone ? element.clone() : element;
- }
- return object;
-};
-Object.prototype.foreach = function (callback) {
- for (var i in this) {
- var element = this[i];
-
- callback(element, i);
- }
-};*/
-
-
-Array.prototype.foreach = function (callback, scope) {
- for (var i = 0; i < this.length; i ++) {
- var element = this[i];
-
- if ((scope !== undefined) ? callback.call(scope, element, i) : callback(element, i)) {
- break;
- }
- }
-};
-Array.prototype.foreachReverse = function (callback, scope) {
- for (var i = this.length-1; i >= 0; i --) {
- var element = this[i];
-
- if ((scope !== undefined) ? callback.call(scope, element, i) : callback(element, i)) {
- break;
- }
- }
-};
-Array.prototype.max = function () {
- var max = -Infinity;
- this.foreach(function (element) {
- if (element > max) {
- max = element;
- }
- });
- return max;
-};
-Array.prototype.min = function () {
- var min = Infinity;
- this.foreach(function (element) {
- if (element < min) {
- min = element;
- }
- });
- return min;
-};
-Array.prototype.clone = function () {
- var array = [];
- this.foreach(function (element) {
- array.push((element.clone !== undefined) ? element.clone() : element);
- });
- return array;
-};
-Array.prototype.remove = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var element = arguments[i];
- var index = this.indexOf(element);
- if (index !== -1) {
- this.splice(index, 1);
- }
- }
-};
-
-var requestAnimFrame = (function () {
- return requestAnimationFrame || webkitRequestAnimationFrame || mozRequestAnimationFrame || function (callback) {
- setTimeout(callback, 1000/60);
- };
-})();
-
-CAL.Vector = function (x, y) {
- this.x = x || 0;
- this.y = y || 0;
-};
-CAL.Vector.prototype.add = function (vector) {
- var x = this.x + vector.x;
- var y = this.y + vector.y;
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.subtract = function (vector) {
- var x = this.x - vector.x;
- var y = this.y - vector.y;
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.scale = function (scalar) {
- var x = this.x * scalar;
- var y = this.y * scalar;
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.rotate = function (angle) {
- var cos = Math.cos(angle);
- var sin = Math.sin(angle);
-
- var x = cos*this.x - sin*this.y;
- var y = sin*this.x + cos*this.y;
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.multiply = function (vector) {
- var x = this.x * vector.x;
- var y = this.y * vector.y;
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.length = function () {
- return Math.sqrt(this.x*this.x + this.y*this.y);
-};
-CAL.Vector.prototype.normal = function () {
- return new CAL.Vector(this.y, -this.x);
-};
-CAL.Vector.prototype.normalize = function () {
- var length = this.length();
-
- var x = this.x/length;
- var y = this.y/length;
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.angle = function () {
- return Math.atan2(this.y, this.x);
-};
-CAL.Vector.prototype.dot = function (vector) {
- return this.x * vector.x + this.y * vector.y;
-};
-CAL.Vector.prototype.cross = function (vector) {
- return this.x * vector.y - this.y * vector.x;
-};
-CAL.Vector.prototype.round = function () {
- var x = Math.round(this.x);
- var y = Math.round(this.y);
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.applyMatrix = function (matrix) {
- var m = matrix.matrix;
-
- var x = m[0]*this.x + m[1]*this.y + m[2];
- var y = m[3]*this.x + m[4]*this.y + m[5];
-
- return new CAL.Vector(x, y);
-};
-CAL.Vector.prototype.clone = function () {
- return new CAL.Vector(this.x, this.y);
-};
-CAL.Vector.prototype.draw = function (context, x, y) {
- var end = new CAL.Vector(this.x + x, this.y + y);
- var arrowOrigin = new CAL.Vector(x, y).add(this.subtract(this.normalize().scale(10)));
- var left = this.normal().normalize().scale(10).add(arrowOrigin);
- var right = this.normal().normalize().scale(-10).add(arrowOrigin);
-
- context.beginPath();
- context.moveTo(x, y);
- context.lineTo(end.x, end.y);
- context.moveTo(left.x, left.y);
- context.lineTo(end.x, end.y);
- context.lineTo(right.x, right.y);
-
- context.stroke();
-};
-
-CAL.Matrix = function (options) {
- options = options || {};
-
- if (options.matrix !== undefined && options.sx !== undefined && options.sy !== undefined && options.rotation !== undefined && options.x !== undefined && options.y !== undefined) {
- this.matrix = options.matrix;
- this._sx = options.sx;
- this._sy = options.sy;
- this._rotation = options.rotation;
- this._x = options.x;
- this._y = options.y;
- }
- else if (options instanceof Array || options.matrix) {
- this.matrix = options.matrix || options;
-
- this._sx = CAL.Math.sign(this.matrix[0])*Math.sqrt(Math.pow(this.matrix[0], 2) + Math.pow(this.matrix[1], 2));
- this._sy = CAL.Math.sign(this.matrix[4])*Math.sqrt(Math.pow(this.matrix[3], 2) + Math.pow(this.matrix[4], 2));
- this._rotation = Math.atan2(-this.matrix[1], this.matrix[0]);
- this._x = this.matrix[2];
- this._y = this.matrix[5];
- //source: http://math.stackexchange.com/questions/13150/extracting-rotation-scale-values-from-2d-transformation-matrix
- //BUG doesn't convert right when both sx and sy aren't 1
- }
- else {
- this._sx = options.sx !== undefined ? options.sx : 1;
- this._sy = options.sy !== undefined ? options.sy : 1;
- this._x = options.x || 0;
- this._y = options.y || 0;
-
- if (options.rotation === undefined) {
- this._rotation = 0;
-
- this.matrix = [
- this._sx, 0, this._x,
- 0, this._sy, this._y
- ];
- }
- else {
- this._rotation = options.rotation;
- this.updateMatrix();
- }
- }
-};
-CAL.Matrix.prototype = {
- get sx () {
- return this._sx;
- },
- set sx (sx) {
- this._sx = sx;
- this.updateMatrix();
- },
- get sy () {
- return this._sy;
- },
- set sy (sy) {
- this._sy = sy;
- this.updateMatrix();
- },
- get rotation () {
- return this._rotation;
- },
- set rotation (rotation) {
- this._rotation = rotation;
- this.updateMatrix();
- },
- get x () {
- return this._x;
- },
- set x (x) {
- this._x = this.matrix[2] = x;
- },
- get y () {
- return this._y;
- },
- set y (y) {
- this._y = this.matrix[5] = y;
- }
-};
-CAL.Matrix.prototype.updateMatrix = function () {
- this.matrix = [
- this._sx * Math.cos(this._rotation), this._sy * -Math.sin(this._rotation), this._x,
- this._sx * Math.sin(this._rotation), this._sy * Math.cos(this._rotation), this._y
- ];
-};
-CAL.Matrix.prototype.multiplyMatrix = function (matrix) {
- var a = this.matrix;
- var b = matrix.matrix;
- var translation = new CAL.Vector(b[2], b[5]).applyMatrix(this);
-
- return new CAL.Matrix([
- a[0]*b[0] + a[3]*b[1], a[1]*b[0] + a[4]*b[1], translation.x,
- a[0]*b[3] + a[3]*b[4], a[1]*b[3] + a[4]*b[4], translation.y,
- ]);
-};
-CAL.Matrix.prototype.inverse = function () {
- var m = this.matrix;
- return new CAL.Matrix([
- m[4], -m[1], -m[2],
- -m[3], m[0], -m[5]
- ]);
-};
-CAL.Matrix.prototype.translate = function (x, y) {
- this.x += x;
- this.y += y;
-
- this.matrix[2] = this.x;
- this.matrix[5] = this.y;
-
- return this;
-};
-CAL.Matrix.prototype.setMatrix = function (matrix) {
- this.matrix = matrix.matrix.clone();
- this._x = matrix._x;
- this._y = matrix._y;
- this._sx = matrix._sx;
- this._sy = matrix._sy;
- this._rotation = matrix._rotation;
-};
-CAL.Matrix.prototype.setContext = function (context) {
- var m = this.matrix;
- context.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
-};
-CAL.Matrix.prototype.rotateAroundAbsolute = function (angle, center) {
- if (angle !== 0) {
- var center = center
- .subtract(new CAL.Vector(this.x, this.y))
- .rotate(-this.rotation)
- .multiply(new CAL.Vector(1/this.sx, 1/this.sy));
-
- this.rotateAroundRelative(angle, center);
- }
-};
-CAL.Matrix.prototype.rotateAroundRelative = function (angle, center) {
- if (angle !== 0) {
- var before = center.applyMatrix(this);
-
- this.rotation += angle;
- var after = center.applyMatrix(this);
-
- var offset = before.subtract(after);
-
- this._x += offset.x;
- this._y += offset.y;
- this.updateMatrix();
- }
-};
-CAL.Matrix.prototype.clone = function () {
- return new CAL.Matrix({
- matrix: this.matrix.clone(),
- sx: this._sx,
- sy: this._sy,
- rotation: this._rotation,
- x: this._x,
- y: this._y
- });
-};
-
-CAL.Draw = function (centerX, centerY, numberWidth, numberHeight, options) {
- CAL.Matrix.call(this, options);
-
- this.visible = options.visible !== undefined ? options.visible : true;
- this.active = options.active || false;
- this.depth = options.depth || 0;
-
- this.alpha = (typeof options.alpha === "number") ? options.alpha : 1;
-
- this.centerX = centerX || 0;
- this.centerY = centerY || 0;
- this.index = 0;
-
- this.numberWidth = numberWidth || 1;
- this.numberHeight = numberHeight || 1;
- this.length = this.numberWidth*this.numberHeight;
-};
-CAL.Draw.prototype = Object.create(CAL.Matrix.prototype);
-CAL.Draw.prototype.draw = function (context, matrix) {
- context.save();
- (matrix || this).setContext(context);
- context.globalAlpha = this.alpha;
- this.drawSimple(context, this.index, 0, 0);
- context.restore();
-};
-CAL.Draw.prototype.drawSimple = function (context, number, x, y) {
- var sx = (number % this.numberWidth)*this.width;
- var sy = Math.floor(number/this.numberWidth)*this.height;
-
- context.drawImage(this.image, sx, sy, this.width, this.height, x-this.centerX, y-this.centerY, this.width, this.height);
-};
-CAL.Draw.prototype.drawAlpha = function (context, number, x, y, alpha) {
- context.globalAlpha = alpha;
- this.drawSimple(context, number, x, y);
- context.globalAlpha = 1;
-};
-CAL.Draw.prototype.drawAngle = function (context, number, x, y, angle) {
- context.save();
- context.translate(x, y);
- context.rotate(angle);
- this.drawSimple(context, number, 0, 0);
- context.restore();
-};
-CAL.Draw.prototype.drawScale = function (context, number, x, y, width, height) {
- var sx = (number % this.numberWidth)*this.width;
- var sy = Math.floor(number/this.numberWidth)*this.height;
-
- context.drawImage(this.image, sx, sy, this.width, this.height, x-this.centerX, y-this.centerY, width, height);
-};
-CAL.Draw.prototype.drawContain = function (context, number, x, y, width, height) {
- if (width/height > this.width/this.height) {
- x = x + (width-height/this.height*this.width)/2;
- width = height/this.height*this.width;
- this.drawScale(context, number, x, y, width, height);
- }
- else {
- y = y + (height-width/this.width*this.height)/2;
- height = width/this.width*this.height;
- this.drawScale(context, number, x, y, width, height);
- }
-};
-
-CAL.Surface = function (options) {
- options = options || {};
- CAL.Draw.call(this, options.centerX, options.centerY, options.numberWidth, options.numberHeight, options);
-
- this.clearColor = options.clearColor || false;
-
- this.setCanvas(options.canvas || document.createElement("canvas"));
-
- this.setSize(options.width, options.height);
-};
-CAL.Surface.prototype = Object.create(CAL.Draw.prototype);
-CAL.Surface.prototype.setSize = function (width, height) {
- this.image.width = width || this.image.width;
- this.image.height = height || this.image.height;
-
- this.width = this.image.width/this.numberWidth;
- this.height = this.image.height/this.numberHeight;
-};
-CAL.Surface.prototype.setCanvas = function (canvas) {
- this.image = canvas;
- this.context = canvas.getContext("2d");
-};
-CAL.Surface.prototype.clear = function () {
- if (this.clearColor) {
- this.clearColor.setColor(this.context);
- this.context.fillRect(0, 0, this.image.width, this.image.height);
- }
- else {
- this.context.clearRect(0, 0, this.image.width, this.image.height);
- }
-};
-CAL.Surface.prototype.getImageData = function (x, y, width, height) {
- var x = x || 0;
- var y = y || 0;
- var width = width || this.image.width;
- var height = height || this.image.height;
-
- return this.context.getImageData(x, y, width, height);
-};
-CAL.Surface.prototype.getDataURL = function () {
- return this.image.toDataURL();
-};
-CAL.Surface.prototype.blur = (function () {
- //source: http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
- //author: Mario Klingemann
-
- var mul_table = [512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,289,287,285,282,280,278,275,273,271,269,267,265,263,261,259];
- var shg_table = [9,11,12,13,13,14,14,15,15,15,15,16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24 ];
-
- return function (radius, x, y, width, height) {
- x = x || 0;
- y = y || 0;
- width = this.image.width || 0;
- height = this.image.height || 0;
- var imageData = this.getImageData(x, y, width, height);
-
- var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum,
- r_out_sum, g_out_sum, b_out_sum, a_out_sum,
- r_in_sum, g_in_sum, b_in_sum, a_in_sum,
- pr, pg, pb, pa, rbs;
-
- var div = radius + radius + 1;
- var w4 = width << 2;
- var widthMinus1 = width - 1;
- var heightMinus1 = height - 1;
- var radiusPlus1 = radius + 1;
- var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;
- var pixels = imageData.data;
-
- var stackStart = {r: 0, g: 0, b: 0, next: null};
- var stack = stackStart;
- for (i = 1; i < div; i ++) {
- stack = stack.next = {r: 0, g: 0, b: 0, next: null};
- if (i == radiusPlus1) {
- var stackEnd = stack;
- }
- }
- stack.next = stackStart;
- var stackIn = null;
- var stackOut = null;
-
- yw = yi = 0;
-
- var mul_sum = mul_table[radius];
- var shg_sum = shg_table[radius];
-
- for (y = 0; y < height; y ++) {
- r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0;
-
- r_out_sum = radiusPlus1 * (pr = pixels[yi]);
- g_out_sum = radiusPlus1 * (pg = pixels[yi+1]);
- b_out_sum = radiusPlus1 * (pb = pixels[yi+2]);
- a_out_sum = radiusPlus1 * (pa = pixels[yi+3]);
-
- r_sum += sumFactor * pr;
- g_sum += sumFactor * pg;
- b_sum += sumFactor * pb;
- a_sum += sumFactor * pa;
-
- stack = stackStart;
-
- for (i = 0; i < radiusPlus1; i ++) {
- stack.r = pr;
- stack.g = pg;
- stack.b = pb;
- stack.a = pa;
- stack = stack.next;
- }
-
- for (i = 1; i < radiusPlus1; i ++) {
- p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);
- r_sum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i);
- g_sum += (stack.g = (pg = pixels[p+1])) * rbs;
- b_sum += (stack.b = (pb = pixels[p+2])) * rbs;
- a_sum += (stack.a = (pa = pixels[p+3])) * rbs;
-
- r_in_sum += pr;
- g_in_sum += pg;
- b_in_sum += pb;
- a_in_sum += pa;
-
- stack = stack.next;
- }
-
- stackIn = stackStart;
- stackOut = stackEnd;
- for (x = 0; x < width; x ++) {
- pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum;
- if (pa === 0) {
- pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0;
- }
- else {
- pa = 255 / pa;
- pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa;
- pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa;
- pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa;
- }
-
-
- r_sum -= r_out_sum;
- g_sum -= g_out_sum;
- b_sum -= b_out_sum;
- a_sum -= a_out_sum;
-
- r_out_sum -= stackIn.r;
- g_out_sum -= stackIn.g;
- b_out_sum -= stackIn.b;
- a_out_sum -= stackIn.a;
-
- p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2;
-
- r_in_sum += (stackIn.r = pixels[p]);
- g_in_sum += (stackIn.g = pixels[p+1]);
- b_in_sum += (stackIn.b = pixels[p+2]);
- a_in_sum += (stackIn.a = pixels[p+3]);
-
- r_sum += r_in_sum;
- g_sum += g_in_sum;
- b_sum += b_in_sum;
- a_sum += a_in_sum;
-
- stackIn = stackIn.next;
-
- r_out_sum += (pr = stackOut.r);
- g_out_sum += (pg = stackOut.g);
- b_out_sum += (pb = stackOut.b);
- a_out_sum += (pa = stackOut.a);
-
- r_in_sum -= pr;
- g_in_sum -= pg;
- b_in_sum -= pb;
- a_in_sum -= pa;
-
- stackOut = stackOut.next;
-
- yi += 4;
- }
- yw += width;
- }
-
-
- for (x = 0; x < width; x ++) {
- g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0;
-
- yi = x << 2;
- r_out_sum = radiusPlus1 * (pr = pixels[yi]);
- g_out_sum = radiusPlus1 * (pg = pixels[yi+1]);
- b_out_sum = radiusPlus1 * (pb = pixels[yi+2]);
- a_out_sum = radiusPlus1 * (pa = pixels[yi+3]);
-
- r_sum += sumFactor * pr;
- g_sum += sumFactor * pg;
- b_sum += sumFactor * pb;
- a_sum += sumFactor * pa;
-
- stack = stackStart;
-
- for (i = 0; i < radiusPlus1; i ++) {
- stack.r = pr;
- stack.g = pg;
- stack.b = pb;
- stack.a = pa;
- stack = stack.next;
- }
-
- yp = width;
-
- for (i = 1; i <= radius; i ++) {
- yi = (yp + x) << 2;
-
- r_sum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i);
- g_sum += (stack.g = (pg = pixels[yi+1])) * rbs;
- b_sum += (stack.b = (pb = pixels[yi+2])) * rbs;
- a_sum += (stack.a = (pa = pixels[yi+3])) * rbs;
-
- r_in_sum += pr;
- g_in_sum += pg;
- b_in_sum += pb;
- a_in_sum += pa;
-
- stack = stack.next;
-
- if (i < heightMinus1) {
- yp += width;
- }
- }
-
- yi = x;
- stackIn = stackStart;
- stackOut = stackEnd;
- for (y = 0; y < height; y ++) {
- p = yi << 2;
- pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum;
- if (pa > 0) {
- pa = 255 / pa;
- pixels[p] = ((r_sum * mul_sum) >> shg_sum) * pa;
- pixels[p+1] = ((g_sum * mul_sum) >> shg_sum) * pa;
- pixels[p+2] = ((b_sum * mul_sum) >> shg_sum) * pa;
- }
- else {
- pixels[p] = pixels[p+1] = pixels[p+2] = 0;
- }
-
- r_sum -= r_out_sum;
- g_sum -= g_out_sum;
- b_sum -= b_out_sum;
- a_sum -= a_out_sum;
-
- r_out_sum -= stackIn.r;
- g_out_sum -= stackIn.g;
- b_out_sum -= stackIn.b;
- a_out_sum -= stackIn.a;
-
- p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2;
-
- r_sum += (r_in_sum += (stackIn.r = pixels[p]));
- g_sum += (g_in_sum += (stackIn.g = pixels[p+1]));
- b_sum += (b_in_sum += (stackIn.b = pixels[p+2]));
- a_sum += (a_in_sum += (stackIn.a = pixels[p+3]));
-
- stackIn = stackIn.next;
-
- r_out_sum += (pr = stackOut.r);
- g_out_sum += (pg = stackOut.g);
- b_out_sum += (pb = stackOut.b);
- a_out_sum += (pa = stackOut.a);
-
- r_in_sum -= pr;
- g_in_sum -= pg;
- b_in_sum -= pb;
- a_in_sum -= pa;
-
- stackOut = stackOut.next;
-
- yi += width;
- }
- }
- return imageData;
- };
-})();
-
-CAL.Draw.prototype.drawBlur = (function () {
- var surface = new CAL.Surface();
-
- return function (context, number, x, y, radius) {
- if (radius > 0) {
- surface.setSize(this.width + 2*radius, this.height + 2*radius);
- this.drawSimple(surface.context, number, this.centerX+radius, this.centerY+radius);
- var imageData = surface.blur(radius);
-
- context.putImageData(imageData, x-this.centerX - radius, y-this.centerY - radius);
-
- /*surface.setSize(this.width, this.height);
- this.drawSimple(surface.context, number, this.centerX, this.centerY);
- var imageData = surface.blur(radius);
-
- context.putImageData(imageData, x-this.centerX, y-this.centerY);*/
- }
- else {
- this.drawSimple(context, number, x, y);
- }
- };
-})();
-
-CAL.Group = function (options) {
- options = options || {};
- CAL.Surface.call(this, options);
-
- this.active = true;
- this.visible = true;
-
- this.objects = [];
- this.useCanvas = options.useCanvas || false;
-
- this.clearCanvas = true;
- this.drawCanvas = true;
-
- this.mouse = {
- x: null,
- y: null,
- startX: null,
- startY: null,
- deltaX: null,
- deltaY: null,
- down: false,
- moved: false
- };
-};
-CAL.Group.prototype = Object.create(CAL.Surface.prototype);
-CAL.Group.prototype.updateEvents = function () {
- var scope = this;
- this.image.onmousedown = function (event) {
- if (scope.useCanvas) {
- scope.mouse.x = scope.mouse.startX = Math.round(scope.image.width / scope.image.clientWidth * event.offsetX);
- scope.mouse.y = scope.mouse.startY = Math.round(scope.image.height / scope.image.clientHeight * event.offsetY);
- scope.mouse.deltaX = 0;
- scope.mouse.deltaY = 0;
- scope.mouse.down = true;
- scope.mouse.moved = false;
-
- scope.mouseDown(scope.mouse, this);
- }
- };
- this.image.onmouseup = function (event) {
- if (scope.useCanvas) {
- scope.mouse.x = Math.round(scope.image.width / scope.image.clientWidth * event.offsetX);
- scope.mouse.y = Math.round(scope.image.height / scope.image.clientHeight * event.offsetY);
- scope.mouse.down = false;
-
- scope.mouseUp(scope.mouse, this);
-
- scope.mouse.startX = null;
- scope.mouse.startY = null;
- scope.mouse.deltaX = null;
- scope.mouse.deltaY = null;
- scope.mouse.moved = false;
- }
- };
- this.image.onmousemove = function (event) {
- if (scope.useCanvas) {
- scope.mouse.x = Math.round(scope.image.width / scope.image.clientWidth * event.offsetX);
- scope.mouse.y = Math.round(scope.image.height / scope.image.clientHeight * event.offsetY);
- if (scope.mouse.down) {
- scope.mouse.moved = true;
- scope.mouse.deltaX = scope.mouse.x - scope.mouse.startX;
- scope.mouse.deltaY = scope.mouse.y - scope.mouse.startY;
- }
- }
- };
- //this.image.ontouchstart = function (event) {scope.touchStart(event);};
- //this.image.ontouchmove = function (event) {scope.touchMove(event);};
- //this.image.ontouchend = function (event) {scope.touchEnd(event);};
-};
-CAL.Group.prototype.setCanvas = function (canvas) {
- /*this.image.onmousedown = null;
- this.image.onmouseup = null;
- this.image.onmousemove = null;
- this.image.ontouchstart = null;
- this.image.ontouchmove = null;
- this.image.ontouchend = null;*/
-
- this.image = canvas;
- this.context = canvas.getContext("2d");
-
- this.drawCanvas = true;
- this.updateEvents();
-};
-CAL.Group.prototype.add = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var object = arguments[i];
- if (this.objects.indexOf(object) === -1) {
- this.objects.push(object);
- if (object.init) {
- object.init(this);
- }
- }
- }
- this.sort();
- this.drawCanvas = true;
-};
-CAL.Group.prototype.remove = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var object = arguments[i];
- this.objects.remove(object);
- if (object.active && object.remove !== undefined) {
- object.remove(this);
- }
- }
- this.drawCanvas = true;
-};
-CAL.Group.prototype.sort = function () {
- this.objects.sort(function (a, b) {
- return (a.depth || 0) - (b.depth || 0);
- });
-};
-CAL.Group.prototype.keyDown = function (keyCode) {
- for (var i = this.objects.length-1; i >= 0; i --) {
- var object = this.objects[i];
- if (object.active && object.keyDown !== undefined) {
- if (object.keyDown(keyCode, this)) {
- break;
- }
- }
- }
-};
-CAL.Group.prototype.keyUp = function (keyCode) {
- for (var i = this.objects.length-1; i >= 0; i --) {
- var object = this.objects[i];
- if (object.active && object.keyUp !== undefined) {
- if (object.keyUp(keyCode, this)) {
- break;
- }
- }
- }
-};
-CAL.Group.prototype.mouseDown = function (mouse) {
- for (var i = this.objects.length-1; i >= 0; i --) {
- var object = this.objects[i];
- if (object.useCanvas !== true && object.active && object.mouseDown !== undefined) {
- if (object.mouseDown(mouse, this)) {
- break;
- }
- }
- }
-};
-CAL.Group.prototype.mouseUp = function (mouse) {
- for (var i = this.objects.length-1; i >= 0; i --) {
- var object = this.objects[i];
- if (object.useCanvas !== true && object.active && object.mouseUp !== undefined) {
- if (object.mouseUp(mouse, this)) {
- break;
- }
- }
- }
-};
-CAL.Group.prototype.step = function (deltaTime) {
- for (var i = 0; i < this.objects.length; i ++) {
- var object = this.objects[i];
- if (object.active && object.step !== undefined) {
- object.step(deltaTime, this);
- }
- }
-
- if (this.clearCanvas && this.useCanvas) {
- this.clear();
- }
-
- if (this.drawCanvas && this.useCanvas) {
- this.draw();
- }
-
- this.clearCanvas = false;
- this.drawCanvas = false;
-};
-CAL.Group.prototype.draw = function (context, matrix) {
- context = this.useCanvas ? this.context : context;
- matrix = this.useCanvas ? this : matrix;
-
- for (var i = 0; i < this.objects.length; i ++) {
- var object = this.objects[i];
- if (object.useCanvas !== true && object.visible && object.draw !== undefined) {
- if (object instanceof CAL.Matrix) {
- object.draw(context, matrix.multiplyMatrix(object));
- }
- else {
- object.draw(context, matrix);
- }
- }
- }
-};
-
-CAL.Scene = function () {
- CAL.Group.call(this, {useCanvas: true});
-
- this.lastTime = new Date().getTime();
-
- this.keysDown = [];
- this.focus = true;
-
- var scope = this;
- window.onkeydown = function (event) {
- if (!scope.keysDown[event.keyCode]) {
- scope.keysDown[event.keyCode] = true;
- scope.keyDown(event.keyCode);
- }
- };
- window.onkeyup = function (event) {
- scope.keysDown[event.keyCode] = false;
-
- scope.keyUp(event.keyCode);
- };
- window.onblur = function (event) {
- this.focus = false;
- };
- window.onfocus = function (event) {
- scope.lastTime = new Date().getTime();
- this.focus = true;
- };
-};
-CAL.Scene.prototype = Object.create(CAL.Group.prototype);
-CAL.Scene.prototype.cycle = function () {
- if (this.focus) {
- var currentTime = new Date().getTime();
- var deltaTime = currentTime-this.lastTime;
- this.lastTime = currentTime;
-
- this.step(deltaTime);
- }
-};
-CAL.Scene = new CAL.Scene();
-
-CAL.Image = function (source, centerX, centerY, numberWidth, numberHeight, options) {
- options = options || {};
- CAL.Draw.call(this, centerX, centerY, numberWidth, numberHeight, options);
-
- this.image = new Image();
- this.source = source;
-};
-CAL.Image.prototype = Object.create(CAL.Draw.prototype);
-CAL.Image.prototype.load = function (callback) {
- var scope = this;
- this.image.onload = function () {
- scope.loaded = true;
-
- scope.width = scope.image.width/scope.numberWidth;
- scope.height = scope.image.height/scope.numberHeight;
-
- if (callback !== undefined) {
- callback();
- }
- };
- this.image.src = this.source;
-};
-
-CAL.ImageLoader = function () {
- this.images = [];
-
- for (var i = 0; i < arguments.length; i ++) {
- var image = arguments[i];
- this.images.push(image);
- }
-};
-CAL.ImageLoader.prototype.add = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var image = arguments[i];
- if (this.images.indexOf(image) === -1) {
- this.images.push(image);
- }
- }
-};
-CAL.ImageLoader.prototype.remove = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var image = arguments[i];
- this.images.remove(image);
- }
-};
-CAL.ImageLoader.prototype.load = function (callback) {
- var imagesToLoad = this.images.length;
- for (var i = 0; i < this.images.length; i ++) {
- var image = this.images[i];
- image.load(function () {
- imagesToLoad --;
- if (imagesToLoad === 0 && callback !== undefined) {
- callback();
- }
- }, this);
- };
-};
-
-CAL.Color = function () {
- if (typeof arguments[0] === "number" && typeof arguments[1] === "number" && typeof arguments[2] === "number") {
- this.r = arguments[0];
- this.g = arguments[1];
- this.b = arguments[2];
- this.a = typeof arguments[3] === "number" ? arguments[3] : 1;
- }
- else if (typeof arguments[0] === "number") {
- var hex = Math.floor(arguments[0]);
-
- this.r = hex >> 16 & 255;
- this.g = hex >> 8 & 255;
- this.b = hex & 255;
- this.a = 1;
- }
- else {
- this.r = 0;
- this.g = 0;
- this.b = 0;
- this.a = 1;
- }
-};
-CAL.Color.prototype.setStroke = function (context) {
- context.strokeStyle = "rgba("+this.r+", "+this.g+", "+this.b+", "+this.a+")";
-};
-CAL.Color.prototype.setFill = function (context) {
- context.fillStyle = "rgba("+this.r+", "+this.g+", "+this.b+", "+this.a+")";
-};
-CAL.Color.prototype.setColor = function (context) {
- this.setStroke(context);
- this.setFill(context);
-};
-
-CAL.Tween = function (object, attributes, duration, options) {
- options = options || {};
- this.visible = false;
- this.active = true;
- this.depth = -10000;
-
- this.object = object;
- this.attributes = attributes;
- this.timer = 0;
- this.duration = duration;
- this.easing = options.easing || CAL.Easings.linear;
- this.callback = options.callback;
-
- this.begin = {};
- for (var i in attributes) {
- this.begin[i] = this.object[i];
- }
-
- this.change = {};
- for (var i in attributes) {
- this.change[i] = attributes[i] - this.begin[i];
- }
-
- this.drawCanvas = options.drawCanvas !== undefined ? options.drawCanvas : true;
- this.clearCanvas = options.clearCanvas !== undefined ? options.clearCanvas : false;
-};
-CAL.Tween.prototype.start = function () {
- this.t = 0;
- this.active = true;
-};
-CAL.Tween.prototype.stop = function () {
- this.t = 0;
- this.active = false;
-};
-CAL.Tween.prototype.pause = function () {
- this.active = false;
-};
-CAL.Tween.prototype.resume = function () {
- this.active = true;
-};
-CAL.Tween.prototype.step = function (deltaTime, group) {
- this.timer += deltaTime;
-
- if (this.timer < this.duration) {
-
- for (var i in this.attributes) {
- var dt = this.timer;
- var d = this.duration;
- var b = this.begin[i];
- var c = this.change[i];
-
- this.object[i] = this.easing(dt, b, c, d);
- }
- }
- else {
- for (var i in this.attributes) {
- this.object[i] = this.attributes[i];
- }
- if (this.callback !== undefined) {
- this.callback();
- }
- group.remove(this);
- }
-
- if (this.clearCanvas) {
- group.clearCanvas = true;
- }
- if (this.drawCanvas) {
- group.drawCanvas = true;
- }
-};
-
-CAL.TimeLine = function (options) {
- options = options || {};
-
- this.visible = false;
- this.active = true;
- this.depth = -10000;
-
- this.moments = [];
- this.autoRemove = (options.autoRemove !== undefined) ? options.autoremove : true;
- this.loop = (options.loop !== undefined) ? options.loop : false;
- this.t = 0;
-
- CAL.Scene.add(this);
-};
-CAL.TimeLine.prototype = {
- addMoment: function (time, callback) {
- this.moments.push({
- time: time,
- callback: callback
- });
- },
- removeMoment: function (remove) {
- for (var i = 0; i < this.moments.length; i ++) {
- var moment = this.moments[i];
-
- if (moment === remove || moment.time === remove || moment.callback === remove) {
- this.moments.remove(moment);
- }
- }
- },
- start: function () {
- this.t = 0;
- this.active = true;
- },
- stop: function () {
- this.t = 0;
- this.active = false;
- },
- pause: function () {
- this.active = false;
- },
- resume: function () {
- this.active = true;
- },
- step: function (dt) {
- var newTime = this.t + dt;
- var remove = true;
-
- for (var i = 0; i < this.moments.length; i ++) {
- var moment = this.moments[i];
- if (moment.time >= this.t) {
- if (moment.time < newTime) {
- moment.callback();
- }
- else {
- remove = false;
- }
- }
- }
-
- if (remove && this.loop) {
- this.t = 0;
- }
- else if (remove && this.autoRemove) {
- CAL.Scene.remove(this);
- }
- this.t = newTime;
- }
-};
-
-CAL.Shape = function (options) {
- options = options || {};
- CAL.Matrix.call(this, options);
-
- this.visible = options.visible !== undefined ? options.visible : true;
- this.active = false;
- this.depth = options.depth || 0;
- this.lines = [];
-
- this.closePath = options.closePath !== undefined ? options.closePath : true;
- this.lineColor = options.lineColor !== undefined ? options.lineColor : new CAL.Color();
- this.shapeColor = options.shapeColor !== undefined ? options.shapeColor : new CAL.Color();
- this.lineWidth = options.lineWidth || 1;
- this.lineJoin = options.lineJoin || "miter";
- this.lineCap = options.lineCap || "square";
-
- this.points = options.points || [];
-};
-CAL.Shape.prototype = Object.create(CAL.Matrix.prototype);
-CAL.Shape.prototype.addPoint = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var point = arguments[i];
- this.points.push(point);
- }
- //this.update();
-};
-CAL.Shape.prototype.hit = function (x, y) {
-
- for (var i = 0; i < this.points.length; i ++) {
- if (new CAL.Vector(x, y).subtract(this.points[i].applyMatrix(this)).dot(this.getNormal(i)) > 0) {
- return false;
- }
- }
-
- return true;
-};
-CAL.Shape.prototype.setContext = function (context, matrix) {
- var matrix = matrix || this;
- context.beginPath();
- for (var i = 0; i < this.points.length; i ++) {
- var point = this.points[i].applyMatrix(matrix);
- context.lineTo(point.x, point.y);
- }
- if (this.closePath) {
- context.closePath();
- }
-};
-CAL.Shape.prototype.getBoundingBox = function () {
- var minX = Infinity;
- var minY = Infinity;
- var maxX = -Infinity;
- var maxY = -Infinity;
-
- for (var i = 0; i < this.points.length; i ++) {
- var point = this.points[i];
- minX = point.x < minX ? point.x : minX;
- minY = point.y < minY ? point.y : minY;
- maxX = point.x > maxX ? point.x : maxX;
- maxY = point.y > maxY ? point.y : maxY;
- };
-
- return {x: minX, y: minY, width: maxX-minX, height: maxY-minY};
-};
-CAL.Shape.prototype.getNormal = function (i) {
- var pointA = this.points[(i+1)%this.points.length].applyMatrix(this);
- var pointB = this.points[i].applyMatrix(this);
- return pointA.subtract(pointB).normal().normalize();
-};
-CAL.Shape.prototype.clip = function (context, matrix) {
- this.setContext(context, matrix);
- context.clip();
-};
-CAL.Shape.prototype.fill = function (context, matrix) {
- this.setContext(context, matrix);
-
- this.shapeColor.setFill(context);
-
- context.fill();
-};
-CAL.Shape.prototype.stroke = function (context, matrix) {
- this.setContext(context, matrix);
-
- context.lineColor = this.lineColor;
- context.lineWidth = this.lineWidth;
- context.lineJoin = this.lineJoin;
- context.lineCap = this.lineCap;
-
- this.lineColor.setStroke(context);
-
- context.stroke();
-};
-CAL.Shape.prototype.draw = function (context, matrix) {
- this.setContext(context, matrix);
-
- if (this.shapeColor) {
- this.shapeColor.setFill(context);
- context.fill();
- }
-
- if (this.lineColor) {
- context.lineColor = this.lineColor;
- context.lineWidth = this.lineWidth;
- context.lineJoin = this.lineJoin;
- context.lineCap = this.lineCap;
- this.lineColor.setStroke(context);
- context.stroke();
- }
-};
-
-CAL.BezierPoint = function (position, controlPointA, controlPointB) {
- this.position = position || new CAL.Vector(0, 0);
- this.controlPointA = controlPointA || new CAL.Vector(0, 0);
- this.controlPointB = controlPointB || new CAL.Vector(0, 0);
-}
-CAL.BezierPoint.prototype.applyMatrix = function (matrix) {
- var position = this.position.applyMatrix(matrix);
- var controlPointA = this.controlPointA.applyMatrix(matrix);
- var controlPointB = this.controlPointB.applyMatrix(matrix);
-
- return new CAL.BezierPoint(position, controlPointA, controlPointB);
-};
-CAL.BezierPoint.prototype.draw = function (context) {
- var leftHandle = this.controlPointA.add(this.position);
- var rightHandle = this.controlPointB.add(this.position);
-
- context.strokeStyle = "#09F";
-
- context.beginPath();
- context.moveTo(leftHandle.x, leftHandle.y);
- context.lineTo(this.position.x, this.position.y);
- context.lineTo(rightHandle.x, rightHandle.y);
- context.stroke();
-
- context.beginPath();
- context.arc(this.position.x, this.position.y, 10, 0, Math.PI*2, true);
- context.stroke();
-
- context.beginPath();
- context.arc(leftHandle.x, leftHandle.y, 5, 0, Math.PI*2, true);
- context.stroke();
-
- context.beginPath();
- context.arc(rightHandle.x, rightHandle.y, 5, 0, Math.PI*2, true);
- context.stroke();
-};
-/*CAL.Shape = function (options) {
- options = options || {};
- CAL.Matrix.call(this, options);
-
- this.visible = options.visible !== undefined ? options.visible : true;
- this.active = false;
- this.depth = options.depth || 0;
-
- this.closePath = options.closePath !== undefined ? options.closePath : true;
- this.lineColor = options.lineColor !== undefined ? options.lineColor : new CAL.Color();
- this.shapeColor = options.shapeColor !== undefined ? options.shapeColor : new CAL.Color();
- this.lineWidth = options.lineWidth || 1;
- this.lineJoin = options.lineJoin || "miter";
- this.lineCap = options.lineCap || "square";
-
- this.points = options.points || [];
- this.precision = options.precision || 3;
-
- this.lines = [];
- this.length = 0;
- this.closed = false;
-}
-CAL.Shape.prototype.init = function (group) {
- for (var i = 0; i < this.points.length; i ++) {
- var point = this.points[i];
- if (point instanceof CAL.Vector) {
- point = new CAL.BezierPoint(point);
- }
- this.points[i] = point;
- }
-
- this.update();
-};
-CAL.Shape.prototype.addPoint = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var point = arguments[i];
-
- if (point instanceof CAL.Vector) {
- point = new CAL.BezierPoint(point);
- }
- if (point instanceof CAL.BezierPoint) {
- this.points.push(point);
- }
- }
-
- this.update();
-};
-CAL.Shape.prototype.collisionBox = function (vec1, vec2) {
- for (var i = 0; i < this.lines.length; i ++) {
- var point = this.lines[i];
-
- if (point.x > vec1.x && point.y > vec1.y && point.x < vec2.x && point.y < vec2.y) {
- return true;
- }
- }
- return false;
-};
-CAL.Shape.prototype.getNormal = function (i) {
- var pointA = this.lines[(i+1)%this.lines.length].applyMatrix(this);
- var pointB = this.lines[i].applyMatrix(this);
- return pointA.subtract(pointB).normal().normalize();
-};
-CAL.Shape.prototype.collisionPoint = function (x, y) {
- for (var i = 0; i < this.lines.length; i ++) {
- if (new CAL.Vector(x, y).subtract(this.lines[i].applyMatrix(this)).dot(this.getNormal(i)) > 0) {
- return false;
- }
- }
-
- return true;
-};
-CAL.Shape.prototype.removePoint = function () {
- for (var i = 0; i < arguments.length; i ++) {
-
- var argument = arguments[i];
-
- if (typeof argument === "number") {
- var index = argument;
- }
- else if (argument instanceof CAL.BezierPoint || argument instanceof CAL.Vector) {
- var index = this.getPointIndex(argument);
- }
-
- if (index !== -1) {
- this.points.splice(index, 1);
- }
- }
-
- this.update();
-};
-
-CAL.Shape.prototype.getPointIndex = function (point) {
- if (point instanceof CAL.BezierPoint) {
- return this.points.indexOf(argument);
- }
- else if (point instanceof CAL.Vector) {
- for (i = 0; i < this.points.length; i ++) {
- var length = this.points[i].position.subtract(point).length();
-
- if (length === 0) {
- return i;
- }
- }
- return -1;
- }
-};
-
-CAL.Shape.prototype.numberPoints = function () {
- return this.points.length;
-};
-
-CAL.Shape.prototype.insertPoint = function (point, index) {
- if (point instanceof CAL.Vector) {
- point = new CAL.BezierPoint(point);
- }
- if (point instanceof CAL.BezierPoint) {
- this.points.splice(index, 0, point);
-
- this.update();
- }
-};
-CAL.Shape.prototype.setClosed = function (closed) {
- this.closed = closed;
- this.update();
-};
-
-CAL.Shape.prototype.setPrecision = function (precision) {
- this.precision = precision;
- this.update();
-};
-
-CAL.Shape.prototype.makeSmooth = function (strength, start, end) {
- start = start || 0;
- end = end || this.points.length;
-
- if (this.closed === false) {
- start = Math.max(start, 1);
- end = Math.min(end, this.points.length-1);
- }
- else {
- start = Math.max(start, 0);
- end = Math.min(end, this.points.length);
- }
-
- for (var i = start; i < end; i ++) {
- var p0 = this.points[i-1];
- var p1 = this.points[i];
- var p2 = this.points[i+1];
-
- if (typeof(p0) === "undefined") {
- p0 = this.points[this.points.length-1];
- }
- else if (typeof(p2) === "undefined") {
- p2 = this.points[0];
- }
-
- var a = p0.position.subtract(p1.position);
- var b = p2.position.subtract(p1.position);
-
- var length = (a.length()+b.length())/4;
-
- var direction = a.normalize().add(b.scale(-1).normalize()).normalize();
-
- p1.controlPointA = direction.scale(length*strength);
- p1.controlPointB = direction.scale(-length*strength);
- }
-
- this.update();
-};
-
-CAL.Shape.prototype.calculateBezierPoints = function (p0, p1) {
- var array = [];
-
- if (p0.controlPointB.length() === 0 && p1.controlPointA.length() === 0) {
- var angle = p1.position.subtract(p0.position).angle();
-
- array.push({
- x: p0.position.x,
- y: p0.position.y,
- angle: angle
- }, {
- x: p1.position.x,
- y: p1.position.y,
- angle: angle
- });
- }
- else {
- var point = {
- x: p1.position.x,
- y: p1.position.y,
- angle: p1.controlPointB.direction()
- }
-
- array = array.concat(
- recursiveBezier(
- p0.position,
- p0.position.add(p0.controlPointB),
- p1.position.add(p1.controlPointA),
- p1.position,
- this.precision
- ),
- [point]
- );
- }
-
- return array;
-};
-
-CAL.Shape.prototype.update = function () {
- if (this.points.length >= 2) {
- if (this.points[0].controlPointB.length() !== 0) {
- var point = {
- x: this.points[0].position.x,
- y: this.points[0].position.y,
- angle: this.points[0].controlPointB.direction()
- };
- this.lines = [point];
- }
-
- for (var i = 0; i < this.points.length-1; i ++) {
- var p0 = this.points[i];
- var p1 = this.points[i+1];
-
- this.lines = this.lines.concat(this.calculateBezierPoints(p0, p1));
- }
-
- if (this.closed === true) {
-
- var p0 = this.points[this.points.length-1];
- var p1 = this.points[0];
-
- this.lines = this.lines.concat(this.calculateBezierPoints(p0, p1));
- }
-
- var pathLength = 0;
- this.lines[0].position = 0;
-
- for (var i = 0; i < this.lines.length-1; i ++) {
-
- var p0 = this.lines[i];
- var p1 = this.lines[i+1];
- var line = new CAL.Vector(p1.x, p1.y).subtract(p0);
- pathLength += line.length();
-
- p1.position = pathLength;
- }
-
- this.length = pathLength;
- }
-};
-
-CAL.Shape.prototype.getPosition = function (t) {
- var t = Math.max(Math.min(t, this.length), 0);
-
- for (var i = 1; true; i ++) {
- var p0 = this.lines[i-1];
- var p1 = this.lines[i];
-
- if (p1.position >= t) {
- t = (t-p0.position) / (p1.position-p0.position);
-
- var position = new CAL.Vector(p0.x, p0.y).scale(1-t).add(new CAL.Vector(p1.x, p1.y).scale(t));
- var angle = p0.angle + ((((p1.angle-p0.angle)%360)+540)%360-180)*t;
-
- return {
- x: position.x,
- y: position.y,
- angle: angle
- };
- }
- }
-};
-
-CAL.Shape.prototype.setContextPart = function (context, begin, end) {
- var beginPos = this.getPosition(begin);
- var endPos = this.getPosition(end);
-
- context.beginPath();
- context.moveTo(beginPos.x, beginPos.y);
-
- for (var i = 0; i < this.lines.length; i ++) {
- var line = this.lines[i];
-
- if (line.position > begin) {
-
- context.lineTo(line.x, line.y);
- if (line.position > end) {
- break;
- }
- }
- }
- context.lineTo(endPos.x, endPos.y);
-};
-
-CAL.Shape.prototype.setContext = function (context) {
- this.setContextPart(context, 0, this.length);
-};
-
-CAL.Shape.prototype.setClippingPart = function (context, begin, end) {
- context.save();
- this.setContextPart(begin, end);
- context.clip();
-};
-
-CAL.Shape.prototype.setClipping = function (context) {
- this.setClippingPart(context, 0, this.length);
-};
-
-CAL.Shape.prototype.drawPart = function (context, begin, end, color, width, cap) {
- this.setContextPart(context, begin, end);
-
- context.strokeStyle = color || "black";
- context.lineWidth = width || 1;
- context.lineCap = cap || 'butt';
- context.stroke();
-};
-CAL.Shape.prototype.setContext = function (context, matrix) {
- var matrix = matrix || this;
- context.beginPath();
- for (var i = 0; i < this.lines.length; i ++) {
- var point = this.lines[i]//.applyMatrix(matrix);
- context.lineTo(point.x, point.y);
- }
- if (this.closePath) {
- context.closePath();
- }
-};
-
-CAL.Shape.prototype.fill = function (context, matrix) {
- this.setContext(context, matrix);
-
- this.shapeColor.setFill(context);
-
- context.fill();
-};
-CAL.Shape.prototype.stroke = function (context, matrix) {
- this.setContext(context, matrix);
- context.lineColor = this.lineColor;
- context.lineWidth = this.lineWidth;
- context.lineJoin = this.lineJoin;
- context.lineCap = this.lineCap;
-
- this.lineColor.setStroke(context);
-
- context.stroke();
-};
-
-CAL.Shape.prototype.draw = function (context, matrix) {
- if (this.shapeColor) {
- this.shapeColor.setFill(context);
- context.fill();
- }
-
- if (this.lineColor) {
- this.stroke(context, matrix);
- }
- this.debugDraw(context);
-};
-CAL.Shape.prototype.debugDraw = function (context) {
- context.beginPath();
- context.lineWidth = 1;
-
- for (var i = 0; i < this.points.length; i ++) {
- var point = this.points[i];
-
- point.draw(context);
- }
-
- context.beginPath();
-
- for (var i = 0; i < this.lines.length; i ++) {
- var point = this.lines[i];
-
- context.lineTo(point.x, point.y);
- context.arc(point.x, point.y, 2, 0, Math.PI*2, true);
- context.lineTo(point.x, point.y);
- }
-
- context.strokeStyle = "black";
- context.stroke();
-};
-
-CAL.Shape.prototype.getSize = function () {
- var width = 0;
- var height = 0;
-
- for (var i = 0; i < this.lines.length; i ++) {
- var line = this.lines[i];
-
- width = Math.max(width, Math.ceil(line.x));
- height = Math.max(width, Math.ceil(line.y));
- }
-
- return {
- width: width,
- height: height
- };
-};
-
-
-CAL.BezierPoint = function (position, controlPointA, controlPointB) {
- this.position = position || new CAL.Vector(0, 0);
- this.controlPointA = controlPointA || new CAL.Vector(0, 0);
- this.controlPointB = controlPointB || new CAL.Vector(0, 0);
-}
-CAL.BezierPoint.prototype.applyMatrix = function (matrix) {
- var position = this.position.applyMatrix(matrix);
- var controlPointA = this.controlPointA.applyMatrix(matrix);
- var controlPointB = this.controlPointB.applyMatrix(matrix);
-
- return new CAL.BezierPoint(position, controlPointA, controlPointB);
-};
-CAL.BezierPoint.prototype.draw = function (context) {
- var leftHandle = this.controlPointA.add(this.position);
- var rightHandle = this.controlPointB.add(this.position);
-
- context.strokeStyle = "#09F";
-
- context.beginPath();
- context.moveTo(leftHandle.x, leftHandle.y);
- context.lineTo(this.position.x, this.position.y);
- context.lineTo(rightHandle.x, rightHandle.y);
- context.stroke();
-
- context.beginPath();
- context.arc(this.position.x, this.position.y, 10, 0, Math.PI*2, true);
- context.stroke();
-
- context.beginPath();
- context.arc(leftHandle.x, leftHandle.y, 5, 0, Math.PI*2, true);
- context.stroke();
-
- context.beginPath();
- context.arc(rightHandle.x, rightHandle.y, 5, 0, Math.PI*2, true);
- context.stroke();
-};
-
-function recursiveBezier (p1, p2, p3, p4, precision) {
- //source: http://antigrain.com/research/adaptive_bezier/
- //source: http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Derivative
-
- var p12 = p1.add(p2).scale(0.5);
- var p23 = p2.add(p3).scale(0.5);
- var p34 = p3.add(p4).scale(0.5);
- var p123 = p12.add(p23).scale(0.5);
- var p234 = p23.add(p34).scale(0.5);
- var p1234 = p123.add(p234).scale(0.5);
-
- var d = p4.subtract(p1);
-
- var d2 = Math.abs((p2.x - p4.x) * d.y - (p2.y - p4.y) * d.x);
- var d3 = Math.abs((p3.x - p4.x) * d.y - (p3.y - p4.y) * d.x);
-
- //if (Math.abs(p1.x + p3.x - p2.x - p2.x) + Math.abs(p1.y + p3.y - p2.y - p2.y) + Math.abs(p2.x + p4.x - p3.x - p3.x) + Math.abs(p2.y + p4.y - p3.y - p3.y) <= precision) {
- if (Math.pow((d2 + d3), 2) < precision * d.dot(d)) {
-
- //var t = 0.5;
- //var derivative = (p2.subtract(p1)).scale(Math.pow(3*(1-t), 2)).add((p3.subtract(p2)).scale(6*(1-t)*t)).add((p4.subtract(p3)).scale(Math.pow(3*t, 2)));
- var derivative = (p2.subtract(p1)).scale(2.25).add((p3.subtract(p2)).scale(1.5)).add((p4.subtract(p3)).scale(2.25));
-
- var point = {
- x: p1234.x,
- y: p1234.y,
- angle: derivative.direction()
- }
-
- return [point];
- }
- else {
-
- return [].concat(
- recursiveBezier(p1, p12, p123, p1234, precision),
- recursiveBezier(p1234, p234, p34, p4, precision)
- );
- }
-}*/
-
-CAL.Text = function (options) {
- options = options || {};
- CAL.Matrix.call(this, options);
-
- this.visible = options.visible !== undefined ? options.visible : true;
- this.active = options.active !== undefined ? options.active : true;
- this.depth = options.depth || 0;
- this.text = options.text || "";
- this.style = options.style || "normal";
- this.variant = options.variant || "normal";
- this.weight = options.weight || "normal";
- this.size = options.size || 12;
- this.font = options.font || "Arial";
-
- this.textAlign = options.textAlign || "left";
-
- this.color = options.color || new CAL.Color();
- this.alpha = typeof options.alpha === "number" ? options.alpha : 1;
-};
-CAL.Text.prototype = Object.create(CAL.Matrix.prototype);
-CAL.Text.prototype.drawText = function (context, text, x, y) {
- context.font = [this.style, this.variant, this.weight, this.size+"px", this.font].join(" ");
- context.textAlign = this.textAlign;
- this.color.setColor(context);
- context.fillText(text, x, y);
-};
-CAL.Text.prototype.drawTextAlpha = function (context, text, x, y, apha) {
- context.font = [this.style, this.variant, this.weight, this.size+"px", this.font].join(" ");
- context.globalAlpha = apha;
- this.color.setColor(context);
- context.fillText(text, x, y);
- context.globalAlpha = 1;
-};
-CAL.Text.prototype.draw = function (context, matrix) {
- context.save();
- matrix.setContext(context);
- context.globalAlpha = this.alpha;
- this.drawText(context, this.text, 0, 0);
- context.restore();
-};
-CAL.Text.prototype.clone = function () {
- return new CAL.text({
- style : this.style,
- variant : this.variant,
- weight : this.weight,
- size : this.size,
- font : this.font,
- color : this.color.clone()
- });
-};
-
-CAL.KeyListener = function (options) {
- options = options || {};
-
- this.visible = false;
- this.active = options.active !== undefined ? option.active : true;
- this.depth = -10000;
-
- this.actions = options.actions || {};
-
- CAL.Scene.add(this);
-};
-CAL.KeyListener.prototype.add = function (key, callback) {
- this.actions[key] = callback;
-};
-CAL.KeyListener.prototype.keyDown = function (key) {
- if (this.actions[key]) {
- this.actions[key]();
- }
-};
-
-CAL.Physics = function () {
- CAL.Scene.add(this);
- this.depth = -1000;
- this.active = true;
- this.visible = false;
-
- this.objects = [];
- this.manifolds = [];
- this.forces = [];
-}
-CAL.Physics.prototype.keyDown = function () {
- //DEBUG REASONS
- //EASIER TO DEBUG ON KEYDOWN
-
- CAL.Scene.clear();
-
- this.test(120);
-
- polygon.debugDraw(CAL.Scene.context);
- box.debugDraw(CAL.Scene.context);
-
-};
-CAL.Physics.prototype.add = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var object = arguments[i];
-
- if (object instanceof CAL.PhysicsObject && this.objects.indexOf(object) === -1) {
- for (var j = 0; j < this.objects.length; j ++) {
- this.manifolds.push(new CAL.Manifold(object, this.objects[j]));
- this.manifolds.push(new CAL.Manifold(this.objects[j], object));
- }
-
- this.objects.push(object);
- }
- else if (object instanceof CAL.Force && this.forces.indexOf(object) === -1) {
- this.forces.push(object);
- }
- }
-};
-CAL.Physics.prototype.test = function (dt) {
- //var dt = 120;
-
- this.objects.foreach(function (object) {
- object.step(dt);
- }, this);
-
- this.forces.foreach(function (force) {
- force.step(dt);
- }, this);
-
- this.manifolds.foreach(function (manifold) {
- manifold.step(dt);
- }, this);
-
-};
-
-CAL.Manifold = function (a, b) {
- this.a = a;
- this.b = b;
-
- this.normal;
-};
-CAL.Manifold.prototype.checkCollision = function (dt) {
- var collisionData = {collision: false};
-
- this.b.shape.points.foreach(function (pointA, i) {
- var pointA = pointA.applyMatrix(this.b.shape);
- var collision = true;
- var bestDistance = -Infinity;
- var bestNormal;
-
- this.a.shape.points.foreach(function (pointB, j) {
- var pointB = pointB.applyMatrix(this.a.shape);
- var normal = this.a.shape.getNormal(j);
- var distance = normal.dot(pointA.subtract(pointB));
-
- if (distance > 0) {
- collision = false;
- return true;
- }
- else if (distance > bestDistance) {
- bestDistance = distance;
- bestNormal = normal;
- }
- }, this);
-
- if (collision) {
- collisionData = {collision: true, penetrationDepth: -bestDistance, normal: bestNormal, impactPoint: pointA};
-
- return true;
- }
-
- }, this);
-
- return collisionData;
-
- /*this.a.shape.points.foreach(function (point, i) {
- var normal = this.a.shape.getNormal(i);
- var support = this.b.getSupport(normal.scale(-1));
-
- var point = point.applyMatrix(this.a.shape);
- var distance = normal.dot(support.subtract(point));
-
- //if (distance > 0) {
- // console.log("test");
- // bestDistance = 1;
- // return true;
- //}
- if (distance > bestDistance || bestDistance === false) {
-
- //var velocity = this.b.velocity.add(this.b.getPointVelocity(support));
- //if (velocity.dot(normal) < 0 || velocity.length === 0) {
-
- bestDistance = distance;
- bestNormal = normal;
- bestImpactPoint = support;
- //bestVelocity = velocity;
- //}
- }
- }, this);
-
- var i = 2;
- var normal = this.a.shape.getNormal(i);
- normal.scale(100).draw(CAL.Scene.context, 200, 200);
- var support = this.b.getSupport(normal.scale(-1));
-
- var point = this.a.shape.points[i].applyMatrix(this.a.shape);
- var distance = normal.dot(support.subtract(point));
-
- console.log(distance);
-
- CAL.Scene.context.beginPath();
- CAL.Scene.context.arc(support.x, support.y, 10, 0, Math.PI*2);
- CAL.Scene.context.stroke();
-
- return {collision: bestDistance < 0, penetrationDepth: bestDistance, normal: bestNormal, impactPoint: bestImpactPoint};*/
-};
-CAL.Manifold.prototype.positionalCorrection = function (collisionData) {
- var percent = 0.2; // usually 20% to 80%
- var slop = 0.1; // usually 0.01 to 0.1
-
- var correction = collisionData.normal.scale(Math.max(collisionData.penetrationDepth - slop, 0) / (1/this.a.mass + 1/this.b.mass) * percent);
-
- var aPos = correction.scale(1/this.a.mass);
- this.a.shape._x += aPos.x;
- this.a.shape._y += aPos.y;
- this.a.shape.updateMatrix();
-
- var bPos = correction.scale(1/this.b.mass);
- this.b.shape._x -= bPos.x;
- this.b.shape._y -= bPos.y;
- this.b.shape.updateMatrix();
-};
-CAL.Manifold.prototype.resolveCollision = function (collisionData) {
- var restVelocity = this.b.velocity.subtract(this.a.velocity);
-
- var velAlongNormal = restVelocity.dot(collisionData.normal);
- if (velAlongNormal > 0) {
- return;
- }
- var restitution = Math.min(this.a.restitution, this.b.restitution);
-
- var force = -(1 + restitution) * velAlongNormal / (1/this.a.mass + 1/this.b.mass);
-
- var impulse = collisionData.normal.scale(force);
-
- this.a.addForce(impulse.scale(-1), collisionData.impactPoint);
- this.b.addForce(impulse, collisionData.impactPoint);
-};
-CAL.Manifold.prototype.step = function (dt) {
- var collisionData = this.checkCollision();
-
- if (collisionData.collision) {
- this.resolveCollision(collisionData);
- this.positionalCorrection(collisionData);
- }
-};
-
-CAL.PhysicsObject = function (options) {
- options = options || {};
-
- this.shape = options.shape || new CAL.Shape();
- this.velocity = options.velocity || new CAL.Vector();
- this.angularVelocity = options.angularVelocity !== undefined ? options.angularVelocity : 0;
- this.restitution = options.restitution !== undefined ? options.restitution : 0.5;
- this.density = options.density || 1;
- this.updateMass();
-};
-CAL.PhysicsObject.prototype.calculateBoundingBox = function (matrix) {
- matrix = matrix || this.shape;
-
- var minX = Infinity;
- var minY = Infinity;
- var maxX = -Infinity;
- var maxY = -Infinity;
- this.shape.points.foreach(function (point) {
- var point = point.applyMatrix(matrix);
-
- minX = (point.x < minX) ? point.x : minX;
- minY = (point.y < minY) ? point.y : minY;
- maxX = (point.x > maxX) ? point.x : maxX;
- maxY = (point.y > maxY) ? point.y : maxY;
- }, this);
-
- return {minX: minX, minY: minY, maxX: maxX, maxY: maxY};
-};
-CAL.PhysicsObject.prototype.addForce = function (impulse, contactVector) {
- this.velocity = this.velocity.add(impulse.scale(1.0/this.mass));
-
- /*if (contactVector !== undefined) {
- this.angularVelocity += contactVector.subtract(this.centerOfMass.applyMatrix(this.shape)).cross(impulse)*(1.0/this.inertia);
- //this.angularVelocity = contactVector.subtract(this.centerOfMass.applyMatrix(this.shape)).cross(impulse)*(1.0/this.inertia);
- }*/
-};
-CAL.PhysicsObject.prototype.pointCollision = function (point) {
- var point = point
- .subtract(new CAL.Vector(this.shape.x, this.shape.y))
- .rotate(-this.shape.rotation)
- .multiply(new CAL.Vector(1/this.shape.sx, 1/this.shape.sy))
- .subtract(new CAL.Vector(this.collisionMask.offsetX, this.collisionMask.offsetY));
-
- if (point.x < 0) return false;
- if (point.y < 0) return false;
- if (point.x > this.collisionMask.width) return false;
- if (point.y > this.collisionMask.height) return false;
-
- var i = Math.round(point.y)*this.collisionMask.width + Math.round(point.x);
- return this.collisionMask.data[i];
-};
-CAL.PhysicsObject.prototype.setDensity = function (density) {
- this.density = density;
- this.mass = this.area*density;
- this.inertia = this.mass*this.area;
-};
-CAL.PhysicsObject.prototype.updateMass = function () {
- var boundingBox = this.calculateBoundingBox(new CAL.Matrix());
- var surface = new CAL.Surface({x: boundingBox.maxX - boundingBox.minX, y: boundingBox.maxY - boundingBox.minY});
- this.shape.clip(surface.context, new CAL.Matrix({x: -boundingBox.minX, y: -boundingBox.minY}));
- surface.context.fillStyle = "black";
- surface.context.fillRect(0, 0, surface.width, surface.height);
-
- var imageData = surface.getImageData();
-
- var point = new CAL.Vector();
- var area = 0;
- this.collisionMask = {
- data: [],
- width: imageData.width,
- height: imageData.height,
- offsetX: boundingBox.minX,
- offsetY: boundingBox.minY
- };
- for (var i = 0; i < imageData.data.length; i += 4) {
- var alpha = imageData.data[i + 3];
- if (alpha > 0) {
- point = point.add(new CAL.Vector(i/4 % imageData.width, Math.floor(i/4/imageData.width)));
- area ++;
- this.collisionMask.data.push(true);
- }
- else {
- this.collisionMask.data.push(false);
- }
- }
- this.area = area/**this.sx*this.sy*/;
- this.mass = area*this.density;
- this.inertia = this.mass*area;
- this.centerOfMass = point.scale(1/area).add(new CAL.Vector(boundingBox.minX, boundingBox.minY));
-};
-CAL.PhysicsObject.prototype.getSupport = function (n) {
- var bestProjection = -Infinity;
- var bestPoint;
-
- for (var i = 0; i < this.shape.points.length; i ++) {
- var point = this.shape.points[i].applyMatrix(this.shape);
- var projection = point.dot(n);
-
- if (projection > bestProjection) {
- bestPoint = point;
- bestProjection = projection;
- }
- }
-
- return bestPoint;
-};
-CAL.PhysicsObject.prototype.getPointVelocity = function (point) {
-
- var relativePoint = point.subtract(this.centerOfMass.applyMatrix(this.shape));
- var rotatedPoint = relativePoint.rotate(this.angularVelocity);
-
- return rotatedPoint.subtract(relativePoint);
-};
-CAL.PhysicsObject.prototype.findCollisionFace = function (point) {
-
-};
-CAL.PhysicsObject.prototype.step = function (dt) {
- //this.rotateAroundRelative(this.torque*dt, this.centerOfMass);
-
- //this.angularVelocity += torque * (1.0 / this.inertia) * dt
-
- /*if (this.velocity.length < 0.0001) {
- this.velocity = new CAL.Vector();
- }
- if (Math.abs(this.angularVelocity) < 0.00001) {
- this.angularVelocity = 0;
- }*/
-
- this.shape._x += this.velocity.x*dt;
- this.shape._y += this.velocity.y*dt;
- this.shape.updateMatrix();
-
- //this.shape.rotateAroundRelative(this.angularVelocity*dt, this.centerOfMass);
-};
-
-CAL.PhysicsObject.prototype.debugDraw = function (context) {
- context.lineWidth = 1;
- context.strokeStyle = "black";
-
- var minX = Infinity;
- var minY = Infinity;
- var maxX = -Infinity;
- var maxY = -Infinity;
- context.beginPath();
- this.shape.points.foreach(function (point) {
- var point = point.applyMatrix(this.shape);
-
- context.lineTo(point.x, point.y);
- context.arc(point.x, point.y, 3, 0, 2*Math.PI*2);
- context.lineTo(point.x, point.y);
-
- minX = (point.x < minX) ? point.x : minX
- minY = (point.y < minY) ? point.y : minY
- maxX = (point.x > maxX) ? point.x : maxX
- maxY = (point.y > maxY) ? point.y : maxY
- }, this);
- context.closePath();
- context.stroke();
-
- this.shape.points.foreach(function (point, i) {
- var point = point.applyMatrix(this.shape);
- var text = new CAL.Text();
- text.drawText(context, i, point.x + 10, point.y - 10);
- //this.getPointVelocity(point).scale(1000).draw(context, point.x, point.y);
- }, this);
-
-
- context.beginPath();
- context.moveTo(minX, minY);
- context.lineTo(minX, maxY);
- context.lineTo(maxX, maxY);
- context.lineTo(maxX, minY);
- context.closePath();
-
- var centerOfMass = this.centerOfMass.applyMatrix(this.shape);
- context.moveTo(centerOfMass.x-5, centerOfMass.y-5);
- context.lineTo(centerOfMass.x+5, centerOfMass.y+5);
- context.moveTo(centerOfMass.x+5, centerOfMass.y-5);
- context.lineTo(centerOfMass.x-5, centerOfMass.y+5);
- context.strokeStyle = "red";
- context.stroke();
-
- var center = this.centerOfMass.applyMatrix(this.shape);
- this.velocity.scale(1000).draw(context, center.x, center.y);
-};
-
-CAL.Force = function (options) {
-
- this.objects = options.objects || [];
- this.velocity = options.velocity || new CAL.Vector();
-}
-CAL.Force.prototype.add = function () {
- for (var i = 0; i < arguments.length; i ++) {
- var argument = arguments[i];
-
- this.objects.push(argument);
- }
-};
-CAL.Force.prototype.step = function (dt) {
-
- for (var i = 0; i < this.objects.length; i ++) {
- var object = this.objects[i];
-
- object.velocity = object.velocity.add(this.velocity.scale(dt));
- }
-};
diff --git a/library/csg.js b/library/csg.js
deleted file mode 100755
index 17b7a2f..0000000
--- a/library/csg.js
+++ /dev/null
@@ -1,595 +0,0 @@
-// Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean
-// operations like union and intersection to combine 3D solids. This library
-// implements CSG operations on meshes elegantly and concisely using BSP trees,
-// and is meant to serve as an easily understandable implementation of the
-// algorithm. All edge cases involving overlapping coplanar polygons in both
-// solids are correctly handled.
-//
-// Example usage:
-//
-// var cube = CSG.cube();
-// var sphere = CSG.sphere({ radius: 1.3 });
-// var polygons = cube.subtract(sphere).toPolygons();
-//
-// ## Implementation Details
-//
-// All CSG operations are implemented in terms of two functions, `clipTo()` and
-// `invert()`, which remove parts of a BSP tree inside another BSP tree and swap
-// solid and empty space, respectively. To find the union of `a` and `b`, we
-// want to remove everything in `a` inside `b` and everything in `b` inside `a`,
-// then combine polygons from `a` and `b` into one solid:
-//
-// a.clipTo(b);
-// b.clipTo(a);
-// a.build(b.allPolygons());
-//
-// The only tricky part is handling overlapping coplanar polygons in both trees.
-// The code above keeps both copies, but we need to keep them in one tree and
-// remove them in the other tree. To remove them from `b` we can clip the
-// inverse of `b` against `a`. The code for union now looks like this:
-//
-// a.clipTo(b);
-// b.clipTo(a);
-// b.invert();
-// b.clipTo(a);
-// b.invert();
-// a.build(b.allPolygons());
-//
-// Subtraction and intersection naturally follow from set operations. If
-// union is `A | B`, subtraction is `A - B = ~(~A | B)` and intersection is
-// `A & B = ~(~A | ~B)` where `~` is the complement operator.
-//
-// ## License
-//
-// Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license.
-
-// # class CSG
-
-// Holds a binary space partition tree representing a 3D solid. Two solids can
-// be combined using the `union()`, `subtract()`, and `intersect()` methods.
-
-CSG = function() {
- this.polygons = [];
-};
-
-// Construct a CSG solid from a list of `CSG.Polygon` instances.
-CSG.fromPolygons = function(polygons) {
- var csg = new CSG();
- csg.polygons = polygons;
- return csg;
-};
-
-CSG.prototype = {
- clone: function() {
- var csg = new CSG();
- csg.polygons = this.polygons.map(function(p) { return p.clone(); });
- return csg;
- },
-
- toPolygons: function() {
- return this.polygons;
- },
-
- // Return a new CSG solid representing space in either this solid or in the
- // solid `csg`. Neither this solid nor the solid `csg` are modified.
- //
- // A.union(B)
- //
- // +-------+ +-------+
- // | | | |
- // | A | | |
- // | +--+----+ = | +----+
- // +----+--+ | +----+ |
- // | B | | |
- // | | | |
- // +-------+ +-------+
- //
- union: function(csg) {
- var a = new CSG.Node(this.clone().polygons);
- var b = new CSG.Node(csg.clone().polygons);
- a.clipTo(b);
- b.clipTo(a);
- b.invert();
- b.clipTo(a);
- b.invert();
- a.build(b.allPolygons());
- return CSG.fromPolygons(a.allPolygons());
- },
-
- // Return a new CSG solid representing space in this solid but not in the
- // solid `csg`. Neither this solid nor the solid `csg` are modified.
- //
- // A.subtract(B)
- //
- // +-------+ +-------+
- // | | | |
- // | A | | |
- // | +--+----+ = | +--+
- // +----+--+ | +----+
- // | B |
- // | |
- // +-------+
- //
- subtract: function(csg) {
- var a = new CSG.Node(this.clone().polygons);
- var b = new CSG.Node(csg.clone().polygons);
- a.invert();
- a.clipTo(b);
- b.clipTo(a);
- b.invert();
- b.clipTo(a);
- b.invert();
- a.build(b.allPolygons());
- a.invert();
- return CSG.fromPolygons(a.allPolygons());
- },
-
- // Return a new CSG solid representing space both this solid and in the
- // solid `csg`. Neither this solid nor the solid `csg` are modified.
- //
- // A.intersect(B)
- //
- // +-------+
- // | |
- // | A |
- // | +--+----+ = +--+
- // +----+--+ | +--+
- // | B |
- // | |
- // +-------+
- //
- intersect: function(csg) {
- var a = new CSG.Node(this.clone().polygons);
- var b = new CSG.Node(csg.clone().polygons);
- a.invert();
- b.clipTo(a);
- b.invert();
- a.clipTo(b);
- b.clipTo(a);
- a.build(b.allPolygons());
- a.invert();
- return CSG.fromPolygons(a.allPolygons());
- },
-
- // Return a new CSG solid with solid and empty space switched. This solid is
- // not modified.
- inverse: function() {
- var csg = this.clone();
- csg.polygons.map(function(p) { p.flip(); });
- return csg;
- }
-};
-
-// Construct an axis-aligned solid cuboid. Optional parameters are `center` and
-// `radius`, which default to `[0, 0, 0]` and `[1, 1, 1]`. The radius can be
-// specified using a single number or a list of three numbers, one for each axis.
-//
-// Example code:
-//
-// var cube = CSG.cube({
-// center: [0, 0, 0],
-// radius: 1
-// });
-CSG.cube = function(options) {
- options = options || {};
- var c = new CSG.Vector(options.center || [0, 0, 0]);
- var r = !options.radius ? [1, 1, 1] : options.radius.length ?
- options.radius : [options.radius, options.radius, options.radius];
- return CSG.fromPolygons([
- [[0, 4, 6, 2], [-1, 0, 0]],
- [[1, 3, 7, 5], [+1, 0, 0]],
- [[0, 1, 5, 4], [0, -1, 0]],
- [[2, 6, 7, 3], [0, +1, 0]],
- [[0, 2, 3, 1], [0, 0, -1]],
- [[4, 5, 7, 6], [0, 0, +1]]
- ].map(function(info) {
- return new CSG.Polygon(info[0].map(function(i) {
- var pos = new CSG.Vector(
- c.x + r[0] * (2 * !!(i & 1) - 1),
- c.y + r[1] * (2 * !!(i & 2) - 1),
- c.z + r[2] * (2 * !!(i & 4) - 1)
- );
- return new CSG.Vertex(pos, new CSG.Vector(info[1]));
- }));
- }));
-};
-
-// Construct a solid sphere. Optional parameters are `center`, `radius`,
-// `slices`, and `stacks`, which default to `[0, 0, 0]`, `1`, `16`, and `8`.
-// The `slices` and `stacks` parameters control the tessellation along the
-// longitude and latitude directions.
-//
-// Example usage:
-//
-// var sphere = CSG.sphere({
-// center: [0, 0, 0],
-// radius: 1,
-// slices: 16,
-// stacks: 8
-// });
-CSG.sphere = function(options) {
- options = options || {};
- var c = new CSG.Vector(options.center || [0, 0, 0]);
- var r = options.radius || 1;
- var slices = options.slices || 16;
- var stacks = options.stacks || 8;
- var polygons = [], vertices;
- function vertex(theta, phi) {
- theta *= Math.PI * 2;
- phi *= Math.PI;
- var dir = new CSG.Vector(
- Math.cos(theta) * Math.sin(phi),
- Math.cos(phi),
- Math.sin(theta) * Math.sin(phi)
- );
- vertices.push(new CSG.Vertex(c.plus(dir.times(r)), dir));
- }
- for (var i = 0; i < slices; i++) {
- for (var j = 0; j < stacks; j++) {
- vertices = [];
- vertex(i / slices, j / stacks);
- if (j > 0) vertex((i + 1) / slices, j / stacks);
- if (j < stacks - 1) vertex((i + 1) / slices, (j + 1) / stacks);
- vertex(i / slices, (j + 1) / stacks);
- polygons.push(new CSG.Polygon(vertices));
- }
- }
- return CSG.fromPolygons(polygons);
-};
-
-// Construct a solid cylinder. Optional parameters are `start`, `end`,
-// `radius`, and `slices`, which default to `[0, -1, 0]`, `[0, 1, 0]`, `1`, and
-// `16`. The `slices` parameter controls the tessellation.
-//
-// Example usage:
-//
-// var cylinder = CSG.cylinder({
-// start: [0, -1, 0],
-// end: [0, 1, 0],
-// radius: 1,
-// slices: 16
-// });
-CSG.cylinder = function(options) {
- options = options || {};
- var s = new CSG.Vector(options.start || [0, -1, 0]);
- var e = new CSG.Vector(options.end || [0, 1, 0]);
- var ray = e.minus(s);
- var r = options.radius || 1;
- var slices = options.slices || 16;
- var axisZ = ray.unit(), isY = (Math.abs(axisZ.y) > 0.5);
- var axisX = new CSG.Vector(isY, !isY, 0).cross(axisZ).unit();
- var axisY = axisX.cross(axisZ).unit();
- var start = new CSG.Vertex(s, axisZ.negated());
- var end = new CSG.Vertex(e, axisZ.unit());
- var polygons = [];
- function point(stack, slice, normalBlend) {
- var angle = slice * Math.PI * 2;
- var out = axisX.times(Math.cos(angle)).plus(axisY.times(Math.sin(angle)));
- var pos = s.plus(ray.times(stack)).plus(out.times(r));
- var normal = out.times(1 - Math.abs(normalBlend)).plus(axisZ.times(normalBlend));
- return new CSG.Vertex(pos, normal);
- }
- for (var i = 0; i < slices; i++) {
- var t0 = i / slices, t1 = (i + 1) / slices;
- polygons.push(new CSG.Polygon([start, point(0, t0, -1), point(0, t1, -1)]));
- polygons.push(new CSG.Polygon([point(0, t1, 0), point(0, t0, 0), point(1, t0, 0), point(1, t1, 0)]));
- polygons.push(new CSG.Polygon([end, point(1, t1, 1), point(1, t0, 1)]));
- }
- return CSG.fromPolygons(polygons);
-};
-
-// # class Vector
-
-// Represents a 3D vector.
-//
-// Example usage:
-//
-// new CSG.Vector(1, 2, 3);
-// new CSG.Vector([1, 2, 3]);
-// new CSG.Vector({ x: 1, y: 2, z: 3 });
-
-CSG.Vector = function(x, y, z) {
- if (arguments.length == 3) {
- this.x = x;
- this.y = y;
- this.z = z;
- } else if ('x' in x) {
- this.x = x.x;
- this.y = x.y;
- this.z = x.z;
- } else {
- this.x = x[0];
- this.y = x[1];
- this.z = x[2];
- }
-};
-
-CSG.Vector.prototype = {
- clone: function() {
- return new CSG.Vector(this.x, this.y, this.z);
- },
-
- negated: function() {
- return new CSG.Vector(-this.x, -this.y, -this.z);
- },
-
- plus: function(a) {
- return new CSG.Vector(this.x + a.x, this.y + a.y, this.z + a.z);
- },
-
- minus: function(a) {
- return new CSG.Vector(this.x - a.x, this.y - a.y, this.z - a.z);
- },
-
- times: function(a) {
- return new CSG.Vector(this.x * a, this.y * a, this.z * a);
- },
-
- dividedBy: function(a) {
- return new CSG.Vector(this.x / a, this.y / a, this.z / a);
- },
-
- dot: function(a) {
- return this.x * a.x + this.y * a.y + this.z * a.z;
- },
-
- lerp: function(a, t) {
- return this.plus(a.minus(this).times(t));
- },
-
- length: function() {
- return Math.sqrt(this.dot(this));
- },
-
- unit: function() {
- return this.dividedBy(this.length());
- },
-
- cross: function(a) {
- return new CSG.Vector(
- this.y * a.z - this.z * a.y,
- this.z * a.x - this.x * a.z,
- this.x * a.y - this.y * a.x
- );
- }
-};
-
-// # class Vertex
-
-// Represents a vertex of a polygon. Use your own vertex class instead of this
-// one to provide additional features like texture coordinates and vertex
-// colors. Custom vertex classes need to provide a `pos` property and `clone()`,
-// `flip()`, and `interpolate()` methods that behave analogous to the ones
-// defined by `CSG.Vertex`. This class provides `normal` so convenience
-// functions like `CSG.sphere()` can return a smooth vertex normal, but `normal`
-// is not used anywhere else.
-
-CSG.Vertex = function(pos, normal) {
- this.pos = new CSG.Vector(pos);
- this.normal = new CSG.Vector(normal);
-};
-
-CSG.Vertex.prototype = {
- clone: function() {
- return new CSG.Vertex(this.pos.clone(), this.normal.clone());
- },
-
- // Invert all orientation-specific data (e.g. vertex normal). Called when the
- // orientation of a polygon is flipped.
- flip: function() {
- this.normal = this.normal.negated();
- },
-
- // Create a new vertex between this vertex and `other` by linearly
- // interpolating all properties using a parameter of `t`. Subclasses should
- // override this to interpolate additional properties.
- interpolate: function(other, t) {
- return new CSG.Vertex(
- this.pos.lerp(other.pos, t),
- this.normal.lerp(other.normal, t)
- );
- }
-};
-
-// # class Plane
-
-// Represents a plane in 3D space.
-
-CSG.Plane = function(normal, w) {
- this.normal = normal;
- this.w = w;
-};
-
-// `CSG.Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a
-// point is on the plane.
-CSG.Plane.EPSILON = 1e-5;
-
-CSG.Plane.fromPoints = function(a, b, c) {
- var n = b.minus(a).cross(c.minus(a)).unit();
- return new CSG.Plane(n, n.dot(a));
-};
-
-CSG.Plane.prototype = {
- clone: function() {
- return new CSG.Plane(this.normal.clone(), this.w);
- },
-
- flip: function() {
- this.normal = this.normal.negated();
- this.w = -this.w;
- },
-
- // Split `polygon` by this plane if needed, then put the polygon or polygon
- // fragments in the appropriate lists. Coplanar polygons go into either
- // `coplanarFront` or `coplanarBack` depending on their orientation with
- // respect to this plane. Polygons in front or in back of this plane go into
- // either `front` or `back`.
- splitPolygon: function(polygon, coplanarFront, coplanarBack, front, back) {
- var COPLANAR = 0;
- var FRONT = 1;
- var BACK = 2;
- var SPANNING = 3;
-
- // Classify each point as well as the entire polygon into one of the above
- // four classes.
- var polygonType = 0;
- var types = [];
- for (var i = 0; i < polygon.vertices.length; i++) {
- var t = this.normal.dot(polygon.vertices[i].pos) - this.w;
- var type = (t < -CSG.Plane.EPSILON) ? BACK : (t > CSG.Plane.EPSILON) ? FRONT : COPLANAR;
- polygonType |= type;
- types.push(type);
- }
-
- // Put the polygon in the correct list, splitting it when necessary.
- switch (polygonType) {
- case COPLANAR:
- (this.normal.dot(polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon);
- break;
- case FRONT:
- front.push(polygon);
- break;
- case BACK:
- back.push(polygon);
- break;
- case SPANNING:
- var f = [], b = [];
- for (var i = 0; i < polygon.vertices.length; i++) {
- var j = (i + 1) % polygon.vertices.length;
- var ti = types[i], tj = types[j];
- var vi = polygon.vertices[i], vj = polygon.vertices[j];
- if (ti != BACK) f.push(vi);
- if (ti != FRONT) b.push(ti != BACK ? vi.clone() : vi);
- if ((ti | tj) == SPANNING) {
- var t = (this.w - this.normal.dot(vi.pos)) / this.normal.dot(vj.pos.minus(vi.pos));
- var v = vi.interpolate(vj, t);
- f.push(v);
- b.push(v.clone());
- }
- }
- if (f.length >= 3) front.push(new CSG.Polygon(f, polygon.shared));
- if (b.length >= 3) back.push(new CSG.Polygon(b, polygon.shared));
- break;
- }
- }
-};
-
-// # class Polygon
-
-// Represents a convex polygon. The vertices used to initialize a polygon must
-// be coplanar and form a convex loop. They do not have to be `CSG.Vertex`
-// instances but they must behave similarly (duck typing can be used for
-// customization).
-//
-// Each convex polygon has a `shared` property, which is shared between all
-// polygons that are clones of each other or were split from the same polygon.
-// This can be used to define per-polygon properties (such as surface color).
-
-CSG.Polygon = function(vertices, shared) {
- this.vertices = vertices;
- this.shared = shared;
- this.plane = CSG.Plane.fromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
-};
-
-CSG.Polygon.prototype = {
- clone: function() {
- var vertices = this.vertices.map(function(v) { return v.clone(); });
- return new CSG.Polygon(vertices, this.shared);
- },
-
- flip: function() {
- this.vertices.reverse().map(function(v) { v.flip(); });
- this.plane.flip();
- }
-};
-
-// # class Node
-
-// Holds a node in a BSP tree. A BSP tree is built from a collection of polygons
-// by picking a polygon to split along. That polygon (and all other coplanar
-// polygons) are added directly to that node and the other polygons are added to
-// the front and/or back subtrees. This is not a leafy BSP tree since there is
-// no distinction between internal and leaf nodes.
-
-CSG.Node = function(polygons) {
- this.plane = null;
- this.front = null;
- this.back = null;
- this.polygons = [];
- if (polygons) this.build(polygons);
-};
-
-CSG.Node.prototype = {
- clone: function() {
- var node = new CSG.Node();
- node.plane = this.plane && this.plane.clone();
- node.front = this.front && this.front.clone();
- node.back = this.back && this.back.clone();
- node.polygons = this.polygons.map(function(p) { return p.clone(); });
- return node;
- },
-
- // Convert solid space to empty space and empty space to solid space.
- invert: function() {
- for (var i = 0; i < this.polygons.length; i++) {
- this.polygons[i].flip();
- }
- this.plane.flip();
- if (this.front) this.front.invert();
- if (this.back) this.back.invert();
- var temp = this.front;
- this.front = this.back;
- this.back = temp;
- },
-
- // Recursively remove all polygons in `polygons` that are inside this BSP
- // tree.
- clipPolygons: function(polygons) {
- if (!this.plane) return polygons.slice();
- var front = [], back = [];
- for (var i = 0; i < polygons.length; i++) {
- this.plane.splitPolygon(polygons[i], front, back, front, back);
- }
- if (this.front) front = this.front.clipPolygons(front);
- if (this.back) back = this.back.clipPolygons(back);
- else back = [];
- return front.concat(back);
- },
-
- // Remove all polygons in this BSP tree that are inside the other BSP tree
- // `bsp`.
- clipTo: function(bsp) {
- this.polygons = bsp.clipPolygons(this.polygons);
- if (this.front) this.front.clipTo(bsp);
- if (this.back) this.back.clipTo(bsp);
- },
-
- // Return a list of all polygons in this BSP tree.
- allPolygons: function() {
- var polygons = this.polygons.slice();
- if (this.front) polygons = polygons.concat(this.front.allPolygons());
- if (this.back) polygons = polygons.concat(this.back.allPolygons());
- return polygons;
- },
-
- // Build a BSP tree out of `polygons`. When called on an existing tree, the
- // new polygons are filtered down to the bottom of the tree and become new
- // nodes there. Each set of polygons is partitioned using the first polygon
- // (no heuristic is used to pick a good split).
- build: function(polygons) {
- if (!polygons.length) return;
- if (!this.plane) this.plane = polygons[0].plane.clone();
- var front = [], back = [];
- for (var i = 0; i < polygons.length; i++) {
- this.plane.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);
- }
- if (front.length) {
- if (!this.front) this.front = new CSG.Node();
- this.front.build(front);
- }
- if (back.length) {
- if (!this.back) this.back = new CSG.Node();
- this.back.build(back);
- }
- }
-};
diff --git a/slice_test.html b/slice_test.html
index aaa29a0..251a7a0 100644
--- a/slice_test.html
+++ b/slice_test.html
@@ -5,7 +5,6 @@
-
diff --git a/src/slicer.js b/src/slicer.js
index f84acd6..68091c8 100644
--- a/src/slicer.js
+++ b/src/slicer.js
@@ -216,8 +216,6 @@ D3D.Slicer.prototype.slicesToData = function (slices, printer) {
for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer];
- var highFillTemplate = this.getFillTemplate(dimensionsZ, wallThickness, (layer % 2 === 0), (layer % 2 === 1));
-
//var outerLayer = ClipperLib.JS.Clean(slice, 1.0);
var outerLayer = slice.clone();
ClipperLib.JS.ScaleUpPaths(outerLayer, scale);
@@ -284,6 +282,10 @@ D3D.Slicer.prototype.slicesToData = function (slices, printer) {
fill = fill.concat(lowFillStrokes);
+ //optimize
+ //make as big as bounding box of highfillArea
+ var highFillTemplate = this.getFillTemplate(dimensionsZ, wallThickness, (layer % 2 === 0), (layer % 2 === 1));
+
var clipper = new ClipperLib.Clipper();
var highFillStrokes = new ClipperLib.Paths();
clipper.AddPaths(highFillTemplate, ClipperLib.PolyType.ptSubject, false);