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

city visualizer

click to load mp3

Cell -> http://wonderfl.net/c/200s @wh0
Clientmp3loader -> http://wonderfl.net/c/zBu2 @wonderwhyer
Get Adobe Flash player
by zob 03 Jan 2012
/**
 * Copyright zob ( http://wonderfl.net/user/zob )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/uWqQ
 */

package  
{
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.geom.Point;

    public class city extends Sprite
    {
        private var main:city3d;
        
        public function city() 
        {    
            Wonderfl.disable_capture();
            main = new city3d(stage);
            stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown);
        }
        
        private function onMouseDown( e:MouseEvent ):void
        {
            main.choseMP3();
        }
    }
}
import flash.display.Loader;
import flash.display3D.Context3DCompareMode;
import flash.display3D.Context3DVertexBufferFormat;
import flash.events.EventDispatcher;
import flash.events.EventPhase;
import flash.events.TimerEvent;
import flash.geom.Matrix;
import flash.geom.Vector3D;
import flash.net.FileFilter;
import flash.net.FileReference;
import flash.utils.getTimer;
import flash.utils.Timer;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.Quad;
import org.libspark.betweenas3.easing.Quart;
import org.libspark.betweenas3.events.TweenEvent;
import org.libspark.betweenas3.tweens.ITween;

class ThreeD extends EventDispatcher
{
    // constant
    public static const ITS_OK:String = "ItsOK";
    public static const BOOT_SUCCESS:String = "BootSuccess";
    private static const INDEX_PADDING:int = 6;
    
    // dependences
    private var stg:Stage;
    
    // 3D
    public var context3D:Context3D;
    public var container:Sprite;
    public var indexBuffer:IndexBuffer3D;
    public var program:Program3D;
    public var asm:AGALMiniAssembler = new AGALMiniAssembler();
    public var projectionMatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();
    public var matrix3D:Matrix3D = new Matrix3D();
    
    // variables
    private var meshes:Vector.<Mesh> = new Vector.<Mesh>;
    private var vertexBuffers:Vector.<VertexBuffer3D> = new Vector.<VertexBuffer3D>;
    private var indexBuffers:Vector.<IndexBuffer3D> = new Vector.<IndexBuffer3D>;
    private var textures:Vector.<Texture> = new Vector.<Texture>;
    
    public function ThreeD(s:Stage)
    {
        stg = s;
    }
    
    public function check():void
    {
        var stage3D:Stage3D = stg.stage3Ds[0];
        stage3D.addEventListener( Event.CONTEXT3D_CREATE,
            function( e:Event ):void {
                // context3d setup
                context3D = e.target.context3D;
                if (!context3D) throw new Error( "no context3D" );
                
                // context
                context3D.enableErrorChecking = true;
                context3D.configureBackBuffer( 465, 465, 0, true );
                context3D.setRenderToBackBuffer();
                context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
                context3D.setCulling(Context3DTriangleFace.BACK);
                dispatchEvent( new Event( ITS_OK ) );
            }
        );
        stage3D.requestContext3D();
    }
    
    public function boot():void
    {    
        // programs
        program = context3D.createProgram();
        program.upload( asm.assemble( "vertex", vs ), asm.assemble( "fragment", fs ) );
        
        // matrix
        projectionMatrix.perspectiveFieldOfViewLH( 60 / 180 * 3.141592653589793, 1, 1, 65000 );
        
        // finish booting
        dispatchEvent( new Event( BOOT_SUCCESS ) );
    }

    public function addMesh( m:Mesh ):void
    {
        var index:int = meshes.length;
        meshes.push( m );
        m.vertices.fixed = true;
        m.indices.fixed = true;
        
        // buffers
        vertexBuffers.push( context3D.createVertexBuffer( m.currentIndex, m.INDEX_PADDING ) );
        indexBuffers.push( context3D.createIndexBuffer( m.indices.length ) );
        vertexBuffers[index].uploadFromVector( m.vertices, 0, m.currentIndex );
        indexBuffers[index].uploadFromVector( m.indices, 0, m.indices.length );
        
        // textures
        textures.push( context3D.createTexture( 512, 512, "bgra", false ) );
        textures[index].uploadFromBitmapData( m.material.bmd );
    }
    
    public function render():void
    {
        context3D.clear( 0.0, 0.0, 0.0, 1 );
        context3D.setDepthTest( true, "less" );
        context3D.setProgram( program );
        
        var i:int = 0;
        while ( i < meshes.length )
        {
            matrix3D.copyFrom( projectionMatrix );
            matrix3D.prepend( meshes[i].matrix );
            if( meshes[i].material.live )
                textures[i].uploadFromBitmapData( meshes[i].material.bmd );
            context3D.setTextureAt( 0, textures[i] );
            if ( meshes[i].live )
            {
                vertexBuffers[i].uploadFromVector( meshes[i].vertices, 0, meshes[i].currentIndex );
                indexBuffers[i].uploadFromVector( meshes[i].indices, 0, meshes[i].indices.length );
            }
            context3D.setVertexBufferAt( 0, vertexBuffers[i], 0, Context3DVertexBufferFormat.FLOAT_4 );
            context3D.setVertexBufferAt( 1, vertexBuffers[i], 4, Context3DVertexBufferFormat.FLOAT_2 );
            context3D.setProgramConstantsFromMatrix( "vertex", 0, matrix3D, true );
            context3D.drawTriangles( indexBuffers[i], 0, meshes[i].indices.length / 3 );
            i++;
        }

        context3D.present();
    }
}

class Material extends EventDispatcher
{
    public var live:Boolean = false;
    public var bmd:BitmapData;
    public function Material()
    {
        
    }
    
    public function update():void {}
}

class VehicleLightMaterial extends Material
{
    public var r:Number = 0;
    public var R:Number = 0;
    public var w:Number = 0;
    public var W:Number = 0;
    
    private var tmp:BitmapData;
    
    public function VehicleLightMaterial( radius:Number = 8, lc:uint = 0xFFFF0000, rc:uint = 0xFFFFCC33 )
    {
        r = radius;
        R = r * 2; // also, diameter
        w = Math.sqrt( R * R / 2 );
        W = 2 * r + w;
        //R = R + 1;
        W = W + 1;
        
        bmd = new BitmapData( 512, 512, true, 0x0 );
        tmp = new BitmapData( W, W, true, 0x0 );

        drawStar( bmd, r, r, lc );
        drawStar( bmd, W - r - 1, W - r - 1, rc );
        var m:Matrix = new Matrix();
        m.scale( bmd.width / tmp.width, bmd.height / tmp.height );
        bmd.draw( bmd, m );
    }
    
    public function drawStar( e:BitmapData, px:int, py:int, c:uint = 0xFFFF0000 ):void
    {
        lineFast( e, px -     r, py        , px +     r, py        , c );
        lineFast( e, px        , py -     r, px        , py +     r, c );
        lineFast( e, px - r / 2, py - r / 2, px + r / 2, py + r / 2, c );
        lineFast( e, px - r / 2, py + r / 2, px + r / 2, py - r / 2, c );
    }
    
    public function lineFast( e:BitmapData, x0:int, y0:int, x1:int, y1:int, c:uint = 0xFFFF0000 ):void
    {    
        var dy       :int = y1 - y0;
        var dx       :int = x1 - x0;
        var adx      :int = 0;
        var ady      :int = 0;
        var stepx    :int;
        var stepy    :int;
        var fraction :int;
        var ratio    :Number = 0;
        var ec       :uint = c & 0xFFFFFF; // ignore alpha
        var tc:uint = ec;
        tc = ec + uint(( 0xFF * 0.05 ) << 24);
        
        if ( dy < 0 ) { dy = -dy;  stepy = -1; } else { stepy = 1; }
        if ( dx < 0 ) { dx = -dx;  stepx = -1; } else { stepx = 1; }
        adx = Math.abs( dx ) + 2;
        ady = Math.abs( dy ) + 2;
        dy <<= 1;
        dx <<= 1;
        
        e.setPixel32( x0, y0, tc );
        if ( dx > dy )
        {
            fraction = dy - ( dx >> 1 );
            while ( x0 != x1 )
            {
                ratio = 1 - Math.abs( Math.abs( x0 - x1 ) / adx - 0.5 ) * 2;
                if ( fraction >= 0 )
                {
                    y0 += stepy;
                    fraction -= dx;
                }
                x0 += stepx;
                fraction += dy;
                tc = ec;
                tc += ( 0xFF * ratio ) << 24;
                e.setPixel32( x0, y0, tc );
            }
        } else {
            fraction = dx - ( dy >> 1 );
            while ( y0 != y1 )
            {
                ratio = 1 - Math.abs( Math.abs( y0 - y1 ) / ady - 0.5 ) * 2;
                if ( fraction >= 0 )
                {
                    x0 += stepx;
                    fraction -= dy;
                }
                y0 += stepy;
                fraction += dx;
                tc = ec;
                tc += ( 0xFF * ratio ) << 24;
                e.setPixel32( x0, y0, tc );
            }
        }
    }
}

class MusicMaterial extends Material
{
    public static const PEAK:String = "peak";
    
    // settings
    private var tcolor:uint = 0xFFFFCC32;
    private var windowX:int = 16;
    private var windowY:int = 32;
    
    // bitmaps
    private var ct:ColorTransform = new ColorTransform( 0.9, 0.8, 0.6, 1 );
    
    // sounds
    private var snd:Sound;
    private var bytes:ByteArray = new ByteArray();
    private var song:SoundChannel;
    private var url:String = "http://level0.kayac.com/images/murai/Digi_GAlessio_-_08_-_ekiti_son_feat_valeska_-_april_deegee_rmx.mp3";
    private var file:FileReference;
    
    public function MusicMaterial()
    {
        live = true;
        
        snd = new Sound();
        snd.load( new URLRequest( url ), new SoundLoaderContext( 10, true ) );
        song = snd.play(0, int.MAX_VALUE);

        bmd = new BitmapData( 512, 512, false, 0x0 );
    }
    
    private function onUserCancelled (e:Event):void { }
    private function onFileSelected (e:Event):void { file.load (); }
    private function onFileLoaded (e:Event):void {
        if ( song ) song.stop();
        
        snd = new Sound();
        snd.loadCompressedDataFromByteArray(file.data, file.data.length);
        song = snd.play(0, int.MAX_VALUE);
    }
    
    
    public function loadMP3():void
    {
        file = new FileReference;
        file.addEventListener (Event.CANCEL, onUserCancelled);
        file.addEventListener (Event.SELECT, onFileSelected);
        file.addEventListener (Event.COMPLETE, onFileLoaded);
        file.browse ([ new FileFilter ("MP3 files", "*.mp3") ]);
    }
    
    private function mp3Loaded(e:Event):void
    {
        if ( song ) song.stop();
        song = snd.play(0, int.MAX_VALUE);
    }
    
    override public function update():void
    {
        SoundMixer.computeSpectrum( bytes, false, 0 );
        var byteTotal:Number = 0;
        var i:int = 0, j:int = 0;
        var byte:Number = 0;
        bytes.position = 0;
        var split:int = 2;
        var dsplit:int = split * 2;
        var w:int = 20 / split;
        var h:int = 25 / split;
        var p:int =  8 / split;
        
        bmd.colorTransform( bmd.rect, ct );

        var size:Number = bmd.width * 0.8;
        var hsize:Number = bmd.width * 0.4;
        var sw:Number = hsize / windowX;
        var sh:Number = hsize / windowY;
        
        var tcolor:uint = 0xFFFFCC33;
        var iw:int = 0;
        var ih:int = 0;
        
        var d:int = 0;
        
        for( i = 0; i < 512; i++ )
        {
            byte = Math.abs( bytes.readFloat() );
            byteTotal += byte;
            if( ( byte > 0.3 && Math.random() > 0.5 ) || Math.random() < 0.0001 )
            {
                for ( j = 0; j < split * 2; j++ )
                {
                    switch( j )
                    {
                        case 0:
                            iw = i % windowX;
                            ih = int( i / windowX );
                            tcolor = 0xFFFFCC33;
                            break;
                        case 1:
                            iw = i % windowX;
                            ih = windowY - int( i / windowX ) - 1;
                            tcolor = 0xFFFFFFFF;
                            break;
                        case 2:
                            iw = windowX - i % windowX - 1;
                            ih = int( i / windowX );
                            tcolor = 0xFFFFFFAA;
                            break;
                        case 3:
                            iw = windowX - i % windowX - 1;
                            tcolor = 0xFF99CCFF;
                            ih = windowY - int( i / windowX ) - 1;
                            break;
                    }
                    if ( Math.random() < 0.001 ) continue;
                    bmd.fillRect( new Rectangle(
                            iw * sw + p / 2 + ( j % split ) * hsize,
                            ih * sh + int( j / split ) * hsize,
                            sw - p, sh - p
                        ), 
                        tcolor 
                    );
                }
            }
        }
        
        byteTotal /= 512;
        
        if ( byteTotal > 0.3 )
        {
            dispatchEvent( new Event( PEAK ) );
        }
        
        /*
        if (byteTotal > 0.3 )
        {
            var k:int = int( Math.random() * 4 );
            for ( i = 0; i < 4; i++ )
            {
                if ( i == k )
                {
                    bmd.fillRect( new Rectangle(
                            i * hsize/2,
                            size,
                            hsize/2, hsize/2
                        ), 
                        0x3FFFCC33 
                    );
                    bmd.fillRect( new Rectangle(
                            ( i % split ) * hsize,
                            int( i / split ) * hsize,
                            hsize, hsize
                        ), 
                        0x3FFFCC33
                    );
                }
            }
        }
        //*/
    }
}

class Mesh
{
    public var INDEX_PADDING:int = 6;
    public var vertices:Vector.<Number>;
    public var indices:Vector.<uint>;
    public var matrix:Matrix3D = new Matrix3D();
    public var material:Material;
    public var live:Boolean = false;
    
    public function Mesh()
    {
        vertices = new Vector.<Number>;
        indices = new Vector.<uint>;
    }
    
    public function pushVertex( ...arg ):Mesh
    {
        for each( var v:Number in arg ) vertices.push( v );
        return this;
    }
    
    public function pushIndex( ...arg ):Mesh
    {
        for each( var v:int in arg ) indices.push( v );
        return this;
    }
    
    public function get currentIndex():int
    {
        return vertices.length / INDEX_PADDING;
    }
}

class ToyCar
{
    public var rotation:Number = 0;
    public var x:Number = 0;
    public var y:Number = 0;
    public function ToyCar() {}
}

class FireworksManager
{
    private static const MAX_FIREWORKS:int = 3;
    private static const MAX_PARTICLES:int = 400;
    private static const PARTICLE_RADIUS:Number = 8;
    private static const PARTICLE_W:Number = Math.sqrt( PARTICLE_RADIUS * PARTICLE_RADIUS / 2 );
    private var particles:Vector.<Vector3D> = new Vector.<Vector3D>;
    private var keeper:Vector.<Vector3D> = new Vector.<Vector3D>;
    
    public function FireworksManager()
    {
        for ( var i:int = 0; i < MAX_PARTICLES; i++ )
        {
            particles.push( new Vector3D() ); // w -> alpha
            keeper.push( particles[i] );
        }
    }
    
    private function withdraw(px:Number, py:Number, pz:Number):Boolean
    {
        if (keeper.length > 0)
        {
            var rd:Number = 2000 + Math.random() * 1000;
            var rand:Number = Math.random() * 2 * Math.PI;
            var rx:Number = Math.cos(rand);
            var ry:Number = Math.sin(rand);
            var rz:Number = (2*Math.random()) - 1;
            var mz:Number = Math.sqrt(1 - rz * rz);
            var r3x:Number = rx * mz * rd;
            var r3y:Number = ry * mz * rd;
            rz *= rd;
            var itw:ITween = BetweenAS3.tween(keeper.shift(), { x:r3x+px, y:r3y+py, z:rz+pz, w:1.0 }, { x:px, y:py, z:pz, w:1.0 }, 0.5+Math.random() * 1.0, Quad.easeOut);
            itw.addEventListener( TweenEvent.COMPLETE, 
                function( e:TweenEvent ):void
                {
                    var iw:ITween = BetweenAS3.tween(e.currentTarget.target, { w:0.0 }, null, 0.5);
                    iw.addEventListener( TweenEvent.COMPLETE, function( e:TweenEvent ):void
                    {
                        keeper.push(e.currentTarget.target);
                    });
                    iw.play()
                });
            itw.play();
            return true;
        }
        return false;
    }
    
    public function explode():void
    {
        if ( keeper.length < 30 ) return;
        var rx:Number = CityFactory.MAP_WIDTH / 4 + Math.random() * CityFactory.MAP_WIDTH / 2;
        var ry:Number = CityFactory.MAX_BUILDING_HEIGHT * 1.5  + Math.random() * 3000;
        var rz:Number = CityFactory.MAP_WIDTH / 4 + Math.random() * CityFactory.MAP_WIDTH / 2;
        for ( var i:int = 0; i < 50; i++ )
        {
            if ( !withdraw( rx, ry, rz ) ) break;
        }
    }
    
    public function initMesh( m:Mesh ):void
    {
        m.vertices = new Vector.<Number>( particles.length * 18, true );
        
        var j:int = 0;
        var k:int = 0, o:int = 0, l:int = 0, u:int = 0;
        for ( var i:int = 0; i < particles.length; i++ )
        {
            j = i * 3;
            
            k = i * 18 + 4;
            if (Math.random() > 0.5)
            {
                m.vertices[k - 1] = 1;
                // .(0,1)
                m.vertices[k] = 0;
                m.vertices[k + 1] = 1;
                
                k += 6;
                m.vertices[k - 1] = 1;
                // .(0,0)
                m.vertices[k] = 0;
                m.vertices[k + 1] = 0;
                
                k += 6;
                m.vertices[k - 1] = 1;
                // .(1,0)
                m.vertices[k] = 1;
                m.vertices[k + 1] = 0;
            } else {
                m.vertices[k - 1] = 1;
                // .(1,0)
                m.vertices[k] = 1;
                m.vertices[k + 1] = 0;
                
                k += 6;
                m.vertices[k - 1] = 1;
                // .(1,1)
                m.vertices[k] = 1;
                m.vertices[k + 1] = 1;
                
                k += 6;
                m.vertices[k - 1] = 1;
                // .(0,1)
                m.vertices[k] = 0;
                m.vertices[k + 1] = 1;
            }
            
            m.pushIndex( 
                j    , j + 1, j + 2
            );
        }
    }
    
    public function updateMesh( m:Mesh, sm:Matrix3D, offset:Point ):void // sprite particle need some magic
    {
        var j:int = 0;
        var k:int = 0;
        var o:int = 0;
        
        var mat:VehicleLightMaterial = VehicleLightMaterial( m.material );
        var r:Number = PARTICLE_RADIUS;
        var w:Number = PARTICLE_W;
        var scale:Number = 40;
        var scale2:Number = 20;
        var tl_x:Number = -r;
        var tl_y:Number = -r;
        var tr_x:Number = w + r;
        var tr_y:Number = -r;
        var bl_x:Number = -r;
        var bl_y:Number = w + r;
        var tri:Vector.<Number> = new Vector.<Number>;
        tri.push(
            bl_x * scale, 0, bl_y * scale,
            tl_x * scale, 0, tl_y * scale,
            tr_x * scale,  0, tr_y * scale
        );

        var cv:Vector3D = new Vector3D();
        for ( var i:int = 0; i < particles.length; i++ )
        {
            for ( k = 0; k < 3; k++ )
            {
                o = i * 18 + k * 6;
                cv.x = particles[i].x + offset.x;
                cv.y = particles[i].y;
                cv.z = particles[i].z + offset.y;
                cv = sm.transformVector( cv);
                m.vertices[o]     = cv.x + tri[k];
                m.vertices[o + 1] = cv.y + tri[k + 1];
                m.vertices[o + 2] = cv.z + tri[k + 2];
                m.vertices[o + 3] = particles[i].w;
            }
        }
    }
}

class TrafficManager
{
    private static const MAX_VEHICLES:int = 300;
    private static const PARTICLE_RADIUS:Number = 8;
    private static const PARTICLE_W:Number = Math.sqrt( PARTICLE_RADIUS * PARTICLE_RADIUS / 2 );
    
    public var worldMatrix:Matrix3D;
    
    public var highways:Vector.<Vector.<Point>>;
    
    public var cars:Vector.<ToyCar> = new Vector.<ToyCar>;
    
    private var count:int = 0;
    
    public function TrafficManager( hw:Vector.<Vector.<Point>> )
    {
        highways = hw;
        for ( var i:int = 0; i < MAX_VEHICLES; i++ )
        {
            cars.push( new ToyCar() );
        }
    }
    
    public function boot():void
    {
        trace("TrafficManager:: boot.");
        
        
        var timer:Timer = new Timer(100);
        timer.addEventListener( TimerEvent.TIMER, addVehicle );
        timer.start();
    }
    
    private function addVehicle( e:TimerEvent ):void
    {
        if ( count < cars.length )
        {
            inviteVehicle( count );
            count++;
        }
    }
    
    private function inviteVehicle( id:int ):void
    {
        var index:int = int( Math.random() * highways.length );
        var highway:Vector.<Point> = highways[index];
        var a:int = 0, b:int = 1;
        var vx:Number = 0, vy:Number = 0, d:Number = 0;
        var rvx:Number = 0, rvy:Number = 0;
        if ( Math.random() < 0.5 )
        {
            a = 1; b = 0;
        }
        vx = highway[b].x - highway[a].x;
        vy = highway[b].y - highway[a].y;
        d = Math.sqrt(vx * vx + vy * vy);
        rvx = -vy/d*160;
        rvy = vx/d*160;
        cars[id].rotation = Math.atan2( vy, vx ) * 180 / Math.PI;
        var itw:ITween = BetweenAS3.tween( cars[id], { x: highway[b].x+rvx, y: highway[b].y+rvy }, { x: highway[a].x+rvx, y: highway[a].y+rvy }, 15.0 * d / 62500 );
        itw.addEventListener( Event.COMPLETE, function( e:Event ):void {
            inviteVehicle( id );
        });
        itw.play();
    }
    
    public function initMesh( m:Mesh ):void
    {
        // 1 car ~ 4 lights ~ 4 triangles ~ 12 indices ~ 12 vertices ~ 12 uv ~ 60 numbers ( 12 x 3 + 12 x 2 ); vertices 0 -> 5 front lights, 6 -> 11 back lights
        m.vertices = new Vector.<Number>( cars.length * 72, true );

        var j:int = 0;
        var k:int = 0, o:int = 0, l:int = 0, u:int = 0;
        for ( var i:int = 0; i < cars.length; i++ )
        {
            j = i * 12;
            l = i * 72;
            for ( k = 0; k < 4; k++ )
            {
                u = i * 72 + k * 18 + 4;
                if (k < 2)
                {
                    // left light   __
                    //             |
                    m.vertices[u - 1] = 1;
                    // .(0,1)
                    m.vertices[u] = 0;
                    m.vertices[u + 1] = 1;
                    u += 6;
                    m.vertices[u - 1] = 1;
                    // .(0,0)
                    m.vertices[u] = 0;
                    m.vertices[u + 1] = 0;
                    u += 6;
                    m.vertices[u - 1] = 1;
                    // .(1,0)
                    m.vertices[u] = 1;
                    m.vertices[u + 1] = 0;
                } else {
                    // right light
                    //              __|
                    m.vertices[u - 1] = 1;
                    // .(1,0)
                    m.vertices[u] = 1;
                    m.vertices[u + 1] = 0;
                    u += 6;
                    m.vertices[u - 1] = 1;
                    // .(1,1)
                    m.vertices[u] = 1;
                    m.vertices[u + 1] = 1;
                    u += 6;
                    m.vertices[u - 1] = 1;
                    // .(0,1)
                    m.vertices[u] = 0;
                    m.vertices[u + 1] = 1;
                }
            }
            m.pushIndex( 
                j    , j + 1, j + 2,
                j + 3, j + 4, j + 5,
                j + 6, j + 7, j + 8, 
                j + 9, j + 10, j + 11 
            );
        }
    }
    
    public function updateMesh( m:Mesh, sm:Matrix3D, offset:Point ):void // sprite particle need some magic
    {
        var j:int = 0;
        var k:int = 0;
        var q:int = 0;
        var o:int = 0;
        var mt:Matrix3D = new Matrix3D();
        mt.copyFrom( sm );
        var v:Vector3D = new Vector3D();
        mt.copyColumnTo(3, v);
        mt.appendTranslation(-v.x, -v.y, -v.z);
        mt.invert();
        
        var mat:VehicleLightMaterial = VehicleLightMaterial( m.material );
        var r:Number = PARTICLE_RADIUS;
        var w:Number = PARTICLE_W;
        var scale:Number = 30;
        var scale2:Number = 20;
        var tl_x:Number = -r;
        var tl_y:Number = -r;
        var tr_x:Number = w + r;
        var tr_y:Number = -r;
        var bl_x:Number = -r;
        var bl_y:Number = w + r;
        var tri:Vector.<Number> = new Vector.<Number>;
        tri.push(
            bl_x * scale, 0, bl_y * scale,
            tl_x * scale, 0, tl_y * scale,
            tr_x * scale,  0, tr_y * scale
        );

        var staticData:Vector.<Number> = new Vector.<Number>;
        staticData.push(
            -3 * scale2, 0, -5 * scale2,
             3 * scale2, 0, -5 * scale2,
            -3 * scale2, 0,  5 * scale2,
             3 * scale2, 0,  5 * scale2
        );
        
        var dynamicData:Vector.<Number> = new Vector.<Number>( 12, true );
        var ma:Matrix3D = new Matrix3D();
        var cv:Vector3D = new Vector3D();
        for ( var i:int = 0; i < cars.length; i++ )
        {
            for ( j = 0; j < 12; j++ )
            {
                dynamicData[j] = staticData[j];
            }
            ma.identity();
            ma.appendRotation( 90 - cars[i].rotation, Vector3D.Y_AXIS );
            ma.transformVectors( dynamicData, dynamicData );
            for ( j = 0; j < 4; j++ )
            {
                for ( k = 0; k < 3; k++ )
                {
                    o = i * 72 + j * 18 + k * 6;
                    q = j * 3;
                    cv.x = dynamicData[q]     + cars[i].x + offset.x;
                    cv.y = dynamicData[q + 1];
                    cv.z = dynamicData[q + 2] + cars[i].y + offset.y;
                    cv = sm.transformVector( cv);
                    m.vertices[o]     = cv.x + tri[k];
                    m.vertices[o + 1] = cv.y + tri[k + 1];
                    m.vertices[o + 2] = cv.z + tri[k + 2];
                }
            }
        }
    }
}

class CityFactory
{
    // settings
    public static const MAP_WIDTH:Number = 42500;
    public static const MAP_HEIGHT:Number = 42500;
    public static const MAX_BUILDING_HEIGHT:Number = 4000;
    public static const SPLIT_AMOUNT:int = 1200;
    private var offset:Point = new Point( -MAP_WIDTH / 2, -MAP_HEIGHT / 2 );
    
    public var building:Mesh = new Mesh();
    public var traffic:Mesh = new Mesh();
    public var fireworks:Mesh = new Mesh();
    
    private var trafficManager:TrafficManager;
    private var fireworksManager:FireworksManager;
    
    public function CityFactory()
    {
        building.material = new MusicMaterial();
        traffic.material = new VehicleLightMaterial(10);
        fireworks.material = new VehicleLightMaterial(18, 0xFFFF33CC, 0xFF33CCFF);
        building.material.addEventListener( MusicMaterial.PEAK, shotFireworks );
    }
    
    public function planAndConstruct():void
    {
        var i:int = 0, j:int = 0;
        var cell:Cell = new Cell(new Point(0 , 0), new Point(MAP_WIDTH, 0), new Point(0, MAP_HEIGHT), new Point(MAP_WIDTH, MAP_HEIGHT));
        cell.setOriginal( cell.tl, cell.tr, cell.bl, cell.br );
        cell.setPatterns(
            function(c:*):Boolean { return c < 6; }, // chose
            null, // slope
            function(c:Number = 1):Number { return 0.993 - Math.random() * 0.001 * c * c; } // size
        );
        for( i = SPLIT_AMOUNT; i; i-- ) cell.leaf( new Point( Math.random() * MAP_WIDTH, Math.random() * MAP_HEIGHT ) ).divide();
                
        var newRegions:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>();
        newRegions = cell.checkOut();
        
        for each( var region:Vector.<Point> in newRegions )
        {
            pushBuilding( region );
        }
        
        var highways:Vector.<Vector.<Point>> = cell.checkOutHighway();
        
        trafficManager = new TrafficManager( highways );
        trafficManager.initMesh( traffic );
        trafficManager.boot();
        traffic.live = true;
        
        fireworksManager = new FireworksManager();
        fireworksManager.initMesh( fireworks );
        fireworks.live = true;
    }
    
    private function pushBuilding( v:Vector.<Point> ):void
    {
        var index:int = 0;
        var split:int = 4;
        var hsplit:int = split / 2;
        var vratio:Number = 0.8;
        var hratio:Number = 0.4;
        var min:Number = MAX_BUILDING_HEIGHT * 0.20;
        var max:Number = MAX_BUILDING_HEIGHT * 0.80;
        var randomHeight:Number = -( min + Math.random() * Math.random() * max );
        var i1:int, i2:int, i3:int, i4:int, j:int, k:int;
        var rand:int = int( Math.random() * 4 );
        var o:int = int( Math.random() * 4 );
        var ox:Number = ( o % 2 ) * hratio;
        var oy:Number = int( o / 2 ) * hratio;
        for(var i:int = 0; i < v.length; i++)
        {
            k = ( i + rand ) % v.length;
            j = ( k + 1 ) % v.length;
            index = building.currentIndex;
            i1 = index;
            i2 = index + 1;
            i3 = index + 2;
            i4 = index + 3;
            building.pushVertex(
                v[k].x + offset.x, 
                -randomHeight, 
                v[k].y + offset.y,
                1,
                ( k % hsplit ) * vratio / split + ox,
                int( k / hsplit ) * vratio / split + oy
            ).pushVertex(
                v[j].x + offset.x,
                -randomHeight,
                v[j].y + offset.y,
                1,
                ( ( k % hsplit ) + 1 ) * vratio / split + ox,
                int( k / hsplit ) * vratio / split + oy
            ).pushVertex(
                v[k].x + offset.x,
                0,
                v[k].y + offset.y,
                1,
                ( k % hsplit ) * vratio / split + ox,
                ( int( k / hsplit ) + 1 ) * vratio / split + oy
            ).pushVertex(
                v[j].x + offset.x,
                0,
                v[j].y + offset.y,
                1,
                ( ( k % hsplit ) + 1 ) * vratio / split + ox,
                ( int( k / hsplit ) + 1 ) * vratio / split + oy
            ).pushIndex( i1, i2, i3, i3, i2, i4 );
        }
        // top
        index = building.currentIndex;
        i1 = index;
        i2 = index + 1;
        i3 = index + 2;
        i4 = index + 3;
        building.pushVertex(
            v[1].x + offset.x,
            -randomHeight,
            v[1].y + offset.y,
            1,
            o*hratio/2, vratio
        ).pushVertex(
            v[0].x + offset.x,
            -randomHeight,
            v[0].y + offset.y,
            1,
            (o+1)*hratio/2, vratio
        ).pushVertex(
            v[2].x + offset.x,
            -randomHeight,
            v[2].y + offset.y,
            1,
            o*hratio/2, 1
        ).pushVertex(
            v[3].x + offset.x,
            -randomHeight,
            v[3].y + offset.y,
            1,
            (o+1)*hratio/2, 1
        ).pushIndex( i1, i2, i3, i3, i2, i4 );
    }
    
    public function shotFireworks( e:Event ):void
    {
        fireworksManager.explode();
    }
    
    public function update():void
    {
        building.material.update();
        building.matrix.identity();
        building.matrix.prependRotation( -45+30*Math.cos(getTimer()/10000), Vector3D.X_AXIS );
        building.matrix.prependRotation( (getTimer() / 200)%360, Vector3D.Y_AXIS );
        building.matrix.appendTranslation( 0, 0, 15000 );
        trafficManager.updateMesh( traffic, building.matrix, offset );
        fireworksManager.updateMesh( fireworks, building.matrix, offset );
    }
}

import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Stage;
import flash.display.Stage3D;
import flash.display3D.Context3D;
import flash.display.Sprite;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DTriangleFace;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.geom.ColorTransform;
import flash.geom.Matrix3D;
import flash.geom.Rectangle;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundMixer;
import flash.display3D.textures.Texture;
import flash.net.URLRequest;
import flash.events.Event;
import flash.utils.ByteArray;

class city3d
{
    // objects
    private var city:CityFactory;
    
    // misc
    private var stg:Stage;
    
    // utils
    private var threeD:ThreeD;
    
    public function city3d(s:Stage)
    {
        stg = s;
        city = new CityFactory();
        threeD = new ThreeD( stg );
        threeD.addEventListener( ThreeD.ITS_OK, initThreeD );
        threeD.check();
    }
    
    private function initThreeD( e:Event ):void
    {
        // init objects
        city.planAndConstruct();
        
        // add objects
        threeD.addMesh( city.building );
        threeD.addMesh( city.traffic );
        threeD.addMesh( city.fireworks );
        
        // boot
        threeD.removeEventListener( ThreeD.ITS_OK, initThreeD );
        threeD.addEventListener( ThreeD.BOOT_SUCCESS,
            function( e:Event ):void
            {
                stg.addEventListener( Event.ENTER_FRAME, processing );
            }
        );
        threeD.boot();
    }
    
    public function choseMP3():void
    {
        MusicMaterial(city.building.material).loadMP3();
    }
    
    private function processing( e:Event ):void
    {
        // update objects
        city.update();
        
        // render
        threeD.render();
    }
}

import flash.geom.Point;
class Cell {
    
    public var tl:Point;
    public var tr:Point;
    public var bl:Point;
    public var br:Point;
    
    private var _tl:Point;
    private var _tr:Point;
    private var _bl:Point;
    private var _br:Point;
    
    private var d0:Point;
    private var d1:Point;
    
    private var hw0:Point;
    private var hw1:Point;
    
    private var c0:Cell;
    private var c1:Cell;
    
    private var margin:Number = 0.2;
    private var hmargin:Number = margin / 2;
    
    private var chosePattern:Function;
    private var slopePattern:Function;
    private var sizePattern:Function;
    
    public var level:int = 0;
    
    public function Cell( tl:Point, tr:Point, bl:Point, br:Point, r:Number = 1, l:int = 0 ) {
        this.level = ++l;
        this.tl = tl.clone();
        this.tr = tr.clone();
        this.bl = bl.clone();
        this.br = br.clone();
        if ( r != 1 ) resizeCell( this.tl, this.tr, this.br, this.bl, r );
    }
    
    public function setOriginal( otl:Point, otr:Point, obl:Point, obr:Point ):void
    {
        this._tl = otl.clone();
        this._tr = otr.clone();
        this._bl = obl.clone();
        this._br = obr.clone();
    }
    
    private function get width():Number {
        return (tr.subtract(tl).length + br.subtract(bl).length) / 2;
    }
    
    private function get height():Number {
        return (bl.subtract(tl).length + br.subtract(tr).length) / 2;
    }
    
    private function get ratio():Number {
        var w:Number = width;
        var h:Number = height;
        return w * w / (w * w + h * h);
    }
    
    public function leaf(p:Point):Cell {
        if (!c0) return this;
        var dp:Point = p.subtract(d0);
        var dd:Point = d1.subtract(d0);
        if (dd.x * dp.y - dd.y * dp.x >= 0) return c0.leaf(p);
        else return c1.leaf(p);
    }
    
    public function divide():void {
        var i0:Number = 0.5 + Math.random() * margin - hmargin;
        var i1:Number = (Math.random() < 0.5)? i0: 0.5 + Math.random() * margin - hmargin;
        var thw0:Point;
        var thw1:Point;
        if (Math.random() < ratio) {
            // vertical
            d0 = interpolate( tl, tr, i0 );
            d1 = interpolate( bl, br, i1 );
            thw0 = intersection( d0, d1, _tl, _tr );
            thw1 = intersection( d0, d1, _bl, _br );
            c0 = new Cell( tl, d0, bl, d1, (sizePattern != null)? sizePattern( level ): 1, level );
            c1 = new Cell( d0, tr, d1, br, (sizePattern != null)? sizePattern( level ): 1, level );
            c0.setOriginal( _tl, thw0, _bl, thw1 );
            c1.setOriginal( thw0, _tr, thw1, _br );
        } else {
            // horizontal
            d0 = interpolate( br, tr, i0 );
            d1 = interpolate( bl, tl, i1 );
            thw0 = intersection( d0, d1, _br, _tr );
            thw1 = intersection( d0, d1, _bl, _tl );
            c0 = new Cell( tl, tr, d1, d0, (sizePattern != null)? sizePattern( level ): 1, level );
            c1 = new Cell( d1, d0, bl, br, (sizePattern != null)? sizePattern( level ): 1, level );
            c0.setOriginal( _tl, _tr, thw1, thw0 );
            c1.setOriginal( thw1, thw0, _bl, _br );
        }
        if ( chosePattern != null && chosePattern( level ) ) { hw0 = thw0.clone(); hw1 = thw1.clone(); }
        c0.setPatterns( this.chosePattern, this.slopePattern, this.sizePattern );
        c1.setPatterns( this.chosePattern, this.slopePattern, this.sizePattern );
    }
    
    public function checkOut():Vector.<Vector.<Point>> {
        var arr:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>();
        pump(arr);
        return arr;
    }
    
    public function checkOutHighway():Vector.<Vector.<Point>> {
        var arr:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>();
        pumpHighway( arr );
        return arr;
    }
    
    public function setPatterns( chose_pattern:Function, slope_pattern:Function, size_pattern:Function ):void
    {
        this.chosePattern = chose_pattern;
        this.slopePattern = slope_pattern;
        this.sizePattern = size_pattern;
    }
    
    public function pump( arr:Vector.<Vector.<Point>> ):void
    {
        if(c0) {
            c0.pump(arr); c1.pump(arr);
        } else {
            var ar:Vector.<Point> = new Vector.<Point>();
            ar.push(tl,tr,br,bl);
            arr.push(ar);
        }
    }
    
    public function pumpHighway( arr:Vector.<Vector.<Point>> ):void
    {
        if(c0) {
            c0.pumpHighway(arr); c1.pumpHighway(arr);
        }
        if ( hw0 )
        {
            var ar:Vector.<Point> = new Vector.<Point>();
            ar.push( hw0, hw1 );
            arr.push( ar );
        }
    }
    
    public function intersection( p1:Point, p2:Point, p3:Point, p4:Point ):Point
    {
        var p21x:Number = p2.x - p1.x;
        var p21y:Number = p2.y - p1.y;
        var p43x:Number = p4.x - p3.x;
        var p43y:Number = p4.y - p3.y;
        var d:Number = p21x * p43y - p21y * p43x;
        if ( d == 0 ) return null;
        var p31x:Number = p3.x - p1.x;
        var p31y:Number = p3.y - p1.y;
        var m1:Number = ( p31x * p43y - p31y * p43x ) / d;
        //if ( ( p31x * p43y - p31y * p43x ) / d < 0 || m1 > 1 ) return null;
        //var m2:Number = (p31x * p21y - p31y * p21x) / d;
        //if ( ( p31x * p21y - p31y * p21x ) / d < 0 || m2 > 1 ) return null;
        return new Point( p1.x + m1 * p21x, p1.y + m1 * p21y );
    }
    
    private static function interpolate( p0:Point, p1:Point, i:Number ):Point {
        var j:Number = 1 - i;
        return new Point( p0.x * j + p1.x * i, p0.y * j + p1.y * i );
    }

    private function resizeCell( p1:Point, p2:Point, p3:Point, p4:Point, r:Number ):void
    {
        var center:Point = com( p1, p2, p3, p4 );
        resizePoint( p1, center, r );
        resizePoint( p2, center, r );
        resizePoint( p3, center, r );
        resizePoint( p4, center, r );
    }
    
    private function resizePoint( p:Point, ct:Point, r:Number ):void
    {
        p.x = ct.x + ( p.x - ct.x ) * r;
        p.y = ct.y + ( p.y - ct.y ) * r;
    }
    
    private function com( p1:Point, p2:Point, p3:Point, p4:Point ):Point
    {
        var arr:Vector.<Point> = new Vector.<Point>();
        arr.push( p1, p2, p3, p4 );
        var cm:Point = new Point();
        var tx:Number = 0;
        var ty:Number = 0;
        var a:Number = area( arr );
        var i:int = 0;
        var j:int = 0;
        var d:Number = 0;
        i = 0;
        while ( i < arr.length )
        {
            
            j = ( i + 1 ) % arr.length;
            d = arr[i].x * arr[j].y - arr[j].x * arr[i].y;
            tx = tx + ( arr[i].x + arr[j].x ) * d;
            ty = ty + ( arr[i].y + arr[j].y ) * d;
            i++;
        }
        a = a * 6;
        d = 1 / a;
        tx = tx * d;
        ty = ty * d;
        cm.x = tx;
        cm.y = ty;
        return cm;
    }
    
    private function area( p:Vector.<Point> ):Number
    {
        var i:int = 0;
        var j:int = 0;
        var a:Number = 0;
        i = 0;
        while ( i < p.length )
        {
            j = ( i + 1 ) % p.length;
            a = a + p[i].x * p[j].y;
            a = a - p[i].y * p[j].x; 
            i++;
        }
        a = a / 2;
        return a;
    }
}

var vs:String = <agalCode><![CDATA[
mov vt0, va0
m44 op, vt0, vc0
mov v0, va1
mov v1, va0
]]></agalCode>;

var fs:String = <agalCode><![CDATA[
tex ft0, v0.xy, fs0 <2d,clamp,nearest>
mul ft0, ft0, v1.www
mov oc, ft0
]]></agalCode>;