開発環境 Apache Flex SDK 4.12.1
FlashDevelop 4.6.1
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 ActionScript 3/AS3 Project
プロジェクト名 AgalMandelbrot


Main.as
package 
{
    import com.adobe.utils.AGALMiniAssembler;
    import flash.display.Sprite;
    import flash.display3D.Context3D;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Context3DVertexBufferFormat;
    import flash.display3D.IndexBuffer3D;
    import flash.display3D.Program3D;
    import flash.display3D.VertexBuffer3D;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
 
    public class Main extends Sprite 
    {
        private var context3D:Context3D;
        private var program:Program3D;
        private var vertexBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
        private var offsetX:Number = 0;
        private var offsetY:Number = 0;
        private var zoom:Number = 4;
 
        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);
            // entry point
 
            stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
            stage.stage3Ds[0].requestContext3D();
 
            //addEventListener(Event.ENTER_FRAME, onRender);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
        }
 
        private function onContext3DCreate(e:Event):void 
        {
            context3D = stage.stage3Ds[0].context3D;
            context3D.configureBackBuffer(800, 600, 2, true);
 
            const vertices:Vector.<Number> = Vector.<Number>([
            //  x,  y,  u, v,
                -1, -1, 0, 0, // LD
                -1, 1, 0, 1, // LU
                1, 1, 1, 1, // RU
                1, -1, 1, 0, // RD
            ]);
            const perVertex:int = 4;
            const numVertices:int = vertices.length / perVertex;
            vertexBuffer = context3D.createVertexBuffer(numVertices, perVertex);
            vertexBuffer.uploadFromVector(vertices, 0, numVertices);
 
            const indices:Vector.<uint> = Vector.<uint>([0, 1, 2, 2, 3, 0]);
            indexBuffer = context3D.createIndexBuffer(indices.length);
            indexBuffer.uploadFromVector(indices, 0, indices.length);
 
            var vertexAssembler:AGALMiniAssembler = new AGALMiniAssembler();
            vertexAssembler.assemble(Context3DProgramType.VERTEX,
                "mov op va0\n" +
                "mov v0 va1\n"
            );
 
            var fragmentAssembler:AGALMiniAssembler = new AGALMiniAssembler();
            fragmentAssembler.assemble(Context3DProgramType.FRAGMENT,
                // c = (uv - 0.5) * aspect * zoom + offset
                "sub ft0.xy v0.xy fc0.zz\n" +  // xy = uv - 0.5
                "mul ft0.xy ft0.xy fc0.xy\n" + // xy = xy * aspect
                "mul ft0.xy ft0.xy fc1.zz\n" + // xy = xy * zoom
                "add ft1.xy ft0.xy fc1.xy\n" + // c = xy + offset
 
                "mov ft2.xyz fc1.www\n" + // p = 0
 
                // px = p.x * p.x - p.y * p.y + cx
                // py = 2 * p.x * p.y + cy
                // if (4 < dot(p, p)) return
                // ループ命令がないので24段くらいが限界
                "mul ft0.xy ft2.xy ft2.xy\n" +  // xy = p * p
                "mul ft0.z ft2.x ft2.y\n" +     // z = x * y
                "sub ft2.x ft0.x ft0.y\n" +     // px = x - y
                "add ft2.y ft0.z ft0.z\n" +     // py = z + z
                "add ft2.xy ft2.xy ft1.xy\n" +  // p = p + c
                "dp3 ft0.x ft2.xyz ft2.xyz\n" + // x = dot(p, p)
                "sub ft0.x fc0.w ft0.x\n" +     // x = 4 - x
                "kil ft0.x\n" +                 // if (x < 0) return
 
                "mul ft0.xy ft2.xy ft2.xy\n" +  // xy = p * p
                "mul ft0.z ft2.x ft2.y\n" +     // z = x * y
                "sub ft2.x ft0.x ft0.y\n" +     // px = x - y
                "add ft2.y ft0.z ft0.z\n" +     // py = z + z
                "add ft2.xy ft2.xy ft1.xy\n" +  // p = p + c
                "dp3 ft0.x ft2.xyz ft2.xyz\n" + // x = dot(p, p)
                "sub ft0.x fc0.w ft0.x\n" +     // x = 4 - x
                "kil ft0.x\n" +                 // if (x < 0) return
 
                "mov oc fc0.xxxx\n" // output color = white
            );
 
            program = context3D.createProgram();
            program.upload(vertexAssembler.agalcode, fragmentAssembler.agalcode);
 
            // va0 : xy
            context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
            // va1 : uv
            context3D.setVertexBufferAt(1, vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
            context3D.setProgram(program);
 
            // fc0 : xy=aspect z=0.5 w=4
            // fc1 : xy=offset z=zoom w=0
            context3D.setProgramConstantsFromVector(
                Context3DProgramType.FRAGMENT, 0, Vector.<Number>([1, 600 / 800, 0.5, 4]));
 
            onRender(null);
        }
 
        private function onRender(e:Event):void 
        {
            if (!context3D) return;
 
            context3D.setProgramConstantsFromVector(
                Context3DProgramType.FRAGMENT, 1, Vector.<Number>([offsetX, offsetY, zoom, 0]));
 
            context3D.clear();
            context3D.drawTriangles(indexBuffer);
            context3D.present();
        }
 
        private function onKeyDown(e:KeyboardEvent):void 
        {
            switch (e.keyCode) 
            {
                case Keyboard.UP:
                    zoom /= 1.02;
                    break;
                case Keyboard.DOWN:
                    zoom *= 1.02;
                    break;
                case Keyboard.A:
                    offsetX -= zoom * 0.01;
                    break;
                case Keyboard.W:
                    offsetY += zoom * 0.01;
                    break;
                case Keyboard.D:
                    offsetX += zoom * 0.01;
                    break;
                case Keyboard.S:
                    offsetY -= zoom * 0.01;
                    break;
                default:
                    return;
            }
            onRender(null);
        }
 
    }
 
}
 
最終更新:2014年06月18日 17:50