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);
}
}
}