Beautifl - Flash Gallery

Thumbnail : 3D text of fire
3D text of fire
yooKo 2010-02-26 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

/**
 * 注意: Frocessing と Papervision3D が必要です
 * 
 * @author yooKo@selflash
 * @version 1.0.0
 * @date    2009/10/24
 * @see     http://selflash.jp/
 * 
 * Please click.
 * The flame becomes deformed.
 *
 * クリックすると炎でできたテキストが変形します
 * 変形中は激重いので注意
 * 誰かが最適化してくれる事を望む
 **/
package {	
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.BlendMode;
    import flash.display.DisplayObject;
    import flash.display.StageQuality;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    import flash.filters.BlurFilter;
    import flash.filters.BitmapFilterQuality;	
    import flash.filters.ColorMatrixFilter;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.events.MouseEvent;		
    import flash.geom.ColorTransform;
    import flash.geom.Point;
    import flash.geom.Matrix;
    import flash.geom.Rectangle;	
    import flash.utils.Timer;
    import flash.utils.getTimer;
	
    import org.papervision3d.cameras.*;   
    import org.papervision3d.view.BasicView;	
    import org.papervision3d.view.layer.ViewportLayer;  
    import org.papervision3d.view.layer.BitmapEffectLayer;			
    import org.papervision3d.core.effects.BitmapLayerEffect;
    import org.papervision3d.core.effects.BitmapColorEffect;	
    import org.papervision3d.core.effects.utils.BitmapClearMode;
    import org.papervision3d.core.geom.Pixels;
    import org.papervision3d.core.geom.renderables.Pixel3D;	
    import org.papervision3d.objects.DisplayObject3D;
  
    import net.hires.debug.Stats;

    import frocessing.color.ColorHSV;
	
    [SWF(width="465", height="465", backgroundColor="0x000000", frameRate="60")]

    public class FireText3D extends BasicView {	
	private var _container:DisplayObject3D;
	private var _pixels:Pixels;
	private var _particles:Array/*Particle*/ = [];
	private var _startTime:int;
	private var _textW:Number;
	private var _textH:Number;
        private var _bmd:BitmapData;        
	private var _currentNum:int = 0;		
        private var _count:int = 0;
		
	//========================================================================
	// constructor
	//========================================================================
	public function FireText3D() {	
            super(0, 0, true, false);			
            
            init();
        }

	//========================================================================
	// init
	//========================================================================
        private function init(e:Event = null):void {	
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.quality = StageQuality.LOW;
            
	    camera.z = -80;
			
            var _layer:BitmapEffectLayer = new BitmapEffectLayer(viewport, stage.stageWidth * 0.8, stage.stageHeight, true, 0, BitmapClearMode.CLEAR_PRE, false);
	    viewport.containerSprite.addLayer(_layer);
	    //_layer.addEffect(new BitmapColorEffect(1, 1, 1, .7));		
	    _layer.addEffect(new BitmapLayerEffect(new BlurFilter(10, 10, BitmapFilterQuality.LOW), true));
	    _layer.addEffect(new BitmapLayerEffect(new ColorMatrixFilter([1.1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0])));	
	    _pixels = new Pixels(_layer);
	    _layer.addDisplayObject3D(_pixels);
	    _container = scene.addChild(new DisplayObject3D());
	    _container.addChild(_pixels);	
			
	    createText();	
			
            createBody(0, .2, 0xFF000000);
	    //perlinNoise は 重い為縦を3倍の長さでBitmapDataを作成する
	    _bmd = new BitmapData(465, 465 * 3.5, false, 0x00000000);
			
	    stage.addEventListener(MouseEvent.CLICK, onClickHandler);
		
	    upDate();
			
	    startRendering();
			
	    stage.addChild(new Stats());
	}
	//========================================================================
	// createText
	//========================================================================
	private function createText():void {
            var tf:TextField = new TextField();
            tf.defaultTextFormat = new TextFormat("小塚ゴシック Pro H", 18, 0x000000, true);
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.text = "FIRE";
            _textW = tf.textWidth;
            _textH = tf.textHeight;            
        
            _bmd = new BitmapData(_textW + 5, _textH + 5, false, 0xFFFFFF);
            _bmd.draw(tf);
	}			
	//========================================================================
	// onClickHandler
	//========================================================================
	private function onClickHandler(e:MouseEvent = null):void {
	    _startTime = getTimer();
	    (_currentNum < 3) ? _currentNum++ : _currentNum = 0; 
	}		
	//========================================================================
	// onEnterFrameHandler
	//========================================================================
	private var _rotateX:Number = 0;
	    private var _rotateY:Number = 0;
	    override protected function onRenderTick(event:Event = null):void { 
	    super.onRenderTick();
	
	    drawEffect();
			
	    switch (_currentNum) {
                case 1: 
                   collapsesAnimation();
		   upDate();
                break;	
		case 3:
		   revivalAnimation();
		   upDate();
		break;
	    }
	    _count++;
			
	    _rotateX += (stage.mouseX - stage.stageWidth * 0.5 - _rotateX) * 0.1;
	    _rotateY += (stage.mouseY - stage.stageHeight * 0.5 - _rotateY) * 0.1;
	    _pixels.rotationY = _rotateX * 0.5;
	    _pixels.rotationX = _rotateY * 0.5;
	}	
	//========================================================================
	// drawEffect
	//========================================================================
        private var _offset:Array = [new Point(), new Point()];		
	    private const DRAW_MATRIX:Matrix = new Matrix(1, 0, 0, 1, 0, 0);
	    private function drawEffect():void {
	    _bmd.lock();		
	    //_countが100の倍数の時だけperlinNoise!
	    if (_count % 240 == 0)_bmd.perlinNoise(30, 50, 1, 0, false, false, 0, true, _offset);	
	    _bmd.scroll(0, -5);			
	    _pixels.layer.canvas.lock();			
	    _pixels.layer.canvas.draw(_bmd, DRAW_MATRIX, null, BlendMode.SUBTRACT);
	    _pixels.layer.canvas.scroll(0, -5);
	    _pixels.layer.canvas.unlock();			
	    _bmd.unlock();		
	}
	//========================================================================
	// 再生アニメーション
	//========================================================================
	private function revivalAnimation():void {
	    var now:int = getTimer();
	    var len:int = _particles.length;
	    for (var i:int = 0; i < len; i++) {
	        var p:Particle = _particles[i];
	        var x_delay:Number = (1 - ((p.tx + _textW * .5) / _textW )) * 5000;
	        var y_delay:Number = (1 - ((p.ty + _textH * .5) / _textH )) * 500;
	        var z_delay:Number = (1 - ((p.tz + 6) / 12 )) * 1000;
	        var delay:Number = x_delay + y_delay + z_delay;
	        if (_startTime + delay > now) continue ;
	        //Math.absの高速化?
	        var xx:Number = p.tx - p.x;
	        var yy:Number = p.ty - p.y;
	        var zz:Number = p.tz - p.z;
	        var x:Number = (xx < 0)?xx * -1:xx;
	        var y:Number = (yy < 0)?yy * -1:yy;
	        var z:Number = (zz < 0)?zz * -1:zz;
	        if (x < .5 && y < .5 && z < .5) {
                p.x = p.tx;
                p.y = p.ty;
	        p.z = p.tz;
	        p.r = 20;
	        p.degree = 10;
	        p.c += (p.tc - p.c) * .2;
            }else {
                p.x += (p.tx - p.x) * .08;
                p.y += (p.ty - p.y) * .08;
                p.z += (p.tz - p.z) * .08;
		color.h = (getTimer() / 20000) * 360;
		p.c = rgb2argb(color.value, 1);						
                if (p.r > 3) {
		    p.x += ((p.x + p.r * Math.sin(Math.PI / 180 * p.degree)) - p.x) * .1;
		    p.y += ((p.y + p.r * Math.cos(Math.PI / 180 * p.degree)) - p.y) * .1;
		    p.z += ((p.z + p.r * Math.sin(Math.PI / 180 * p.degree)) - p.z) * .1;
		}
		if (p.r > 0) p.r -= .3;
		p.degree += 10;
             }
	}
}
	//========================================================================
	// collapsesAnimation
	//========================================================================
	private var color:ColorHSV = new ColorHSV(0, 0.5); 
            private function collapsesAnimation():void {
	        var now:int = getTimer();
		var len:int = _particles.length;
		for (var i:int = 0; i < len; i++) {
		    var p:Particle = _particles[i];
		    var x_delay:Number = (1 - ((p.tx + _textW * .6) / _textW )) * 5000;
		    var y_delay:Number = (1 - ((p.ty + _textH * .8) / _textH )) * 500;
		    var z_delay:Number = (1 - ((p.tz + 8 * .5) / 8 )) * 1000;
		    var delay:Number = x_delay + y_delay + z_delay;
		    if (_startTime + delay > now) continue ;
		    //Math.absの高速化?
		    var xx:Number = p.ex - p.x;
		    var yy:Number = p.ey - p.y;
		    var zz:Number = p.ez - p.z;
		    var x:Number = (xx < 0)?xx * -1:xx;
		    var y:Number = (yy < 0)?yy * -1:yy;
		    var z:Number = (zz < 0)?zz * -1:zz;
		    if (x < .5 && y < .5 && z < .5) {
			p.x = p.ex;
			p.y = p.ey;
			p.z = p.ez;
			p.r = 20;
			p.degree = 10;
		    }else {
			p.x += (p.ex - p.x) * .08;
			p.y += (p.ey - p.y) * .08;
			p.z += (p.ez - p.z) * .08;
			if (p.r > 3) {
		            p.x += ((p.ex + p.r * Math.cos(Math.PI / 180 * p.degree)) - p.x) * .1;
			    p.y += ((p.ey + p.r * Math.cos(Math.PI / 180 * p.degree)) - p.y) * .1;
			    p.z += ((p.ez + p.r * Math.sin(Math.PI / 180 * p.degree)) - p.z) * .1;
			}
			if (p.r) p.r -= .3;
			p.degree += 10;
		    }
		}
	}
	//========================================================================
	// Particleが保持している情報を元にPixelsにaddPixel3D()
	//========================================================================
	private var _pixel3Ds:Array/*Pixel3D*/ = [];		
	private function upDate():void {
	    _pixels.removeAllpixels();
	    var len:int = _particles.length;
	    for (var i:int = 0; i < len; i++) {
	        var p:Particle = _particles[i];				
		var px:Pixel3D;
		color.h = (getTimer() / 5000) * 360;
		var c:int = rgb2argb(color.value, 1);						
		if (_pixel3Ds[i]) {
		    px = _pixel3Ds[i];
		    px.color = c;
		    px.x = p.x;
		    px.y = p.y;
		    px.z = p.z;
		}else {
		    _pixel3Ds[i] = new Pixel3D(rgb2argb(0xEFDD6D, 1), p.x, p.y, p.z);
		};
	    px = _pixel3Ds[i];
	    _pixels.addPixel3D(px);
	    }			
	}
	//========================================================================
	// createBody
	//========================================================================
	private var _c:uint;
	private function createBody(depth:Number = 0, distance:Number = 2, color:Number = NaN):void {
	    var p:Particle;	
	    var w:Number = _textW * .5;
	    var h:Number = _textH * .4;			
				
	    for (var i:int = 0, _y:Number = 0; _y < _textH; _y += distance ) {
		for (var _x:Number = 0; _x < _textW; _x += distance ) {
	            _c = _bmd.getPixel( _x, _y );
		    if (_c != 0xFFFFFF) {
		        _c = (color)?color:rgb2argb(_c, 1);	
		        p = _particles[i] || new Particle();
		        p.c = _c;
                        p.x = _x - w;
		        p.y = - _y + h;
		        p.z = depth;
		        p.tx = p.x;
		        p.ty = p.y;
		        p.tz = p.z;
		        p.tc = p.c;
		        _particles[i] = p;
		        i++;					
		    }
	        }
	    }
        }	
	//========================================================================
        // RGBをARGBに変換する
        //========================================================================
        private function rgb2argb(rgb:uint, alpha:Number):uint {
            return ((alpha * 0xff) << 24) + rgb;
        }
    }
}
//========================================================================
// 座標、色情報を保持するクラス		
//========================================================================
class Particle {
    public var x:Number;
    public var y:Number;
    public var z:Number;
    public var c:int;	
    public var tx:Number;
    public var ty:Number;
    public var tz:Number;
    public var tc:int;	
    public var ex:Number = (Math.random() - .5) * 2;
    public var ey:Number = (Math.random() - .5) * 2 - 30;
    public var ez:Number = (Math.random() - .5) * 2;
    public var ec:int;	
    public var r:Number = 2;
    public var degree:Number = 5;
}