/**
* Copyright rainafter ( http://wonderfl.net/user/rainafter )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/oJ9J
*/
// forked from Test_Dept's Kaleidoscope
package {
import flash.display.Sprite;
/**
* Kaleidoscope
* @author Test Dept
*/
[SWF(backgroundColor="#ffffff", width="465", height="465")]
public class Kaleidoscope extends Sprite {
public function Kaleidoscope() {
addChild(new KaleidoscopeImpl() );
}
}
}
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.media.Camera;
import flash.media.Video;
import flash.geom.Rectangle;
class KaleidoscopeImpl extends Sprite {
private var _a : UIPoint;
private var _b : UIPoint;
private var _c : UIPoint;
private var _d : UIPoint;
private var _o : UIPoint;
private var _p : UIPoint;
private var _bmp : BitmapData;
private var _video : Video;
public function KaleidoscopeImpl() {
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(event : Event) : void {
var width : Number = stage.stageWidth;
var height : Number = stage.stageHeight;
addChild(_a = new UIPoint(0x000000, 10, height / 2, "a", true) );
addChild(_b = new UIPoint(0x000000, width - 10, height / 2 - 40, "b", true) );
addChild(_c = new UIPoint(0x000000, width / 2, height / 2, "c", true) );
addChild(_o = new UIPoint(0x000000, 0, 0, "o") );
addChild(_p = new UIPoint(0x000000, 0, 0, "p") );
addChild(_d = new UIPoint(0x000000, 0, 0, "c'") );
_bmp = new BitmapData(width, height, false, 0xffffff);
_bmp.draw(new RandomImage(width, height) );
var camera : Camera = Camera.getCamera();
if (camera != null) {
camera.setMode(width, height, 16, true);
_video = new Video(camera.width, camera.height);
_video.attachCamera(camera);
} else {
_video = null;
}
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
private function enterFrameHandler(event : Event) : void {
var a : Point = new Point(_a.x, _a.y);
var b : Point = new Point(_b.x, _b.y);
var c : Point = new Point(_c.x, _c.y);
var o : Point = GeoUtil.getCenter(a, b, c);
_o.x = o.x;
_o.y = o.y;
var ref_c : Point = GeoUtil.getCRef(a, b, c);
_d.x = ref_c.x;
_d.y = ref_c.y;
var p_bc : Point = GeoUtil.getCrossPoint(o, a, b, ref_c);
var p_ac : Point = GeoUtil.getCrossPoint(o, b, a, ref_c);
var new_c : Point;
if (p_bc != null) {
new_c = p_bc;
} else if (p_ac != null) {
new_c = p_ac;
} else {
new_c = ref_c;
}
_p.visible = (new_c != ref_c);
_p.x = new_c.x;
_p.y = new_c.y;
if (_video != null) {
_bmp.draw(_video, new Matrix(_video.scaleX, 0, 0, _video.scaleY) );
}
var ksImage : KaleidoscopeImage = new KaleidoscopeImage(_bmp.width, _bmp.height);
var g : Graphics = graphics;
g.clear();
g.lineStyle(1, 0x000000, 0.5);
g.beginBitmapFill(_bmp);
ksImage.draw(g, o, a, b, c);
g.endFill();
}
}
class KaleidoscopeImage {
private var _width : Number;
private var _height : Number;
private var _maxNest : int;
private var _o : Point;
private var _vertices : Vector.<Number>;
private var _indices : Vector.<int>;
private var _uvtData : Vector.<Number>;
public function KaleidoscopeImage(width : Number, height : Number, maxNest : int = 16) {
_width = width;
_height = height;
_maxNest = maxNest;
}
public function draw(g : Graphics, o : Point, a : Point, b : Point, c : Point) : void {
_o = o;
_vertices = new Vector.<Number>();
_indices = new Vector.<int>();
_uvtData = new Vector.<Number>();
var t : Point = get_uvt(a);
var u : Point = get_uvt(b);
var v : Point = get_uvt(c);
addTriangle(a, b, c, t, u, v);
reflect(a, b, c, t, u, v, 0);
reflect(b, c, a, u, v, t, 0);
reflect(c, a, b, v, t, u, 0);
g.drawTriangles(_vertices, null, _uvtData);
}
private function reflect(
a : Point, b : Point, c : Point,
t : Point, u : Point, v : Point,
nest : int
) : void {
if (nest > _maxNest) {
return;
}
if (!isVisible(a, b, c) ) {
return;
}
var ref_c : Point = GeoUtil.getCRef(a, b, c);
var c_bc : Point = GeoUtil.getCrossPoint(_o, a, b, ref_c);
var c_ac : Point = GeoUtil.getCrossPoint(_o, b, a, ref_c);
var new_c : Point;
if (c_bc != null) {
new_c = c_bc;
} else if (c_ac != null) {
new_c = c_ac;
} else {
new_c = ref_c;
}
var new_v : Point = GeoUtil.createTransformMatrix(a, b, ref_c, t, u, v)
.transformPoint(new_c);
addTriangle(a, b, new_c, t, u, new_v);
if (c_bc == null) {
reflect(new_c, a, b, new_v, t, u, nest + 1);
}
if (c_ac == null) {
reflect(new_c, b, a, new_v, u, t, nest + 1);
}
}
private function addTriangle(
a : Point, b : Point, c : Point,
t : Point, u : Point, v : Point
) : void {
_vertices.push(a.x, a.y, b.x, b.y, c.x, c.y);
_indices.push(0, 1, 2);
_uvtData.push(t.x, t.y, u.x, u.y, v.x, v.y);
}
private function get_uvt(p : Point) : Point {
return new Point(p.x / _width, p.y / _height);
}
private function isVisible(a : Point, b : Point, c : Point) : Boolean {
var minX : Number = Math.min(a.x, b.x, c.x);
var minY : Number = Math.min(a.y, b.y, c.y);
var maxX : Number = Math.max(a.x, b.x, c.x);
var maxY : Number = Math.max(a.y, b.y, c.y);
var r1 : Rectangle = new Rectangle(
0, 0, _width, _height);
var r2 : Rectangle = new Rectangle(
minX, minY, maxX - minX, maxY - minY);
return r1.intersects(r2);
}
}
class RandomImage extends Sprite {
public function RandomImage(width : Number, height : Number) {
var colors : Array = [
0xff0000,
0xffff00,
0x00ff00,
0x00ffff,
0x0000ff,
0xff00ff
];
// var rand : Function = Math.random;
var rand : Function = FakeRand.random;
var g : Graphics = graphics;
g.clear();
for (var i : int = 0; i < 100; i++) {
var x : Number = rand() * width;
var y : Number = rand() * height;
var r : Number = rand() * 50 + 10;
var c : uint = colors[i % colors.length];
g.beginFill(c, 0.4);
g.drawCircle(x, y, r);
g.endFill();
}
}
}
class FakeRand {
private var _num : Number;
private var _digits : int;
public function FakeRand(seed : Number = 0, digits : int = 10000) {
_num = Math.exp(seed);
_digits = digits;
}
public function next() : Number {
_num = _num * _digits + Math.PI;
_num = _num - Math.floor(_num);
return int(_num * _digits) % _digits / _digits;
}
private static var _instance : FakeRand = new FakeRand();
public static function random() : Number {
return _instance.next();
}
}
class GeoUtil {
public static function getCenter(
a : Point, b : Point, c : Point
) : Point {
var bc : Point = new Point(
(b.x + c.x) / 2,
(b.y + c.y) / 2);
return new Point(
a.x + (bc.x - a.x) * 2 / 3,
a.y + (bc.y - a.y) * 2 / 3);
}
public static function createMatrix(
a : Point, b : Point, c : Point,
invert : Boolean = false
) : Matrix {
var m : Matrix = new Matrix(
b.x - a.x, b.y - a.y,
c.x - a.x, c.y - a.y);
if (invert) {
m.invert();
}
return m;
}
public static function createTransformMatrix(
a : Point, b : Point, c : Point,
t : Point, u : Point, v : Point
) : Matrix {
var m1 : Matrix = new Matrix();
m1.translate(-a.x, -a.y);
m1.concat(createMatrix(a, b, c, true) );
m1.concat(createMatrix(t, u, v) );
m1.translate(t.x, t.y);
return m1;
}
public static function getCRef(
a : Point, b : Point, c : Point
) : Point {
var m1 : Matrix = new Matrix();
var m2 : Matrix = new Matrix(
b.x - a.x, b.y - a.y, a.y - b.y, b.x - a.x);
var m3 : Matrix = new Matrix(1, 0, 0, -1);
m1.translate(-a.x, -a.y);
m2.invert();
m1.concat(m2);
m1.concat(m3);
m2.invert();
m1.concat(m2);
m1.translate(a.x, a.y);
return m1.transformPoint(new Point(c.x, c.y) );
}
public static function getCrossPoint(
o : Point,
a : Point, b : Point, c : Point
) : Point {
var mat : Matrix = new Matrix(
a.x - o.x, a.y - o.y,
c.x - b.x, c.y - b.y);
mat.invert();
var st : Point = mat.transformPoint(b.subtract(o) );
var s : Number = st.x;
var t : Number = -st.y;
if (0 <= t && t <= 1) {
return new Point(
o.x + (a.x - o.x) * s,
o.y + (a.y - o.y) * s);
} else {
return null;
}
}
}
class UIPoint extends Sprite {
private var _pressed : Boolean;
private var _dragX : Number;
private var _dragY : Number;
public function UIPoint(
color : uint, x : Number, y : Number, label : String,
movable : Boolean = false
) {
var g : Graphics = graphics;
g.clear();
g.beginFill(color, 0.5);
g.drawCircle(0, 0, 10);
g.endFill();
var labelField : TextField = new TextField();
labelField.type = TextFieldType.DYNAMIC;
labelField.autoSize = TextFieldAutoSize.LEFT;
labelField.selectable = true;
labelField.text = label;
labelField.x = 4;
labelField.y = 4;
addChild(labelField);
this.x = x;
this.y = y;
buttonMode = movable;
useHandCursor = movable;
if (movable) {
_pressed = false;
addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
}
}
private function mouseDownHandler(event : MouseEvent) : void {
if (_pressed) return;
stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMoveHandler);
stage.addEventListener(Event.MOUSE_LEAVE, stage_mouseLeaveHandler);
_dragX = mouseX;
_dragY = mouseY;
_pressed = true;
}
private function stage_mouseMoveHandler(event : MouseEvent) : void {
x += (mouseX - _dragX);
y += (mouseY - _dragY);
}
private function stage_mouseUpHandler(event : MouseEvent) : void {
releaseMouse();
}
private function stage_mouseLeaveHandler(event : Event) : void {
releaseMouse();
}
private function releaseMouse() : void {
if (!_pressed) return;
stage.removeEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMoveHandler);
stage.removeEventListener(Event.MOUSE_LEAVE, stage_mouseLeaveHandler);
_pressed = false;
}
}