/**
* Copyright ohisama ( http://wonderfl.net/user/ohisama )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/n6Fc
*/
package
{
import flash.net.*;
import flash.events.Event;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.system.Security;
import org.papervision3d.cameras.CameraType;
import org.papervision3d.events.FileLoadEvent;
import org.papervision3d.view.BasicView;
import net.hires.debug.Stats;
[SWF (backgroundColor="#000000")]
public class MocapTest extends BasicView
{
public var bvh : BVH;
public var BVHData : Class;
public var status : TextField;
private var loader : URLLoader = new URLLoader();
public function MocapTest()
{
super(0, 0, true, false, CameraType.FREE);
addChild(new Stats());
init();
}
private function init() : void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.frameRate = 30;
stage.quality = StageQuality.BEST;
status = new TextField();
status.x = status.y = 70;
status.width = 300;
status.selectable = false;
status.multiline = false;
status.defaultTextFormat = new TextFormat("Arial", 12, 0xff0000);
addChild(status);
status.text = "ok0";
testBVH();
startRendering();
}
private function testBVH() : void
{
camera.moveForward(50);
bvh = new BVH();
bvh.addEventListener(FileLoadEvent.LOAD_COMPLETE, onBVHComplete);
bvh.addEventListener(FileLoadEvent.ANIMATIONS_COMPLETE, onBVHAnimationsComplete);
bvh.addEventListener(FileLoadEvent.ANIMATIONS_PROGRESS, onBVHAnimationsProgress);
var bvhData : String;
var parseAnimationsAsync : Boolean = false;
Security.loadPolicyFile('http://p.jsapp.us/crossdomain.xml');
var request : URLRequest = new URLRequest('http://p.jsapp.us/proxy/' + "http://www5b.biglobe.ne.jp/~pengin1/mqo/avatar_bow.bvh");
var ul : URLLoader = new URLLoader(request);
ul.addEventListener(Event.COMPLETE, function (e : Event) : void
{
bvhData = ul.data;
status.text = "ok1";
bvh.parse(bvhData, parseAnimationsAsync);
});
}
private function onBVHComplete(event : FileLoadEvent) : void
{
scene.addChild(bvh);
bvh.rotationY = 180;
status.text = "ok2";
}
private function onBVHAnimationsComplete(event : FileLoadEvent) : void
{
bvh.animation.play();
status.text = String(bvh._numFrames);
//status.text = String(bvh.sampleRate);
}
private function onBVHAnimationsProgress(event : FileLoadEvent) : void
{
status.text = "loading frame #" + event.bytesLoaded + " of #" + event.bytesTotal;
}
}
}
//package org.papervision3d.objects.parsers.mocap
{
import flash.events.TimerEvent;
import flash.utils.Dictionary;
import flash.utils.Timer;
import org.ascollada.utils.StringUtil;
import org.papervision3d.core.animation.channel.transform.MatrixChannel3D;
import org.papervision3d.core.animation.curve.Curve3D;
import org.papervision3d.core.animation.key.LinearCurveKey3D;
import org.papervision3d.core.controller.AnimationController;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.Matrix3D;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.core.render.data.RenderSessionData;
import org.papervision3d.events.FileLoadEvent;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Sphere;
class BVH extends DisplayObject3D
{
public static const DEFAULT_SAMPLE_RATE : Number = 0.033333;
public var animation : AnimationController;
public var bvhRoot : DisplayObject3D;
public var sampleRate : Number;
private var _channels : Dictionary;
private var _channelInfo : Dictionary;
private var _offsets : Dictionary;
private var _frames : Array;
public var _numFrames : uint;
private var _currentFrame : uint;
private var _timer : Timer;
public function BVH(name : String = null)
{
super(name);
this.animation = new AnimationController();
}
protected function createEndSite(name : String, material : MaterialObject3D=null) : DisplayObject3D
{
return new DisplayObject3D(name);
}
protected function createJoint(name : String, material : MaterialObject3D=null) : DisplayObject3D
{
material = material || new WireframeMaterial(0xffff00);
return new Sphere(material, 2, 3, 2);
}
protected function createRoot(name : String, material : MaterialObject3D=null) : DisplayObject3D
{
material = material || new WireframeMaterial(0xff0000);
return new Sphere(material, 4, 3, 2);
}
public function parse(data : String, async : Boolean = false) : void
{
var lines : Array = data.split("\n");
var objects : Array = new Array();
var parent : DisplayObject3D = this;
var instance : DisplayObject3D;
var parseAnimations : Boolean = false;
var curOffset : int = 0;
var line : String;
var parts : Array;
var cmd : String;
var i : int, j : int;
_frames = new Array();
_offsets = new Dictionary();
_channelInfo = new Dictionary();
_channels = new Dictionary();
sampleRate = DEFAULT_SAMPLE_RATE;
for (i = 0; i < lines.length; i++)
{
line = StringUtil.trim(lines[i]);
parts = line.split(/\s+/);
cmd = parts[0];
switch (cmd)
{
case "HIERARCHY" :
break;
case "ROOT" :
this.bvhRoot = instance = createRoot(parts[1]);
addChild(instance);
break;
case "JOINT" :
instance = createJoint(parts[1]);
parent.addChild(instance);
break;
case "End" :
instance = createEndSite(parent.name + "_EndSite");
parent.addChild(instance);
break;
case "OFFSET":
var offset : Vertex3D = new Vertex3D();
offset.x = parseFloat(parts[1]);
offset.y = parseFloat(parts[2]);
offset.z = parseFloat(parts[3]);
_offsets[instance] = offset;
break;
case "CHANNELS" :
parts.shift();
var info : ChannelInfo = new ChannelInfo(parts);
var channel : MatrixChannel3D = new MatrixChannel3D(instance.transform);
//for (j = 0; j < 12; j++)
//{
// channel.addCurve(new Curve3D());
//}
_channelInfo[instance] = info;
_channels[instance] = channel;
info.offset = curOffset;
curOffset += info.numChannels;
break;
case "{" :
objects.push(parent);
parent = instance;
break;
case "}" :
parent = objects.pop() as DisplayObject3D;
break;
case "MOTION" :
parseAnimations = true;
break;
case "Frames : " :
break;
case "Frame" :
if (parts[1] == "Time : ")
{
sampleRate = parseFloat(parts[2]);
}
break;
default :
if (!isNaN(parseFloat(parts[0])))
{
var frameData : Array = new Array();
for (j = 0; j < parts.length; j++)
{
frameData.push(parseFloat(parts[j]));
}
_frames.push(frameData);
}
break;
}
}
_numFrames = (_frames ? _frames.length : 0);
_currentFrame = 0;
if (async)
{
_timer = new Timer(10, 1);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, createNextChannel);
_timer.start();
}
else
{
for (_currentFrame = 0; _currentFrame < _numFrames; _currentFrame++)
{
createAnimationChannels(this.bvhRoot, _currentFrame);
dispatchEvent(new FileLoadEvent(FileLoadEvent.ANIMATIONS_PROGRESS, "", _currentFrame, _numFrames));
}
dispatchEvent(new FileLoadEvent(FileLoadEvent.LOAD_COMPLETE));
dispatchEvent(new FileLoadEvent(FileLoadEvent.ANIMATIONS_COMPLETE));
}
}
override public function project(parent : DisplayObject3D, renderSessionData : RenderSessionData) : Number
{
if (animation)
{
animation.update();
}
return super.project(parent, renderSessionData);
}
private function createAnimationChannels(object : DisplayObject3D, frame : int) : void
{
var child : DisplayObject3D;
var offset : Vertex3D = _offsets[object];
var tx : Number = 0, ty : Number = 0, tz : Number = 0;
var rx : Number = 0, ry : Number = 0, rz : Number = 0;
var channelInfo : ChannelInfo = _channelInfo[object];
var channel : MatrixChannel3D = _channels[object];
var frameData : Array = _frames[frame];
var time : Number = sampleRate * frame;
var dataPtr : int;
var i : int, j : int;
if (offset)
{
tx = offset.x;
ty = offset.y;
tz = offset.z;
}
if (channelInfo && channelInfo.channels)
{
dataPtr = channelInfo.offset;
for (i = 0; i < channelInfo.channels.length; i++)
{
switch (channelInfo.channels[i])
{
case "Xposition" :
tx = frameData[int(dataPtr + i)];
break;
case "Yposition" :
ty = frameData[int(dataPtr + i)];
break;
case "Zposition" :
tz = frameData[int(dataPtr + i)];
break;
case "Xrotation" :
rx = frameData[int(dataPtr + i)];
break;
case "Yrotation" :
ry = frameData[int(dataPtr + i)];
break;
case "Zrotation" :
rz = frameData[int(dataPtr + i)];
break;
default :
break;
}
}
}
if (channel)
{
var matrix : Matrix3D = Matrix3D.IDENTITY;
var toRadians : Number = Math.PI / 180
var curve : Curve3D;
matrix.calculateMultiply(Matrix3D.rotationMatrix(0, 1, 0, ry * toRadians), matrix);
matrix.calculateMultiply(Matrix3D.rotationMatrix(1, 0, 0, rx * toRadians), matrix);
matrix.calculateMultiply(Matrix3D.rotationMatrix(0, 0, 1, rz * toRadians), matrix);
matrix.calculateMultiply(Matrix3D.translationMatrix(tx, ty, tz), matrix);
var values : Array =
[
matrix.n11, matrix.n12, matrix.n13, matrix.n14,
matrix.n21, matrix.n22, matrix.n23, matrix.n24,
matrix.n31, matrix.n32, matrix.n33, matrix.n34
];
for (i = 0; i < 12; i++)
{
curve = new Curve3D();
curve.addKey(new LinearCurveKey3D(time, values[i]));
channel.addCurve(curve);
}
if (frame == _numFrames - 1)
{
//channel.updateStartAndEndTime();
this.animation.addChannel(channel);
}
}
for each (child in object.children)
{
createAnimationChannels(child, frame);
}
}
private function createNextChannel(e : TimerEvent) : void
{
if (_currentFrame < _numFrames)
{
dispatchEvent(new FileLoadEvent(FileLoadEvent.ANIMATIONS_PROGRESS, "", _currentFrame, _numFrames));
createAnimationChannels(this.bvhRoot, _currentFrame++);
_timer.start();
}
else
{
dispatchEvent(new FileLoadEvent(FileLoadEvent.LOAD_COMPLETE));
dispatchEvent(new FileLoadEvent(FileLoadEvent.ANIMATIONS_COMPLETE));
}
}
public function get frames() : Array
{
return _frames;
}
public function get numFrames() : int
{
return _numFrames;
}
}
}
internal class ChannelInfo
{
public var numChannels : uint;
public var offset : int;
public var channels : Array;
public function ChannelInfo(parts : Array) : void
{
this.numChannels = parseInt(parts.shift(), 10);
this.channels = new Array();
while (parts.length)
{
this.channels.push(parts.shift());
}
}
}