movieProjector
happy halloween!
(minor update)
/**
* Copyright zob ( http://wonderfl.net/user/zob )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/hjHu
*/
package {
import flash.display.*;
import flash.filters.*;
import flash.events.*;
import flash.net.*;
import flash.utils.*;
import flash.geom.*;
import flash.text.*;
import flash.system.*;
import flash.ui.*;
import flash.media.*;
import net.hires.debug.Stats;
import com.bit101.components.PushButton;
[SWF(width=465,height=465,backgroundColor=0x222222,frameRate=30)]
public class movieProjector extends Sprite
{
// 3d
private var focal :Number = 0;
private var viewport :Shape = new Shape();
private var world :Matrix3D = new Matrix3D();
private var projected :Vector.<Number> = new Vector.<Number>;
private var projection :PerspectiveProjection = new PerspectiveProjection();
//objects
private var _faces :Array = [];
private var trans :Matrix3D = new Matrix3D();
private var cubes :Vector.<Cube> = new Vector.<Cube>;
private var _indices :Vector.<int> = new Vector.<int>;
private var _sortedIndices :Vector.<int> = new Vector.<int>;
private var _uvNorms :Vector.<Number> = new Vector.<Number>;
private var _statics :Vector.<Number> = new Vector.<Number>;
private var _verts :Vector.<Number> = new Vector.<Number>;
//graphics
private var FILE_PATH :String = "http://our-work.com.my/livetesting/";
private var urls :Vector.<String> = new Vector.<String>;
private var images :Vector.<BitmapData> = new Vector.<BitmapData>;
private var framePrj :BitmapData;
private var skin :BitmapData;
//interaction
private var dragging :Boolean = false;
private var drag_mode :Boolean = false;
private var ct :ColorTransform = new ColorTransform(1,1,1,0.7);
private var old_mouse :Point = new Point();
private var new_mouse :Point = new Point();
//video
private var playing :Boolean = false;
private var VIDEO_URL :String = "thisishalloween3.flv";
private var VIDEO_WIDTH :int = 320;
private var VIDEO_HEIGHT :int = 240;
private var ns :NetStream;
private var nc :NetConnection;
private var video :Video;
private var video_bmpd :BitmapData;
private var video_pos :Point = new Point();
public function movieProjector()
{
//(in case we need more images)
urls.push(
"wall.jpg",
"thisishalloween.jpg"
);
beginLoad();
}
private function beginLoad():void{
var ld:Loader = new Loader();
ld.contentLoaderInfo.addEventListener(Event.COMPLETE , loadComplete );
var url:String = urls.shift();
ld.load( new URLRequest(FILE_PATH+url) , new LoaderContext(true));
}
private function loadComplete(e:Event):void{
try
{
images.push(Bitmap(e.target.content).bitmapData);
} catch(e:Error) {}
if(urls.length >0){
beginLoad();
}else{
init();
}
}
private function init(e:Event = null):void
{
skin = images[0];
framePrj = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x0);
video_bmpd = new BitmapData(VIDEO_WIDTH, VIDEO_HEIGHT, false, 0x0);
video_pos.x = (framePrj.width - video_bmpd.width )/2;
video_pos.y = (framePrj.height - video_bmpd.height)/2;
video_bmpd.copyPixels(images[1], images[1].rect, new Point());
init3D();
}
private function init3D():void
{
viewport.x = stage.stageWidth / 2;
viewport.y = stage.stageHeight / 2;
projection.fieldOfView = 45;
focal = projection.focalLength;
var i:int = 0;
var j:int = 0;
var temp_length:int = 0;
for(i = 0; i < 16; i++)
{
cubes.push(new Cube(i, -150 + (i%4)*100, -150 + int(i/4)*100 ,0, 80, 80, 80));
temp_length += cubes[i]._uvts.length;
_indices = _indices.concat(cubes[i]._indices);
}
var panel:Sprite = new Sprite;
new PushButton(panel, stage.stageWidth - 125, 5, "switch drag mode", onSDM).setSize(120, 16);
new PushButton(panel, stage.stageWidth - 250, 5, "play/pause video", onPV ).setSize(120, 16);
addChild(viewport);
addChild(panel);
addChild(new Stats());
stage.addEventListener(Event.ENTER_FRAME, processing);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onmouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onmouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onmouseMove);
}
private function playVideo():void
{
if(!nc)
{
nc = new NetConnection();
nc.connect(null);
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, videoNetStatusHandler);
ns.client = {
onMetaData:function(param:Object):void{}
};
ns.checkPolicyFile = true;
ns.play(FILE_PATH+VIDEO_URL);
video = new Video();
video.attachNetStream(ns);
} else { ns.resume(); playing = !playing;}
}
private function videoNetStatusHandler(e:NetStatusEvent):void
{
switch(e.info.code) {
case "NetStream.Play.Start":
playing = !playing;
break;
case "NetStream.Play.Stop":
ns.seek(0); //replay
break;
}
}
private function processing(e:Event):void
{
update();
render();
}
private function update():void
{
var i:int = 0;
var j:int = 0;
var face:Face;
var inc:int = 0;
var matrix:Matrix3D = new Matrix3D();
//flush
_sortedIndices.splice(0,_sortedIndices.length);
//_indices.splice(0, _indices.length); //not sorting indices for now
_faces.splice(0, _faces.length);
_uvNorms.splice(0, _uvNorms.length);
_statics.splice(0, _statics.length);
_verts.splice(0, _verts.length);
for(i = 0; i < cubes.length; i++)
{
cubes[i].crx = getTimer() * cubes[i].rx;
cubes[i].cry = getTimer() * cubes[i].ry;
cubes[i].crz = getTimer() * cubes[i].rz;
matrix.identity();
matrix.appendRotation(cubes[i].crx, Vector3D.X_AXIS);
matrix.appendRotation(cubes[i].cry, Vector3D.Y_AXIS);
matrix.appendRotation(cubes[i].crz, Vector3D.Z_AXIS);
matrix.transformVectors(cubes[i]._vNorms, cubes[i]._uvNorms);
matrix.appendTranslation(cubes[i].x, cubes[i].y, 0); //ignore z
matrix.transformVectors(cubes[i]._verts, cubes[i]._mverts);
for(j = 0; j < cubes[i]._uvNorms.length; j+=3)
{
// update here
//cubes[i]._uvNorms[j ] = cubes[i].x/stage.stageWidth + 0.5 + cubes[i]._uvNorms[j ] * 0.15;
//cubes[i]._uvNorms[j + 1] = cubes[i].y/stage.stageHeight + 0.5 + cubes[i]._uvNorms[j + 1] * 0.15;
//cubes[i]._uvNorms[j + 2] = 0.5 + cubes[i]._uvNorms[j + 2] * 0.15; // redundant
cubes[i]._uvNorms[j ] = ((cubes[i]._mverts[j ])/stage.stageWidth + 0.5); // use vertices position instead, should use this depends on app
cubes[i]._uvNorms[j + 1] = ((cubes[i]._mverts[j + 1])/stage.stageHeight + 0.5);
}
_sortedIndices = _sortedIndices.concat(cubes[i]._indices);
_faces = _faces.concat(cubes[i]._faces);
_uvNorms = _uvNorms.concat(cubes[i]._uvNorms);
_statics = _statics.concat(cubes[i]._static);
_verts = _verts.concat(cubes[i]._mverts);
}
world.identity();
world.append(trans);
world.appendTranslation(0, 0, focal);
world.append(projection.toMatrix3D());
Utils3D.projectVectors(world, _verts, projected, _uvNorms);
Utils3D.projectVectors(world, _verts, projected, _statics);
for (i = 0; i<_indices.length; i+=3){
face = _faces[inc];
face.i0 = _indices[i];
face.i1 = _indices[int(i + 1)];
face.i2 = _indices[int(i + 2)];
var i3:int = i * 3;
face.z = (_uvNorms[int(face.i0*3 + 2)] + _uvNorms[int(face.i1*3 + 2)] + _uvNorms[int(face.i2*3 + 2)]) * 0.333333;
inc++;
}
_faces.sortOn("z", Array.NUMERIC);
inc = 0;
for each (face in _faces){
_sortedIndices[inc++] = face.i0;
_sortedIndices[inc++] = face.i1;
_sortedIndices[inc++] = face.i2;
}
}
private function render():void
{
if(playing) video_bmpd.draw(video); //update video bitmapdata
framePrj.fillRect(framePrj.rect, 0x0);
framePrj.copyPixels(video_bmpd, video_bmpd.rect, video_pos);
framePrj.colorTransform(framePrj.rect, ct);
viewport.graphics.clear();
viewport.graphics.beginBitmapFill(skin, null, false, false);
//viewport.graphics.drawTriangles(projected, _sortedIndices, _uvNorms, TriangleCulling.NEGATIVE);
viewport.graphics.drawTriangles(projected, _indices, _statics, TriangleCulling.NEGATIVE); //_indices will not be sorted for now
viewport.graphics.endFill();
viewport.graphics.beginBitmapFill(framePrj, null, false, false);
viewport.graphics.drawTriangles(projected, _sortedIndices, _uvNorms, TriangleCulling.NEGATIVE);
//viewport.graphics.drawTriangles(projected, _indices, _statics, TriangleCulling.NEGATIVE);
viewport.graphics.endFill();
}
/////events
private function onSDM(...arg):void
{
drag_mode = !drag_mode;
}
private function onPV(...arg):void
{
if(!playing)
{
playVideo();
} else {
ns.pause();
playing = !playing;
}
}
private function onmouseDown(e:MouseEvent):void
{
old_mouse.x = mouseX;
old_mouse.y = mouseY;
dragging = true;
}
private function onmouseMove(e:MouseEvent):void
{
if(dragging)
{
if(!drag_mode)
{
video_pos.x = mouseX-150;
video_pos.y = mouseY-100;
} else {
new_mouse.x = mouseX
new_mouse.y = mouseY;
var difference:Point = new_mouse.subtract(old_mouse);
var vector:Vector3D = new Vector3D(difference.x, difference.y, 0);
var rotationAxis:Vector3D = vector.crossProduct(new Vector3D(0,0,1));
rotationAxis.normalize();
var distance:Number = Point.distance(new_mouse, old_mouse);
var rotationMatrix:Matrix3D = new Matrix3D();
rotationMatrix.appendRotation(distance, rotationAxis);
trans.append(rotationMatrix);
old_mouse.x = new_mouse.x;
old_mouse.y = new_mouse.y;
}
}
}
private function onmouseUp(e:MouseEvent):void
{
dragging = false;
}
}
}
class Cube
{
public var x :Number = 0;
public var y :Number = 0;
public var z :Number = 0;
public var rx :Number = 0;
public var ry :Number = 0;
public var rz :Number = 0;
public var crx :Number = 0;
public var cry :Number = 0;
public var crz :Number = 0;
public var _faces :Array = new Array();
public var _indices :Vector.<int> = new Vector.<int>;
public var _verts :Vector.<Number> = new Vector.<Number>;
public var _mverts :Vector.<Number> = new Vector.<Number>;
public var _vNorms :Vector.<Number> = new Vector.<Number>;
public var _uvts :Vector.<Number> = new Vector.<Number>;
public var _uvNorms :Vector.<Number> = new Vector.<Number>;
public var _static :Vector.<Number> = new Vector.<Number>;
public function Cube(id:int, px:Number, py:Number, pz:Number, w:Number, h:Number, leng:Number):void{
x = px;
y = py;
z = pz;
rx = Math.random()*0.05;
ry = Math.random()*0.05;
rz = Math.random()*0.05;
rx = (Math.random()< 0.5)?-rx:rx;
ry = (Math.random()< 0.5)?-ry:ry;
rz = (Math.random()< 0.5)?-rz:rz;
var hw :Number = w * 0.5;
var hh :Number = h * 0.5;
var hl :Number = leng * 0.5;
var xA :Number = -hw;
var xB :Number = hw;
var yA :Number = -hh;
var yB :Number = hh;
var zA :Number = -hl;
var zB :Number = hl;
var index :int = id * 24; // each cube has 24 indices
var i :int = 0;
/*
* 4_________5
* /\ /\
* / \ / \
* 0____\_____1 \
* \ 6____\_____7
* \ / \ / ^" ,,, ^"
* \ / \ / (<o>_._<o>) < modified from http://actionsnippet.com/?p=2158
* 2/_________3 `u---u--c)~ http://wonderfl.net/c/dy0Z/
* thanks @shapevent
**************************************************************************************************/
//////////////////////id.. index.. face..
_verts.push(
xA, yA, zA, //0 //0 //FRONT
xB, yA, zA, //1 //1
xA, yB, zA, //2 //2
xB, yB, zA, //3 //3
xA, yB, zB, //6 //4 //BACK
xB, yB, zB, //7 //5
xA, yA, zB, //4 //6
xB, yA, zB, //5 //7
xB, yA, zA, //1 //8 //RIGHT
xB, yA, zB, //5 //9
xB, yB, zA, //3 //10
xB, yB, zB, //7 //11
xA, yA, zB, //4 //12 //TOP
xB, yA, zB, //5 //13
xA, yA, zA, //0 //14
xB, yA, zA, //1 //15
xA, yB, zA, //2 //16 //LEFT
xA, yB, zB, //6 //17
xA, yA, zA, //0 //18
xA, yA, zB, //4 //19
xA, yB, zA, //2 //20 //BOTTOM
xB, yB, zA, //3 //21
xA, yB, zB, //6 //22
xB, yB, zB //7 //23
);
for(i = 0; i < _verts.length; i+=3)
{
_vNorms.push(0, 0, 0);
}
calculateNormal();
var i0:int = index , i1:int = index + 1, i2:int = index + 2;
var i3:int = index + 3, i4:int = index + 4, i5:int = index + 5;
var i6:int = index + 6, i7:int = index + 7, i8:int = index + 8;
var i9:int = index + 9, i10:int = index + 10, i11:int = index + 11;
var i12:int = index + 12, i13:int = index + 13, i14:int = index + 14;
var i15:int = index + 15, i16:int = index + 16, i17:int = index + 17;
var i18:int = index + 18, i19:int = index + 19, i20:int = index + 20;
var i21:int = index + 21, i22:int = index + 22, i23:int = index + 23;
_indices.push( i0, i1, i2, // 3 //FRONT
i1, i3, i2, // 6
i4, i5, i6, // 9 //BACK
i5, i7, i6, //12
i8, i9, i10, //15 //RIGHT
i11, i10, i9, //18
i12, i13, i14, //21 //TOP
i15, i14, i13, //24
i16, i17, i18, //27 //LEFT
i18, i17, i19, //30
i20, i21, i22, //33 //BOTTOM
i21, i23, i22 //36
);
_faces.push(
new Face(), new Face(), new Face(),
new Face(), new Face(), new Face(),
new Face(), new Face(), new Face(),
new Face(), new Face(), new Face()
);
_uvts.push(
0, 0, 0, //FRONT
1, 0, 0,
0, 1, 0,
1, 1, 0,
0, 0, 0, //BACK
1, 0, 0,
0, 1, 0,
1, 1, 0,
0, 0, 0, //RIGHT
1, 0, 0,
0, 1, 0,
1, 1, 0,
0, 0, 0, //TOP
1, 0, 0,
0, 1, 0,
1, 1, 0,
0, 0, 0, //LEFT
1, 0, 0,
0, 1, 0,
1, 1, 0,
0, 0, 0, //BOTTOM
1, 0, 0,
0, 1, 0,
1, 1, 0
);
for(i = 0; i < _uvts.length; i++)
{
_static.push(_uvts[i]);
}
}
public function calculateNormal():void
{
var i :int = 0;
var vx :Number = 0;
var vy :Number = 0;
var vz :Number = 0;
var vlen :Number = 0;
for(i = 0; i < _verts.length; i+=3)
{
vx = _verts[i ];
vy = _verts[i + 1];
vz = _verts[i + 2];
vlen = Math.sqrt(vx*vx + vy*vy + vz*vz);
_vNorms[i ] = vx/vlen;
_vNorms[i + 1] = vy/vlen;
_vNorms[i + 2] = vz/vlen;
}
}
}
class Face{
public var i0:Number;
public var i1:Number;
public var i2:Number;
public var z :Number;
}