ノスタルジック?な感じ?
ノスタルジックな雰囲気になった。かな?
* またも ActionScript3 Thread Library 使って作りました :-)
*
* コメントが壊れたカタコトの英語でごめんなさい :-(
/**
* ノスタルジックな雰囲気になった。かな?
* またも ActionScript3 Thread Library 使って作りました :-)
*
* コメントが壊れたカタコトの英語でごめんなさい :-(
*/
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import com.flashdynamix.utils.SWFProfiler;
import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
[SWF(width=465, height=465, frameRate=30, backgroundColor=0xffffff)]
/**
* document class.
*/
public class Deploy extends Sprite
{
/**
* constructor.
*/
public function Deploy()
{
addEventListener(Event.ADDED_TO_STAGE, initialize);
}
/**
* initialize the object.
*/
private function initialize(evt:Event):void
{
// check is thread system already initialized?
if (!Thread.isReady)
{
// fixed stage settings.
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.MEDIUM;
stage.scaleMode = StageScaleMode.NO_SCALE;
SWFProfiler.init(this);
// initialize the thread system.
Thread.initialize(new EnterFrameThreadExecutor());
}
// wake up main task thread.
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.Sprite;
import flash.display.Stage;
import flash.errors.IOError;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BitmapFilter;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.system.LoaderContext;
import com.adobe.serialization.json.JSON;
import org.libspark.thread.Monitor;
import org.libspark.thread.Thread;
import org.libspark.thread.threads.display.LoaderThread;
import org.libspark.thread.threads.net.URLLoaderThread;
import org.libspark.thread.utils.ParallelExecutor;
/**
* main task thread.
*/
internal class MainThread extends Thread
{
private var layer:DisplayObjectContainer;
private var loader:LoadDataThread;
/**
* constructor.
*/
public function MainThread(layer:DisplayObjectContainer)
{
this.layer = layer;
}
/**
* first executable.
*/
override protected function run():void
{
var waitor:Thread;
// wake up handle background task.
new HandleBackgroundThread(layer).start();
// wake up wait animation task.
waitor = new WaitAnimationThread(layer);
waitor.start();
waitor.join();
// stack next task(s).
next(loadData);
}
/**
* load data from flickr.
*/
private function loadData():void
{
loader = new LoadDataThread();
loader.start();
loader.join();
// stack next task(s).
next(loadComplete);
}
/**
* laod and display images.
*/
private function loadComplete():void
{
var data:Array,
queue:FlickrImageQueue,
container:Sprite;
data = loader.data;
// create photo image queue.
queue = new FlickrImageQueue();
// create images container.
container = new Sprite();
container.scaleX = 2;
container.scaleY = 2;
layer.addChild(container);
// wake up fix position task thread.
new FollowMousePositionThread(container).start();
// wake up display image task thread.
new DisplayImageThread(container, queue).start();
// wake up load image task thread(s).
new LoadImageThread(data, queue).start();
new LoadImageThread(data, queue).start();
new LoadImageThread(data, queue).start();
}
/**
* finalize the object.
*/
override protected function finalize():void
{
layer = null;
}
}
/**
* handle background noise task.
*/
internal class HandleBackgroundThread extends Thread
{
public static const TICK_THRESHOLD:uint = 3;
private var layer:DisplayObjectContainer;
private var background:Bitmap;
private var tick:uint;
/**
* constructor.
*/
public function HandleBackgroundThread(layer:DisplayObjectContainer)
{
this.layer = layer;
this.tick = 0;
}
/**
* first executable.
*/
override protected function run():void
{
var s:Stage;
s = layer.stage;
// create background noise canvas.
var bmd:BitmapData = new BitmapData(s.stageWidth / 2, s.stageHeight / 2, true, 0);
// create bitmap for background.
background = new Bitmap(bmd);
background.scaleX = 2;
background.scaleY = 2;
background.alpha = .15;
// add background to layer.
layer.addChild(background);
// update background immediately.
update();
}
/**
* update background.
*/
private function update():void
{
var s:Stage;
s = background.stage;
// if removed background from stage or interrupted, halt process.
if (!s || checkInterrupted()) return;
// check triggerable?
if (tick % TICK_THRESHOLD == 0)
{
// regenerate noise.
background.bitmapData.noise(Math.random() * 100);
}
// increment tick in range.
tick = ++tick % TICK_THRESHOLD;
// stack next task(s).
next(update);
event(s, Event.RESIZE, resized);
}
private function resized(evt:Event):void
{
var s:Stage,
pb:BitmapData,
nb:BitmapData;
// cast target as stage object.
s = evt.target as Stage;
// if missing target or interrupted, halt process.
if (!s || checkInterrupted()) return;
// recreate noise bitmap data.
pb = background.bitmapData;
nb = new BitmapData(s.stageWidth / 2, s.stageHeight / 2, true, 0);
background.bitmapData = nb;
// release old data resource.
pb.dispose();
// reset tick counter.
tick = 0;
// update background noise immediately.
update();
}
/**
* finalize the object.
*/
override protected function finalize():void
{
if (layer.contains(background))
{
layer.removeChild(background);
}
layer = null;
background.bitmapData.dispose();
background = null;
}
}
/**
* wait animation to til user's first action.
*/
internal class WaitAnimationThread extends Thread
{
private var layer:DisplayObjectContainer;
private var message:DisplayObject;
private var handlers:ParallelExecutor;
/**
* constructor.
*/
public function WaitAnimationThread(layer:DisplayObjectContainer)
{
this.layer = layer;
}
/**
* first executable.
*/
override protected function run():void
{
var txt:TextField,
fmt:TextFormat,
bmd:BitmapData;
// create format for message text.
fmt = new TextFormat();
fmt.color = 0x000000;
fmt.size = 48;
fmt.font = 'sans-serif';
// create message text.
txt = new TextField();
txt.autoSize = TextFieldAutoSize.LEFT;
txt.defaultTextFormat = fmt;
txt.text = 'click to start.';
// create message data.
bmd = new BitmapData(txt.textWidth, txt.textHeight, true, 0);
// draw text to bitmap data.
bmd.draw(txt);
// create message.
message = new Sprite();
// add bitmap to message layer.
Sprite(message).addChild(new Bitmap(bmd));
// hide message. will disappear later.
message.visible = false;
// add message to layer.
layer.addChild(message);
// create sub processes handler.
handlers = new ParallelExecutor();
// stack fixed position task.
handlers.addThread(new FixCenterPositionThread(message));
// wake up handling focus/blur task.
handlers.addThread(new HandleFocusThread(message));
// start each sub processes.
handlers.start();
// stack next task(s).
event(message, MouseEvent.CLICK, hideMessage);
}
/**
* hide message.
* will execute when message is clicked.
*/
private function hideMessage(evt:MouseEvent):void
{
// interrupt sub processes.
handlers.interrupt();
handlers = null;
// wake up hide message task.
new HideMessageThread(message).start();
}
/**
* finalize the object.
*/
override protected function finalize():void
{
layer = null;
message = null;
}
}
/**
* hide message task.
*/
internal class HideMessageThread extends Thread
{
private var message:DisplayObject;
/**
* constructor.
*/
public function HideMessageThread(message:DisplayObject)
{
this.message = message;
}
/**
* first executable.
*/
override protected function run():void
{
message.alpha *= .95;
if (message.alpha < .02)
{
message.alpha = 0;
}
else
{
next(run);
}
}
/**
* finalize the object.
*/
override protected function finalize():void
{
var p:DisplayObjectContainer;
p = message.parent;
if (p)
{
p.removeChild(message);
}
message = null;
}
}
/**
* fix center position task thread.
*/
internal class FixCenterPositionThread extends Thread
{
private var target:DisplayObject;
/**
* constructor.
*/
public function FixCenterPositionThread(target:DisplayObject)
{
this.target = target;
}
/**
* first executable.
*/
override protected function run():void
{
var s:Stage;
s = target.stage;
// if missing stage, halt process.
if (!s) return;
// fix target position.
target.x = (s.stageWidth - target.width) / 2;
target.y = (s.stageHeight - target.height) / 2;
// if hide object yet, disappear.
if (!target.visible)
{
target.visible = true;
}
// stack next task(s).
event(s, Event.RESIZE, resized);
interrupted(shutdown);
}
/**
* will execute when stage is resized.
*/
private function resized(evt:Event):void
{
var s:Stage;
s = target.stage;
// if missing stage, halt process.
if (!s) return;
// fix target position.
target.x = (s.stageWidth - target.width) / 2;
target.y = (s.stageHeight - target.height) / 2;
// stack next task(s).
event(s, Event.RESIZE, resized);
interrupted(shutdown);
}
/**
* default interrupted handler.
*/
private function shutdown(...args):void
{
// do nothing.
}
override protected function finalize():void
{
target = null;
}
}
/**
* handling focus/blur task thread.
*/
internal class HandleFocusThread extends Thread
{
private var target:DisplayObject;
/**
* constructor.
*/
public function HandleFocusThread(target:DisplayObject)
{
this.target = target;
}
/**
* first executable.
*/
override protected function run():void
{
// reset filters.
target.filters = [
new BlurFilter(8, 8, BitmapFilterQuality.LOW),
];
// bind each events.
events();
}
/**
* bind each events.
*/
private function events():void
{
// stack next task(s).
event(target, MouseEvent.ROLL_OVER, focus);
event(target, MouseEvent.ROLL_OUT, blur);
interrupted(shutdown);
}
/**
* will execute when target is focused.
*/
private function focus(evt:MouseEvent):void
{
// reset filters.
target.filters = [
new BlurFilter(2, 2, BitmapFilterQuality.LOW),
];
// bind each events.
events();
}
/**
* will execute when target is unfocused.
*/
private function blur(evt:MouseEvent):void
{
// reset filters.
target.filters = [
new BlurFilter(8, 8, BitmapFilterQuality.LOW),
];
// bind each events.
events();
}
/**
* default shutdown handler.
*/
private function shutdown(...args):void
{
// do nothing.
}
/**
* finalize the object.
*/
override protected function finalize():void
{
target = null;
}
}
/**
* load data from flickr task thread.
*/
internal class LoadDataThread extends Thread
{
public static const YQL_URL:String = 'http://query.yahooapis.com/v1/public/yql';
private var loader:URLLoaderThread;
private var _data:Array;
public function get data():Array
{
return _data.concat();
}
/**
* constructor.
*/
public function LoadDataThread()
{
_data = [];
}
/**
* first executable.
*/
override protected function run():void
{
var req:URLRequest,
data:URLVariables;
data = new URLVariables();
data['q'] = 'select * from flickr.photos.recent(64)';
data['format'] = 'json';
req = new URLRequest();
req.url = YQL_URL;
req.data = data;
loader = new URLLoaderThread(req);
loader.start();
loader.join();
next(loadComplete);
error(IOError, loadFailure);
error(SecurityError, loadFailure);
}
/**
* will execute when load data complete.
*/
private function loadComplete():void
{
var json:Object,
row:Object;
json = JSON.decode(loader.loader.data);
if (!json.query || !json.query.results) return;
for each (row in json.query.results.photo)
{
_data.push(new FlickrPhoto(row));
}
}
/**
* will execute when load data failure.
*/
private function loadFailure(e:Error, t:Thread):void
{
trace("CAUGHT EXCEPTION: ", e);
//trace(e.getStackTrace());
}
}
/**
*
*/
internal class DisplayImageThread extends Thread
{
private var layer:DisplayObjectContainer;
private var queue:FlickrImageQueue;
/**
* constructor.
*/
public function DisplayImageThread(layer:DisplayObjectContainer, queue:FlickrImageQueue)
{
this.layer = layer;
this.queue = queue;
}
/**
* first executable.
*/
override protected function run():void
{
if (queue.checkPoll())
{
var i:uint,
wrapper:Sprite;
i = layer.numChildren;
wrapper = new Sprite();
wrapper.addChild(queue.poll());
wrapper.x = Math.floor(i % 8) * 80;
wrapper.y = Math.floor(i / 8) * 80;
wrapper.blendMode = BlendMode.HARDLIGHT;
new HandleFocusThread(wrapper).start();
layer.addChild(wrapper);
}
// stack next task(s).
next(run);
}
/**
* finalize the object.
*/
override protected function finalize():void
{
layer = null;
queue = null;
}
}
/**
* load each image task thread.
*/
internal class LoadImageThread extends Thread
{
private var data:Array;
private var queue:FlickrImageQueue;
private var loader:LoaderThread;
/**
* constructor.
*/
public function LoadImageThread(data:Array, queue:FlickrImageQueue)
{
this.data = data;
this.queue = queue;
}
/**
* first executable.
*/
override protected function run():void
{
if (!data.length || checkInterrupted()) return;
var row:FlickrPhoto,
req:URLRequest,
ctx:LoaderContext;
row = data.shift() as FlickrPhoto;
req = new URLRequest(row.thumbnailURL);
ctx = new LoaderContext(true);
loader = new LoaderThread(req, ctx);
loader.start();
loader.join();
next(loadComplete);
error(IOError, loadFailure);
error(SecurityError, loadFailure);
interrupted(shutdown);
}
/**
* will execute when load data complete.
*/
private function loadComplete():void
{
// push new task into queue.
queue.offer(Bitmap(loader.loader.content));
// stack next task(s).
next(run);
}
/**
* will execute when load data failure.
*/
private function loadFailure(e:Error, t:Thread):void
{
loader = null;
// stack next task(s).
next(run);
}
/**
* default interrupted handler.
*/
private function shutdown(...args):void
{
// do nothing.
}
/**
* finalize the object.
*/
override protected function finalize():void
{
loader = null;
data = null;
queue = null;
}
}
/**
* follow the mouse point
*/
internal class FollowMousePositionThread extends Thread
{
public static const MARGIN:Number = 150;
private var target:DisplayObject;
/**
* constructor.
*/
public function FollowMousePositionThread(target:DisplayObject)
{
this.target = target;
}
/**
* first executable.
*/
override protected function run():void
{
var s:Stage;
s = target.stage;
if (!s) return;
target.x = MARGIN;
target.y = MARGIN;
event(s, MouseEvent.MOUSE_MOVE, moved);
interrupted(shutdown);
}
/**
* will execute when mouse moved.
*/
private function moved(evt:MouseEvent):void
{
update();
}
/**
* update target position.
*/
private function update():void
{
var s:Stage,
ax:Number, ay:Number,
dx:Number, dy:Number;
s = target.stage;
// if missing stage, halt process.
if (!s) return;
ax = s.mouseX / s.stageWidth;
ay = s.mouseY / s.stageHeight;
dx = MARGIN - (target.width - s.stageWidth + MARGIN * 2) * ax;
dy = MARGIN - (target.height - s.stageHeight + MARGIN * 2) * ay;
target.x += (dx - target.x) / 20;
target.y += (dy - target.y) / 20;
if (Math.abs(dx - target.x) < 1 && Math.abs(dy - target.y) < 1)
{
target.x = dx;
target.y = dy;
event(s, MouseEvent.MOUSE_MOVE, moved);
interrupted(shutdown);
}
else
{
next(update);
}
}
/**
* default interrupted handler.
*/
private function shutdown(...args):void
{
// do nothing.
}
/**
* finalize the object.
*/
override protected function finalize():void
{
target = null;
}
}
/**
* stack flickr image queue.
*/
internal class FlickrImageQueue
{
private var queue:Array;
private var monitor:Monitor;
/**
* checking is task empty in queue.
*/
public function get isEmpty():Boolean
{
return queue.length <= 0;
}
/**
* constructor.
*/
public function FlickrImageQueue()
{
queue = [];
monitor = new Monitor();
}
/**
* checking already stack new task into queue.
*/
public function checkPoll():Boolean
{
var f:Boolean = true;
if (isEmpty)
{
f = false;
monitor.wait();
}
return f;
}
/**
* shift stack task.
*/
public function poll():Bitmap
{
return queue.shift();
}
/**
*
*/
public function offer(v:Bitmap):void
{
// push new data into queue.
queue.push(v);
// notify all wait task.
monitor.notifyAll();
}
}
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'] || '';
}
public function toString():String
{
return thumbnailURL;
}
}