forked from: Pyramids
@author Anatoly Zenkov
http://anatolyzenkov.com/
CLICK TO REGENERATE
// forked from anatolyzenkov's Pyramids
package {
/**
* @author Anatoly Zenkov
* http://anatolyzenkov.com/
*/
// CLICK TO REGENERATE
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import flash.system.LoaderContext;
[SWF(backgroundColor=0x000000,frameRate=41)]
public class Pyramids extends Sprite {
private var _bitmap : Bitmap;
private var _pyramids : Array;
static public const DOUBLE_PI : Number = 2 * Math.PI;
static public const HALF_PI : Number = .5 * Math.PI;
static public var OFFSET_X : Number;
static public var OFFSET_Y : Number;
private var _pyramidLayer : Shape;
private var _gradient : BitmapData;
private var _currentBitmap : BitmapData;
private const REFLECTIONS : int = 4;
private const MAX_PYRAMIDS : int = 6;
private const SIDES : int = 7;
public function Pyramids() {
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(event : Event) : void {
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
addChild(_bitmap = new Bitmap());
_gradient = new BitmapData(600, 600, false);
_currentBitmap = _gradient;
var rect : Rectangle = new Rectangle(0, 0, 600, 600 / 255);
for (var i : int = 0;i < 255;i++) {
rect.y = i / 255 * 600;
_currentBitmap.fillRect(rect, i << 16 | i << 8 | i);
}
_bitmap.bitmapData = _currentBitmap.clone();
alignBitmap();
load("http://assets.anatolyzenkov.com/misc/pool.jpg");
_pyramidLayer = new Shape();
stage.addEventListener(MouseEvent.CLICK, addPyramids);
addPyramids(null);
addEventListener(Event.ENTER_FRAME, updatePyramids);
}
private function updatePyramids(event : Event) : void {
_bitmap.bitmapData.copyPixels(_currentBitmap, _currentBitmap.rect, new Point());
var rects : Array = [];
var p : Pyramid;
for each (p in _pyramids) {
p.update((stage.stageWidth * .5 - mouseX) / stage.stageWidth * 2, (stage.stageHeight * .5 - mouseY) / stage.stageHeight * 2);
rects[rects.length] = p.getBoundRect();
}
var m : Number;
for (var i : int = 0;i < REFLECTIONS;i++) {
m = 0.9 + .1 * i / REFLECTIONS;
var j : int = 0;
var colortrans : ColorTransform = new ColorTransform(m, m, m);
for each (p in _pyramids) {
_pyramidLayer.graphics.clear();
p.draw(_pyramidLayer.graphics, _bitmap.bitmapData);
_bitmap.bitmapData.draw(_pyramidLayer, new Matrix(1, 0, 0, 1, -OFFSET_X, -OFFSET_Y), colortrans, BlendMode.NORMAL, rects[j]);
j++;
}
}
}
private function addPyramids(event : MouseEvent) : void {
_pyramids = [];
var r : Number;
var p : Pyramid;
for (var i : int = 0;i < 2 + (MAX_PYRAMIDS - 2) * Math.random();i++) {
var points : Array = [];
for (var j : Number = 0;j < DOUBLE_PI;j += DOUBLE_PI / (2 + (SIDES - 2) * Math.random())) {
r = 100 + Math.random() * 50;
points[points.length] = new Point(r * Math.cos(j), r * Math.sin(j));
}
p = new Pyramid(points);
p.x = 50 + (stage.stageWidth - 100) * Math.random();
p.y = 50 + (stage.stageHeight - 100) * Math.random();
p.scale = .6 + .6 * Math.random();
p.scale *= p.scale;
_pyramids[_pyramids.length] = p;
}
_pyramids.sortOn("scale");
}
private function alignBitmap() : void {
_bitmap.x = OFFSET_X = int((stage.stageWidth - _bitmap.width) * .5);
_bitmap.y = OFFSET_Y = int((stage.stageHeight - _bitmap.height) * .5);
}
///////////////////////////////////////////////////////////////////////////////
// imageLoader stuff
///////////////////////////////////////////////////////////////////////////////
private function load(url : String) : void {
var imageLoader : Loader = new Loader();
imageLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, imageLoader_ioErrorEventHandler);
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoader_compelteEventHandler);
imageLoader.load(new URLRequest(url), new LoaderContext(true));
}
private function imageLoader_compelteEventHandler(event : Event) : void {
var content : DisplayObject = (event.target as LoaderInfo).content;
_currentBitmap = (content as Bitmap).bitmapData;
_bitmap.bitmapData = _currentBitmap.clone();
alignBitmap();
clearLoader(event.target as LoaderInfo);
}
private function imageLoader_ioErrorEventHandler(event : IOErrorEvent) : void {
clearLoader(event.target as LoaderInfo);
}
private function clearLoader(loaderInfo : LoaderInfo) : void {
loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, imageLoader_ioErrorEventHandler);
loaderInfo.removeEventListener(Event.COMPLETE, imageLoader_compelteEventHandler);
}
///////////////////////////////////////////////////////////////////////////////
}
}
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
class Pyramid {
private var _points : Array;
private var _centralPoint : Point;
private var _matrix : Matrix;
private var _targetAngle : Number;
public var scale : Number;
public var angle : Number;
public var x : Number;
public var y : Number;
private var _easyAngle : Number;
private var _transformedPoints : Array;
private var _targetMouseX : Number;
private var _targetMouseY : Number;
public function Pyramid(points : Array) {
_centralPoint = new Point();
_points = points;
_matrix = new Matrix();
_targetAngle = Pyramids.DOUBLE_PI * Math.random();
_easyAngle = Pyramids.DOUBLE_PI * Math.random();
_targetMouseX = 0;
_targetMouseY = 0;
scale = 1;
angle = Pyramids.DOUBLE_PI * Math.random();
x = 0;
y = 0;
}
public function draw(graphics : Graphics, bitmapData : BitmapData) : void {
_transformedPoints = [];
for each (var p : Point in _points) {
_transformedPoints[_transformedPoints.length] = _matrix.transformPoint(p);
}
var cp : Point = _matrix.transformPoint(_centralPoint);
cp.x -= 50 * _targetMouseX * scale * scale;
cp.y -= 50 * _targetMouseY * scale * scale;
p = new Point();
var p0 : Point = _transformedPoints[0];
var p1 : Point;
var sp : Point = new Point();
var mtrx : Matrix = new Matrix();
for (var i : int = 1;i <= _transformedPoints.length;i++) {
p1 = _transformedPoints[i % _transformedPoints.length];
sp.x = p0.x - Pyramids.OFFSET_X;
sp.y = p0.y - Pyramids.OFFSET_Y;
var a0 : Number = Math.atan2(sp.y, sp.x);
var a1 : Number = Math.atan2(p0.y - p1.y, p0.x - p1.x);
var d : Number = 2 * sp.length * Math.cos(Pyramids.HALF_PI - a1 + a0);
var a : Number = a1 - Pyramids.HALF_PI;
p.x = Math.cos(a) * d;
p.y = Math.sin(a) * d;
mtrx.identity();
mtrx.scale(-1, 1);
mtrx.rotate(2 * a);
mtrx.translate(p.x + Pyramids.OFFSET_X, p.y + Pyramids.OFFSET_Y);
with (graphics) {
beginBitmapFill(bitmapData, mtrx, true, true);
moveTo(p0.x, p0.y);
lineTo(p1.x, p1.y);
lineTo(cp.x, cp.y);
lineTo(p0.x, p0.y);
endFill();
}
p0 = p1;
}
}
public function update(tx : Number, ty : Number) : void {
if (Math.random() < .005) _targetAngle = (6 - 12 * Math.random()) * Pyramids.DOUBLE_PI;
var da : Number = correctAngle(_targetAngle, _easyAngle);
_easyAngle -= Math.min(Math.abs(da), 0.6) * .1 * sign(da);
angle -= correctAngle(_easyAngle, angle) * .05;
tx = Math.max(Math.min(tx, .7), -.7);
ty = Math.max(Math.min(ty, .7), -.7);
_targetMouseX += (tx - _targetMouseX) * .1;
_targetMouseY += (ty - _targetMouseY) * .1;
_matrix.identity();
_matrix.scale(scale, scale);
_matrix.rotate(angle);
_matrix.translate(x - 300 * _targetMouseX * scale * scale, y - 300 * _targetMouseY * scale * scale);
}
public function getBoundRect() : Rectangle {
var r : Rectangle = new Rectangle(Infinity, Infinity, -Infinity, -Infinity);
for each (var p : Point in _transformedPoints) {
if (p.x < r.x) r.x = p.x;
if (p.y < r.y) r.y = p.y;
if (p.x > r.width) r.width = p.x;
if (p.y > r.height) r.height = p.y;
}
r.width = r.width - r.x + 2;
r.height = r.height - r.y + 2;
r.x -= Pyramids.OFFSET_X + 1;
r.y -= Pyramids.OFFSET_Y + 1;
return r;
}
public static function sign(n : Number) : Number {
if (!n) return 0;
return n > 0 ? 1 : -1;
}
public static function correctAngle(a0 : Number, a1 : Number) : Number {
var d : Number = a1 - a0;
if (d > Pyramids.HALF_PI) return d % Pyramids.DOUBLE_PI;
if (d < -Pyramids.HALF_PI) return d % (-Pyramids.DOUBLE_PI);
return d;
}
}