In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

3D Particle Text Effect

Get Adobe Flash player
by ThatsAsif 16 Apr 2012
/**
 * Copyright ThatsAsif ( http://wonderfl.net/user/ThatsAsif )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/4XIT
 */

// forked from clockmaker's Xmas Message with Twitter
/**
 * ネットで投稿されたメッセージが
 * クリスマスの夜空を飾ります
 * 
 * クリスマスメッセージは
 * 「Twitter」と「はてなブックマーク」で送ることができます
 * ※追記:11/5(木)、Twitter仕様変更によりTwitter投稿はできなくなりました
 * 
 * ※投稿はFlash内のボタンを押して、
 * Twitterの場合は[]内にコメントを
 * はてなブックマークの場合は、ブックマークコメントを記入下さい
 * 
 * このFlashはwonderfl上の様々なテクニックを元に作られました
 * 
 * Twitter連動
 * http://wonderfl.net/code/04d6d1ae7e943b7faab88623ed83404e7a40c5f7
 * 
 * キラキラ3D
 * http://wonderfl.net/code/c0f513f31389ba07e375331256c2bfa3a8b9006c
 * 
 * 文字のパーティクル化
 * http://wonderfl.net/code/08ec1c2c8da8e9e487867a8e2ab8cddeb75f8986
 * 
 * 木を作る再帰関数
 * http://wonderfl.net/code/00cbe3ecbf0db2e865bc410a8ea54677c19ba4c6 
 * 
 * 配列のシャッフル
 * http://wonderfl.net/code/8cfa39c9e91a268791142fe605c010dc30338588 
 * 
 * BetweenAS3の時間調整
 * http://wonderfl.net/code/59af9d8a3cc45e4c2e6fcf12a9bc9ea55b1576e7
 * 
 */
package {
    import flash.filters.BlurFilter;
    import flash.filters.GlowFilter;
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.display.PixelSnapping;
    
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.TimerEvent;
    
    import flash.geom.Matrix;
    import flash.geom.ColorTransform;
    
    import flash.net.URLLoader;
    import flash.net.URLLoaderDataFormat;
    import flash.net.URLRequest;
    
    import flash.utils.Timer;
    import flash.utils.setTimeout;
    
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.text.TextFieldAutoSize;
    
    import org.libspark.betweenas3.BetweenAS3;
    import org.libspark.betweenas3.easing.*;
    import org.libspark.betweenas3.tweens.ITween;
    
    import org.papervision3d.core.effects.*;
    import org.papervision3d.core.math.Number3D;
    import org.papervision3d.core.geom.Pixels;
    import org.papervision3d.core.geom.renderables.Pixel3D;
    import org.papervision3d.core.utils.Mouse3D;
    import org.papervision3d.render.BasicRenderEngine;
    import org.papervision3d.view.BasicView;
    import org.papervision3d.view.Viewport3D;
    import org.papervision3d.view.layer.BitmapEffectLayer;
    import org.papervision3d.view.layer.ViewportLayer;
    import org.papervision3d.view.layer.util.ViewportLayerSortMode;
    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.materials.ColorMaterial;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.objects.parsers.DAE;
    import org.papervision3d.events.InteractiveScene3DEvent;
    import org.papervision3d.events.FileLoadEvent;
    

    [SWF(width=590,height=300,frameRate=30,backgroundColor=0x000000)]
    
    public class Main extends Sprite {

        static private const MAX_PARTICLES:Number = 2500;
        // color
        public static const WHITE:uint = 0xFFF0F0F0;
        public static const GREEN:uint = 0xFF008800;
        public static const RED:uint = 0xFFCC0000;
        public static const GOLD:uint = 0xFFFFCC66;
        public static const SILVER:uint = 0xFFCCCCCC;
        public static const COLORS:Array = [WHITE, GREEN, RED, GOLD, SILVER];
        // 3d
        private var scene:Scene3D;
        private var renderer:BasicRenderEngine;
        private var viewport:Viewport3D;
        private var camera:Camera3D;
        // 3d objects
        private const MAX_RADIUS:int = 10000;
        private const PIXCEL_MARGIN:Number = 1.25;
        private var textPixels:Pixels;
        private var bfx:BitmapEffectLayer;
        private var dmyObjs:Array = [];
        private var tweens:Array = [];
        private var preRenderedTests:Array = [];
        // 3d camera
        public var cameraDistance:Number = 10;
        public var cameraYaw:Number = 0;
        public var cameraPitch:Number = 0;
        // 2d 
        private var canvas:BitmapData;
        private var mtx:Matrix;
        // Message array
        private var messages:Array = [];
        // data
        private var index:Number = 0;
        private const RESET_TIMER:Timer = new Timer(11 * 1000);
        
        private const PLANE_Y:int = 500;
        private const FLOOR_LENGTH:int = 2000;
        private var sceneWidth:int;
        private var sceneHeight:int;
        
        private var tween:ITween;
        
        private var glowTimer:Timer;
        
        private var loadText:TextField;
        private var loadSprite:Sprite;
        private var loadTimer:Timer;
        
        public function Main(scw:int = 590, sch:int = 300):void {
            stage.quality = StageQuality.MEDIUM;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            graphics.beginFill(0x000000, 1);
            graphics.drawRect(0, 0, scw, sch);
            graphics.endFill();
            
            sceneWidth = scw;
            sceneHeight = sch;
            
            setLoaderDisplay();
            messages.push( { comment: "Particle Text" } );
            messages.push( { comment: "betweenas3" } );
            messages.push( { comment: "pv3d" } );
            messages.push( { comment: "wonderfl" } );
            setScene();
        }

        
        private function setLoaderDisplay():void {
            loadSprite = new Sprite();
            loadSprite.x = loadSprite.y = 0;
            loadSprite.graphics.beginFill(0x000000, .8);
            loadSprite.graphics.drawRect(0, 0, sceneWidth, sceneHeight);
            loadSprite.graphics.endFill();
            addChild(loadSprite);
            
            var tf:TextFormat = new TextFormat();
            tf.size = 20;
            tf.font = "Arial";
            tf.bold = true;
            
            loadText = new TextField();
            loadText.multiline = true;
            loadText.autoSize = "left";
            loadText.defaultTextFormat = tf;
            loadSprite.addChild(loadText);
            
            loadText.filters = [new GlowFilter(COLORS[1], 1, 3, 3, 5, 1, false, true)];
            
            loadTimer = new Timer(1000);
            loadTimer.addEventListener(TimerEvent.TIMER, loadTimerHandler);
            
            setLoaderText("Loading...");
        }
        
        private function loadTimerHandler(t:TimerEvent):void {
            var col:uint = COLORS[COLORS.length * Math.random() | 0];
            var ct:ColorTransform = new ColorTransform();
            ct.color = col;
            
            BetweenAS3.to(loadText, {transform: {colorTransform: {redOffset: ct.redOffset, greenOffset: ct.greenOffset, blueOffset: ct.blueOffset}}}, 1, Linear.easeIn).play();
        }
        
        private function setLoaderText(str:String):void {
            loadText.text = str;
            loadText.x = (loadSprite.width / 2) - (loadText.width / 2);
            loadText.y = (loadSprite.height / 2) - (loadText.height / 2);
            setChildIndex(loadSprite, numChildren - 1);
            loadSprite.visible = true;
            if (!loadTimer.running){
                loadTimer.start();
            }
        }
        
        private function hideLoaderText():void {
            loadTimer.stop();
            loadSprite.visible = false;
        }
        
        private function setScene():void {
            //Particles Layers and bitmap
            scene = new Scene3D();
            viewport = new Viewport3D(sceneWidth, sceneHeight);
            camera = new Camera3D();
            addChild(viewport);
            
            bfx = new BitmapEffectLayer(viewport, sceneWidth, sceneHeight);
            bfx.addEffect(new BitmapColorEffect(1, 1, 1, 0.75));
            viewport.containerSprite.addLayer(bfx);
            
            textPixels = new Pixels(bfx);
            scene.addChild(textPixels);
            
            var glowScale:Number = 4;
            
            canvas = new BitmapData(sceneWidth / glowScale, sceneHeight / glowScale, false, 0x0000000);
            var bitmap:Bitmap = new Bitmap(canvas, PixelSnapping.NEVER, true);
            bitmap.scaleX = bitmap.scaleY = glowScale;
            bitmap.blendMode = BlendMode.ADD;
            addChild(bitmap);
            
            mtx = new Matrix();
            mtx.scale(1 / glowScale, 1 / glowScale);


            camera.target = DisplayObject3D.ZERO;
            renderer = new BasicRenderEngine();
            
            var i:Number;
            var arr:Array = [];
            for (i = 0; i < messages.length; i++){
                dmyObjs[i] = new DisplayObject3D();
                while (true){
                    var angle:Number = 360 * Math.random();
                    dmyObjs[i].x = 2000 * Math.sin(angle * Number3D.toRADIANS);
                    dmyObjs[i].y = 2000 * (Math.random() - 0.5);
                    dmyObjs[i].z = 2000 * Math.cos(angle * Number3D.toRADIANS);
                    if (i == 0)
                        break;
                    else {
                        if (DisplayObject3D(dmyObjs[i]).distanceTo(dmyObjs[i - 1]) >= 500)
                            break;
                    }
                }
                dmyObjs[i].lookAt(DisplayObject3D.ZERO);
            }
            
            for (i = 0; i < MAX_PARTICLES; i++){
                var p:Pixel3D = new Pixel3D(COLORS[COLORS.length * Math.random() | 0]);
                textPixels.addPixel3D(p);
            }
            
            for (i = 0; i < messages.length; i++){
                preRenderText(i);
                createText(i);
            }
            
            runAnimation();
        }
        
        private function timerHandler(e:TimerEvent = null):void {
            var i:Number;
            var arr:Array = [];
            for (i = 0; i < textPixels.pixels.length; i++){
                arr[i] = BetweenAS3.serial(BetweenAS3.delay(BetweenAS3.to(textPixels.pixels[i], getRandomPos(), 3, Expo.easeInOut), Math.random()));
            }
            
            BetweenAS3.serial(BetweenAS3.parallelTweens(arr), BetweenAS3.func(function():void {
                    setTimeout(motionText, 2 * 1000);
                })).play();
            var cameraTarget:DisplayObject3D = new DisplayObject3D();
            cameraTarget.copyTransform(dmyObjs[index]);
            cameraTarget.moveBackward(250);
            var dis:Number = cameraTarget.distanceTo(DisplayObject3D.ZERO);
            var rot:Number = Math.atan2(cameraTarget.x, cameraTarget.z);
            
            BetweenAS3.parallel(BetweenAS3.delay(BetweenAS3.bezier(this, {cameraYaw: rot, cameraDistance: dis, cameraPitch: cameraTarget.y}, null, getRandomPos(), 10.5, Expo.easeInOut), 1.0), BetweenAS3.serial(BetweenAS3.to(camera, {fov: 60}, 4, Sine.easeInOut), BetweenAS3.to(camera, {fov: 50}, 8, Sine.easeInOut))).play();
        }
        
        private function motionText():void {
            var tw:ITween = BetweenAS3.parallelTweens(tweens[index]);
            tw = BetweenAS3.scale(tw, 3.5 / tw.duration);
            tw.play();
            index++;
            if (index == messages.length){
                index = 0;
            }
        }
        
        private function preRenderText(itemIndex:Number):void {
            preRenderedTests[itemIndex] = [];
            var text:TextField = new TextField();
            text.multiline = true;
            text.autoSize = TextFieldAutoSize.LEFT;
            
            var size:Number = 24;
            
            var tf:TextFormat = new TextFormat();
            tf.size = size;
            tf.font = "Arial";
            tf.bold = true;
            text.defaultTextFormat = tf;
            
            text.text = messages[itemIndex].comment;
            
            var twh:Number = text.textWidth * text.textHeight;
            
            while (twh > MAX_PARTICLES){
                size--;
                tf.size = size;
                text.defaultTextFormat = tf;
                text.text = messages[itemIndex].comment;
                twh = text.textWidth * text.textHeight;
            }
            
            var cap:BitmapData = new BitmapData(text.textWidth + 10, text.textHeight, true, 0xFFFFFFFF);
            cap.lock();
            cap.draw(text);
            for (var i:Number = 0; i < text.textWidth + 10; i++){
                for (var j:Number = 0; j < text.textHeight; j++){
                    if (cap.getPixel(i, j) == 0xFFFFFF)
                        continue;
                    if (preRenderedTests[itemIndex].length >= MAX_PARTICLES)
                        break;
                    preRenderedTests[itemIndex].push({x: i, y: j, textWidth: text.textWidth, textHeight: text.textHeight});
                }
            }
            cap.unlock();
            cap.dispose();
        }
        
        private function createText(itemIndex:Number):void {
            var t:DisplayObject3D = dmyObjs[itemIndex];
            var arr:Array = [];
            var col:uint = COLORS[Math.floor(Math.random() * (COLORS.length))];
            for (var i:Number = 0; i < preRenderedTests[itemIndex].length; i++){
                var pix:Object = preRenderedTests[itemIndex][i];
                var p:Pixel3D = textPixels.pixels[i];
                var vec:DisplayObject3D = new DisplayObject3D();
                vec.x = (pix.x - pix.textWidth / 2) * PIXCEL_MARGIN;
                vec.y = 100 + (pix.textHeight / 2 - pix.y) * PIXCEL_MARGIN;
                vec.z = 50;
                vec.transform.calculateMultiply(t.transform, vec.transform);
                arr[i] = BetweenAS3.bezier(p, {x: vec.x, y: vec.y, z: vec.z, color: col}, null, getRandomPos(), 1.2 + Math.random() * 0.25 + i * 0.002, Expo.easeOut);
            }
            tweens.push(arr);
        }
        
        private function loop(e:Event = null):void {
            camera.x = cameraDistance * Math.sin(cameraYaw);
            camera.y = cameraPitch;
            camera.z = cameraDistance * Math.cos(cameraYaw);
            
            renderer.renderScene(scene, camera, viewport);
            
            canvas.fillRect(canvas.rect, 0x000000);
            canvas.draw(viewport, mtx);
        }
        
        private function getRandomPos():Object {
            return {x: MAX_RADIUS * (Math.random() - 0.5), y: MAX_RADIUS * (Math.random() - 0.5), z: MAX_RADIUS * (Math.random() - 0.5)};
        }
        
        private function runAnimation():void {
            hideLoaderText();
            
            RESET_TIMER.addEventListener(TimerEvent.TIMER, timerHandler);
            RESET_TIMER.start();
            
            timerHandler();
            addEventListener(Event.ENTER_FRAME, loop);
        }
    }
}