//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * ベクトル線形補間実装
 * @author Junpee
 */

#include "LampBasic.h"
#include "Animation/VectorInterpolator/VectorLinearInterpolator.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
VectorLinearInterpolator::VectorLinearInterpolator() :
	keys_(NULL), keyCount_(0), lastestUseKeyIndex_(0){
}
//------------------------------------------------------------------------------
// デストラクタ
VectorLinearInterpolator::~VectorLinearInterpolator(){
	SafeArrayDelete(keys_);
}
//------------------------------------------------------------------------------
// コピーコンストラクタ
VectorLinearInterpolator::VectorLinearInterpolator(
	const VectorLinearInterpolator& copy){
	keyCount_ = copy.keyCount_;
	lastestUseKeyIndex_ = 0;
	// コピーコンストラクタは強制的にNULL設定
	keys_ = NULL;
	if(keyCount_ == 0){ return; }
	keys_ = new Key[keyCount_];
	std::memcpy(keys_, copy.keys_, sizeof(Key) * keyCount_);
}
//------------------------------------------------------------------------------
// 代入演算子
VectorLinearInterpolator& VectorLinearInterpolator::operator =(
	const VectorLinearInterpolator& copy){
	// 自分自身ならリターン
	if(this == &copy){ return *this; }
	keyCount_ = copy.keyCount_;
	lastestUseKeyIndex_ = 0;
	// 代入の際は解放してNULLを設定
	SafeArrayDelete(keys_);
	if(keyCount_ == 0){ return *this; }
	keys_ = new Key[keyCount_];
	std::memcpy(keys_, copy.keys_, sizeof(Key) * keyCount_);
	return *this;
}
//------------------------------------------------------------------------------
// 長さ
//------------------------------------------------------------------------------
// 長さの取得
float VectorLinearInterpolator::getLength() const{
	Assert((keyCount_ > 0) && (keys_ != NULL));
	return keys_[keyCount_ - 1].time_;
}
//------------------------------------------------------------------------------
// バウンディング
//------------------------------------------------------------------------------
// バウンディングボックスの取得
AxisAlignedBox VectorLinearInterpolator::getBoundingBox() const{
	AxisAlignedBox result(AxisAlignedBox::zero);
	if(keyCount_ == 0){ return result; }
	result.set(keys_[0].value_, keys_[0].value_);
	for(int i = 1; i < keyCount_; i++){ result.merge(keys_[i].value_); }
	return result;
}
//------------------------------------------------------------------------------
// 補間
//------------------------------------------------------------------------------
// 補間
Vector3 VectorLinearInterpolator::interpolate(float time){
	Assert(keys_ != NULL);
	// 時間が前にあふれている
	if(time <= 0.f){ return keys_[0].value_; }
	// 時間が後ろにあふれている
	float length = getLength();
	int maxKeyIndex = keyCount_ - 1;
	if(time >= length){ return keys_[maxKeyIndex].value_; }

	// キーの探索、前回のキー位置から探索する
	int keyIndex = lastestUseKeyIndex_;
	Assert((keyIndex >= 0) && (keyIndex < maxKeyIndex));
	for(int i = 0; i < maxKeyIndex; i++){
		const Key& preKey = keys_[keyIndex];
		const Key& postKey = keys_[keyIndex + 1];
		Assert(preKey.time_ < postKey.time_);
		if((time >= preKey.time_) && (time < postKey.time_)){ break; }
		keyIndex++;
		if(keyIndex == maxKeyIndex){ keyIndex = 0; }
		Assert((keyIndex >= 0) && (keyIndex < maxKeyIndex));
	}
	Assert((keyIndex >= 0) && (keyIndex < maxKeyIndex));
	lastestUseKeyIndex_ = keyIndex;

	// 線形補間
	const Key& key = keys_[keyIndex];
	float keyTime = key.time_;
	const Key& nextKey = keys_[keyIndex + 1];
	Assert(keyTime < nextKey.time_);
	Assert((time >= keyTime) && (time < nextKey.time_));
	float rate = (time - keyTime) / (nextKey.time_ - keyTime);
	const Vector3& keyValue = key.value_;
	return keyValue + (nextKey.value_ - keyValue) * rate;
}
//------------------------------------------------------------------------------
// キー
//------------------------------------------------------------------------------
// キー数の設定
void VectorLinearInterpolator::setKeyCount(int keyCount){
	// 補間の為には2以上のキー数が必要
	Assert(keyCount > 1);
	keyCount_ = keyCount;
	SafeArrayDelete(keys_);
	keys_ = new Key[keyCount_];
	lastestUseKeyIndex_ = 0;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
