//------------------------------------------------------------------------------
// 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/InputOutput/TextAnimationLoader.h"
#include "Core/InputOutput/FilePath.h"
#include "Core/InputOutput/TextFileReader.h"
#include "Core/InputOutput/StreamTokenizer.h"
#include "Animation/VectorInterpolator/VectorConstantInterpolator.h"
#include "Animation/VectorInterpolator/VectorArrayInterpolator.h"
#include "Animation/VectorInterpolator/VectorLinearInterpolator.h"
#include "Animation/RotationInterpolator/RotationConstantInterpolator.h"
#include "Animation/RotationInterpolator/EulerArrayInterpolator.h"
#include "Animation/RotationInterpolator/QuaternionArrayInterpolator.h"
#include "Animation/RotationInterpolator/QuaternionLinearInterpolator.h"

#include "Animation/System/AnimationManager.h"
#include "Animation/System/AnimationSet.h"
#include "Animation/Camera/CameraAnimation.h"
#include "Animation/SceneNode/SceneNodeAnimation.h"
#include "Animation/Model/CharacterModelAnimation.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
TextAnimationLoader::TextAnimationLoader(){
}
//------------------------------------------------------------------------------
// デストラクタ
TextAnimationLoader::~TextAnimationLoader(){
}
//------------------------------------------------------------------------------
// ロード
void TextAnimationLoader::load(
	const String& filePath, AnimationManager* manager){
	FilePath path(filePath);
	Assert(path.existFile());
	TextFileReader* textFileReader = new TextFileReader(filePath);
	load(textFileReader, manager);
	delete textFileReader;
}
//------------------------------------------------------------------------------
// ロード
void TextAnimationLoader::load(
	TextReader* textReader, AnimationManager* manager){
	tokenizer_ = new StreamTokenizer(textReader);
	manager_ = manager;

	// ヘッダの読み込み
	readHeader();

	while(true){
		// トークン読み終わり
		if(!tokenizer_->nextToken()){ break; }
		String chunkName = tokenizer_->getToken();
		if(chunkName == "AnimationSet"){
			readAnimationSetList();
		}else if(chunkName == "CameraAnimation"){
			// カメラアニメーション
			openChunk();
			while(true){
				String token = readToken("readCameraAnimation()");
				if(token == "}"){ break; }
				readCameraAnimation(token);
			}
		}else if(chunkName == "CameraAnimationData"){
			// カメラアニメーションデータ
			openChunk();
			while(true){
				String token = readToken("readCameraAnimationData()");
				if(token == "}"){ break; }
				readCameraAnimationData(token);
			}
		}else if(chunkName == "SceneNodeAnimation"){
			// シーンノードアニメーション
			openChunk();
			while(true){
				String token = readToken("readSceneNodeAnimation()");
				if(token == "}"){ break; }
				readSceneNodeAnimation(token);
			}
		}else if(chunkName == "SceneNodeAnimationData"){
			// シーンノードアニメーションデータ
			openChunk();
			while(true){
				String token = readToken("readSceneNodeAnimationData()");
				if(token == "}"){ break; }
				readSceneNodeAnimationData(token);
			}
		}else if(chunkName == "CharacterModelAnimation"){
			// キャラクタモデルアニメーション
			openChunk();
			while(true){
				String token = readToken("readCharacterModelAnimation()");
				if(token == "}"){ break; }
				readCharacterModelAnimation(token);
			}
		}else if(chunkName == "CharacterModelAnimationData"){
			// キャラクタモデルアニメーションデータ
			openChunk();
			while(true){
				String token = readToken("readCharacterModelAnimationData()");
				if(token == "}"){ break; }
				readCharacterModelAnimationData(token);
			}
		}else if(chunkName == "AnimationSetLink"){
			readAnimationSetLinkList();
		}else if(chunkName == "CameraLink"){
			readCameraLinkList();
		}else if(chunkName == "SceneNodeLink"){
			readSceneNodeLinkList();
		}else if(chunkName == "CharacterModelLink"){
			readCharacterModelLinkList();
		}else{
			ErrorOut("TextAnimationLoader::load() "
				"invalid chunk %s (line %d)",
				chunkName.getBytes(), tokenizer_->getLineNumber());
		}
	}
	delete tokenizer_;
}
//------------------------------------------------------------------------------
// ヘッダの読み込み
void TextAnimationLoader::readHeader(){
	skipWord("Header");
	openChunk();
	skipWord("type");
	skipWord("LampTextAnimationFormat");
	skipWord("version");
	skipWord("0_9_0");
	closeChunk();
}
//------------------------------------------------------------------------------
// アニメーションセット
//------------------------------------------------------------------------------
// アニメーションセットリストの読み込み
void TextAnimationLoader::readAnimationSetList(){
	openChunk();
	while(true){
		String token = readToken("readAnimationSetList()");
		if(token == "}"){ break; }
		readAnimationSet(token);
	}
}
//------------------------------------------------------------------------------
// アニメーションセットの読み込み
void TextAnimationLoader::readAnimationSet(const String& name){
	AnimationSet* animation = manager_->createAnimationSet(name);
	openChunk();
	// 有効、無効フラグ
	skipWord("enabled");
	animation->setEnabled(readBool());
	closeChunk();
}
//------------------------------------------------------------------------------
// カメラ
//------------------------------------------------------------------------------
// カメラアニメーションの読み込み
void TextAnimationLoader::readCameraAnimation(const String& name){
	CameraAnimation* animation = manager_->createCamera(name);
	openChunk();
	// ターゲット名
	skipWord("targetName");
	animation->setTargetName(readToken("readCameraAnimation()"));
	// 有効、無効フラグ
	skipWord("enabled");
	animation->setEnabled(readBool());
	closeChunk();
}
//------------------------------------------------------------------------------
// カメラアニメーションデータの読み込み
void TextAnimationLoader::readCameraAnimationData(const String& name){
	CameraAnimationData* data = manager_->createCameraData(name);
	openChunk();
	skipWord("sequenceCount");
	int sequenceCount = readInt();
	data->setSequenceCount(sequenceCount);
	for(int i = 0; i < sequenceCount; i++){
		skipWord("sequence");
		int sequenceNumber = readInt();
		Assert(i == sequenceNumber);
		openChunk();
		// 回転
		skipWord("rotation");
		data->setRotation(i, readRotationInterpolator());
		// 移動
		skipWord("translation");
		data->setTranslation(i, readVectorInterpolator());
		// ループ
		skipWord("looped");
		data->setLooped(i, readBool());
		closeChunk();
	}
	closeChunk();
}
//------------------------------------------------------------------------------
// シーンノード
//------------------------------------------------------------------------------
// シーンノードアニメーションの読み込み
void TextAnimationLoader::readSceneNodeAnimation(const String& name){
	SceneNodeAnimation* animation = manager_->createSceneNode(name);
	openChunk();
	skipWord("targetName");
	animation->setTargetName(readToken("readSceneNodeAnimation()"));
	// 有効、無効フラグ
	skipWord("enabled");
	animation->setEnabled(readBool());
	closeChunk();
}
//------------------------------------------------------------------------------
// シーンノードアニメーションデータの読み込み
void TextAnimationLoader::readSceneNodeAnimationData(const String& name){
	SceneNodeAnimationData* data = manager_->createSceneNodeData(name);
	openChunk();
	skipWord("sequenceCount");
	int sequenceCount = readInt();
	data->setSequenceCount(sequenceCount);
	for(int i = 0; i < sequenceCount; i++){
		skipWord("sequence");
		int sequenceNumber = readInt();
		Assert(i == sequenceNumber);
		openChunk();
		// スケール
		skipWord("scale");
		data->setScale(i, readVectorInterpolator());
		// 回転
		skipWord("rotation");
		data->setRotation(i, readRotationInterpolator());
		// 移動
		skipWord("translation");
		data->setTranslation(i, readVectorInterpolator());
		// ループ
		skipWord("looped");
		data->setLooped(i, readBool());
		closeChunk();
	}
	closeChunk();
}
//------------------------------------------------------------------------------
// キャラクタモデル
//------------------------------------------------------------------------------
// キャラクタモデルアニメーションの読み込み
void TextAnimationLoader::readCharacterModelAnimation(const String& name){
	CharacterModelAnimation* animation =
		manager_->createCharacterModel(name);
	openChunk();
	skipWord("targetName");
	animation->setTargetName(readToken("readCharacterModelAnimation()"));
	skipWord("boneCount");
	int boneCount = readInt();
	animation->setBoneCount(boneCount);
	openChunk();
	for(int i = 0; i < boneCount; i++){
		animation->setBoneName(i, readToken("readCharacterModelAnimation()"));
	}
	closeChunk();
	// 有効、無効フラグ
	skipWord("enabled");
	animation->setEnabled(readBool());
	closeChunk();
}
//------------------------------------------------------------------------------
// キャラクタモデルアニメーションデータの読み込み
void TextAnimationLoader::readCharacterModelAnimationData(const String& name){
	CharacterModelAnimationData* data =
		manager_->createCharacterModelData(name);
	openChunk();
	skipWord("boneCount");
	int boneCount = readInt();
	data->setBoneCount(boneCount);
	skipWord("sequenceCount");
	int sequenceCount = readInt();
	data->setSequenceCount(sequenceCount);
	for(int i = 0; i < sequenceCount; i++){
		skipWord("sequence");
		int sequenceNumber = readInt();
		Assert(i == sequenceNumber);
		openChunk();
		for(int j = 0; j < boneCount; j++){
			skipWord("bone");
			int boneNumber = readInt();
			Assert(j == boneNumber);
			openChunk();
			// スケール
			skipWord("scale");
			data->setScale(i, j, readVectorInterpolator());
			// 回転
			skipWord("rotation");
			data->setRotation(i, j, readRotationInterpolator());
			// 移動
			skipWord("translation");
			data->setTranslation(i, j, readVectorInterpolator());
			closeChunk();
		}
		// ループ
		skipWord("looped");
		data->setLooped(i, readBool());
		closeChunk();
	}
	closeChunk();
}
//------------------------------------------------------------------------------
// アニメーションセットリンク
//------------------------------------------------------------------------------
// アニメーションセットリンクリストの読み込み
void TextAnimationLoader::readAnimationSetLinkList(){
	openChunk();
	while(true){
		String token = readToken("readAnimationSetLinkList()");
		if(token == "}"){ break; }
		readAnimationSetLink(token);
	}
}
//------------------------------------------------------------------------------
// アニメーションセットリンクの読み込み
void TextAnimationLoader::readAnimationSetLink(const String& name){
	AnimationSet* animationSet = NULL;
	Animation* animation = manager_->search(name);
	if(animation != NULL){ animationSet = animation->castAnimationSet(); }
	if(animationSet == NULL){
		ErrorOut("TextAnimationLoader::readAnimationSetLink() "
			"not found AnimationSet %s (line %d)",
			name.getBytes(), tokenizer_->getLineNumber());
	}
	openChunk();
	while(true){
		String token = readToken("readAnimationSetLink()");
		if(token == "}"){ break; }
		// アニメーションとのリンク
		Animation* child = manager_->search(token);
		if(child == NULL){
			ErrorOut("TextAnimationLoader::readAnimationSetLink() "
				"not found animation %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		animationSet->addAnimation(child);
	}
}
//------------------------------------------------------------------------------
// カメラアニメーションリンク
//------------------------------------------------------------------------------
// カメラアニメーションリンクリスト読み込み
void TextAnimationLoader::readCameraLinkList(){
	CameraAnimation* camera;
	CameraAnimationData* cameraData;
	openChunk();
	while(true){
		String token = readToken("readCameraLinkList()");
		if(token == "}"){ break; }
		Animation* animation = manager_->search(token);
		if(animation == NULL){
			ErrorOut("TextAnimationLoader::readCameraLinkList() "
				"not found CameraAnimation %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		camera = animation->castCameraAnimation();
		if(camera == NULL){
			ErrorOut("TextAnimationLoader::readCameraLinkList() "
				"not found CameraAnimation %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		String target = readToken("readCameraLinkList()");
		AnimationData* data = manager_->searchData(target);
		if(data == NULL){
			ErrorOut("TextAnimationLoader::readCameraLinkList() "
				"not found CameraAnimationData %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		cameraData = data->castCameraAnimationData();
		if(cameraData == NULL){
			ErrorOut("TextAnimationLoader::readCameraLinkList() "
				"not found CameraAnimationData %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		camera->setCameraAnimationData(cameraData);
	}
}
//------------------------------------------------------------------------------
// シーンノードアニメーションリンク
//------------------------------------------------------------------------------
// シーンノードアニメーションリンクリスト読み込み
void TextAnimationLoader::readSceneNodeLinkList(){
	SceneNodeAnimation* sceneNode;
	SceneNodeAnimationData* sceneNodeData;
	openChunk();
	while(true){
		String token = readToken("readSceneNodeLinkList()");
		if(token == "}"){ break; }
		Animation* animation = manager_->search(token);
		if(animation == NULL){
			ErrorOut("TextAnimationLoader::readSceneNodeLinkList() "
				"not found SceneNodeAnimation %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		sceneNode = animation->castSceneNodeAnimation();
		if(sceneNode == NULL){
			ErrorOut("TextAnimationLoader::readSceneNodeLinkList() "
				"not found SceneNodeAnimation %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		String target = readToken("readSceneNodeLinkList()");
		AnimationData* data = manager_->searchData(target);
		if(data == NULL){
			ErrorOut("TextAnimationLoader::readSceneNodeLinkList() "
				"not found SceneNodeAnimationData %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		sceneNodeData = data->castSceneNodeAnimationData();
		if(sceneNodeData == NULL){
			ErrorOut("TextAnimationLoader::readSceneNodeLinkList() "
				"not found SceneNodeAnimationData %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		sceneNode->setSceneNodeAnimationData(sceneNodeData);
	}
}
//------------------------------------------------------------------------------
// キャラクタモデルアニメーションリンク
//------------------------------------------------------------------------------
// キャラクタモデルアニメーションリンクリスト読み込み
void TextAnimationLoader::readCharacterModelLinkList(){
	CharacterModelAnimation* characterModel;
	CharacterModelAnimationData* characterModelData;
	openChunk();
	while(true){
		String token = readToken("readCharacterModelLinkList()");
		if(token == "}"){ break; }
		Animation* animation = manager_->search(token);
		if(animation == NULL){
			ErrorOut("TextAnimationLoader::readCharacterModelLinkList() "
				"not found CharacterModelAnimation %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		characterModel = animation->castCharacterModelAnimation();
		if(characterModel == NULL){
			ErrorOut("TextAnimationLoader::readCharacterModelLinkList() "
				"not found CharacterModelAnimation %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		String target = readToken("readCharacterModelLinkList()");
		AnimationData* data = manager_->searchData(target);
		if(data == NULL){
			ErrorOut("TextAnimationLoader::readCharacterModelLinkList() "
				"not found CharacterModelAnimationData %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		characterModelData = data->castCharacterModelAnimationData();
		if(characterModelData == NULL){
			ErrorOut("TextAnimationLoader::readCharacterModelLinkList() "
				"not found CharacterModelAnimationData %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		characterModel->setCharacterModelAnimationData(characterModelData);
	}
}
//------------------------------------------------------------------------------
// 値の読み込み
//------------------------------------------------------------------------------
// bool値の読み込み
bool TextAnimationLoader::readBool(){
	String token = readToken("readBool()");
	if(token == "true"){ return true; }
	else if(token == "false"){ return false; }
	ErrorOut("TextAnimationLoader::readBool() invalid token %s (line %d)",
		token.getBytes(), tokenizer_->getLineNumber());
	return false;
}
//------------------------------------------------------------------------------
// int値の読み込み
int TextAnimationLoader::readInt(){
	String token = readToken("readInt()");
	int value = 0;
	bool result = token.parseInt(&value);
	if(!result){
		ErrorOut("TextAnimationLoader::readInt() invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return value;
}
//------------------------------------------------------------------------------
// float値の読み込み
float TextAnimationLoader::readFloat(){
	String token = readToken("readFloat()");
	float value = 0.f;
	bool result = token.parseFloat(&value);
	if(!result){
		ErrorOut("TextAnimationLoader::readFloat() invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return value;
}
//------------------------------------------------------------------------------
// Vector3値の読み込み
Vector3 TextAnimationLoader::readVector3(){
	Vector3 result;
	openChunk();
	result.x = readFloat();
	result.y = readFloat();
	result.z = readFloat();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// Quaternion値の読み込み
Quaternion TextAnimationLoader::readQuaternion(){
	Quaternion result;
	openChunk();
	result.x = readFloat();
	result.y = readFloat();
	result.z = readFloat();
	result.w = readFloat();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// ベクトル補間の読み込み
//------------------------------------------------------------------------------
// ベクトル補間の読み込み
VectorInterpolator* TextAnimationLoader::readVectorInterpolator(){
	String token = readToken("readVectorInterpolator()");
	// NULLチェック
	if(token.equals("NULL")){
		return NULL;
	}else if(token.equals("{")){
		// タイプチェック
		skipWord("type");
		String type = readToken("readVectorInterpolator()");
		if(type.equals("Constant")){
			return readVectorConstantInterpolator();
		}else if(type.equals("Array")){
			return readVectorArrayInterpolator();
		}else if(type.equals("Linear")){
			return readVectorLinearInterpolator();
		}else{
			ErrorOut("TextAnimationLoader::readVectorInterpolator() "
				"Unknown interpolator type %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
	}else{
		ErrorOut("TextAnimationLoader::readVectorInterpolator() "
			"invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return NULL;
}
//------------------------------------------------------------------------------
// ベクトル定数補間の読み込み
VectorInterpolator* TextAnimationLoader::readVectorConstantInterpolator(){
	VectorConstantInterpolator* interpolator = new VectorConstantInterpolator();
	skipWord("length");
	interpolator->setLength(readFloat());
	skipWord("value");
	interpolator->setValue(readVector3());
	closeChunk();
	return interpolator;
}
//------------------------------------------------------------------------------
// ベクトル配列補間の読み込み
VectorInterpolator* TextAnimationLoader::readVectorArrayInterpolator(){
	VectorArrayInterpolator* interpolator = new VectorArrayInterpolator();
	skipWord("value");
	int size = readInt();
	interpolator->setSize(size);
	openChunk();
	for(int i = 0; i < size; i++){ interpolator->setValue(i, readVector3()); }
	closeChunk();
	closeChunk();
	return interpolator;
}
//------------------------------------------------------------------------------
// ベクトル線形補間の読み込み
VectorInterpolator* TextAnimationLoader::readVectorLinearInterpolator(){
	VectorLinearInterpolator* interpolator = new VectorLinearInterpolator();
	skipWord("value");
	int keyCount = readInt();
	interpolator->setKeyCount(keyCount);
	openChunk();
	for(int i = 0; i < keyCount; i++){
		float time = readFloat();
		interpolator->setKey(i, time, readVector3());
	}
	closeChunk();
	closeChunk();
	return interpolator;
}
//------------------------------------------------------------------------------
// 回転補間の読み込み
//------------------------------------------------------------------------------
// 回転補間の読み込み
RotationInterpolator* TextAnimationLoader::readRotationInterpolator(){
	String token = readToken("readRotationInterpolator()");
	// NULLチェック
	if(token.equals("NULL")){
		return NULL;
	}else if(token.equals("{")){
		// タイプチェック
		skipWord("type");
		String type = readToken("readRotationInterpolator()");
		if(type.equals("Constant")){
			return readRotationConstantInterpolator();
		}else if(type.equals("EulerArray")){
			return readEulerArrayInterpolator();
		}else if(type.equals("QuaternionArray")){
			return readQuaternionArrayInterpolator();
		}else if(type.equals("QuaternionLinear")){
			return readQuaternionLinearInterpolator();
		}else{
			ErrorOut("TextAnimationLoader::readRotationInterpolator() "
				"Unknown interpolator type %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
	}else{
		ErrorOut("TextAnimationLoader::readRotationInterpolator() "
			"invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return NULL;
}
//------------------------------------------------------------------------------
// 回転定数補間の読み込み
RotationInterpolator* TextAnimationLoader::readRotationConstantInterpolator(){
	RotationConstantInterpolator* interpolator =
		new RotationConstantInterpolator();
	skipWord("length");
	interpolator->setLength(readFloat());
	String valueType = readToken("readRotationConstantInterpolator()");
	if(valueType.equals("quaternionValue")){
		interpolator->setQuaternion(readQuaternion());
	}else if(valueType.equals("eulerValue")){
		interpolator->setEuler(readVector3());
	}else{
		ErrorOut("TextAnimationLoader::readRotationConstantInterpolator() "
			"Unknown value type %s (line %d)",
			valueType.getBytes(), tokenizer_->getLineNumber());
	}
	closeChunk();
	return interpolator;
}
//------------------------------------------------------------------------------
// オイラー回転配列補間の読み込み
RotationInterpolator* TextAnimationLoader::readEulerArrayInterpolator(){
	EulerArrayInterpolator* interpolator =
		new EulerArrayInterpolator();
	skipWord("value");
	int size = readInt();
	interpolator->setSize(size);
	openChunk();
	for(int i = 0; i < size; i++){ interpolator->setValue(i, readVector3()); }
	closeChunk();
	closeChunk();
	return interpolator;
}
//------------------------------------------------------------------------------
// 四元数回転配列補間の読み込み
RotationInterpolator* TextAnimationLoader::readQuaternionArrayInterpolator(){
	QuaternionArrayInterpolator* interpolator =
		new QuaternionArrayInterpolator();
	skipWord("value");
	int size = readInt();
	interpolator->setSize(size);
	openChunk();
	for(int i = 0; i < size; i++){
		interpolator->setValue(i, readQuaternion());
	}
	closeChunk();
	closeChunk();
	return interpolator;
}
//------------------------------------------------------------------------------
// 四元数回転線形補間の読み込み
RotationInterpolator* TextAnimationLoader::readQuaternionLinearInterpolator(){
	QuaternionLinearInterpolator* interpolator =
		new QuaternionLinearInterpolator();
	skipWord("value");
	int keyCount = readInt();
	interpolator->setKeyCount(keyCount);
	openChunk();
	for(int i = 0; i < keyCount; i++){
		float time = readFloat();
		interpolator->setKey(i, time, readQuaternion());
	}
	closeChunk();
	closeChunk();
	return interpolator;
}
//------------------------------------------------------------------------------
// ユーティリティ
//------------------------------------------------------------------------------
// トークンの読み込み
String TextAnimationLoader::readToken(const String& caller){
	bool hasNext = tokenizer_->nextToken();
	if(!hasNext){
		ErrorOut("TextAnimationLoader::%s nothing token (line %d)",
			caller.getBytes(), tokenizer_->getLineNumber());
	}
	return tokenizer_->getToken();
}
//------------------------------------------------------------------------------
// 指定ワードの読み飛ばし
void TextAnimationLoader::skipWord(const String& word){
	String token = readToken("skipWord()");
	if(token != word){
		ErrorOut("TextAnimationLoader::skipWord(%s) "
			"invalid token %s (line %d)",
			word.getBytes(), token.getBytes(), tokenizer_->getLineNumber());
	}
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
