/** * Spark 勉強会の Geoff Stearns 氏のハッピーバースデー企画 * お誕生日おめでとーございまーす :-) * * @see http://wiki.libspark.org/wiki/SparkStudy/09 */ 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.Thread; import org.libspark.thread.EnterFrameThreadExecutor; import org.papervision3d.cameras.Camera3D; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.render.LazyRenderEngine; import org.papervision3d.scenes.Scene3D; import org.papervision3d.view.Viewport3D; [SWF(width=465, height=465, frameRate=60, backgroundColor=0x000000)] /** * document class. */ public class CodeBreak extends Sprite { /** * constructor. */ public function CodeBreak() { addEventListener(Event.ADDED_TO_STAGE, initialize); } /** * initialize the object. */ private function initialize(evt:Event):void { removeEventListener(Event.ADDED_TO_STAGE, initialize); if (!Thread.isReady) { stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.HIGH; stage.scaleMode = StageScaleMode.NO_SCALE; SWFProfiler.init(this); Thread.initialize(new EnterFrameThreadExecutor()); } var ctx:Context, camera:Camera3D, scene:Scene3D, viewport:Viewport3D, container:DisplayObject3D, renderer:LazyRenderEngine; // camera. camera = new Camera3D(); camera.z = 1000; //camera.focus = 20; //camera.zoom = 40; camera.lookAt(DisplayObject3D.ZERO); // scene. scene = new Scene3D(); // container. container = new DisplayObject3D(); scene.addChild(container); // viewport. viewport = new Viewport3D(stage.stageWidth, stage.stageHeight, true); addChild(viewport); // render engine. renderer = new LazyRenderEngine(scene, camera, viewport); // context. ctx = new Context(); ctx.layer = this; ctx.stage = stage; ctx.camera = camera; ctx.scene = scene; ctx.container = container; ctx.viewport = viewport; ctx.renderer = renderer; new MainThread(ctx).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.display.StageDisplayState; import flash.events.Event; import flash.events.MouseEvent; import flash.filters.GlowFilter; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import frocessing.color.ColorHSV; import org.libspark.betweenas3.BetweenAS3; import org.libspark.betweenas3.tweens.ITween; import org.libspark.betweenas3.targets.single.ISingleTweenTarget; import org.libspark.betweenas3.easing.*; import org.libspark.betweenas3.events.BetweenEvent; import org.libspark.thread.Monitor; import org.libspark.thread.Thread; import org.libspark.thread.threads.net.URLLoaderThread; import org.papervision3d.cameras.Camera3D; import org.papervision3d.core.math.Matrix3D; import org.papervision3d.core.math.Number3D; import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.render.LazyRenderEngine; import org.papervision3d.scenes.Scene3D; import org.papervision3d.typography.Font3D; import org.papervision3d.typography.Text3D; import org.papervision3d.typography.fonts.HelveticaBold; import org.papervision3d.view.Viewport3D; internal const SOURCE_URL:String = "http://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject_src.js"; internal const TARGET_WORDS:String = "Happy Birthday ;)"; /** * context object. */ internal class Context { /** * reference of document class object. */ public var layer:DisplayObjectContainer; /** * reference of stage object. */ public var stage:Stage; /** * reference of pv3d camera object. */ public var camera:Camera3D; /** * reference of pv3d container object. */ public var container:DisplayObject3D; /** * reference of pv3d scene object. */ public var scene:Scene3D; /** * reference of pv3d renderer object. */ public var renderer:LazyRenderEngine; /** * reference of pv3d viewport object. */ public var viewport:Viewport3D; } /** * main task of this applicaiton. */ internal class MainThread extends Thread { private var context:Context; private var loader:URLLoaderThread; /** * constructor. */ public function MainThread(context:Context) { this.context = context; } /** * first executable. */ override protected function run():void { var t:Thread; t = new WaitAnimationThread(context); t.start(); t.join(); new HandleScreenThread(context).start(); next(startAnimation); } private function startAnimation():void { var req:URLRequest; req = new URLRequest(SOURCE_URL); loader = new URLLoaderThread(req); loader.start(); loader.join(); next(loadComplete); error(Error, loadFailure); } private function loadComplete():void { var data:String; data = String(loader.loader.data); new PV3DRenderThread(context).start(); new MainAnimationThread(context, data).start(); } private function loadFailure(e:Error, t:Thread):void { trace(e.getStackTrace()); } /** * finalize the object. */ override protected function finalize():void { context = null; } } /** * wait user's action. */ internal class WaitAnimationThread extends Thread { private var context:Context; private var message:Bitmap; /** * constructor. */ public function WaitAnimationThread(context:Context) { this.context = context; } /** * first executable. */ override protected function run():void { var txt:TextField, fmt:TextFormat, bmd:BitmapData; fmt = new TextFormat(); fmt.font = 'Lucida Grande'; fmt.size = 64; fmt.color = 0x000000; txt = new TextField(); txt.autoSize = TextFieldAutoSize.LEFT; txt.defaultTextFormat = fmt; txt.text = "click to start"; bmd = new BitmapData(txt.width, txt.height, true, 0); bmd.draw(txt); message = new Bitmap(bmd); message.x = (context.stage.stageWidth - message.width) >> 1; message.y = (context.stage.stageHeight - message.height) >> 1; message.blendMode = BlendMode.INVERT; context.layer.addChild(message); event(context.stage, MouseEvent.CLICK, clicked); event(context.stage, Event.RESIZE, resized); } /** * will execute when clicked stage. */ private function clicked(evt:MouseEvent):void { message.x = (context.stage.stageWidth - message.width) >> 1; message.y = (context.stage.stageHeight - message.height) >> 1; new HideMessageThread(message).start(); } /** * will execute when resized stage size. */ private function resized(evt:Event):void { message.x = (context.stage.stageWidth - message.width) >> 1; message.y = (context.stage.stageHeight - message.height) >> 1; event(context.stage, MouseEvent.CLICK, clicked); event(context.stage, Event.RESIZE, resized); } /** * finalize the object. */ override protected function finalize():void { message = null; context = null; } } /** * hide splash message. */ internal class HideMessageThread extends Thread { private var message:DisplayObject; private var monitor:Monitor; /** * constructor. */ public function HideMessageThread(message:DisplayObject) { this.message = message; this.monitor = new Monitor(); } /** * first executable. */ override protected function run():void { var b:ITween, from:Object, to:Object; to = { 'alpha': 0, //'y': message.stage.stageHeight, '_blurFilter': { 'blurX': 128, 'blurY': 128 } }; b = BetweenAS3.tween(message, to, from, 2, Quadratic.easeIn); b.onComplete = monitor.notifyAll; b.play(); monitor.wait(); } /** * finalize the object. */ override protected function finalize():void { message.parent.removeChild(message); message = null; monitor = null; } } /** * handle full screen. */ internal class HandleScreenThread extends Thread { private var context:Context; /** * constructor. */ public function HandleScreenThread(context:Context) { this.context = context; } /** * first executable. */ override protected function run():void { event(context.stage, MouseEvent.CLICK, toggleDisplayState, false, int.MAX_VALUE); } /** * toggle full screen and normal. */ private function toggleDisplayState(evt:MouseEvent):void { var s:Stage; s = context.stage; s.displayState = s.displayState == StageDisplayState.NORMAL ? StageDisplayState.FULL_SCREEN : StageDisplayState.NORMAL; event(s, MouseEvent.CLICK, toggleDisplayState, false, int.MAX_VALUE); } /** * finalize the object. */ override protected function finalize():void { context = null; } } /** * main animation. */ internal class MainAnimationThread extends Thread { private var context:Context; private var monitor:Monitor; private var data:String; private var hsv:ColorHSV; private var dataIndex:uint; private var targetIndex:uint; /** * constructor. */ public function MainAnimationThread(context:Context, data:String) { this.context = context; this.data = data.replace(/\r+|\n+|\s+/g, ' '); hsv = new ColorHSV(0, 1, 1, 1); dataIndex = 0; targetIndex = 0; monitor = new Monitor(); } /** * first executable. */ override protected function run():void { if (targetIndex >= TARGET_WORDS.length) { showFullMessage(); } else if (dataIndex >= data.length) { // todo: logic implement. } else { var t:String, c:String; t = TARGET_WORDS.charAt(targetIndex); c = data.charAt(dataIndex); if (t == c) { addTargetCharacter(t); } else { addDefaultCharacter(c); } next(run); } } /** * add target character. */ private function addTargetCharacter(str:String):void { var b:ITween, mat:Letter3DMaterial, fnt:Font3D, txt:Text3D, rot:Number3D; targetIndex++; dataIndex++; rot = Matrix3D.matrix2euler(context.camera.transform); fnt = new HelveticaBold(); mat = new Letter3DMaterial(0xffffff); try { txt = new Text3D(str, fnt, mat); } catch (e:Error) { return; } txt.z = 950; txt.rotationX = rot.x; txt.rotationY = rot.y; txt.rotationZ = rot.z; txt.filters = [ new GlowFilter(0xffffff, 1, 8, 8) ]; txt.useOwnContainer = true; context.container.addChild(txt); b = BetweenAS3.tween(txt, { 'z': 0, 'alpha': 0, 'rotationX': 360 * Math.random(), 'rotationY': 360 * Math.random(), 'rotationZ': 360 * Math.random() }, null, 1, Expo.easeIn); b.addEventListener(BetweenEvent.COMPLETE, completeHandler); if (targetIndex >= TARGET_WORDS.length) { b.onComplete = monitor.notifyAll; monitor.wait(); } else { sleep(200); } b.play(); } /** * add character. */ private function addDefaultCharacter(str:String):void { var b:ITween, to:Object, from:Object, mat:Letter3DMaterial, fnt:Font3D, txt:Text3D, rot:Number3D; dataIndex++; hsv.h += 5; rot = Matrix3D.matrix2euler(context.camera.transform); fnt = new HelveticaBold(); mat = new Letter3DMaterial(hsv.value, .25); try { txt = new Text3D(str, fnt, mat); } catch (e:Error) { return; } txt.z = 950; txt.rotationX = rot.x; txt.rotationY = rot.y; txt.rotationZ = rot.z; txt.filters = [ new GlowFilter(0xffffff, 1, 8, 8) ]; txt.useOwnContainer = true; context.container.addChild(txt); b = BetweenAS3.tween(txt, { 'z': 0, 'alpha': 0, 'rotationX': 360 * Math.random(), 'rotationY': 360 * Math.random(), 'rotationZ': 360 * Math.random() }, null, .75, Quadratic.easeIn); b.addEventListener(BetweenEvent.COMPLETE, completeHandler); if (dataIndex >= data.length) { b.onComplete = monitor.notifyAll; monitor.wait(); } else { sleep(50); } b.play(); } /** * show complete message. */ private function showFullMessage():void { var b:ITween, mat:Letter3DMaterial, fnt:Font3D, txt:Text3D, rot:Number3D; rot = Matrix3D.matrix2euler(context.camera.transform); mat = new Letter3DMaterial(0xffffff); fnt = new HelveticaBold(); txt = new Text3D(TARGET_WORDS, fnt, mat); txt.z = -1000; txt.rotationX = Math.random() * 360; txt.rotationY = Math.random() * 360; txt.rotationZ = Math.random() * 360; txt.alpha = 0; txt.useOwnContainer = true; context.container.addChild(txt); b = BetweenAS3.tween(txt, { 'z': 500, 'alpha': 1, 'rotationX': rot.x, 'rotationY': rot.y, 'rotationZ': rot.z }, null, 5, Elastic.easeOut); b.play(); } /** * will execute when tween complete betweenas3. */ private function completeHandler(evt:BetweenEvent):void { var b:ITween, t:ISingleTweenTarget, obj:DisplayObject3D; b = ITween(evt.target); t = ISingleTweenTarget(b.tweenTarget); obj = DisplayObject3D(t.target); obj.parent.removeChild(obj); } /** * finalize the object. */ override protected function finalize():void { context = null; data = null; } } /** * rendering pv3d. */ internal class PV3DRenderThread extends Thread { private var context:Context; /** * constructor. */ public function PV3DRenderThread(context:Context) { this.context = context; } /** * first executable. */ override protected function run():void { if (checkInterrupted()) return; context.renderer.render(); next(run); } /** * finalize the object. */ override protected function finalize():void { context = null; } } Happy Birthday ;)