forked from: 10k boxes
forked from 10k boxes (diff: 2)
ActionScript3 source code
/**
* Copyright signedvoid ( http://wonderfl.net/user/signedvoid )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/iu0j
*/
// forked from shen_0_'s 10k boxes
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.VertexBuffer3D;
import flash.display3D.textures.Texture;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix3D;
import net.hires.debug.Stats;
[SWF(frameRate=60, width="700", height="550")]
public class Boxes2 extends Sprite {
public static const NUM_MAX:int=1024;
public static const NUM_PARTICLE:int=10000;
public static const W:int=680;
public static const H:int=530;
public static const SIZE:int=5;
public static const ROWS:int=H / SIZE;
public static const COLS:int=W / SIZE;
public static const SPEED:Number=Number((SIZE / .8)); //moving speed
public static const SPEED_No_SQRT:Number=SPEED * SPEED * 0.5;
///////////////////stage3D
private var obsList:Array=[];
private var boxList:Array=[];
private var nets:Array=[];
private var program:ShaderProgram;
private var context:Context3D;
private var rotBmp:BitmapData;
private var texture:Texture;
private var iBuffer:IndexBuffer3D;
private var vBuffer:VertexBuffer3D;
private var uvBuffer:VertexBuffer3D;
private var uvb:Vector.<Number>=new Vector.<Number>();
private var ib:Vector.<uint>=new Vector.<uint>();
private var vb:Vector.<Number>=new Vector.<Number>();
private const vunit:int=4;
private const uvunit:int=2;
private var ortho:Matrix3D=new Matrix3D();
private var r_rot_steps:Vector.<Number>=Vector.<Number>([0, 0, 0, 0]);
//each time it draw 1024 boxes
private var allWnums:int=0;
private var allWIndex:int=0;
//create boxes
private var nums:int=NUM_PARTICLE;
public function Boxes2() {
stage.align=StageAlign.TOP_LEFT;
stage.scaleMode=StageScaleMode.NO_SCALE;
rotBmp=new BitmapData(16, 4, true, 0);
const ox:Number=0.5;
var sp:Shape=new Shape();
sp.graphics.lineStyle(0, 0x555555, 0.5); //not smooth fix
sp.graphics.beginFill(0x333333);
sp.graphics.drawRect(ox, ox, 3, 3);
sp.graphics.endFill();
sp.graphics.lineStyle(0, 0x555555, 0.5); //smooth fix
sp.graphics.beginFill(0xaaaaaa);
sp.graphics.drawRect(ox + 4, ox, 3, 3);
sp.graphics.endFill();
sp.graphics.lineStyle(0, 0x9B8553, 0.5); //not smooth
sp.graphics.beginFill(0x9B8553);
sp.graphics.drawRect(ox + 8, ox, 3, 3);
sp.graphics.endFill();
sp.graphics.lineStyle(0, 0x50857A, 0.5); //smooth
sp.graphics.beginFill(0x50857A);
sp.graphics.drawRect(ox + 12, ox, 3, 3);
sp.graphics.endFill();
rotBmp.draw(sp);
var rotBM:Bitmap=new Bitmap(rotBmp);
rotBM.x=100;
var i:int, j:int;
for (j=0; j < ROWS; j++) {
nets[j]=[];
for (i=0; i < COLS; i++) {
nets[j][i]=null;
}
}
createAllObstacle()
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, createContext3D);
stage.stage3Ds[0].requestContext3D(Context3DRenderMode.AUTO);
addChild(new Stats());
addChild(rotBM);
}
//init context3D obj
private function createContext3D(e:Event):void {
context=(e.target as Stage3D).context3D;
context.removeEventListener(Event.CONTEXT3D_CREATE, createContext3D);
context.configureBackBuffer(W, H, 0, false);
context.setRenderToBackBuffer();
context.enableErrorChecking=true;
//program
program=new ShaderProgram(context, new VertexShader(), new FragmentShader());
ortho=MatrixUtil.ortho(W, H, false);
//index, vertex, uv
const part:Number=0.25;
for (var i:int=0; i < NUM_MAX; i++) {
vb.push(0, 0, 0, 0);
vb.push(0, 0, 0, 0);
vb.push(0, 0, 0, 0);
vb.push(0, 0, 0, 0);
uvb.push(0, 0);
uvb.push(part, 0);
uvb.push(part, 1);
uvb.push(0, 1);
ib.push(i * 4 + 0, i * 4 + 1, i * 4 + 2, i * 4 + 0, i * 4 + 2, i * 4 + 3);
}
vb.fixed=true;
uvb.fixed=true;
ib.fixed=true;
vBuffer=context.createVertexBuffer(vb.length / vunit, vunit);
vBuffer.uploadFromVector(vb, 0, vb.length / vunit);
uvBuffer=context.createVertexBuffer(uvb.length / uvunit, uvunit);
uvBuffer.uploadFromVector(uvb, 0, uvb.length / uvunit);
iBuffer=context.createIndexBuffer(ib.length);
iBuffer.uploadFromVector(ib, 0, ib.length);
r_rot_steps[0]=part;
//texture
texture=context.createTexture(16, 4, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(rotBmp);
context.setTextureAt(0, texture);
//setting
context.setProgram(program.program);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, ortho, true);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, r_rot_steps);
context.setVertexBufferAt(2, uvBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
//enter frame
stage.addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(Event.RESIZE, resize);
stage.addEventListener(MouseEvent.CLICK, change);
}
//event function
private function loop(e:Event):void {
context.clear(0, 0, 0);
//var tt:Number=getTimer();
boxsLoop();
writeBegin();
writeBuffer(obsList);
writeBuffer(boxList);
writeEnd();
context.present();
}
private function resize(e:Event):void {
context.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0, false);
}
private function change(e:Event):void {
nums=NUM_PARTICLE;
boxList.length=0;
obsList.length=0;
var i:int, j:int;
for (j=0; j < ROWS; j++) {
for (i=0; i < COLS; i++) {
nets[j][i]=null;
}
}
createAllObstacle()
}
private function boxsLoop():void {
var box:Box, tx:int, ty:int, bool:Boolean;
var len:int=boxList.length;
for each (box in boxList) {
if (box.getSleep()) {
continue;
}
if (!box.needMoving) {
tx=box.cx;
ty=box.cy;
bool=true;
if (ty < ROWS - 1) {
var box2:Box=getBox(tx, ty + 1);
if (!box2) {
box.setGoto(tx, ty + 1);
bool=false;
} else if (!box2.getFixed() || (box2.getSmooth())) {
if (tx > 0 && isEmpty(tx - 1, ty) && isEmpty(tx - 1, ty + 1)) {
box.setGoto(tx - 1, ty);
bool=false;
} else if (tx < COLS - 1 && isEmpty(tx + 1, ty) && isEmpty(tx + 1, ty + 1)) {
box.setGoto(tx + 1, ty);
bool=false;
}
}
}
if (bool) {
box.setSleep(true);
}
}
if (box.needMoving) {
box.move();
}
}
if (nums > 0) {
for (var i:int=5; i > 0; i--) {
var randX:int=Math.random() * COLS
if (!getBox(randX, Math.random() * 5)) {
createBox(randX, 0);
}
}
}
}
//obstacle
private function createAllObstacle():void {
var a:int=COLS - 20;
var b:int=ROWS - 20;
for (var i:int=0; i < 20; i++) {
createObstacle(a * Math.random(), 10 + b * Math.random(), 20 * Math.random());
}
}
private function createObstacle(x:int, y:int, len:int):void {
for (var i:int=0; i < len; i++) {
createBox(x + i, y, true);
}
}
private function createBox(x:int, y:int, isFixed:Boolean=false):Box {
if (!isEmpty(x, y)) {
return null;
}
var box:Box=new Box(this, x, y, isFixed, Math.random() > 0.5);
if (isFixed) {
obsList.push(box);
} else {
boxList.push(box);
nums--;
}
setCheckBox(x, y, box);
return box;
}
//check this position box;
private function getBox(x:int, y:int):Box {
if (x > -1 && y > -1 && x < COLS && y < ROWS) {
return nets[y][x];
}
return null;
}
private function isEmpty(x:int, y:int):Boolean {
if (x > -1 && y > -1 && x < COLS && y < ROWS) {
return !(nets[y][x]);
}
return false;
}
public function setCheckBox(x:int, y:int, box:Box):void {
nets[y][x]=box;
}
public function wakeOther(x:int, y:int):void {
//wake.wake.wake
//wake.move.wake
var box:Box=getBox(x - 1, y); //x-1,y
if (box)
box.setSleep(false);
box=getBox(x + 1, y); //x+1,y
if (box)
box.setSleep(false);
box=getBox(x, y - 1); //x,y-1
if (box)
box.setSleep(false);
box=getBox(x - 1, y - 1); //x-1,y-1
if (box)
box.setSleep(false);
box=getBox(x + 1, y - 1); //x+1,y-1
if (box)
box.setSleep(false);
}
private function writeBegin():void {
allWnums=0;
allWIndex=0;
}
private function writeBuffer(vs:Array):void {
const len:int=vs.length;
var oldX:Number, oldY:Number;
var box:Box;
var i:int;
var id:int=0;
while (i < len) {
for (i=i; i < len; i++) {
box=vs[i];
oldX=box.x;
oldY=box.y;
id=box.getSkin();
vb[allWIndex++]=oldX;
vb[allWIndex++]=oldY;
vb[allWIndex++]=id;
allWIndex++;
vb[allWIndex++]=oldX + SIZE;
vb[allWIndex++]=oldY;
vb[allWIndex++]=id;
allWIndex++;
vb[allWIndex++]=oldX + SIZE;
vb[allWIndex++]=oldY + SIZE;
vb[allWIndex++]=id;
allWIndex++;
vb[allWIndex++]=oldX;
vb[allWIndex++]=oldY + SIZE;
vb[allWIndex++]=id;
allWIndex++;
allWnums++;
if (allWnums == NUM_MAX) {
allWIndex=0;
allWnums=0;
i++;
vBuffer.uploadFromVector(vb, 0, NUM_MAX * vunit);
context.setVertexBufferAt(0, vBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context.setVertexBufferAt(1, vBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
context.drawTriangles(iBuffer, 0, 2 * NUM_MAX);
break;
}
}
}
}
private function writeEnd():void {
if (allWIndex > 0) {
var len:int=allWIndex / 16;
vBuffer.uploadFromVector(vb, 0, len * vunit);
context.setVertexBufferAt(0, vBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context.setVertexBufferAt(1, vBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
context.drawTriangles(iBuffer, 0, 2 * len);
}
}
}
}
//Stage3D
import com.adobe.utils.AGALMiniAssembler;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Program3D;
import flash.geom.Matrix3D;
import flash.geom.Point;
class Box {
public var cx:int=0;
public var cy:int=0;
public var toX:int=0;
public var toY:int=0;
public var x:Number=0;
public var y:Number=0;
public var needMoving:Boolean=false;
private var _fixed:Boolean=false;
private var _sleep:Boolean=false;
private var _smooth:Boolean=true;
private var _v:Point=new Point();
private var _skin:int=0;
private var world:Boxes2=null;
public function Box(world:Boxes2, x:int, y:int, fixed:Boolean=false, smooth:Boolean=true) {
this.world=world;
setPos(x, y);
_fixed=fixed;
_smooth=smooth;
_skin=fixed ? 0 : 2;
_skin+=smooth ? 1 : 0;
}
//get fixed
public function getFixed():Boolean {
return _fixed;
}
public function getSkin():int {
return _skin;
}
//sleep
public function getSleep():Boolean {
return _sleep;
}
public function getSmooth():Boolean {
return _smooth;
}
public function move():void {
var tx:Number=this.x - toX * Boxes2.SIZE;
var ty:Number=this.y - toY * Boxes2.SIZE;
if ((tx * tx + ty * ty) < Boxes2.SPEED_No_SQRT) {
world.wakeOther(cx, cy);
world.setCheckBox(cx, cy, null);
setPos(toX, toY);
needMoving=false;
_v.x=0;
_v.y=0;
} else {
this.x+=_v.x;
this.y+=_v.y;
}
}
public function setGoto(xa:int, ya:int):void {
world.setCheckBox(xa, ya, this);
toX=xa;
toY=ya;
needMoving=false;
_v.x=0;
_v.y=0;
//set the moving speed
if (toX != cx || toY != cy) {
needMoving=true;
var v:int=toX - cx;
if (v != 0) {
_v.x=v < 0 ? -Boxes2.SPEED : Boxes2.SPEED;
}
v=toY - cy;
if (v != 0) {
_v.y=v < 0 ? -Boxes2.SPEED : Boxes2.SPEED;
}
}
}
public function setPos(xa:int, ya:int):void {
cx=xa;
cy=ya;
x=xa * Boxes2.SIZE;
y=ya * Boxes2.SIZE;
}
public function setSleep(bool:Boolean):void {
if (_sleep != bool) {
_sleep=bool;
}
}
}
class ShaderProgram {
public function ShaderProgram(context:Context3D, vsh:AGALMiniAssembler, fsh:AGALMiniAssembler) {
program=context.createProgram();
program.upload(vsh.agalcode, fsh.agalcode);
}
public var program:Program3D=null;
}
class VertexShader extends AGALMiniAssembler {
public function VertexShader() {
assemble(Context3DProgramType.VERTEX, src);
}
private var src:String="m44 op, va0, vc0 \n" +
"mov v0, va2 \n" +
"mul vt0.x, va1.x, vc4.x \n" + //offset = base frame% x step
"add v0.x, va2.x, vt0.x \n" + //new u = u + offset
"";
}
class FragmentShader extends AGALMiniAssembler {
public function FragmentShader() {
assemble(Context3DProgramType.FRAGMENT, src);
}
private var src:String="mov ft0, v0\n" +
"tex ft1, ft0.xy, " +
"fs0 <2d,linear,nomip>\n" +
"mov oc, ft1\n";
}
class MatrixUtil {
public static function ortho(w:int, h:int, rev:Boolean):Matrix3D {
var m:Matrix3D=new Matrix3D();
m.appendTranslation(-w * 0.5, -h * 0.5, 0);
m.appendScale(2 / w, rev ? 2 / h : -2 / h, 1);
return m;
}
}