//------------------------------------------------------------------------------
// 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 <direct.h>
#include "Graphics/InputOutput/TextSceneSaver.h"
#include "Core/InputOutput/TextFileWriter.h"
#include "Core/InputOutput/FilePath.h"
#include "Core/Codec/Tga/TargaSaver.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{

//------------------------------------------------------------------------------
// コンストラクタ
TextSceneSaver::TextSceneSaver(){
}
//------------------------------------------------------------------------------
// デストラクタ
TextSceneSaver::~TextSceneSaver(){
}
//------------------------------------------------------------------------------
// セーブ
void TextSceneSaver::save(const String& filePath, Scene* scene){
	FilePath path(filePath);
	TextFileWriter* textFileWriter = new TextFileWriter(filePath);
	save(textFileWriter, scene, path.getFolderPath());
	delete textFileWriter;
}
//------------------------------------------------------------------------------
// セーブ
void TextSceneSaver::save(TextWriter* textWriter, Scene* scene,
	const String& basePath){
	writer_ = textWriter;
	basePath_ = basePath;
	scene_ = scene;
	sceneNodeManager_ = scene->getSceneNodeManager();
	lightManager_ = scene->getLightManager();
	modelManager_ = scene->getModelManager();
	meshManager_ = scene->getMeshManager();
	meshDataManager_ = scene->getMeshDataManager();
	materialManager_ = scene->getMaterialManager();
	textureManager_ = scene->getTextureManager();
	pictureManager_ = scene->getPictureManager();

	// ヘッダの書き出し
	writeHeader();

	// オブジェクトリストの書き出し
	int objectCount = writeObjectList();

	// リンクの書き出し
	writeLink(objectCount);
}
//------------------------------------------------------------------------------
// ヘッダの書き出し
void TextSceneSaver::writeHeader(){
	writeBlockComment("Header");
	writer_->writeText("Header {\n");
	writer_->writeText("\ttype LampTextSceneFormat\n");
	writer_->writeText("\tversion 0_9_0\n");
	writer_->writeText("}\n\n");
}
//------------------------------------------------------------------------------
// オブジェクトリストの書き出し
int TextSceneSaver::writeObjectList(){
	int objectCount = 0;

	// フォグの書き出し
	writeFog(scene_->getFog());

	// シーンノードリストの書き出し
	int sceneNodeCount = sceneNodeManager_->getCount();
	if(sceneNodeCount > 1){// ルートノードは出力しないので2以上
		writeBlockComment("SceneNode");
		writer_->writeText("SceneNode {\n");
		writeSceneNodeList();
		writer_->writeText("}\n\n");
	}
	objectCount += sceneNodeCount;

	// ライトリストの書き出し
	int lightCount = lightManager_->getCount();
	if(lightCount > 0){
		writeBlockComment("Light");
		writer_->writeText("Light {\n");
		writeLightList();
		writer_->writeText("}\n\n");
	}
	// 現在オブジェクトカウントはリンクのために使用されているので
	// ライトはオブジェクト数にカウントしない

	// モデルリストの書き出し
	int modelCount = modelManager_->getCount();
	if(modelCount > 0){
		writeBlockComment("Model");
		writer_->writeText("Model {\n");
		writeModelList();
		writer_->writeText("}\n\n");
	}
	objectCount += modelCount;

	// メッシュリストの書き出し
	int meshCount = meshManager_->getCount();
	if(meshCount > 0){
		writeBlockComment("Mesh");
		writer_->writeText("Mesh {\n");
		writeMeshList();
		writer_->writeText("}\n\n");
	}
	objectCount += meshCount;

	// メッシュデータリストの書き出し
	int meshDataCount = meshDataManager_->getCount();
	if(meshDataCount > 0){
		writeBlockComment("MeshData");
		writer_->writeText("MeshData {\n");
		writeMeshDataList();
		writer_->writeText("}\n\n");
	}
	objectCount += meshDataCount;

	// マテリアルリストの書き出し
	int materialCount = materialManager_->getCount();
	if(materialCount > 0){
		writeBlockComment("Material");
		writer_->writeText("Material {\n");
		writeMaterialList();
		writer_->writeText("}\n\n");
	}
	objectCount += materialCount;

	// テクスチャリストの書き出し
	int textureCount = textureManager_->getCount();
	if(textureCount > 0){
		writeBlockComment("Texture");
		writer_->writeText("Texture {\n");
		writeTextureList();
		writer_->writeText("}\n\n");
	}
	objectCount += textureCount;

	// ピクチャリストの書き出し
	int pictureCount = pictureManager_->getCount();
	if(pictureCount > 0){
		writeBlockComment("Picture");
		writer_->writeText("Picture {\n");
		for(int i = 0; i < pictureCount; i++){
			writePicture(pictureManager_->get(i));
		}
		writer_->writeText("}\n\n");
	}
	objectCount += pictureCount;

	return objectCount;
}
//------------------------------------------------------------------------------
// リンクの書き出し
void TextSceneSaver::writeLink(int objectCount){
	// オブジェクトが2個以上ならリンクが存在する
	if(objectCount > 1){ writeBlockComment("Link"); }

	// シーンノードリンクの書き出し
	int sceneNodeCount = sceneNodeManager_->getCount();
	if(sceneNodeCount > 1){
		writer_->writeText("SceneNodeLink {\n");
		for(int i = 0; i < sceneNodeCount; i++){
			writeSceneNodeLink(sceneNodeManager_->get(i));
		}
		writer_->writeText("}\n\n");
		writeLineComment();
	}

	// モデルリンクの書き出し
	int modelCount = modelManager_->getCount();
	if(modelCount > 0){
		writer_->writeText("ModelLink {\n");
		for(int i = 0; i < modelCount; i++){
			writeModelLink(modelManager_->get(i));
		}
		writer_->writeText("}\n\n");
		writeLineComment();
	}

	// メッシュリンクの書き出し
	int meshCount = meshManager_->getCount();
	if(meshCount > 0){
		writer_->writeText("MeshLink {\n");
		for(int i = 0; i < meshCount; i++){
			writeMeshLink(meshManager_->get(i));
		}
		writer_->writeText("}\n\n");
		writeLineComment();
	}

	// マテリアルテクスチャリンクの書き出し
	// テクスチャが存在すればマテリアルからのリンクがある
	int textureCount = textureManager_->getCount();
	if(textureCount > 0){
		writeMaterialLinkList();
		writeLineComment();
	}

	// テクスチャリンクの書き出し
	if(textureCount > 0){
		writer_->writeText("TextureLink {\n");
		for(int i = 0; i < textureCount; i++){
			writeTextureLink(textureManager_->get(i));
		}
		writer_->writeText("}\n\n");
		writeLineComment();
	}
}
//------------------------------------------------------------------------------
// フォグ
//------------------------------------------------------------------------------
// フォグの書き出し
void TextSceneSaver::writeFog(Fog* fog){
	writeBlockComment("Fog");
	writer_->writeText("Fog {\n");
	// カラー
	Color4c color = fog->getColor();
	writer_->writeFormat("\tcolor { %d %d %d %d }\n",
		color.r, color.g, color.b, color.a);
	// モード
	writer_->writeFormat("\tmode %s\n", fog->getModeString());
	// 濃度
	writer_->writeFormat("\tdensity %.8f\n", fog->getDensity());
	// ニア
	writer_->writeFormat("\tnear %.8f\n", fog->getNear());
	// ファー
	writer_->writeFormat("\tfar %.8f\n", fog->getFar());
	// 有効、無効
	writer_->writeText("\tenabled ");
	writeBool(fog->isEnabled());
	writer_->writeText("\n}\n\n");
}
//------------------------------------------------------------------------------
// シーンノード
//------------------------------------------------------------------------------
// シーンノードリストの書き出し
void TextSceneSaver::writeSceneNodeList(){
	int sceneNodeCount = sceneNodeManager_->getCount();
	// ルートノードは出力しない
	for(int i = 1; i < sceneNodeCount; i++){
		SceneNode* sceneNode = sceneNodeManager_->get(i);
		if(sceneNode->isLODSceneNode()){
			writeLODSceneNode(sceneNode->castLODSceneNode());
		}else{
			writeSceneNode(sceneNode);
		}
	}
}
//------------------------------------------------------------------------------
// シーンノードの書き出し
void TextSceneSaver::writeSceneNode(SceneNode* sceneNode){
	writer_->writeText("\t");
	writer_->writeText(sceneNode->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Standard\n");
	// スケール
	Vector3 scale = sceneNode->getScale();
	writer_->writeFormat("\t\tscale { %.8f %.8f %.8f }\n",
		scale.x, scale.y, scale.z);
	// 回転
	Vector3 rotation = sceneNode->getRotationXYZ();
	writer_->writeFormat("\t\trotation { %.8f %.8f %.8f }\n",
		rotation.x, rotation.y, rotation.z);
	// 移動
	Vector3 translation = sceneNode->getTranslation();
	writer_->writeFormat("\t\ttranslation { %.8f %.8f %.8f }\n",
		translation.x, translation.y, translation.z);
	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(sceneNode->isEnabled());
	writer_->writeText("\n\t}\n\n");
}
//------------------------------------------------------------------------------
// レベルオブディティールシーンノードの書き出し
void TextSceneSaver::writeLODSceneNode(LODSceneNode* sceneNode){
	writer_->writeText("\t");
	writer_->writeText(sceneNode->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype LOD\n");
	// スケール
	Vector3 scale = sceneNode->getScale();
	writer_->writeFormat("\t\tscale { %.8f %.8f %.8f }\n",
		scale.x, scale.y, scale.z);
	// 回転
	Vector3 rotation = sceneNode->getRotationXYZ();
	writer_->writeFormat("\t\trotation { %.8f %.8f %.8f }\n",
		rotation.x, rotation.y, rotation.z);
	// 移動
	Vector3 translation = sceneNode->getTranslation();
	writer_->writeFormat("\t\ttranslation { %.8f %.8f %.8f }\n",
		translation.x, translation.y, translation.z);
	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(sceneNode->isEnabled());
	writer_->writeText("\n");
	// LOD分割数
	int lodThresholdCount = sceneNode->getLODThresholdCount();
	writer_->writeFormat("\t\tlodThresholdCount %d {\n", lodThresholdCount);
	// LOD分割値
	for(int i = 0; i < lodThresholdCount; i++){
		writer_->writeFormat("\t\t\t%.8f\n", sceneNode->getLODThreshold(i));
	}
	writer_->writeText("\t\t}\n");
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// ライト
//------------------------------------------------------------------------------
// ライトリストの書き出し
void TextSceneSaver::writeLightList(){
	int lightCount = lightManager_->getCount();
	for(int i = 0; i < lightCount; i++){
		Light* light = lightManager_->get(i);
		if(light->isAmbientLight()){
			writeAmbientLight(light->castAmbientLight());
		}else if(light->isDirectionalLight()){
			writeDirectionalLight(light->castDirectionalLight());
		}else if(light->isPointLight()){
			writePointLight(light->castPointLight());
		}else{
			ErrorOut("TextSceneSaver::writeLightList() unsupported light %s",
				light->getName().getBytes());
		}
	}
}
//------------------------------------------------------------------------------
// ライトの書き出し
void TextSceneSaver::writeLight(Light* light){
	writer_->writeText("\t\tLight {\n");
	// ライトマスク
	writer_->writeFormat("\t\t\tlightMask %u\n", light->getLightMask());
	// 有効、無効
	writer_->writeText("\t\t\tenabled ");
	writeBool(light->isEnabled());
	writer_->writeText("\n\t\t}\n");
}
//------------------------------------------------------------------------------
// アンビエントライトの書き出し
void TextSceneSaver::writeAmbientLight(AmbientLight* light){
	writer_->writeText("\t");
	writer_->writeText(light->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Ambient\n");
	// カラー
	Color3f color = light->getColor();
	writer_->writeFormat("\t\tcolor { %.8f %.8f %.8f }\n",
		color.r, color.g, color.b);
	// ライトの書き出し
	writeLight(light);
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// ディレクショナルライトの書き出し
void TextSceneSaver::writeDirectionalLight(DirectionalLight* light){
	writer_->writeText("\t");
	writer_->writeText(light->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Directional\n");
	// ディフューズカラー
	Color3f diffuse = light->getDiffuseColor();
	writer_->writeFormat("\t\tdiffuse { %.8f %.8f %.8f }\n",
		diffuse.r, diffuse.g, diffuse.b);
	// スペキュラカラー
	Color3f	specular = light->getSpecularColor();
	writer_->writeFormat("\t\tspecular { %.8f %.8f %.8f }\n",
		specular.r, specular.g, specular.b);
	// 方向
	Vector3 direction = light->getDirection();
	writer_->writeFormat("\t\tdirection { %.8f %.8f %.8f }\n",
		direction.x, direction.y, direction.z);
	// ライトの書き出し
	writeLight(light);
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// ポイントライトの書き出し
void TextSceneSaver::writePointLight(PointLight* light){
	writer_->writeText("\t");
	writer_->writeText(light->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Point\n");
	// ディフューズカラー
	Color3f diffuse = light->getDiffuseColor();
	writer_->writeFormat("\t\tdiffuse { %.8f %.8f %.8f }\n",
		diffuse.r, diffuse.g, diffuse.b);
	// スペキュラカラー
	Color3f	specular = light->getSpecularColor();
	writer_->writeFormat("\t\tspecular { %.8f %.8f %.8f }\n",
		specular.r, specular.g, specular.b);
	// 位置
	Vector3 position = light->getPosition();
	writer_->writeFormat("\t\tposition { %.8f %.8f %.8f }\n",
		position.x, position.y, position.z);
	// レンジ
	writer_->writeFormat("\t\trange %.8f\n", light->getRange());
	// 減衰係数
	writer_->writeFormat("\t\tattenuation { %.8f %.8f %.8f }\n",
		light->getAttenuation0(), light->getAttenuation1(),
		light->getAttenuation2());
	// ライトの書き出し
	writeLight(light);
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// モデル
//------------------------------------------------------------------------------
// モデルリストの書き出し
void TextSceneSaver::writeModelList(){
	int modelCount = modelManager_->getCount();
	for(int i = 0; i < modelCount; i++){
		Model* model = modelManager_->get(i);
		if(model->isStandardModel()){
			writeStandardModel(model->castStandardModel());
		}else if(model->isCharacterModel()){
			writeCharacterModel(model->castCharacterModel());
		}else{
			ErrorOut("TextSceneSaver::writeModelList() unsupported model %s",
				model->getName().getBytes());
		}
	}
}
//------------------------------------------------------------------------------
// 標準モデルの書き出し
void TextSceneSaver::writeStandardModel(StandardModel* model){
	writer_->writeText("\t");
	writer_->writeText(model->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Standard\n");
	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(model->isEnabled());
	writer_->writeText("\n\t}\n\n");
}
//------------------------------------------------------------------------------
// キャラクタモデルの書き出し
void TextSceneSaver::writeCharacterModel(CharacterModel* model){
	writer_->writeText("\t");
	writer_->writeText(model->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Character\n");
	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(model->isEnabled());
	// ボーンの書き出し
	writer_->writeText("\n\t\tbone {\n");
	int boneCount = model->getBoneCount();
	for(int i = 0; i < boneCount; i++){
		writeBone(model->getBone(i));
	}
	writer_->writeText("\t\t}\n");
	// ボーンリンクの書き出し
	writer_->writeText("\t\tboneLink {\n");
	for(int i = 0; i < boneCount; i++){
		writeBoneLink(model->getBone(i));
	}
	writer_->writeText("\t\t}\n");
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// ボーンの書き出し
void TextSceneSaver::writeBone(Bone* bone){
	writer_->writeText("\t\t\t");
	writer_->writeText(bone->getName());
	writer_->writeText(" {\n");
	// ポーズ逆行列
	Matrix34 invPose = bone->getInversePoseMatrix();
	writer_->writeFormat("\t\t\t\tinversePoseMatrix Matrix34 {\n"
		"\t\t\t\t\t %.8f %.8f %.8f %.8f\n\t\t\t\t\t %.8f %.8f %.8f %.8f\n"
		"\t\t\t\t\t %.8f %.8f %.8f %.8f\n\t\t\t\t}\n",
		invPose.m00, invPose.m01, invPose.m02, invPose.m03,
		invPose.m10, invPose.m11, invPose.m12, invPose.m13,
		invPose.m20, invPose.m21, invPose.m22, invPose.m23);
	// スケール
	Vector3 scale = bone->getScale();
	writer_->writeFormat("\t\t\t\tscale { %.8f %.8f %.8f }\n",
		scale.x, scale.y, scale.z);
	// 回転
	Vector3 rotation = bone->getRotationXYZ();
	writer_->writeFormat("\t\t\t\trotation { %.8f %.8f %.8f }\n",
		rotation.x, rotation.y, rotation.z);
	// 移動
	Vector3 translation = bone->getTranslation();
	writer_->writeFormat("\t\t\t\ttranslation { %.8f %.8f %.8f }\n",
		translation.x, translation.y, translation.z);

	writer_->writeText("\t\t\t}\n");
}
//------------------------------------------------------------------------------
// ボーンリンクの書き出し
void TextSceneSaver::writeBoneLink(Bone* bone){
	int boneCount = bone->getBoneCount();
	if(boneCount == 0){ return; }
	writer_->writeText("\t\t\t");
	writer_->writeText(bone->getName());
	writer_->writeText(" {\n");
	for(int i = 0; i < boneCount; i++){
		Bone* child = bone->getBone(i);
		writer_->writeText("\t\t\t\t");
		writer_->writeText(child->getName());
		writer_->writeText("\n");
	}
	writer_->writeText("\t\t\t}\n");
}
//------------------------------------------------------------------------------
// メッシュ
//------------------------------------------------------------------------------
// メッシュリストの書き出し
void TextSceneSaver::writeMeshList(){
	int meshCount = meshManager_->getCount();
	for(int i = 0; i < meshCount; i++){
		Mesh* mesh = meshManager_->get(i);
		if(mesh->isRigidMesh()){
			writeRigidMesh(mesh->castRigidMesh());
		}else if(mesh->isCharacterMesh()){
			writeCharacterMesh(mesh->castCharacterMesh());
		}else{
			ErrorOut("TextSceneSaver::writeMeshList() unsupported mesh %s",
				mesh->getName().getBytes());
		}
	}
}
//------------------------------------------------------------------------------
// 剛体メッシュの書き出し
void TextSceneSaver::writeRigidMesh(RigidMesh* mesh){
	writer_->writeText("\t");
	writer_->writeText(mesh->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Rigid\n");
	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(mesh->isEnabled());
	writer_->writeText("\n\t}\n\n");
}
//------------------------------------------------------------------------------
// キャラクタメッシュの書き出し
void TextSceneSaver::writeCharacterMesh(CharacterMesh* mesh){
	writer_->writeText("\t");
	writer_->writeText(mesh->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Character\n");
	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(mesh->isEnabled());
	writer_->writeText("\n\t}\n\n");
}
//------------------------------------------------------------------------------
// メッシュデータ
//------------------------------------------------------------------------------
// メッシュデータリストの書き出し
void TextSceneSaver::writeMeshDataList(){
	int meshDataCount = meshDataManager_->getCount();
	for(int i = 0; i < meshDataCount; i++){
		writeMeshData(meshDataManager_->get(i));
	}
}
//------------------------------------------------------------------------------
// メッシュデータの書き出し
void TextSceneSaver::writeMeshData(MeshData* meshData){
	writer_->writeText("\t");
	writer_->writeText(meshData->getName());
	writer_->writeText(" {\n");
	// バウンディングボックス
	const AxisAlignedBox& box = meshData->getBoundingBox();
	writer_->writeFormat(
		"\t\tboundingBox { %.8f %.8f %.8f } { %.8f %.8f %.8f }\n",
		box.getMinimum().x, box.getMinimum().y, box.getMinimum().z,
		box.getMaximum().x, box.getMaximum().y, box.getMaximum().z);
	// バウンディングスフィア
	const Sphere& sphere = meshData->getBoundingSphere();
	writer_->writeFormat(
		"\t\tboundingSphere { %.8f %.8f %.8f %.8f }\n",
		sphere.getCenter().x, sphere.getCenter().y, sphere.getCenter().z,
		sphere.getRadius());
	// プリミティブタイプ
	writer_->writeText("\t\tprimitiveType ");
	writer_->writeText(Mesh::primitiveTypeToString(
		meshData->getPrimitiveType()));
	writer_->writeText("\n");
	// トライアングルリストのインデックス出力
	if(meshData->getPrimitiveType() == Mesh::indexedTriangleList){
		int vertexIndexCount = meshData->getVertexIndexCount();
		writer_->writeFormat("\t\tindices %d {\n", vertexIndexCount);
		vertexIndexCount /= 3;
		for(int i = 0; i < vertexIndexCount; i++){
			int index = i * 3;
			writer_->writeFormat("\t\t\t%d %d %d\n",
				meshData->getVertexIndex(index),
				meshData->getVertexIndex(index + 1),
				meshData->getVertexIndex(index + 2));
		}
		writer_->writeFormat("\t\t}\n");
	}
	// 法線を持っているか
	bool hasNormal = meshData->hasNormal();
	writer_->writeText("\t\thasNormal ");
	writeBool(hasNormal);
	// 頂点カラーを持っているか
	bool hasColor = meshData->hasColor();
	writer_->writeText("\n\t\thasColor ");
	writeBool(hasColor);
	// テクスチャ座標セット数
	int texCoordSetCount = meshData->getTexCoordSetCount();
	writer_->writeFormat("\n\t\ttexCoordSetCount %d\n", texCoordSetCount);
	// テクスチャ座標タイプ
	writer_->writeText("\t\ttexCoordType");
	int texCoordType[TexCoord::maxSetCount];
	for(int i = 0; i < texCoordSetCount; i++){
		texCoordType[i] = meshData->getTexCoordType(i);
		writer_->writeFormat(" %d", texCoordType[i]);
	}
	writer_->writeText("\n");
	// 頂点あたりボーン数
	int bonesPerVertex = meshData->getBonesPerVertex();
	writer_->writeFormat("\t\tbonesPerVertex %d\n", bonesPerVertex);
	// 頂点あたりウェイト数
	int weightsPerVertex = meshData->getWeightsPerVertex();
	// 頂点リスト
	int vertexCount = meshData->getVertexCount();
	writer_->writeFormat("\t\tvertices %d {\n", vertexCount);
	for(int i = 0; i < vertexCount; i++){
		// 位置
		Vector3 pos = meshData->getPosition(i);
		writer_->writeFormat("\t\t\t%d { %.8f %.8f %.8f }",
			i, pos.x, pos.y, pos.z);
		// 法線
		if(hasNormal){
			Vector3 nom = meshData->getNormal(i);
			writer_->writeFormat(" { %.8f %.8f %.8f }",
				nom.x, nom.y, nom.z);
		}
		// 頂点カラー
		if(hasColor){
			Color4c color = meshData->getColor(i);
			writer_->writeFormat(" { %d %d %d %d }",
				color.r, color.g, color.b, color.a);
		}
		// テクスチャ座標
		for(int j = 0; j < texCoordSetCount; j++){
			writer_->writeText(" { ");
			for(int k = 0; k < texCoordType[j]; k++){
				writer_->writeFormat("%.8f ",
					*(meshData->getTexCoordArray(j) + (i * texCoordType[j]) + k));
			}
			writer_->writeText("}");
		}
		// ボーンインデックス
		if(bonesPerVertex != 0){
			writer_->writeText(" { ");
			for(int j = 0; j < bonesPerVertex; j++){
				writer_->writeFormat("%d ",
					(int)meshData->getBoneIndex(i, j));
			}
			writer_->writeText("}");
		}
		// ウェイト
		if(weightsPerVertex != 0){
			writer_->writeText(" { ");
			for(int j = 0; j < weightsPerVertex; j++){
				writer_->writeFormat("%.8f ", meshData->getWeight(i, j));
			}
			writer_->writeText("}");
		}
		writer_->writeText("\n");
	}
	writer_->writeText("\t\t}\n");
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// マテリアル
//------------------------------------------------------------------------------
// マテリアルリストの書き出し
void TextSceneSaver::writeMaterialList(){
	int materialCount = materialManager_->getCount();
	for(int i = 0; i < materialCount; i++){
		Material* material = materialManager_->get(i);
		if(material->isBasicMaterial()){
			writeBasicMaterial(material->castBasicMaterial());
		}else{
			ErrorOut("TextSceneSaver::writeMaterialList() "
				"unsupported material %s", material->getName().getBytes());
		}
	}
}
//------------------------------------------------------------------------------
// マテリアルの書き出し
void TextSceneSaver::writeMaterial(const Material* material){
	writer_->writeText("\t\tMaterial {\n");
	writer_->writeFormat("\t\t\tpriority %d\n", material->getPriority());
	writer_->writeText("\t\t\tblendMode ");
	writer_->writeText(Material::blendModeToString(material->getBlendMode()));
	writer_->writeFormat("\n\t\t\talpha %.8f\n", material->getAlpha());
	writer_->writeText("\t\t\tblendSource ");
	writer_->writeText(
		Material::blendStateToString(material->getBlendSource()));
	writer_->writeText("\n\t\t\tblendDestination ");
	writer_->writeText(
		Material::blendStateToString(material->getBlendDestination()));
	writer_->writeText("\n\t\t\tzWrite ");
	writeBool(material->useZWrite());
	writer_->writeText("\n\t\t\tzTest ");
	writeBool(material->useZTest());
	writer_->writeText("\n\t\t\tfogOption ");
	writer_->writeText(Material::fogOptionToString(material->getFogOption()));
	writer_->writeFormat("\n\t\t\tlightMask %u\n", material->getLightMask());
	writer_->writeText("\t\t}\n");
}
//------------------------------------------------------------------------------
// 基本マテリアルの書き出し
void TextSceneSaver::writeBasicMaterial(const BasicMaterial* material){
	writer_->writeText("\t");
	writer_->writeText(material->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Basic\n");
	writer_->writeFormat("\t\tbaseUVIndex %d\n", material->getBaseUVIndex());
	writer_->writeFormat("\t\tglossUVIndex %d\n", material->getGlossUVIndex());
	writer_->writeFormat("\t\tlightUVIndex %d\n", material->getLightUVIndex());
	writer_->writeFormat("\t\tstainUVIndex %d\n", material->getStainUVIndex());
	Color3f diffuse = material->getDiffuseColor();
	writer_->writeFormat("\t\tdiffuseColor { %.8f %.8f %.8f }\n",
		diffuse.r, diffuse.g, diffuse.b);
	Color3f specular = material->getSpecularColor();
	writer_->writeFormat("\t\tspecularColor { %.8f %.8f %.8f }\n",
		specular.r, specular.g, specular.b);
	writer_->writeFormat("\t\tspecularPower %.8f\n",
		material->getSpecularPower());
	Color3f ambient = material->getAmbientColor();
	writer_->writeFormat("\t\tambientColor { %.8f %.8f %.8f }\n",
		ambient.r, ambient.g, ambient.b);
	Color3f emissive = material->getEmissiveColor();
	writer_->writeFormat("\t\temissiveColor { %.8f %.8f %.8f }\n",
		emissive.r, emissive.g, emissive.b);
	// マテリアルの書き出し
	writeMaterial(material);
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// テクスチャ
//------------------------------------------------------------------------------
// テクスチャリストの書き出し
void TextSceneSaver::writeTextureList(){
	int textureCount = textureManager_->getCount();
	for(int i = 0; i < textureCount; i++){
		Texture* texture = textureManager_->get(i);
		if(texture->isSurfaceTexture()){
			writeSurfaceTexture(texture->castSurfaceTexture());
		}else{
			ErrorOut("TextSceneSaver::writeTextureList() unsupported texture %s",
				texture->getName().getBytes());
		}
	}
}
//------------------------------------------------------------------------------
// サーフェーステクスチャの書き出し
void TextSceneSaver::writeSurfaceTexture(const SurfaceTexture* texture){
	writer_->writeText("\t");
	writer_->writeText(texture->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Surface\n");
	writer_->writeText("\t\taddressModeU ");
	writer_->writeText(Texture::addressModeToString(
		texture->getAddressModeU()));
	writer_->writeText("\n\t\taddressModeV ");
	writer_->writeText(Texture::addressModeToString(
		texture->getAddressModeV()));
	TexCoord2 repeat = texture->getRepeatUV();
	writer_->writeFormat("\n\t\trepeatUV { %.8f %.8f }", repeat.u, repeat.v);
	TexCoord2 offset = texture->getOffsetUV();
	writer_->writeFormat("\n\t\toffsetUV { %.8f %.8f }", offset.u, offset.v);
	writer_->writeText("\n\t}\n\n");
}
//------------------------------------------------------------------------------
// ピクチャ
//------------------------------------------------------------------------------
// ピクチャの書き出し
void TextSceneSaver::writePicture(const Picture* picture){
	writer_->writeText("\t");
	writer_->writeText(picture->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\tpath ");
	String path = picture->getPath();
	writer_->writeText(path);
	writer_->writeText("\n\t}\n\n");
	// ピクチャ出力ディレクトリの作成
	FilePath filePath(path);
	path = filePath.getFolderPath();
	if(path != ""){
		path = basePath_ + path;
		mkdir(path.getBytes());
	}
	// ピクチャファイルの保存
	TargaSaver saver;
	if(picture->isPictureRGB8()){
		// RGB8は24bitのTargaで保存
		PictureRGB8* rgb8 = picture->castPictureRGB8();
		saver.save(basePath_ + rgb8->getPath(),
			rgb8->getSize(), rgb8->getImage());
	}else if(picture->isPictureRGBA8()){
		// RGBA8は32bitのTargaで保存
		PictureRGBA8* rgba8 = picture->castPictureRGBA8();
		saver.save(basePath_ + rgba8->getPath(),
			rgba8->getSize(), rgba8->getImage());
	}else{
		ErrorOut("TextSceneSaver::writePictureList() "
			"unsupported picture %s", picture->getName().getBytes());
	}
}
//------------------------------------------------------------------------------
// リンク
//------------------------------------------------------------------------------
// シーンノードリンクの書き出し
void TextSceneSaver::writeSceneNodeLink(SceneNode* sceneNode){
	// リンクが0かどうかチェック
	int sceneNodeCount = sceneNode->getSceneNodeCount();
	int sceneLeafCount = sceneNode->getSceneLeafCount();
	if(sceneNodeCount + sceneLeafCount == 0){ return; }
	writer_->writeText("\t");
	writer_->writeText(sceneNode->getName());
	writer_->writeText(" {\n");
	if(sceneNodeCount > 0){
		writer_->writeText("\t\tSceneNode {\n");
		for(int i = 0; i < sceneNodeCount; i++){
			SceneNode* linkNode = sceneNode->getSceneNode(i);
			writer_->writeText("\t\t\t");
			writer_->writeText(linkNode->getName());
			writer_->writeText("\n");
		}
		writer_->writeText("\t\t}\n");
	}
	if(sceneLeafCount > 0){
		writer_->writeText("\t\tSceneLeaf {\n");
		for(int i = 0; i < sceneLeafCount; i++){
			SceneLeaf* sceneLeaf = sceneNode->getSceneLeaf(i);
			if(sceneLeaf->isModel()){
				writer_->writeText("\t\t\tModel ");
				writer_->writeText(sceneLeaf->getName());
				writer_->writeText("\n");
			}else if(sceneLeaf->isLight()){
				writer_->writeText("\t\t\tLight ");
				writer_->writeText(sceneLeaf->getName());
				writer_->writeText("\n");
			}else{
				Assert(false);
			}
		}
		writer_->writeText("\t\t}\n");
	}
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// モデルリンクの書き出し
void TextSceneSaver::writeModelLink(const Model* model){
	int meshCount = model->getMeshCount();
	if(meshCount == 0){ return; }
	writer_->writeText("\t");
	writer_->writeText(model->getName());
	writer_->writeText(" {\n");
	for(int i = 0; i < meshCount; i++){
		Mesh* mesh = model->getMesh(i);
		writer_->writeText("\t\t");
		writer_->writeText(mesh->getName());
		writer_->writeText("\n");
	}
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// メッシュリンクの書き出し
void TextSceneSaver::writeMeshLink(const Mesh* mesh){
	if((mesh->getMeshData() == NULL) &&
		(mesh->getMaterial() == NULL)){ return; }
	writer_->writeText("\t");
	writer_->writeText(mesh->getName());
	writer_->writeText(" {\n");
	// メッシュデータ
	if(mesh->getMeshData() != NULL){
		writer_->writeText("\t\tMeshData ");
		writer_->writeText(mesh->getMeshData()->getName());
		writer_->writeText("\n");
	}
	// マテリアル
	if(mesh->getMaterial() != NULL){
		writer_->writeText("\t\tMaterial ");
		writer_->writeText(mesh->getMaterial()->getName());
		writer_->writeText("\n");
	}
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// マテリアルリンクリストの書き出し
void TextSceneSaver::writeMaterialLinkList(){
	writer_->writeText("MaterialLink {\n");
	int materialCount = materialManager_->getCount();
	for(int i = 0; i < materialCount; i++){
		Material* material = materialManager_->get(i);
		if(material->isBasicMaterial()){
			writeBasicMaterialLink(material->castBasicMaterial());
		}else{
			ErrorOut("TextSceneSaver::writeMaterialLinkList() "
				"unsupported material %s", material->getName().getBytes());
		}
	}
	writer_->writeText("}\n\n");
}
//------------------------------------------------------------------------------
// 基本マテリアルリンクの書き出し
void TextSceneSaver::writeBasicMaterialLink(const BasicMaterial* material){
	Texture* baseTexture = material->getBaseTexture();
	Texture* glossTexture = material->getGlossTexture();
	Texture* lightTexture = material->getLightTexture();
	Texture* stainTexture = material->getStainTexture();
	// テクスチャの有無をチェック
	if((baseTexture == NULL) && (glossTexture == NULL) &&
		(lightTexture == NULL) && (stainTexture == NULL)){ return; }
	writer_->writeText("\t");
	writer_->writeText(material->getName());
	writer_->writeText(" {\n");
	writer_->writeText("\t\ttype Basic\n");
	if(baseTexture != NULL){
		writer_->writeText("\t\tbaseTexture ");
		writer_->writeText(baseTexture->getName());
		writer_->writeText("\n");
	}
	if(glossTexture != NULL){
		writer_->writeText("\t\tglossTexture ");
		writer_->writeText(glossTexture->getName());
		writer_->writeText("\n");
	}
	if(lightTexture != NULL){
		writer_->writeText("\t\tlightTexture ");
		writer_->writeText(lightTexture->getName());
		writer_->writeText("\n");
	}
	if(stainTexture != NULL){
		writer_->writeText("\t\tstainTexture ");
		writer_->writeText(stainTexture->getName());
		writer_->writeText("\n");
	}
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// テクスチャリンクの書き出し
void TextSceneSaver::writeTextureLink(const Texture* texture){
	int pictureCount = texture->getPictureCount();
	if(pictureCount == 0){ return; }
	writer_->writeText("\t");
	writer_->writeText(texture->getName());
	writer_->writeText(" {\n");
	for(int i = 0; i < pictureCount; i++){
		Picture* picture = texture->getPicture(i);
		writer_->writeText("\t\t");
		writer_->writeText(picture->getName());
		writer_->writeText("\n");
	}
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// ユーティリティ
//------------------------------------------------------------------------------
// boolの書き出し
void TextSceneSaver::writeBool(bool flag){
	if(flag){
		writer_->writeText("true");
	}else{
		writer_->writeText("false");
	}
}
//------------------------------------------------------------------------------
// 線コメントの書き出し
void TextSceneSaver::writeLineComment(){
	writer_->writeText("//----------------------------"
		"--------------------------------------------------\n");
}
//------------------------------------------------------------------------------
// ブロックコメントの書き出し
void TextSceneSaver::writeBlockComment(const String& blockName){
	writeLineComment();
	writer_->writeText("// ");
	writer_->writeText(blockName);
	writer_->writeText(" Block\n");
	writeLineComment();
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
