Particle Video
http://blog.bongiovi.tw/?p=338
/**
* Copyright bongiovi015 ( http://wonderfl.net/user/bongiovi015 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/fypQ
*/
package {
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;
import com.bit101.components.CheckBox;
import com.bit101.components.ComboBox;
import com.bit101.components.HSlider;
import com.bit101.components.Window;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
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.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import flash.utils.ByteArray;
import net.hires.debug.Stats;
[SWF(width=465, height=465, frameRate=30, backgroundColor=0x000000)]
public class ParticleVideo extends Sprite {
public var W : int;
public var H : int;
public var context : Context3D;
public var depthSort : Boolean = false;
public var smoothLevel : int = 0;
public const VIDEO_WIDTH : int = 360;
public const VIDEO_HEIGHT : int = 180;
public const SCALE : Number = 2;
public const INDEX : Vector.<uint> = Vector.<uint>([0, 1, 2]);
public const SIZE : Number = 1;
public const ROOT3 : Number = 1.73;
public const MAX_COLOR_LENGTH : int = 195075;
public const MAX : int = 20000;
public const MAX_BUFFER : int = 16;
public const OFFSET : int = 4;
private var fallingSpeed:Number = .3;
private var bmpdPlayer:BitmapData;
private var mtxDraw:Matrix;
private var projectionTransform:PerspectiveMatrix3D;
private var m:Matrix3D;
private var zFar:Number = 5;
private var program:Program3D;
private var buffers:Vector.<VertexBuffer3D>;
private var vBufferPos:VertexBuffer3D;
private var iBuffer:IndexBuffer3D;
private var btnDir:CheckBox;
private var sliderSpeed:HSlider;
private var rx:Number = 0;
private var ry:Number = 0;
private var offsetY:Number = 0;
private var videoList:ComboBox;
private var videoURL:String = "SigurRos.flv";
private var player:VideoPlayer;
private var stats:Stats;
public function ParticleVideo() {
W = stage.stageWidth;
H = stage.stageHeight;
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, _onContext);
stage.stage3Ds[0].requestContext3D();
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
_initPlayer();
stats = new Stats();
addChild(stats).y = 365;
Wonderfl.capture_delay(30);
}
protected function _onContext(e:Event) : void {
stage.stage3Ds[0].removeEventListener(Event.CONTEXT3D_CREATE, _onContext);
context = stage.stage3Ds[0].context3D;
context.configureBackBuffer(W, H, smoothLevel, depthSort);
_init();
stage.addEventListener(Event.RESIZE, __onResize);
}
private function __onResize(e:Event) : void {
context.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0, false);
stats.y = stage.stageHeight - 100;
}
protected function _init() : void {
_initControl();
_initShader();
_initBuffer();
_initMatrix();
var data:Vector.<Number> = Vector.<Number>([0, -SIZE, 0, 1]);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 10, data, 1);
data = Vector.<Number>([SIZE*.5*ROOT3, SIZE*.5*ROOT3, 0, 1]);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 11, data, 1);
data = Vector.<Number>([-SIZE*.5*ROOT3, SIZE*.5*ROOT3, 0, 1]);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 12, data, 1);
context.setProgram(program);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
addEventListener(Event.ENTER_FRAME, _loop);
}
private function _initControl() : void {
var window:Window = new Window(this, 5, 5, "Controls");
window.width = 150;
window.height = 90;
btnDir = new CheckBox(window.content, 5, 5, "UP / DOWN");
sliderSpeed = new HSlider(window.content, 5, 20);
sliderSpeed.value = 50;
videoList = new ComboBox(window.content, 5, 40, "SigurRos.flv", ["SigurRos.flv", "color2_800x450.f4v", "iron.flv"]);
videoList.selectedIndex = 0;
}
private function _loop(e:Event) : void {
if(videoURL != videoList.selectedItem.toString() ) {
videoURL = videoList.selectedItem.toString();
// trace("Video:" + videoURL);
player.setVideoURL("http://www.bongiovi.tw/experiments/particleVideo/" + videoURL);
player.play();
}
context.clear(0, 0, 0, 1);
// RESET THE MATRIX
m = new Matrix3D;
m.appendScale(2/W, -2/H, 1);
var center:Vector3D = new Vector3D(1, 0, 2);
var xx:Number = stage.mouseY/stage.stageHeight * 45;
var yy:Number = (stage.mouseX/stage.stageWidth - .5)* 90;
var off:Number =
rx += ( xx-rx ) * .2;
ry += ( yy-ry ) * .2;
offsetY += (stage.mouseY/stage.stageHeight - offsetY) * .2;
m.appendRotation(rx, Vector3D.X_AXIS, center);
m.appendRotation(ry, Vector3D.Y_AXIS, center);
m.appendTranslation(-1, 1+offsetY, 0);
m.append(projectionTransform);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
// CREATE CURRENT FRAME IMAGE
var vbuffer:VertexBuffer3D = _getCurrentImageBuffer();
// PUSHING IN TO BUFFERS
buffers.unshift(vbuffer);
if(buffers.length > MAX_BUFFER) buffers.pop();
// DRAW EACH FRAM
// UPDATING TIME DATA
var data:Vector.<Number> = Vector.<Number>([0, 10, 0, 1]);
var data1:Vector.<Number> = Vector.<Number>([0, 10, 0, 1]);
var offset:Number = 0;
var buf:VertexBuffer3D;
var f:Function;
for (var i:int = buffers.length-1; i >=0; i--) {
offset = 1 - i/MAX_BUFFER;
offset = Math.sin(offset * Math.PI * .5);
data = Vector.<Number>([offset, offset, offset, offset]);
f = btnDir.selected ? Math.sin : Math.cos;
data1 = Vector.<Number>([f(i/MAX_BUFFER * Math.PI * .5)*sliderSpeed.value/100, 0, 0, 0]);
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, data, 1);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 5, data1, 1);
context.setVertexBufferAt(0, vBufferPos, 0, Context3DVertexBufferFormat.FLOAT_4);
context.setVertexBufferAt(1, buffers[i], 0, Context3DVertexBufferFormat.FLOAT_3);
context.drawTriangles(iBuffer);
}
context.present();
}
private function _getCurrentImageBuffer() : VertexBuffer3D {
var vBufferPos:VertexBuffer3D = context.createVertexBuffer(MAX * 3, 3);
bmpdPlayer.draw(player, mtxDraw);
var colors:Vector.<uint> = bmpdPlayer.getVector(bmpdPlayer.rect);
var i:int, j:int, posIndex:int, color:uint;;
var vBufPos:Vector.<Number> = new Vector.<Number>(MAX * 3 * 3);
var r:Number, g:Number, b:Number;
var oColor:Object;
for(j=0; j<bmpdPlayer.height; j++) {
for(i=0; i<bmpdPlayer.width; i++) {
color = colors[j*bmpdPlayer.width + i];
oColor = getRGB(color);
r = oColor.r/255;
g = oColor.g/255;
b = oColor.b/255;
for(var k:int=0; k<3; k++) {
vBufPos[posIndex++] = r;
vBufPos[posIndex++] = g;
vBufPos[posIndex++] = b;
}
}
}
vBufferPos.uploadFromVector(vBufPos, 0, MAX * 3);
return vBufferPos;
}
private function _initBuffer() : void {
buffers = new Vector.<VertexBuffer3D>();
// INDICES
iBuffer = context.createIndexBuffer(MAX * 3);
var iBuf:Vector.<uint> = new Vector.<uint>(MAX*3);
var t:int = 0, index:int=0, i:int, j:int, posIndex:int;
for( i=0; i<MAX; i++) {
for(t=0; t<INDEX.length; t++) {
iBuf[index++] = INDEX[t] + i*3;
}
}
iBuffer.uploadFromVector(iBuf, 0, MAX * 3);
// VERTICES
var vBufPos:Vector.<Number> = new Vector.<Number>(MAX * 3 * 4);
var tx:Number, ty:Number, tz:Number;
var count : int = 0, bufferCount:int = 0;
for(j=0; j<bmpdPlayer.height; j++) {
for(i=0; i<bmpdPlayer.width; i++) {
tx = i*OFFSET + (W - bmpdPlayer.width*OFFSET) * .5;
ty = j*OFFSET + (H - bmpdPlayer.height*OFFSET) * .5;
tz = 0;
for(var k:int=0; k<3; k++) {
vBufPos[posIndex++] = tx;
vBufPos[posIndex++] = ty;
vBufPos[posIndex++] = tz;
vBufPos[posIndex++] = 10+k;
}
}
}
vBufferPos = context.createVertexBuffer(MAX * 3, 4);
vBufferPos.uploadFromVector(vBufPos, 0, MAX * 3);
}
private function _initShader() : void {
var assembler : AGALMiniAssembler = new AGALMiniAssembler;
var code:String = "";
code += "mov vt0, vc[va0.w]\n";
code += "add vt1, va0, vt0\n";
code += "mov vt1.w, vt0.w\n";
code += "mov vt2, va1\n";
code += "mul vt3, vt2, vt2\n";
code += "add vt3.x, vt3.x, vt3.y\n";
code += "add vt3.x, vt3.x, vt3.z\n";
code += "mul vt3.x, vt3.x, vc13.w\n";
code += "div vt3.x, vt3.x, vc13.x\n";
code += "mul vt3.x, vt3.x, vc13.y\n";
code += "add vt3.x, vt3.x, vc13.z\n";
code += "add vt3.x, vt3.x, vc5.x\n";
code += "mov vt1.z, vt3.x\n";
code += "m44 op, vt1, vc0\n";
code += "mov v0, vt2\n";
var vertextShader : ByteArray = assembler.assemble(Context3DProgramType.VERTEX, code);
code = "mul oc, v0, fc0\n";
var fragmentShader : ByteArray = assembler.assemble(Context3DProgramType.FRAGMENT, code);
var far:Number = 3;
var data:Vector.<Number> = Vector.<Number>([3, -far*.3, far, .5]);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 13, data, 1);
program = context.createProgram();
program.upload(vertextShader, fragmentShader);
}
private function _initMatrix() : void {
projectionTransform = new PerspectiveMatrix3D();
var aspect:Number = 4/3;
var zNear:Number = 0.1;
var fov:Number = 45*Math.PI/180;
projectionTransform.perspectiveFieldOfViewLH(fov, aspect, zNear, zFar);
m = new Matrix3D;
m.appendScale(4/W, -4/H, 1);
m.appendTranslation(-2, 2, 0);
m.append(projectionTransform);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
}
private function _initPlayer() : void {
player = new VideoPlayer(VIDEO_WIDTH, VIDEO_HEIGHT);
player.setVideoURL("http://www.bongiovi.tw/experiments/particleVideo/" + videoURL);
player.play();
player.setVolume(0);
bmpdPlayer = new BitmapData(VIDEO_WIDTH/SCALE, VIDEO_HEIGHT/SCALE, false, 0);
mtxDraw = new Matrix;
mtxDraw.scale(1/SCALE, 1/SCALE);
}
public static function getRGB(pixelValue:uint) : Object {
var red:uint = pixelValue >> 16 & 0xFF;
var green:uint = pixelValue >> 8 & 0xFF;
var blue:uint = pixelValue & 0xFF;
return {r:red, g:green, b:blue};
}
}
}
import flash.display.Sprite;
import flash.events.AsyncErrorEvent;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.media.SoundTransform;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
class VideoPlayer extends Sprite {
private var _nc:NetConnection;
private var _ns:NetStream;
private var _video:Video;
private var _url:String;
public function VideoPlayer(width:int, height:int) {
_nc = new NetConnection();
_nc.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
_nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
_nc.connect(null);
_ns = new NetStream(_nc);
_ns.client = this;
_ns.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
_ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onError);
_ns.checkPolicyFile = true;
_video = new Video(width, height);
_video.smoothing = true;
_video.attachNetStream(_ns);
addChild(_video);
}
public function setVideoURL(videoURL:String):void {
_url = videoURL;
stop();
}
public function play():void {
if (!_url) {
stop();
trace("No URL set. Please use the 'setVideoURL' method.");
} else {
_ns.play(_url);
}
}
public function stop():void {
_ns.close();
_video.clear();
}
public function setVolume(volume:Number):void {
var st:SoundTransform = _ns.soundTransform;
st.volume = volume;
_ns.soundTransform = st;
}
private function onError(e:ErrorEvent) : void { trace(e.text); }
private function onStatus(e:NetStatusEvent) : void { trace(e.info.code); }
public function onMetaData(o:Object):void { }
public function onXMPData(info:Object):void { }
}