/**
 * MikuMikuDance VMD形式再生用ボーンパラメータ列
 *
 * @author b2ox
 */
package org.b2ox.pv3d.MikuMikuDance
{
	import org.b2ox.pv3d.MikuMikuDance.*;
	import org.b2ox.pv3d.Utils;
	import org.papervision3d.core.math.*;

	/**
	 * ボーンパラメータ列の格納
	 */
	public class VMDBoneParamSequence
	{
		private var keyFrame:Vector.<KeyFrameInfo> = new Vector.<KeyFrameInfo>();
		private var frameLength:int = 0;
		public var boneName:String;

		public function VMDBoneParamSequence(boneName:String):void 
		{
			this.boneName = boneName;
		}

		public function addBoneParam(frameNo:int, param:VMDBoneParam):void
		{
			// 既に登録済みのフレームの場合は上書き
			for (var i:int = keyFrame.length-1; i >= 0; i--)
			{
				if (keyFrame[i].frameNo == frameNo) {
					keyFrame[i].param = param;
					return;
				}
			}
			keyFrame.push(new KeyFrameInfo(frameNo, param));
		}

		public function fixSequence(frameLength:int):void
		{
			keyFrame = keyFrame.sort(KeyFrameInfo.compare);
			keyFrame.fixed = true;
			this.frameLength = frameLength;
			trace("bone["+boneName+"]: キーフレーム総数 "+keyFrame.length);
		}

		private function searchRange(start:int, end:int, frameNo:int):int
		{
			if (keyFrame[start].frameNo == frameNo || end == start + 1) return start;
			var n:int = (start + end) / 2;
			if (frameNo < keyFrame[n].frameNo) return searchRange(start, n, frameNo);
			return searchRange(n, end, frameNo);
		}

		public function getBoneParam(frameNo: int):VMDBoneParam
		{
			var n:int = keyFrame.length - 1;
			var kf:KeyFrameInfo = keyFrame[n];
			if (kf.frameNo <= frameNo) return kf.param;
			n = searchRange(0, n, frameNo);
			kf = keyFrame[n];
			var kf2:KeyFrameInfo = keyFrame[n + 1];
			var t:Number = (frameNo - kf.frameNo) / (kf2.frameNo - kf.frameNo);
			return kf.param.interpolateParam(kf2.param, t);
		}
	}
}

import org.b2ox.pv3d.MikuMikuDance.*;

class KeyFrameInfo
{
	public var frameNo:int;
	public var param:VMDBoneParam;

	public function KeyFrameInfo(frameNo:int, param:VMDBoneParam):void
	{
		this.frameNo = frameNo;
		this.param = param;
	}
	
	public static function compare(a:KeyFrameInfo, b:KeyFrameInfo):Number
	{
		return (a.frameNo == b.frameNo) ? 0 : (a.frameNo < b.frameNo) ? -1 : 1;
	}
}