Twisty Disco

by devon_o
♥0 | Line 209 | Modified 2014-09-12 00:06:36 | MIT License
play

ActionScript3 source code

/**
 * Copyright devon_o ( http://wonderfl.net/user/devon_o )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/tjzT
 */

package 
{
    
import com.adobe.utils.AGALMiniAssembler;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProfile;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundMixer;
import flash.net.URLRequest;
import flash.system.Security;
import flash.utils.ByteArray;

/**
 * Twisty Disco
 * Based on: https://www.shadertoy.com/view/MdsSDM
 * 
 * Music from Ministry
 */

[SWF(width='465', height='465', backgroundColor='#000000', frameRate='60')]
public class Main extends Sprite 
{
 
    private static var VERTEX_SHADER:String =
    <![CDATA[
    
    m44 op, va0, vc0
    mov v0, va1 
    
    ]]>;
    
    
    private static var FRAGMENT_SHADER:String =
    <![CDATA[
    
    mov ft0.x, fc0.x
    sin ft0.x, ft0.x
    mul ft0.x, ft0.x, fc0.z

    mul ft0.y, v0.x, fc0.w
    add ft0.y, fc0.x, ft0.y
    sub ft0.x, ft0.y, ft0.x
    sin ft0.x, ft0.x

    mul ft0.y, v0.y, fc0.z
    add ft0.x, ft0.y, ft0.x
    sub ft0.x, ft0.x, fc1.x
    abs ft0.z, ft0.x
    add ft0.z, ft0.z, fc3.x
    div ft0.z, ft0.x, ft0.z
    mul ft0.x, ft0.z, fc3.y

    mul ft0.x, ft0.x, fc1.z
    mul ft0.y, v0.x, fc1.w

    mov ft0.z, fc0.x
    mul ft0.z, ft0.z, fc1.y
    
    sub ft0.x, ft0.y, ft0.x
    add ft0.x, ft0.x, ft0.z

    sin ft1.x, ft0.x

    mov ft0.x, fc0.x
    sin ft0.x, ft0.x
    mul ft0.x, ft0.x, fc0.z

    mul ft0.y, v0.x, fc0.w
    add ft0.y, ft0.y, fc0.x
    sub ft0.x, ft0.y, ft0.x
    sin ft0.x, ft0.x
    mul ft0.y, v0.y, fc0.z
    add ft0.x, ft0.y, ft0.x
    sub ft0.x, ft0.x, fc2.z
    abs ft0.z, ft0.x
    add ft0.z, ft0.z, fc3.x
    div ft0.z, ft0.x, ft0.z
    mul ft0.x, ft0.z, fc3.y

    abs ft0.x, ft0.x

    neg ft1.y, ft0.x

    mov ft0.x, fc0.x
    mul ft0.x, ft0.x, fc1.w
    mul ft0.y, v0.x, fc2.x
    add ft0.x, ft0.y, ft0.x
    cos ft0.x, ft0.x
    
    sub ft1.z, ft1.x, ft0.x

    add ft0.x, ft1.y, fc2.y
    div ft0.x, ft0.x, fc2.y
    sat ft0.x, ft0.x

    mul ft1.w, ft0.x, fc1.x

    sub ft2.x, ft1.z, ft1.w

    mul ft2.y, ft1.z, fc2.z
    abs ft2.y, ft2.y
    sub ft2.y, ft2.y, ft1.w

    sub ft2.z, fc2.w, ft1.z
    sub ft2.z, ft2.z, ft1.w
    
    mov ft2.w, ft1.z

    mov oc, ft2
    
    ]]>;
    
    private static const POLICY:String   = "http://www.onebyonedesign.com/crossdomain.xml";
    private static const SOUND:String = "http://www.onebyonedesign.com/flash/djscratch/sound3.mp3";
    
    private var context:Context3D;
    private var isReady:Boolean;
    private var program:Program3D;
    private var renderMatrix:Matrix3D;
    private var vertexBuffer:VertexBuffer3D;
    private var indexBuffer:IndexBuffer3D;
    private var sound:Sound
    private var soundBytes:ByteArray = new ByteArray();
    private var soundVector:Vector.<Number> = new Vector.<Number>(512, true);
    private var time:Number = 0.0;
    
    public function Main():void 
    {
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    private function init(e:Event = null):void 
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;
        
        Security.loadPolicyFile(POLICY);
        
        this.isReady = false;
        this.renderMatrix = new Matrix3D();
        
        loadSound();
        requestContext();
        startRender();
    }
    
    private function startRender():void
    {
        addEventListener(Event.ENTER_FRAME, onFrame);
    }
    
    private function requestContext():void
    {
        stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onStage3dContext);
        stage.stage3Ds[0].requestContext3D(Context3DRenderMode.AUTO, Context3DProfile.BASELINE);
    }
    
    private function onStage3dContext(e:Event):void
    {
        this.context = stage.stage3Ds[0].context3D;
        this.context.configureBackBuffer(stage.stageWidth, stage.stageHeight, 1, false, false);
        
        createVertexBuffer();
        createIndexBuffer();
        createPrograms();
        
        this.isReady = true;
    }
    
    private var channel:SoundChannel;
    private function loadSound():void
    {
        this.sound = new Sound();
        this.sound.load(new URLRequest(SOUND), new SoundLoaderContext(5000, true));
        this.channel = this.sound.play();
    }
    
    private function bytesToVector(bytes:ByteArray, v:Vector.<Number>):void
    {
        var i:int = 0;
        while (bytes.bytesAvailable)
            v[i++] = bytes.readFloat();
    }
    
    private function createVertexBuffer():void
    {
        var vertices:Vector.<Number> = new <Number>[
        //      x          y        u  v
            -1.0,      1.0,     0, 0, 
             1.0,       1.0,     1, 0,
            -1.0,      -1.0,     0, 1,
             1.0,     -1.0,     1, 1  ];
            
        this.vertexBuffer = this.context.createVertexBuffer(4, 4);
        this.vertexBuffer.uploadFromVector(vertices, 0, 4);
    }
    
    private function createIndexBuffer():void
    {
        this.indexBuffer = this.context.createIndexBuffer(6);
        
       // 2 triangles (0, 1, 2) & (1, 3, 2)
       //   0 - 1
       //   | / |
       //   2 - 3
        this.indexBuffer.uploadFromVector(new <uint>[0, 1, 2,   1, 3, 2], 0, 6);
    }
    
    private function createPrograms():void
    {
        var vertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
        vertexShaderAssembler.assemble(Context3DProgramType.VERTEX, VERTEX_SHADER);
        
        var fragmentShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
        fragmentShaderAssembler.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER);
        
        this.program = this.context.createProgram();
        this.program.upload(vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
    }
    
    private var fc0:Vector.<Number> = new <Number>[0.0, 1.0, 4, 4.0];
    private var fc1:Vector.<Number> = new <Number>[2.0, 10.0, 64.0, 32.0];
    private var fc2:Vector.<Number> = new <Number>[125.0, 1.0, 0.5, 0.1];
    private var fc3:Vector.<Number> = new <Number>[1.0, Math.PI/2, 0, 0];
    
    private var c1:Number = 1.0;
    private var c2:Number = 1.0;
    private var c3:Number = 1.0;
    private function onFrame(e:Event):void
    {
        if (!this.isReady)
            return;
        
        this.soundBytes.clear();
        
        SoundMixer.computeSpectrum(this.soundBytes, true);
        bytesToVector(this.soundBytes, this.soundVector);   
         
        this.context.clear(0, 0, 0, 1);
        
        this.context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, this.renderMatrix, true);

        this.context.setVertexBufferAt(0, this.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
        this.context.setVertexBufferAt(1, this.vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
        
        fc0[0] = this.time;
        
        this.c1 += (this.soundVector[32] * 3.0 - this.c1) / 4;
        this.c2 += (this.soundVector[16] * 3.0 - this.c2) / 10;
        this.c3 += (this.soundVector[8] * 3.0 - this.c3) / 4;
        fc2[1] = c1 + 1.0;
        fc2[2] = c3 + .50;
        fc2[3] = c2;
        
        this.time += 12 / 512;
        
        this.context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, fc0, 1);
        this.context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 1, fc1, 1);
        this.context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 2, fc2, 1);
        this.context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 3, fc3, 1);
        
        this.context.setProgram(this.program);
        this.context.drawTriangles(this.indexBuffer);  
        this.context.present();
    }
    
}
    
}