//------------------------------------------------------------------------------
// 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 "Graphics/InputOutput/TextSceneLoader.h"
#include "Core/InputOutput/TextFileReader.h"
#include "Core/InputOutput/StreamTokenizer.h"
#include "Core/InputOutput/FilePath.h"
#include "Core/Codec/Tga/TargaLoader.h"

#include "Graphics/Scene/Scene.h"
#include "Graphics/Fog/Fog.h"
#include "Graphics/Light/LightManager.h"
#include "Graphics/SceneNode/SceneNodeManager.h"
#include "Graphics/Model/ModelManager.h"
#include "Graphics/Mesh/MeshManager.h"
#include "Graphics/MeshData/MeshDataManager.h"
#include "Graphics/Material/MaterialManager.h"
#include "Graphics/Texture/TextureManager.h"
#include "Graphics/Picture/PictureManager.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
TextSceneLoader::TextSceneLoader(){
}
//------------------------------------------------------------------------------
// デストラクタ
TextSceneLoader::~TextSceneLoader(){
}
//------------------------------------------------------------------------------
// ロード
void TextSceneLoader::load(const String& filePath, Scene* scene){
	load(filePath, scene, scene->getRootNode());
}
//------------------------------------------------------------------------------
// ロード
void TextSceneLoader::load(const String& filePath, Scene* scene,
	SceneNode* rootNode){
	FilePath path(filePath);
	Assert(path.existFile());
	TextFileReader* textFileReader = new TextFileReader(filePath);
	load(textFileReader, scene, rootNode, path.getFolderPath());
	delete textFileReader;
}
//------------------------------------------------------------------------------
// ロード
void TextSceneLoader::load(TextReader* textReader, Scene* scene,
	const String& basePath){
	load(textReader, scene, scene->getRootNode(), basePath);
}
//------------------------------------------------------------------------------
// ロード
void TextSceneLoader::load(TextReader* textReader, Scene* scene,
	SceneNode* rootNode, const String& basePath){
	// 初期化
	basePath_ = basePath;
	tokenizer_ = new StreamTokenizer(textReader);
	scene_ = scene;
	rootNode_ = rootNode;
	sceneNodeManager_ = scene->getSceneNodeManager();
	lightManager_ = scene->getLightManager();
	modelManager_ = scene->getModelManager();
	meshManager_ = scene->getMeshManager();
	meshDataManager_ = scene->getMeshDataManager();
	materialManager_ = scene->getMaterialManager();
	textureManager_ = scene->getTextureManager();
	pictureManager_ = scene->getPictureManager();

	// ルートノードを無効にしておく
	bool rootNodeEnabled = rootNode_->isEnabled();
	rootNode_->setEnabled(false);

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

	while(true){
		// トークン読み終わり
		if(!tokenizer_->nextToken()){ break; }
		String chunkName = tokenizer_->getToken();
		if(chunkName == "Fog"){
			readFog();
		}else if(chunkName == "SceneNode"){
			readSceneNodeList();
		}else if(chunkName == "Light"){
			readLightList();
		}else if(chunkName == "Model"){
			readModelList();
		}else if(chunkName == "Mesh"){
			readMeshList();
		}else if(chunkName == "MeshData"){
			readMeshDataList();
		}else if(chunkName == "Material"){
			readMaterialList();
		}else if(chunkName == "Texture"){
			readTextureList();
		}else if(chunkName == "Picture"){
			readPictureList();
		}else if(chunkName == "SceneNodeLink"){
			readSceneNodeLinkList();
		}else if(chunkName == "ModelLink"){
			readModelLinkList();
		}else if(chunkName == "MeshLink"){
			readMeshLinkList();
		}else if(chunkName == "MaterialLink"){
			readMaterialLinkList();
		}else if(chunkName == "TextureLink"){
			readTextureLinkList();
		}else{
			ErrorOut("TextSceneLoader::load() "
				"invalid chunk %s (line %d)",
				chunkName.getBytes(), tokenizer_->getLineNumber());
		}
	}
	delete tokenizer_;

	rootNode_->setEnabled(rootNodeEnabled);
}
//------------------------------------------------------------------------------
// ヘッダの読み込み
void TextSceneLoader::readHeader(){
	skipWord("Header");
	openChunk();
	skipWord("type");
	skipWord("LampTextSceneFormat");
	skipWord("version");
	skipWord("0_9_0");
	closeChunk();
}
//------------------------------------------------------------------------------
// フォグ
//------------------------------------------------------------------------------
// フォグの読み込み
void TextSceneLoader::readFog(){
	Fog* fog = scene_->getFog();
	openChunk();
	// カラー
	skipWord("color");
	fog->setColor(readColor4c());
	// モード
	skipWord("mode");
	fog->setModeString(readToken("TextSceneLoader::readFog()"));
	// 濃度
	skipWord("density");
	fog->setDensity(readFloat());
	// ニア
	skipWord("near");
	fog->setNear(readFloat());
	// ファー
	skipWord("far");
	fog->setFar(readFloat());
	// 有効、無効
	skipWord("enabled");
	fog->setEnabled(readBool());
	closeChunk();
}
//------------------------------------------------------------------------------
// シーンノード
//------------------------------------------------------------------------------
// シーンノードリストの読み込み
void TextSceneLoader::readSceneNodeList(){
	openChunk();
	while(true){
		String token = readToken("readSceneNodeList()");
		if(token == "}"){ break; }
		// シーンノードの識別
		openChunk();
		skipWord("type");
		String type = readToken("readSceneNodeList()");
		if(type == "Standard"){
			readSceneNode(token);
		}else if(type == "LOD"){
			readLODSceneNode(token);
		}else{
			ErrorOut("TextSceneLoader::readSceneNodeList() "
				"invalid type %s (line %d)",
				type.getBytes(), tokenizer_->getLineNumber());
		}
		closeChunk();
	}
}
//------------------------------------------------------------------------------
// シーンノードの読み込み
void TextSceneLoader::readSceneNode(const String& name){
	SceneNode* sceneNode = sceneNodeManager_->createSceneNode(name);
	// スケール
	skipWord("scale");
	sceneNode->setScale(readVector3());
	// 回転
	skipWord("rotation");
	sceneNode->setRotationXYZ(readVector3());
	// 移動
	skipWord("translation");
	sceneNode->setTranslation(readVector3());
	// 有効、無効フラグ
	skipWord("enabled");
	sceneNode->setEnabled(readBool());
}
//------------------------------------------------------------------------------
// レベルオブディティールシーンノードの読み込み
void TextSceneLoader::readLODSceneNode(const String& name){
	LODSceneNode* sceneNode = sceneNodeManager_->createLODSceneNode(name);
	// スケール
	skipWord("scale");
	sceneNode->setScale(readVector3());
	// 回転
	skipWord("rotation");
	sceneNode->setRotationXYZ(readVector3());
	// 移動
	skipWord("translation");
	sceneNode->setTranslation(readVector3());
	// 有効、無効フラグ
	skipWord("enabled");
	sceneNode->setEnabled(readBool());
	// LOD分割数
	skipWord("lodThresholdCount");
	int lodThresholdCount = readInt();
	sceneNode->setLODThresholdCount(lodThresholdCount);
	// LOD分割値
	openChunk();
	for(int i = 0; i < lodThresholdCount; i++){
		sceneNode->setLODThreshold(i, readFloat());
	}
	closeChunk();
}
//------------------------------------------------------------------------------
// ライト
//------------------------------------------------------------------------------
// ライトリストの読み込み
void TextSceneLoader::readLightList(){
	openChunk();
	while(true){
		String token = readToken("readLightList()");
		if(token == "}"){ break; }
		// ライトの識別
		openChunk();
		skipWord("type");
		String type = readToken("readLightList()");
		if(type == "Ambient"){
			readAmbientLight(token);
		}else if(type == "Directional"){
			readDirectionalLight(token);
		}else if(type == "Point"){
			readPointLight(token);
		}else{
			ErrorOut("TextSceneLoader::readLightList() "
				"invalid type %s (line %d)",
				type.getBytes(), tokenizer_->getLineNumber());
		}
		closeChunk();
	}
}
//------------------------------------------------------------------------------
// ライトの読み込み
void TextSceneLoader::readLight(Light* light){
	skipWord("Light");
	openChunk();
	// ライトマスク
	skipWord("lightMask");
	light->setLightMask(readUInt());
	// 有効、無効フラグ
	skipWord("enabled");
	light->setEnabled(readBool());
	closeChunk();
}
//------------------------------------------------------------------------------
// アンビエントライトの読み込み
void TextSceneLoader::readAmbientLight(const String& name){
	AmbientLight* light = lightManager_->createAmbientLight(name);
	// ライトカラー
	skipWord("color");
	light->setColor(readColor3f());
	// ライトの読み込み
	readLight(light);
}
//------------------------------------------------------------------------------
// ディレクショナルライトの読み込み
void TextSceneLoader::readDirectionalLight(const String& name){
	DirectionalLight* light = lightManager_->createDirectionalLight(name);
	// ディフューズカラー
	skipWord("diffuse");
	light->setDiffuseColor(readColor3f());
	// スペキュラカラー
	skipWord("specular");
	light->setSpecularColor(readColor3f());
	// 方向
	skipWord("direction");
	light->setDirection(readVector3());
	// ライトの読み込み
	readLight(light);
}
//------------------------------------------------------------------------------
// ポイントライトの読み込み
void TextSceneLoader::readPointLight(const String& name){
	PointLight* light = lightManager_->createPointLight(name);
	// ディフューズカラー
	skipWord("diffuse");
	light->setDiffuseColor(readColor3f());
	// スペキュラカラー
	skipWord("specular");
	light->setSpecularColor(readColor3f());
	// 位置
	skipWord("position");
	light->setPosition(readVector3());
	// レンジ
	skipWord("range");
	light->setRange(readFloat());
	// 減衰係数
	skipWord("attenuation");
	Vector3 attenuation = readVector3();
	light->setAttenuation(attenuation.x, attenuation.y, attenuation.z);
	// ライトの読み込み
	readLight(light);
}
//------------------------------------------------------------------------------
// モデル
//------------------------------------------------------------------------------
// モデルリストの読み込み
void TextSceneLoader::readModelList(){
	openChunk();
	while(true){
		String token = readToken("readModelList()");
		if(token == "}"){ break; }
		// モデルの識別
		openChunk();
		skipWord("type");
		String type = readToken("readModelList()");
		if(type == "Standard"){
			readStandardModel(token);
		}else if(type == "Character"){
			readCharacterModel(token);
		}else{
			ErrorOut("TextSceneLoader::readModelList() "
				"invalid type %s (line %d)",
				type.getBytes(), tokenizer_->getLineNumber());
		}
		closeChunk();
	}
}
//------------------------------------------------------------------------------
// 標準モデルの読み込み
void TextSceneLoader::readStandardModel(const String& name){
	StandardModel* model = modelManager_->createStandardModel(name);
	// 有効、無効フラグ
	skipWord("enabled");
	model->setEnabled(readBool());
}
//------------------------------------------------------------------------------
// キャラクタモデルの読み込み
void TextSceneLoader::readCharacterModel(const String& name){
	CharacterModel* model = modelManager_->createCharacterModel(name);
	// 有効、無効フラグ
	skipWord("enabled");
	model->setEnabled(readBool());
	// ボーン
	skipWord("bone");
	openChunk();
	while(true){
		String boneName = readToken("TextSceneLoader::readCharacterModel()");
		if(boneName == "}"){ break; }
		readBone(model, boneName);
	}
	// ボーンリンク
	skipWord("boneLink");
	openChunk();
	while(true){
		String boneName = readToken("TextSceneLoader::readCharacterModel()");
		if(boneName == "}"){ break; }
		Bone* bone = model->searchBone(boneName);
		openChunk();
		while(true){
			String childName = readToken("TextSceneLoader::readCharacterModel()");
			if(childName == "}"){ break; }
			Bone* child = model->searchBone(childName);
			bone->addBone(child);
		}
	}
}
//------------------------------------------------------------------------------
// ボーンの読み込み
void TextSceneLoader::readBone(CharacterModel* model, const String& name){
	Bone* bone = model->createBone(name);
	openChunk();
	// ポーズ逆行列
	skipWord("inversePoseMatrix");
	skipWord("Matrix34");
	bone->setInversePoseMatrix(readMatrix34());
	// スケール
	skipWord("scale");
	bone->setScale(readVector3());
	// 回転
	skipWord("rotation");
	bone->setRotationXYZ(readVector3());
	// 移動
	skipWord("translation");
	bone->setTranslation(readVector3());
	closeChunk();
}
//------------------------------------------------------------------------------
// メッシュ
//------------------------------------------------------------------------------
// メッシュリストの読み込み
void TextSceneLoader::readMeshList(){
	openChunk();
	while(true){
		String token = readToken("readMeshList()");
		if(token == "}"){ break; }
		// メッシュの識別
		openChunk();
		skipWord("type");
		String type = readToken("readMeshList()");
		if(type == "Rigid"){
			readRigidMesh(token);
		}else if(type == "Character"){
			readCharacterMesh(token);
		}else{
			ErrorOut("TextSceneLoader::readMeshList() "
				"invalid type %s (line %d)",
				type.getBytes(), tokenizer_->getLineNumber());
		}
		closeChunk();
	}
}
//------------------------------------------------------------------------------
// 剛体メッシュの読み込み
void TextSceneLoader::readRigidMesh(const String& name){
	RigidMesh* mesh = meshManager_->createRigidMesh(name);
	// 有効、無効フラグ
	skipWord("enabled");
	mesh->setEnabled(readBool());
}
//------------------------------------------------------------------------------
// キャラクタメッシュの読み込み
void TextSceneLoader::readCharacterMesh(const String& name){
	CharacterMesh* mesh = meshManager_->createCharacterMesh(name);
	// 有効、無効フラグ
	skipWord("enabled");
	mesh->setEnabled(readBool());
}
//------------------------------------------------------------------------------
// メッシュデータ
//------------------------------------------------------------------------------
// メッシュデータリストの読み込み
void TextSceneLoader::readMeshDataList(){
	openChunk();
	while(true){
		String token = readToken("readMeshDataList()");
		if(token == "}"){ break; }
		// メッシュデータの読み込み
		readMeshData(token);
	}
}
//------------------------------------------------------------------------------
// メッシュデータの読み込み
void TextSceneLoader::readMeshData(const String& name){
	MeshData* meshData = meshDataManager_->createMeshData(name);
	openChunk();
	// バウンディングボックス
	skipWord("boundingBox");
	meshData->setBoundingBox(readAxisAlignedBox());
	// バウンディングスフィア
	skipWord("boundingSphere");
	meshData->setBoundingSphere(readSphere());
	// プリミティブタイプ
	skipWord("primitiveType");
	String primitiveType = readToken("readMeshData()");
	meshData->setPrimitiveType(Mesh::primitiveTypeFromString(primitiveType));
	// 頂点インデックスの読み出し
	if(meshData->hasVertexIndices()){
		skipWord("indices");
		int indexCount = readInt();
		meshData->setVertexIndexCount(indexCount);
		openChunk();
		for(int i = 0; i < indexCount; i++){
			meshData->setVertexIndex(i, readUShort());
		}
		closeChunk();
	}
	// 法線を持っているか
	skipWord("hasNormal");
	bool hasNormal = readBool();
	meshData->enableNormal(hasNormal);
	// 頂点カラーを持っているか
	skipWord("hasColor");
	bool hasColor = readBool();
	meshData->enableColor(hasColor);
	// テクスチャ座標セット数
	skipWord("texCoordSetCount");
	int texCoordSetCount = readInt();
	meshData->setTexCoordSetCount(texCoordSetCount);
	// テクスチャ座標タイプ
	skipWord("texCoordType");
	int texCoordType[TexCoord::maxSetCount];
	for(int i = 0; i < texCoordSetCount; i++){
		texCoordType[i] = readInt();
		meshData->setTexCoordType(i, (TexCoord::Type)texCoordType[i]);
	}
	// 頂点あたりボーン数
	skipWord("bonesPerVertex");
	int bonesPerVertex = readInt();
	meshData->setBonesPerVertex(bonesPerVertex);
	int weightsPerVertex = meshData->getWeightsPerVertex();
	// 頂点データ
	skipWord("vertices");
	int vertexCount = readInt();
	meshData->setVertexCount(vertexCount);
	openChunk();
	for(int i = 0; i < vertexCount; i++){
		int index = readInt();
		if(index != i){
			ErrorOut("TextSceneLoader::readMeshData() "
				"invalid index %d (line %d)",
				index, tokenizer_->getLineNumber());
		}
		// 位置の読み込み
		meshData->setPosition(i, readVector3());
		// 法線の読み込み
		if(hasNormal){ meshData->setNormal(i, readVector3()); }
		// 頂点カラーの読み込み
		if(hasColor){ meshData->setColor(i, readColor4c()); }
		// テクスチャ座標の読み込み
		float texCoord[4];
		for(int j = 0; j < texCoordSetCount; j++){
			openChunk();
			for(int k = 0; k < texCoordType[j]; k++){
				texCoord[k] = readFloat();
			}
			closeChunk();
			meshData->setTexCoord(i, j, texCoord, texCoordType[j]);
		}
		// ボーンインデックスの読み込み
		if(bonesPerVertex != 0){
			openChunk();
			for(int j = 0; j < bonesPerVertex; j++){
				meshData->setBoneIndex(i, j, readUChar());
			}
			closeChunk();
		}
		// ウェイトの読み込み
		if(weightsPerVertex != 0){
			openChunk();
			for(int j = 0; j < weightsPerVertex; j++){
				meshData->setWeight(i, j, readFloat());
			}
			closeChunk();
		}
	}
	closeChunk();
	closeChunk();
}
//------------------------------------------------------------------------------
// マテリアル
//------------------------------------------------------------------------------
// マテリアルリストの読み込み
void TextSceneLoader::readMaterialList(){
	openChunk();
	while(true){
		String token = readToken("readMaterialList()");
		if(token == "}"){ break; }
		// マテリアルの識別
		openChunk();
		skipWord("type");
		String type = readToken("readMaterialList()");
		if(type == "Basic"){
			readBasicMaterial(token);
		}else{
			ErrorOut("TextSceneLoader::readMaterialList() "
				"invalid type %s (line %d)",
				type.getBytes(), tokenizer_->getLineNumber());
		}
		closeChunk();
	}
}
//------------------------------------------------------------------------------
// マテリアルの読み込み
void TextSceneLoader::readMaterial(Material* material){
	skipWord("Material");
	openChunk();
	// 優先度
	skipWord("priority");
	material->setPriority(readInt());
	// ブレンドモード
	skipWord("blendMode");
	String blendMode = readToken("readMaterial()");
	material->setBlendMode(Material::blendModeFromString(blendMode));
	// アルファ値
	skipWord("alpha");
	material->setAlpha(readFloat());
	// ブレンドソース
	skipWord("blendSource");
	String blendSource = readToken("readMaterial()");
	material->setBlendSource(Material::blendStateFromString(blendSource));
	// ブレンドデスティネーション
	skipWord("blendDestination");
	String blendDestination = readToken("readMaterial()");
	material->setBlendDestination(
		Material::blendStateFromString(blendDestination));
	// Z書き込み
	skipWord("zWrite");
	material->setZWrite(readBool());
	// Zテスト
	skipWord("zTest");
	material->setZTest(readBool());
	// フォグオプション
	skipWord("fogOption");
	String fogOption = readToken("readMaterial()");
	material->setFogOption(Material::fogOptionFromString(fogOption));
	// ライトマスク
	skipWord("lightMask");
	material->setLightMask(readUInt());
	closeChunk();
}
//------------------------------------------------------------------------------
// 基本マテリアルの読み込み
void TextSceneLoader::readBasicMaterial(const String& name){
	BasicMaterial* material = materialManager_->createBasicMaterial(name);
	// ベースUVインデックス
	skipWord("baseUVIndex");
	material->setBaseUVIndex(readInt());
	// 光沢UVインデックス
	skipWord("glossUVIndex");
	material->setGlossUVIndex(readInt());
	// ライトUVインデックス
	skipWord("lightUVIndex");
	material->setLightUVIndex(readInt());
	// 汚れUVインデックス
	skipWord("stainUVIndex");
	material->setStainUVIndex(readInt());

	// ディフューズカラー
	skipWord("diffuseColor");
	material->setDiffuseColor(readColor3f());
	// スペキュラカラー
	skipWord("specularColor");
	material->setSpecularColor(readColor3f());
	// スペキュラパワー
	skipWord("specularPower");
	material->setSpecularPower(readFloat());
	// アンビエントカラー
	skipWord("ambientColor");
	material->setAmbientColor(readColor3f());
	// エミッシブカラー
	skipWord("emissiveColor");
	material->setEmissiveColor(readColor3f());
	// マテリアルの読み込み
	readMaterial(material);
}
//------------------------------------------------------------------------------
// テクスチャ
//------------------------------------------------------------------------------
// テクスチャリストの読み込み
void TextSceneLoader::readTextureList(){
	openChunk();
	while(true){
		String token = readToken("readTextureList()");
		if(token == "}"){ break; }
		// テクスチャの識別
		openChunk();
		skipWord("type");
		String type = readToken("readTextureList()");
		if(type == "Surface"){
			readSurfaceTexture(token);
		}else{
			ErrorOut("TextSceneLoader::readTextureList() "
				"invalid type %s (line %d)",
				type.getBytes(), tokenizer_->getLineNumber());
		}
		closeChunk();
	}
}
//------------------------------------------------------------------------------
// サーフェーステクスチャの読み込み
void TextSceneLoader::readSurfaceTexture(const String& name){
	SurfaceTexture* texture = textureManager_->createSurfaceTexture(name);
	// アドレスモードU
	skipWord("addressModeU");
	String addressModeU = readToken("readSurfaceTexture()");
	texture->setAddressModeU(Texture::addressModeFromString(addressModeU));
	// アドレスモードV
	skipWord("addressModeV");
	String addressModeV = readToken("readSurfaceTexture()");
	texture->setAddressModeV(Texture::addressModeFromString(addressModeV));
	// リピートUV
	skipWord("repeatUV");
	texture->setRepeatUV(readTexCoord2());
	// オフセットUV
	skipWord("offsetUV");
	texture->setOffsetUV(readTexCoord2());
}
//------------------------------------------------------------------------------
// ピクチャ
//------------------------------------------------------------------------------
// ピクチャリストの読み込み
void TextSceneLoader::readPictureList(){
	openChunk();
	while(true){
		String token = readToken("readPictureList()");
		if(token == "}"){ break; }
		openChunk();
		skipWord("path");
		String path = readToken("readPictureList()");
		closeChunk();
		// 拡張子を取得
		FilePath filePath(path);
		String extension = filePath.getExtension();
		// 拡張子にあわせてピクチャを読み分ける
		Picture* picture;
		if(extension == "tga"){
			TargaLoader loader(basePath_ + path);
			loader.loadHeader();
			// アルファの有無
			if(loader.hasAlpha()){
				picture = readPictureRGBA8(token, loader);
			}else{
				picture = readPictureRGB8(token, loader);
			}
		}else{
			ErrorOut("TextSceneLoader::readPictureList() "
				"Unsupported picture format %s (line %d)",
				path.getBytes(), tokenizer_->getLineNumber());
			return;
		}
		// パスを設定する
		picture->setPath(path);
	}
}
//------------------------------------------------------------------------------
// RGB8ビットピクチャの読み込み
Picture* TextSceneLoader::readPictureRGB8(
	const String& name, TargaLoader& loader){
	PictureRGB8* picture = pictureManager_->createPictureRGB8(name);
	picture->setSize(loader.getSize());
	loader.loadImage(picture->getImageBuffer());
	return picture;
}
//------------------------------------------------------------------------------
// RGBA8ビットピクチャの読み込み
Picture* TextSceneLoader::readPictureRGBA8(
	const String& name, TargaLoader& loader){
	PictureRGBA8* picture = pictureManager_->createPictureRGBA8(name);
	picture->setSize(loader.getSize());
	loader.loadImage(picture->getImageBuffer());
	return picture;
}
//------------------------------------------------------------------------------
// シーンノードリンク
//------------------------------------------------------------------------------
// シーンノードリンクリストの読み込み
void TextSceneLoader::readSceneNodeLinkList(){
	openChunk();
	while(true){
		String token = readToken("readSceneNodeLinkList()");
		if(token == "}"){ break; }
		readSceneNodeLink(token);
	}
}
//------------------------------------------------------------------------------
// シーンノードリンクの読み込み
void TextSceneLoader::readSceneNodeLink(const String& name){
	SceneNode* sceneNode;
	if(name.equals("RootNode")){
		sceneNode = rootNode_;
	}else{
		sceneNode = sceneNodeManager_->search(name);
		if(sceneNode == NULL){
			ErrorOut("TextSceneLoader::readSceneNodeLink() "
				"not found sceneNode %s (line %d)",
				name.getBytes(), tokenizer_->getLineNumber());
		}
	}

	openChunk();
	while(true){
		String token = readToken("readSceneNodeLink()");
		if(token == "}"){ break; }
		if(token == "SceneNode"){
			// シーンノードリンク
			openChunk();
			while(true){
				String subToken = readToken("readSceneNodeLink()");
				if(subToken == "}"){ break; }
				SceneNode* childNode = sceneNodeManager_->search(subToken);
				if(childNode == NULL){
					ErrorOut("TextSceneLoader::readSceneNodeLink() "
						"not found sceneNode %s (line %d)",
						subToken.getBytes(), tokenizer_->getLineNumber());
				}
				sceneNode->addSceneNode(childNode);
			}
		}else if(token == "SceneLeaf"){
			// シーンリーフリンク
			openChunk();
			while(true){
				String subToken = readToken("readSceneNodeLink()");
				if(subToken == "}"){ break; }
				SceneLeaf* sceneLeaf = NULL;
				String sceneLeafName = readToken("readSceneNodeLink()");
				if(subToken.equals("Model")){
					sceneLeaf = modelManager_->search(sceneLeafName);
				}else if(subToken.equals("Light")){
					sceneLeaf = lightManager_->search(sceneLeafName);
				}else{
					ErrorOut("TextSceneLoader::readSceneNodeLink() "
						"unsupported type %s (line %d)",
						subToken.getBytes(), tokenizer_->getLineNumber());
				}
				if(sceneLeaf == NULL){
					ErrorOut("TextSceneLoader::readSceneNodeLink() "
						"not found sceneLeaf %s (line %d)",
						sceneLeafName.getBytes(), tokenizer_->getLineNumber());
				}
				sceneNode->addSceneLeaf(sceneLeaf);
			}
		}else{
			ErrorOut("TextSceneLoader::readSceneNodeLink() "
				"invalid token %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
	}
}
//------------------------------------------------------------------------------
// モデルリンク
//------------------------------------------------------------------------------
// モデルリンクリストの読み込み
void TextSceneLoader::readModelLinkList(){
	openChunk();
	while(true){
		String token = readToken("readModelLinkList()");
		if(token == "}"){ break; }
		readModelLink(token);
	}
}
//------------------------------------------------------------------------------
// モデルリンクの読み込み
void TextSceneLoader::readModelLink(const String& name){
	Model* model = modelManager_->search(name);
	if(model == NULL){
		ErrorOut("TextSceneLoader::readModelLink() "
			"not found model %s (line %d)",
			name.getBytes(), tokenizer_->getLineNumber());
	}
	openChunk();
	while(true){
		String token = readToken("readModelLink()");
		if(token == "}"){ break; }
		// メッシュとのリンク
		Mesh* mesh = meshManager_->search(token);
		if(mesh == NULL){
			ErrorOut("TextSceneLoader::readModelLink() "
				"not found mesh %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		model->addMesh(mesh);
	}
}
//------------------------------------------------------------------------------
// メッシュリンク
//------------------------------------------------------------------------------
// メッシュリンクリストの読み込み
void TextSceneLoader::readMeshLinkList(){
	openChunk();
	while(true){
		String token = readToken("readMeshLinkList()");
		if(token == "}"){ break; }
		readMeshLink(token);
	}
}
//------------------------------------------------------------------------------
// メッシュリンクの読み込み
void TextSceneLoader::readMeshLink(const String& name){
	Mesh* mesh = meshManager_->search(name);
	if(mesh == NULL){
		ErrorOut("TextSceneLoader::readMeshLink() "
			"not found mesh %s (line %d)",
			name.getBytes(), tokenizer_->getLineNumber());
	}
	openChunk();
	while(true){
		String token = readToken("readMeshLink()");
		if(token == "}"){ break; }
		if(token == "MeshData"){
			// メッシュデータとのリンク
			String subToken = readToken("readMeshLink()");
			MeshData* meshData = meshDataManager_->search(subToken);
			if(meshData == NULL){
				ErrorOut("TextSceneLoader::readMeshLink() "
					"not found meshData %s (line %d)",
					subToken.getBytes(), tokenizer_->getLineNumber());
			}
			mesh->setMeshData(meshData);
		}else if(token == "Material"){
			// マテリアルとのリンク
			String subToken = readToken("readMeshLink()");
			Material* material = materialManager_->search(subToken);
			if(material == NULL){
				ErrorOut("TextSceneLoader::readMeshLink() "
					"not found material %s (line %d)",
					subToken.getBytes(), tokenizer_->getLineNumber());
			}
			mesh->setMaterial(material);
		}else{
			ErrorOut("TextSceneLoader::readMeshLink() "
				"invalid token %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
	}
}
//------------------------------------------------------------------------------
// マテリアルリンク
//------------------------------------------------------------------------------
// マテリアルリンクリストの読み込み
void TextSceneLoader::readMaterialLinkList(){
	openChunk();
	while(true){
		String token = readToken("readMaterialLinkList()");
		if(token == "}"){ break; }
		openChunk();
		skipWord("type");
		String type = readToken("readMaterialLinkList()");
		if(type == "Basic"){
			readBasicMaterialLink(token);
		}else{
			ErrorOut("TextSceneLoader::readMaterialLinkList() "
				"invalid type %s (line %d)",
				type.getBytes(), tokenizer_->getLineNumber());
		}
	}
}
//------------------------------------------------------------------------------
// マテリアルリンクの読み込み
void TextSceneLoader::readBasicMaterialLink(const String& name){
	BasicMaterial* material =
		materialManager_->search(name)->castBasicMaterial();
	if(material == NULL){
		ErrorOut("TextSceneLoader::readBasicMaterialLink() "
			"not found material %s (line %d)",
			name.getBytes(), tokenizer_->getLineNumber());
	}
	while(true){
		String token = readToken("readMaterialLink()");
		if(token == "}"){ break; }
		if(token == "baseTexture"){
			// ベーステクスチャとのリンク
			String textureName = readToken("readBasicMaterialLink()");
			Texture* texture = textureManager_->search(textureName);
			if(texture == NULL){
				ErrorOut("TextSceneLoader::readBasicMaterialLink() "
					"not found baseTexture %s (line %d)",
					textureName.getBytes(), tokenizer_->getLineNumber());
			}
			material->setBaseTexture(texture);
		}else if(token == "glossTexture"){
			// 光沢テクスチャとのリンク
			String textureName = readToken("readBasicMaterialLink()");
			Texture* texture = textureManager_->search(textureName);
			if(texture == NULL){
				ErrorOut("TextSceneLoader::readBasicMaterialLink() "
					"not found glossTexture %s (line %d)",
					textureName.getBytes(), tokenizer_->getLineNumber());
			}
			material->setGlossTexture(texture);
		}else if(token == "lightTexture"){
			// ライトテクスチャとのリンク
			String textureName = readToken("readBasicMaterialLink()");
			Texture* texture = textureManager_->search(textureName);
			if(texture == NULL){
				ErrorOut("TextSceneLoader::readBasicMaterialLink() "
					"not found lightTexture %s (line %d)",
					textureName.getBytes(), tokenizer_->getLineNumber());
			}
			material->setLightTexture(texture);
		}else if(token == "stainTexture"){
			// 汚れテクスチャとのリンク
			String textureName = readToken("readBasicMaterialLink()");
			Texture* texture = textureManager_->search(textureName);
			if(texture == NULL){
				ErrorOut("TextSceneLoader::readBasicMaterialLink() "
					"not found stainTexture %s (line %d)",
					textureName.getBytes(), tokenizer_->getLineNumber());
			}
			material->setStainTexture(texture);
		}else{
			ErrorOut("TextSceneLoader::readBasicMaterialLink() "
				"invalid token %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
	}
}
//------------------------------------------------------------------------------
// テクスチャリンク
//------------------------------------------------------------------------------
// テクスチャリンクリストの読み込み
void TextSceneLoader::readTextureLinkList(){
	openChunk();
	while(true){
		String token = readToken("readTextureLinkList()");
		if(token == "}"){ break; }
		readTextureLink(token);
	}
}
//------------------------------------------------------------------------------
// テクスチャリンクの読み込み
void TextSceneLoader::readTextureLink(const String& name){
	Texture* texture = textureManager_->search(name);
	if(texture == NULL){
		ErrorOut("TextSceneLoader::readTextureLink() "
			"not found texture %s (line %d)",
			name.getBytes(), tokenizer_->getLineNumber());
	}
	openChunk();
	while(true){
		String token = readToken("readTextureLink()");
		if(token == "}"){ break; }
		// ピクチャとのリンク
		Picture* picture = pictureManager_->search(token);
		if(picture == NULL){
			ErrorOut("TextSceneLoader::readTextureLink() "
				"not found picture %s (line %d)",
				token.getBytes(), tokenizer_->getLineNumber());
		}
		texture->addPicture(picture);
	}
}
//------------------------------------------------------------------------------
// 値の読み込み
//------------------------------------------------------------------------------
// bool値の読み込み
bool TextSceneLoader::readBool(){
	String token = readToken("readBool()");
	if(token == "true"){ return true; }
	else if(token == "false"){ return false; }
	ErrorOut("TextSceneLoader::readBool() invalid token %s (line %d)",
		token.getBytes(), tokenizer_->getLineNumber());
	return false;
}
//------------------------------------------------------------------------------
// u_char値の読み込み
u_char TextSceneLoader::readUChar(){
	String token = readToken("readUChar()");
	u_char value = 0;
	bool result = token.parseUChar(&value);
	if(!result){
		ErrorOut("TextSceneLoader::readUChar() invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return value;
}
//------------------------------------------------------------------------------
// u_short値の読み込み
u_short TextSceneLoader::readUShort(){
	String token = readToken("readUShort()");
	u_short value = 0;
	bool result = token.parseUShort(&value);
	if(!result){
		ErrorOut("TextSceneLoader::readUShort() invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return value;
}
//------------------------------------------------------------------------------
// int値の読み込み
int TextSceneLoader::readInt(){
	String token = readToken("readInt()");
	int value = 0;
	bool result = token.parseInt(&value);
	if(!result){
		ErrorOut("TextSceneLoader::readInt() invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return value;
}
//------------------------------------------------------------------------------
// u_int値の読み込み
u_int TextSceneLoader::readUInt(){
	String token = readToken("readInt()");
	u_int value = 0;
	bool result = token.parseUInt(&value);
	if(!result){
		ErrorOut("TextSceneLoader::readUInt() invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return value;
}
//------------------------------------------------------------------------------
// float値の読み込み
float TextSceneLoader::readFloat(){
	String token = readToken("readFloat()");
	float value = 0.f;
	bool result = token.parseFloat(&value);
	if(!result){
		ErrorOut("TextSceneLoader::readFloat() invalid token %s (line %d)",
			token.getBytes(), tokenizer_->getLineNumber());
	}
	return value;
}
//------------------------------------------------------------------------------
// Vector3値の読み込み
Vector3 TextSceneLoader::readVector3(){
	Vector3 result;
	openChunk();
	result.x = readFloat();
	result.y = readFloat();
	result.z = readFloat();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// Matrix34値の読み込み
Matrix34 TextSceneLoader::readMatrix34(){
	Matrix34 result;
	openChunk();
	for(int i = 0; i < 12; i++){
		result.array[i] = readFloat();
	}
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// 三要素整数カラー値の読み込み
Color3c TextSceneLoader::readColor3c(){
	Color3c result;
	openChunk();
	result.r = readUChar();
	result.g = readUChar();
	result.b = readUChar();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// 四要素整数カラー値の読み込み
Color4c TextSceneLoader::readColor4c(){
	Color4c result;
	openChunk();
	result.r = readUChar();
	result.g = readUChar();
	result.b = readUChar();
	result.a = readUChar();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// 三要素実数カラー値の読み込み
Color3f TextSceneLoader::readColor3f(){
	Color3f result;
	openChunk();
	result.r = readFloat();
	result.g = readFloat();
	result.b = readFloat();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// 四要素実数カラー値の読み込み
Color4f TextSceneLoader::readColor4f(){
	Color4f result;
	openChunk();
	result.r = readFloat();
	result.g = readFloat();
	result.b = readFloat();
	result.a = readFloat();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// 二次元テクスチャ座標値の読み込み
TexCoord2 TextSceneLoader::readTexCoord2(){
	TexCoord2 result;
	openChunk();
	result.u = readFloat();
	result.v = readFloat();
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// 軸沿いボックスの読み込み
AxisAlignedBox TextSceneLoader::readAxisAlignedBox(){
	AxisAlignedBox result;
	Vector3 minimum, maximum;
	openChunk();
	minimum.x = readFloat();
	minimum.y = readFloat();
	minimum.z = readFloat();
	closeChunk();
	openChunk();
	maximum.x = readFloat();
	maximum.y = readFloat();
	maximum.z = readFloat();
	closeChunk();
	result.set(minimum, maximum);
	return result;
}
//------------------------------------------------------------------------------
// 球の読み込み
Sphere TextSceneLoader::readSphere(){
	Sphere result;
	Vector3 vector;
	openChunk();
	vector.x = readFloat();
	vector.y = readFloat();
	vector.z = readFloat();
	result.setCenter(vector);
	result.setRadius(readFloat());
	closeChunk();
	return result;
}
//------------------------------------------------------------------------------
// ユーティリティ
//------------------------------------------------------------------------------
// トークンの読み込み
String TextSceneLoader::readToken(const String& caller){
	bool hasNext = tokenizer_->nextToken();
	if(!hasNext){
		ErrorOut("TextSceneLoader::%s nothing token (line %d)",
			caller.getBytes(), tokenizer_->getLineNumber());
	}
	return tokenizer_->getToken();
}
//------------------------------------------------------------------------------
// 指定ワードの読み飛ばし
void TextSceneLoader::skipWord(const String& word){
	String token = readToken("skipWord()");
	if(token != word){
		ErrorOut("TextSceneLoader::skipWord(%s) invalid token %s (line %d)",
			word.getBytes(), token.getBytes(), tokenizer_->getLineNumber());
	}
}
//------------------------------------------------------------------------------
// チャンクの読み飛ばし
void TextSceneLoader::skipChunk(){
	int chunkLine = tokenizer_->getLineNumber();
	int chunkCounter = 0;
	while(true){
		bool hasNext = tokenizer_->nextToken();
		if(!hasNext){
			ErrorOut("TextSceneLoader::skipChunk(%d) nothing token (line %d)",
				chunkLine, tokenizer_->getLineNumber());
		}
		String token = tokenizer_->getToken();
		if(token == "{"){
			chunkCounter++;
		}else if(token == "}"){
			chunkCounter--;
			// デクリメント時にループを抜けるチェックを行う
			if(chunkCounter == 0){ break; }
			if(chunkCounter < 0){
				ErrorOut("TextSceneLoader::skipChunk(%d) "
					"invalid chunk (line %d)",
					chunkLine, tokenizer_->getLineNumber());
			}
		}
	}
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
