forked from: Flickr Tricks For Aurora Crowley!!
ActionScript3 Thread library のサンプルになれば幸いです :-)
*
* @see http://www.flickr.com/photos/auroracrowley/
* @see http://www.libspark.org/htdocs/as3/thread-files/document/
/**
* Copyright Floor11 ( http://wonderfl.net/user/Floor11 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wRYr
*/
// forked from soundkitchen's Flickr Tricks For Aurora Crowley!!
/**
* ActionScript3 Thread library のサンプルになれば幸いです :-)
*
* @see http://www.flickr.com/photos/auroracrowley/
* @see http://www.libspark.org/htdocs/as3/thread-files/document/
*/
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
[SWF(frameRate=60, width=465, height=465, backgroundColor=0x000000)]
public class Tmp extends Sprite
{
public function Tmp()
{
addEventListener(Event.ADDED_TO_STAGE, initialize);
}
private function initialize(evt:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initialize);
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
stage.scaleMode = StageScaleMode.NO_SCALE;
if (!Thread.isReady)
{
Thread.initialize(new EnterFrameThreadExecutor());
}
new MainThread(this).start();
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.filters.BitmapFilter;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.ui.Mouse;
import com.adobe.serialization.json.JSON;
import org.libspark.thread.Thread;
import org.libspark.thread.threads.display.LoaderThread;
import org.libspark.thread.threads.net.URLLoaderThread;
import org.libspark.thread.utils.IProgress;
import org.libspark.thread.utils.IProgressNotifier;
import org.libspark.thread.utils.MultiProgress;
import org.libspark.thread.utils.ParallelExecutor;
import org.libspark.thread.utils.SerialExecutor;
internal var FILTER_BLUR:BlurFilter = new BlurFilter(4, 4, BitmapFilterQuality.LOW);
internal var POINT_ZERO:Point = new Point();
import flash.display.Shape;
internal class Indicator extends Shape
{
public function Indicator()
{
var i:uint,
cx:Number, cy:Number,
numNeedles:uint = 12,
innerR:Number = 7,
outerR:Number = 5,
cAngle:Number = -Math.PI / 2,
nAngle:Number;
nAngle = Math.PI * 2 / numNeedles;
for (i=0; i<numNeedles; i++)
{
cAngle += nAngle;
cx = Math.cos(cAngle) * innerR;
cy = Math.sin(cAngle) * innerR;
graphics.moveTo(cx, cy);
cx = Math.cos(cAngle) * outerR;
cy = Math.sin(cAngle) * outerR;
graphics.lineStyle(2, 0xffffff, i/numNeedles);
graphics.lineTo(cx, cy);
}
}
}
internal class MainThread extends Thread
{
private var layer:DisplayObjectContainer;
private var imageLoader:LoadImageThread;
private var contents:Array;
private var canvas:Bitmap;
private var currentIndex:uint;
public function MainThread(layer:DisplayObjectContainer)
{
this.layer = layer;
}
override protected function run():void
{
var t:Thread;
t = new WaitAnimationThread(layer);
t.start();
t.join();
next(loadImage);
}
private function loadImage():void
{
var executor:ParallelExecutor;
executor = new ParallelExecutor();
imageLoader = new LoadImageThread();
executor.addThread(imageLoader);
executor.addThread(new LoadImageProgressThread(layer, imageLoader.progress));
executor.start();
executor.join();
next(loadComplete);
}
private function loadComplete():void
{
var s:Stage,
data:BitmapData;
contents = imageLoader.contents.concat();
imageLoader.contents.length = 0;
imageLoader.contents = null;
currentIndex = 0;
s = layer.stage;
data = new BitmapData(450, 450, true, 0);
canvas = new Bitmap(data);
canvas.x = (s.stageWidth - canvas.width) / 2;
canvas.y = (s.stageHeight - canvas.height) / 2;
layer.addChild(canvas);
next(changeImage);
}
private function changeImage():void
{
if (currentIndex >= contents.length)
{
currentIndex = 0;
}
var image:Bitmap,
th:Thread;
image = contents[currentIndex++] as Bitmap;
th = new HandleImageThread(image, canvas);
th.start();
th.join();
next(changeImage);
}
override protected function finalize():void
{
layer = null;
imageLoader = null;
}
}
internal class WaitAnimationThread extends Thread
{
private var layer:DisplayObjectContainer;
private var message:Bitmap;
public function WaitAnimationThread(layer:DisplayObjectContainer)
{
this.layer = layer;
}
override protected function run():void
{
var s:Stage,
txt:TextField,
fmt:TextFormat,
bmd:BitmapData;
s = layer.stage;
fmt = new TextFormat();
fmt.color = 0x000000;
fmt.size = 24;
fmt.font = 'Trebuchet MS';
txt = new TextField();
txt.autoSize = TextFieldAutoSize.LEFT;
txt.defaultTextFormat = fmt;
txt.text = 'click to start.';
bmd = new BitmapData(txt.textWidth, txt.textHeight, true, 0);
bmd.draw(txt);
message = new Bitmap(bmd);
message.blendMode = BlendMode.INVERT;
message.x = (s.stageWidth - message.width) / 2;
message.y = (s.stageHeight - message.height) / 2;
layer.addChild(message);
event(s, MouseEvent.CLICK, hideMessage);
}
private function hideMessage(evt:MouseEvent):void
{
new HideMessageThread(message).start();
}
override protected function finalize():void
{
layer = null;
message = null;
}
}
internal class HideMessageThread extends Thread
{
private var message:DisplayObject;
private var wrapper:Bitmap;
private var parent:DisplayObjectContainer;
private var film:BitmapData;
private var particles:Vector.<HideMessageParticle>;
public function HideMessageThread(message:DisplayObject)
{
this.message = message;
this.parent = message.parent;
this.particles = new Vector.<HideMessageParticle>();
}
override protected function run():void
{
var s:Stage,
c:uint,
w:Number, h:Number,
offsetX:Number, offsetY:Number,
i:uint, j:uint,
bmd:BitmapData;
s = message.stage;
bmd = Bitmap(message).bitmapData;
w = bmd.width;
h = bmd.height;
offsetX = message.x;
offsetY = message.y;
for (i=0; i<w; i++)
{
for (j=0; j<h; j++)
{
c = bmd.getPixel32(i,j);
if (!c) continue;
particles.push(new HideMessageParticle(offsetX + i, offsetY + j, c));
}
}
bmd.dispose();
film = new BitmapData(s.stageWidth, s.stageHeight, true, 0);
wrapper = new Bitmap(film);
wrapper.blendMode = BlendMode.INVERT;
parent.addChild(wrapper);
parent.removeChild(message);
next(step);
}
private function step():void
{
var i:uint,
l:uint,
s:Stage,
p:HideMessageParticle;
film.lock();
film.applyFilter(film, film.rect, POINT_ZERO, FILTER_BLUR);
l = particles.length;
for (i=0; i<l; i++)
{
p = particles[i];
p.update();
film.setPixel32(p.x, p.y, p.color);
if (!film.rect.contains(p.x, p.y))
{
particles.splice(i, 1);
i--;
l = particles.length;
}
}
film.unlock();
if (l) next(step);
}
override protected function finalize():void
{
parent.removeChild(wrapper);
film.dispose();
parent = null;
wrapper = null;
message = null;
}
}
internal class LoadImageThread extends Thread
implements IProgressNotifier
{
public var contents:Array;
private var mainProgress:MultiProgress;
private var subProgress:MultiProgress;
private var jsonLoader:URLLoaderThread;
private var imageLoader:SerialExecutor;
public function get progress():IProgress
{
return mainProgress;
}
public function LoadImageThread()
{
var req:URLRequest,
data:URLVariables;
req = new URLRequest('http://query.yahooapis.com/v1/public/yql');
data = new URLVariables();
data['q'] = "SELECT * FROM flickr.photos.search(10) WHERE user_id='34356909@N06'";
data['format'] = 'json';
req.data = data;
jsonLoader = new URLLoaderThread(req);
mainProgress = new MultiProgress();
subProgress = new MultiProgress();
mainProgress.addProgress(jsonLoader.progress, 0.1);
mainProgress.addProgress(subProgress);
}
override protected function run():void
{
jsonLoader.start();
jsonLoader.join();
next(loadDataComplete);
}
private function loadDataComplete():void
{
var json:Object,
row:Object,
th:LoaderThread,
req:URLRequest,
ctx:LoaderContext,
flickr:FlickrPhoto;
json = JSON.decode(jsonLoader.loader.data);
ctx = new LoaderContext(true);
imageLoader = new SerialExecutor();
for each (row in json.query.results.photo)
{
flickr = new FlickrPhoto(row);
req = new URLRequest(flickr.thumbnailURL);
th = new LoaderThread(req, ctx);
imageLoader.addThread(th);
subProgress.addProgress(th.progress);
}
imageLoader.start();
imageLoader.join();
next(loadImageComplete);
}
private function loadImageComplete():void
{
var i:uint,
l:uint,
th:LoaderThread;
contents = [];
l = imageLoader.numThreads;
for (i=0; i<l; i++)
{
th = imageLoader.getThreadAt(i) as LoaderThread;
contents.push(th.loader.content);
}
}
override protected function finalize():void
{
jsonLoader = null;
imageLoader = null;
}
}
internal class LoadImageProgressThread extends Thread
{
private var progress:IProgress;
private var layer:DisplayObjectContainer;
private var indicator:HandleIndicatorThread;
public function LoadImageProgressThread(layer:DisplayObjectContainer, progress:IProgress)
{
this.layer = layer;
this.progress = progress;
}
override protected function run():void
{
indicator = new HandleIndicatorThread(layer);
indicator.start();
next(step);
}
private function step():void
{
if (progress.isCompleted||progress.isFailed||progress.isCanceled)
{
next(shutDown);
return;
}
// TODO: なにかしらやる。
var percent:Number = progress.percent;
if (percent >= 1)
{
next(shutDown);
}
else
{
next(step);
}
}
private function shutDown():void
{
indicator.interrupt();
}
override protected function finalize():void
{
progress = null;
layer = null;
indicator = null;
}
}
internal class HandleImageThread extends Thread
{
public static const PARTICLE_MARGIN:Number = 6;
private var original:Bitmap;
private var destination:Bitmap;
private var showParticles:Vector.<ShowImageParticle>;
private var hideParticles:Vector.<HideImageParticle>;
public function HandleImageThread(original:Bitmap, destination:Bitmap)
{
this.original = original;
this.destination = destination;
this.showParticles = new Vector.<ShowImageParticle>();
this.hideParticles = new Vector.<HideImageParticle>();
}
override protected function run():void
{
var w:Number, h:Number, c:uint,
tx:Number, ty:Number,
sx:Number, sy:Number,
cx:Number, cy:Number,
angle:Number,
i:uint, j:uint,
s:Stage,
data:BitmapData;
s = destination.stage;
data = original.bitmapData;
w = data.width;
h = data.height;
cx = s.stageWidth / 2;
cy = s.stageHeight / 2;
for (i=0; i<w; i++)
{
for (j=0; j<h; j++)
{
c = data.getPixel32(i, j);
if (!c) continue;
angle = Math.random() * Math.PI * 2;
sx = Math.cos(angle) * 500 + cx;
sy = Math.sin(angle) * 500 + cy;
tx = i * PARTICLE_MARGIN;
ty = j * PARTICLE_MARGIN;
showParticles.push(new ShowImageParticle(sx, sy, tx, ty, c));
hideParticles.push(new HideImageParticle(tx, ty, sx, sy, c, s.frameRate));
}
}
next(showStep);
}
private function showStep():void
{
var i:uint,
l:uint,
c:uint,
a:Number,
f:Boolean,
p:ShowImageParticle,
data:BitmapData;
data = destination.bitmapData;
data.lock();
data.applyFilter(data, data.rect, POINT_ZERO, FILTER_BLUR);
l = showParticles.length;
f = false;
for (i=0; i<l; i++)
{
p = showParticles[i];
if (p.isAlive)
{
f = true;
p.update();
}
data.setPixel32(p.x, p.y, p.color);
}
data.unlock();
if (!f)
{
next(fixedImage);
}
else
{
next(showStep);
}
}
private function hideStep():void
{
var i:uint,
l:uint,
c:uint,
a:Number,
f:Boolean,
p:HideImageParticle,
data:BitmapData;
data = destination.bitmapData;
data.lock();
data.colorTransform(data.rect, new ColorTransform(1, 1, 1, .97, 0, 0, 0, 0));
data.applyFilter(data, data.rect, POINT_ZERO, FILTER_BLUR);
l = hideParticles.length;
for (i=0; i<l; i++)
{
p = hideParticles[i];
p.update();
data.setPixel32(p.x, p.y, p.color);
if (!data.rect.contains(p.x, p.y))
{
hideParticles.splice(i, 1);
i--;
l = hideParticles.length;
}
}
data.unlock();
//trace(p.x, p.y);
if (l) next(hideStep);
}
private function fixedImage():void
{
sleep(3000);
next(hideStep);
}
override protected function finalize():void
{
original = null;
destination = null;
showParticles.length = 0;
showParticles = null;
hideParticles.length = 0;
hideParticles = null;
}
}
internal class HandleIndicatorThread extends Thread
{
private var layer:DisplayObjectContainer;
private var indicator:DisplayObject;
public function HandleIndicatorThread(layer:DisplayObjectContainer)
{
this.layer = layer;
}
override protected function run():void
{
Mouse.hide();
layer.stage.mouseChildren = false;
indicator = new Indicator();
indicator.x = layer.mouseX;
indicator.y = layer.mouseY;
layer.addChild(indicator);
next(step);
}
private function step():void
{
if (checkInterrupted()) return;
indicator.rotation = (indicator.rotation + 360 / indicator.stage.frameRate) % 360;
indicator.x = layer.mouseX;
indicator.y = layer.mouseY;
next(step);
}
override protected function finalize():void
{
Mouse.show();
layer.stage.mouseChildren = true;
layer.removeChild(indicator);
layer = null;
indicator = null;
}
}
internal class HideMessageParticle
{
public var x:Number;
public var y:Number;
public var ax:Number;
public var ay:Number;
public var vx:Number;
public var vy:Number;
public var color:uint;
public function HideMessageParticle(x:Number, y:Number, color:Number)
{
var len:Number,
angle:Number;
len = Math.random() * 5;
angle = Math.random() * Math.PI * 2;
this.ax = Math.cos(angle) * len;
this.ay = Math.sin(angle) * len;
this.x = x;
this.y = y;
this.color = color;
this.vx = 0;
this.vy = 0;
}
public function update():void
{
vx += ax;
vy += ay;
x += vx;
y += vy;
}
}
import flash.geom.Point;
internal class ShowImageParticle
{
public var x:Number;
public var y:Number;
public var color:uint;
private var targetX:Number;
private var targetY:Number;
private var _isAlive:Boolean;
public function get isAlive():Boolean
{
return _isAlive;
}
public function ShowImageParticle(x:Number, y:Number, targetX:Number, targetY:Number, color:uint)
{
this.x = x;
this.y = y;
this.color = color;
this.targetX = targetX;
this.targetY = targetY;
this._isAlive = true;
}
public function update():void
{
x += (targetX - x) * .05;
y += (targetY - y) * .05;
if (Math.abs(targetX - x) < .5 && Math.abs(targetY - y) < .5)
{
x = targetX;
y = targetY;
_isAlive = false;
}
}
}
internal class HideImageParticle
{
public var x:Number;
public var y:Number;
public var color:uint;
private var vx:Number;
private var vy:Number;
private var ax:Number;
private var ay:Number;
private var rate:Number;
public function HideImageParticle(x:Number, y:Number, targetX:Number, targetY:Number, color:uint, rate:Number)
{
var dx:Number,
dy:Number,
len:Number,
angle:Number;
dx = targetX - x;
dy = targetY - y;
len = 9.8;
angle = Math.atan2(dy, dx);
this.x = x;
this.y = y;
this.vx = 0;
this.vy = 0;
this.ax = Math.cos(angle) * len;
this.ay = Math.sin(angle) * len;
this.color = color;
this.rate = rate;
}
public function update():void
{
vx += ax / rate;
vy += ay / rate;
x += vx;
y += vy;
}
}
internal class FlickrPhoto
{
private var _id:String;
public function get id():String
{
return _id;
}
private var _secret:String;
public function get secret():String
{
return _secret;
}
private var _server:String;
public function get server():String
{
return _server;
}
private var _farm:String;
public function get farm():String
{
return _farm;
}
public function get thumbnailURL():String
{
return ['http://farm', farm, '.static.flickr.com/', server, '/', id, '_', secret, '_s.jpg'].join('');
}
public function FlickrPhoto(data:Object)
{
this._id = data['id'] || '';
this._secret = data['secret'] || '';
this._server = data['server'] || '';
this._farm = data['farm'] || '';
}
}