UNPKG

jsx

Version:

a faster, safer, easier JavaScript

344 lines (253 loc) 8.33 kB
// Curvature Sakura // // originated from http://jsdo.it/sasaplus1/yREo, // which is forked from http://jsdo.it/totetero/sakura import "js/web.jsx"; import "timer.jsx"; class Config { static const NUMBER_OF_PETALS = 24; // min/max size of a sakura petal static const MIN_SIZE = 5; static const SIZE_RANGE = 15; static const TEXTURE_FILE = "sakura.png"; static const STAGE_WIDTH = 400; // dom.window.innerWidth static const STAGE_HEIGHT = 400; // dom.window.innerHeight } final class Sakura { var x : number; var y : number; var vx : number; var vy : number; var size : number; var rotq0 = [0, 0, 0, 1]; var rotq1 = [0, 0, 0, 1]; function constructor(size : int, width : int, height : int) { this.size = size; this.init(width, height); } function randq(q : Array.<number>, rot : number) : void { var x = Math.random() - 0.5; var y = Math.random() - 0.5; var z = Math.random() - 0.5; var r = x * x + y * y + z * z; if (r == 0) { x = r = 1; y = z = 0; } var s = Math.sin(rot) / Math.sqrt(r); q[0] = x * s; q[1] = y * s; q[2] = z * s; q[3] = Math.cos(rot); } function init(width : int, height : int) : void { if (Math.random() > 0.5) { this.x = Math.random() * width; this.y = 0 - this.size; } else { this.x = 0 - this.size; this.y = Math.random() * height; } this.vx = (Math.random() * 1.5 + 2.5) * this.size / 20; this.vy = (Math.random() * 1.5 + 0.5) * this.size / 20; this.randq(this.rotq0, Math.random() * Math.PI); this.randq(this.rotq1, Math.random() * 0.1); } function update(width : int, height : int) : void { this.x += this.vx; this.y += this.vy; if (this.x > width + this.size || this.y > height + this.size) { this.init(width, height); } if (Math.random() > 0.95) { this.randq(this.rotq1, Math.random() * 0.1); } var qax = this.rotq0[0]; var qay = this.rotq0[1]; var qaz = this.rotq0[2]; var qaw = this.rotq0[3]; var qbx = this.rotq1[0]; var qby = this.rotq1[1]; var qbz = this.rotq1[2]; var qbw = this.rotq1[3]; this.rotq0[0] = qax*qbw + qaw*qbx + qay*qbz - qaz*qby; this.rotq0[1] = qay*qbw + qaw*qby + qaz*qbx - qax*qbz; this.rotq0[2] = qaz*qbw + qaw*qbz + qax*qby - qay*qbx; this.rotq0[3] = qaw*qbw - qax*qbx - qay*qby - qaz*qbz; } } final class Stage { // the stage width and height var width : number; var height : number; // the render context of the stage var context: CanvasRenderingContext2D; // data of petal var canvasdat : ImageData; // data of texture var imgdat : ImageData; // petals for sakura-fubuki var sakura = new Array.<Sakura>(); function constructor(canvas : HTMLCanvasElement, imgdat : ImageData) { assert canvas != null; assert imgdat != null; this.width = canvas.width = Config.STAGE_WIDTH; this.height = canvas.height = Config.STAGE_HEIGHT; this.context = canvas.getContext('2d') as CanvasRenderingContext2D; this.canvasdat = this.context.createImageData(this.width, this.height); this.imgdat = imgdat; var sakuraPosXMax = 0; var sakuraPosYMax = 0; for (var i = 0; i < Config.NUMBER_OF_PETALS; ++i) { this.sakura[i] = new Sakura(( (Math.random() * Config.SIZE_RANGE) + Config.MIN_SIZE) as int, this.width, this.height); if (this.sakura[i].x > sakuraPosXMax) { sakuraPosXMax = this.sakura[i].x; } if (this.sakura[i].y > sakuraPosYMax) { sakuraPosYMax = this.sakura[i].y; } } for (i = 0; i < Config.NUMBER_OF_PETALS; ++i) { this.sakura[i].x -= sakuraPosXMax + 50; } this.sakura.sort(function (a, b) { return a.size - b.size; }); } function clear(): void { var data = this.canvasdat.data; for(var i = 0; i < this.height; i++){ for(var j = 0; j < this.width; j++){ var index = i * this.width + j; data[index * 4 + 0] = 0; data[index * 4 + 1] = 0; data[index * 4 + 2] = 0; data[index * 4 + 3] = 255; } } } function drawTexture(gray : number, x : number, y : number, z : number, q : Array.<number>, index: number) : void { var ix = q[3] * x + q[1] * z - q[2] * y; var iy = q[3] * y + q[2] * x - q[0] * z; var iz = q[3] * z + q[0] * y - q[1] * x; var iw = -q[0] * x - q[1] * y - q[2] * z; x = ix * q[3] - iw * q[0] - iy * q[2] + iz * q[1]; y = iy * q[3] - iw * q[1] - iz * q[0] + ix * q[2]; z = iz * q[3] - iw * q[2] - ix * q[1] + iy * q[0]; var u = Math.atan2(z, x) / Math.PI; if(0 <= u && u <= 1){ var v = Math.acos(y) / Math.PI; u = ((1 - u) * this.imgdat.height) as int; v = ((1 - v) * this.imgdat.width) as int; var index2 = v * this.imgdat.width + u; if (this.imgdat.data[index2 * 4 + 3] > 128) { var dst = this.canvasdat.data; var src = this.imgdat.data; dst[index * 4 + 0] = src[index2 * 4 + 0] * gray; dst[index * 4 + 1] = src[index2 * 4 + 1] * gray; dst[index * 4 + 2] = src[index2 * 4 + 2] * gray; } } } function drawSakura(x0 : number, y0 : number, q : Array.<number>, size : number) : void { var xmin = x0 - size; var xmax = x0 + size; var ymin = y0 - size; var ymax = y0 + size; for (var i = ymin; i < ymax; i++) { if (i < 0) { continue; } else if (i >= this.height) { break; } for (var j = xmin; j < xmax; j++) { if (j < 0) { continue; } else if (j >= this.width) { break; } var index = i * this.width + j; var x = (j - x0) / size; var y = (i - y0) / size; var r = x * x + y * y; if (r <= 1) { var z = Math.sqrt(1 - r); this.drawTexture(0.4, x, y, -z, q, index); this.drawTexture(1.0, x, y, z, q, index); } } } this.drawSphere(x0, y0, q, size); } function drawSphere(x0 : number, y0 : number, q : Array.<number>, size : number) : void { var x1 = x0 + (size * 1.6 * (q[0] * q[2] - q[1] * q[3])) as int; var y1 = y0 + (size * 1.6 * (q[0] * q[3] + q[1] * q[2])) as int; var xmin = x1 - size; var xmax = x1 + size; var ymin = y1 - size; var ymax = y1 + size; var data = this.canvasdat.data; for (var i = ymin; i < ymax; i++) { if (i < 0) { continue; } else if (i >= this.height) { break; } for (var j = xmin; j < xmax; j++) { if (j < 0) { continue; } else if (j >= this.width) { break; } var index = i * this.width + j; var x = (j - x1) / size; var y = (i - y1) / size; var r = 128 * (1 - (x * x + y * y)); if (r > 0) { data[index * 4 + 0] += r; data[index * 4 + 1] += r; data[index * 4 + 2] += r; } } } } function tick(): void { this.clear(); var len = this.sakura.length; for (var i = 0; i < len; ++i) { var s = this.sakura[i]; s.update(this.width, this.height); this.drawSakura( s.x as int, s.y as int, s.rotq0, s.size); } this.context.putImageData(this.canvasdat, 0, 0); } } final class _Main { static function main(args : string[]) : void { // load textrue data and start main loop var img = dom.createElement('img') as HTMLImageElement; img.addEventListener("load", function (event) { var texture = dom.createElement('canvas') as HTMLCanvasElement; var context = texture.getContext('2d') as CanvasRenderingContext2D; texture.width = texture.height = 256; context.drawImage(img, 0, 0, texture.width, texture.height); var world = dom.id("world") as HTMLCanvasElement; var texturedat = context.getImageData(0, 0, texture.width, texture.height); var stage = new Stage(world, texturedat); (function callTick(timeToCall : number) : void { stage.tick(); Timer.requestAnimationFrame(callTick); }(0)); }); img.src = Config.TEXTURE_FILE; } } // vim: set expandtab : // vim: set tabstop=2 : // vim: set shiftwidth=2 :