//------------------------------------------------------------------------------
// 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/BinarySceneSaver.h"
#include "Core/InputOutput/BinaryFileWriter.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{

//------------------------------------------------------------------------------
// コンストラクタ
BinarySceneSaver::BinarySceneSaver(){
}
//------------------------------------------------------------------------------
// デストラクタ
BinarySceneSaver::~BinarySceneSaver(){
}
//------------------------------------------------------------------------------
// セーブ
void BinarySceneSaver::save(const String& filePath, Scene* scene){
	FilePath path(filePath);
	BinaryFileWriter* binaryFileWriter = new BinaryFileWriter(filePath);
	save(binaryFileWriter, scene, path.getFolderPath());
	delete binaryFileWriter;
}
//------------------------------------------------------------------------------
// セーブ
void BinarySceneSaver::save(BinaryWriter* binaryWriter, Scene* scene,
	const String& basePath){
	// 初期化
	writer_ = binaryWriter;
	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 linkCount = writeObjectList();

	// リンクの書き出し
	writeLink(linkCount);
}
//------------------------------------------------------------------------------
// ヘッダの書き出し
void BinarySceneSaver::writeHeader(){
	// フォーマットIDの書き出し
	writeID("LBScene");
	// バージョン番号の書き出し
	u_int binaryVersion = 0x00000900;
	writer_->writeUInt(binaryVersion);
	align();
}
//------------------------------------------------------------------------------
// オブジェクトリストの書き出し
int BinarySceneSaver::writeObjectList(){
	int linkCount = 0;
	// フォグの書き出し
	writeFog(scene_->getFog());
	// フォグはリンクされないのでカウントしない

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

	// ライトリストの書き出し
	int lightCount = lightManager_->getCount();
	if(lightCount > 0){	writeLightList(); }
	// ライトはリンクされないのでカウントしない

	// モデルリストの書き出し
	int modelCount = modelManager_->getCount();
	if(modelCount > 0){ writeModelList(); }
	linkCount += modelCount;

	// メッシュリストの書き出し
	int meshCount = meshManager_->getCount();
	if(meshCount > 0){ writeMeshList(); }
	linkCount += meshCount;

	// メッシュデータリストの書き出し
	int meshDataCount = meshDataManager_->getCount();
	if(meshDataCount > 0){ writeMeshDataList(); }
	linkCount += meshDataCount;

	// マテリアルリストの書き出し
	int materialCount = materialManager_->getCount();
	if(materialCount > 0){ writeMaterialList(); }
	linkCount += materialCount;

	// テクスチャリストの書き出し
	int textureCount = textureManager_->getCount();
	if(textureCount > 0){ writeTextureList(); }
	linkCount += textureCount;

	// ピクチャリストの書き出し
	int pictureCount = pictureManager_->getCount();
	if(pictureCount > 0){
		int startAddress = startBlock("Picture");
		for(int i = 0; i < pictureCount; i++){
			writePicture(pictureManager_->get(i));
		}
		endBlock(startAddress);
	}
	linkCount += pictureCount;

	return linkCount;
}
//------------------------------------------------------------------------------
// リンクの書き出し
void BinarySceneSaver::writeLink(int linkCount){
	// オブジェクトが1個以下ならリンクは存在しない
	if(linkCount <= 1){ return; }

	{ // シーンノードリンクの書き出し
		int startAddress = startBlock("SceneNodeLin");
		int sceneNodeCount = sceneNodeManager_->getCount();
		for(int i = 0; i < sceneNodeCount; i++){
			writeSceneNodeLink(sceneNodeManager_->get(i));
		}
		endBlock(startAddress);
	}

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

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

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

	// テクスチャリンクの書き出し
	if(textureCount > 0){
		int startAddress = startBlock("TextureLink");
		for(int i = 0; i < textureCount; i++){
			writeTextureLink(textureManager_->get(i));
		}
		endBlock(startAddress);
	}
}
//------------------------------------------------------------------------------
// フォグ
//------------------------------------------------------------------------------
// フォグの書き出し
void BinarySceneSaver::writeFog(Fog* fog){
	int startAddress = startBlock("Fog");
	// カラー
	writeColor4c(fog->getColor());
	// モード
	writer_->writeInt(fog->getMode());
	// 濃度
	writer_->writeFloat(fog->getDensity());
	// ニア
	writer_->writeFloat(fog->getNear());
	// ファー
	writer_->writeFloat(fog->getFar());
	// 有効、無効
	writer_->writeBool(fog->isEnabled());
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// シーンノード
//------------------------------------------------------------------------------
// シーンノードリストの書き出し
void BinarySceneSaver::writeSceneNodeList(){
	int startAddress = startBlock("SceneNode");
	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);
		}
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// シーンノードの書き出し
void BinarySceneSaver::writeSceneNode(SceneNode* sceneNode){
	int startAddress = startBlock("Standard");
	// 名前
	writeString(sceneNode->getName());
	// スケール
	writeVector3(sceneNode->getScale());
	// 回転
	writeVector3(sceneNode->getRotationXYZ());
	// 移動
	writeVector3(sceneNode->getTranslation());
	// 有効、無効
	writer_->writeBool(sceneNode->isEnabled());
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// レベルオブディティールシーンノードの書き出し
void BinarySceneSaver::writeLODSceneNode(LODSceneNode* sceneNode){
	int startAddress = startBlock("LOD");
	// 名前
	writeString(sceneNode->getName());
	// スケール
	writeVector3(sceneNode->getScale());
	// 回転
	writeVector3(sceneNode->getRotationXYZ());
	// 移動
	writeVector3(sceneNode->getTranslation());
	// LOD分割数
	int lodThresholdCount = sceneNode->getLODThresholdCount();
	writer_->writeInt(lodThresholdCount);
	for(int i = 0; i < lodThresholdCount; i++){
		writer_->writeFloat(sceneNode->getLODThreshold(i));
	}
	// 有効、無効
	writer_->writeBool(sceneNode->isEnabled());
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// ライト
//------------------------------------------------------------------------------
// ライトリストの書き出し
void BinarySceneSaver::writeLightList(){
	int startAddress = startBlock("Light");
	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("BinarySceneSaver::writeLightList() unsupported light %s",
				light->getName().getBytes());
		}
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// ライトの書き出し
void BinarySceneSaver::writeLight(Light* light){
	// ライトマスク
	writer_->writeUInt(light->getLightMask());
	// 有効、無効
	writer_->writeBool(light->isEnabled());
}
//------------------------------------------------------------------------------
// アンビエントライトの書き出し
void BinarySceneSaver::writeAmbientLight(AmbientLight* light){
	int startAddress = startBlock("Ambient");
	// 名前
	writeString(light->getName());
	// カラー
	writeColor3f(light->getColor());
	// ライトの書き出し
	writeLight(light);
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// ディレクショナルライトの書き出し
void BinarySceneSaver::writeDirectionalLight(DirectionalLight* light){
	int startAddress = startBlock("Directional");
	// 名前
	writeString(light->getName());
	// ディフューズカラー
	writeColor3f(light->getDiffuseColor());
	// スペキュラカラー
	writeColor3f(light->getSpecularColor());
	// 方向
	writeVector3(light->getDirection());
	// ライトの書き出し
	writeLight(light);
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// ポイントライトの書き出し
void BinarySceneSaver::writePointLight(PointLight* light){
	int startAddress = startBlock("Point");
	// 名前
	writeString(light->getName());
	// ディフューズカラー
	writeColor3f(light->getDiffuseColor());
	// スペキュラカラー
	writeColor3f(light->getSpecularColor());
	// 位置
	writeVector3(light->getPosition());
	// レンジ
	writer_->writeFloat(light->getRange());
	// 減衰係数
	writer_->writeFloat(light->getAttenuation0());
	writer_->writeFloat(light->getAttenuation1());
	writer_->writeFloat(light->getAttenuation2());
	// ライトの書き出し
	writeLight(light);
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// モデル
//------------------------------------------------------------------------------
// モデルリストの書き出し
void BinarySceneSaver::writeModelList(){
	int startAddress = startBlock("Model");
	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("BinarySceneSaver::writeModelList() "
				"unsupported model %s", model->getName().getBytes());
		}
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// 標準モデルの書き出し
void BinarySceneSaver::writeStandardModel(StandardModel* model){
	int startAddress = startBlock("Standard");
	// 名前
	writeString(model->getName());
	// 有効、無効
	writer_->writeBool(model->isEnabled());
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// キャラクタモデルの書き出し
void BinarySceneSaver::writeCharacterModel(CharacterModel* model){
	int startAddress = startBlock("Character");
	// 名前
	writeString(model->getName());
	// 有効、無効
	writer_->writeBool(model->isEnabled());
	// アライメント
	align();
	// ボーンの書き出し
	int boneCount = model->getBoneCount();
	writer_->writeInt(boneCount);
	for(int i = 0; i < boneCount; i++){ writeBone(model->getBone(i)); }
	// ボーンリンクの書き出し
	for(int i = 0; i < boneCount; i++){
		writeBoneLink(model, model->getBone(i));
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// ボーンの書き出し
void BinarySceneSaver::writeBone(Bone* bone){
	// 名前
	writeString(bone->getName());
	// ポーズ逆行列
	writeMatrix34(bone->getInversePoseMatrix());
	// スケール
	writeVector3(bone->getScale());
	// 回転
	writeVector3(bone->getRotationXYZ());
	// 移動
	writeVector3(bone->getTranslation());
}
//------------------------------------------------------------------------------
// ボーンリンクの書き出し
void BinarySceneSaver::writeBoneLink(CharacterModel* model, Bone* bone){
	int boneCount = bone->getBoneCount();
	writer_->writeInt(boneCount);
	for(int i = 0; i < boneCount; i++){
		writer_->writeInt(model->getBoneIndex(bone->getBone(i)));
	}
}
//------------------------------------------------------------------------------
// メッシュ
//------------------------------------------------------------------------------
// メッシュリストの書き出し
void BinarySceneSaver::writeMeshList(){
	int startAddress = startBlock("Mesh");
	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("BinarySceneSaver::writeMeshList() unsupported mesh %s",
				mesh->getName().getBytes());
		}
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// 剛体メッシュの書き出し
void BinarySceneSaver::writeRigidMesh(RigidMesh* mesh){
	int startAddress = startBlock("Rigid");
	// 名前
	writeString(mesh->getName());
	// 有効、無効
	writer_->writeBool(mesh->isEnabled());
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// キャラクタメッシュの書き出し
void BinarySceneSaver::writeCharacterMesh(CharacterMesh* mesh){
	int startAddress = startBlock("Character");
	// 名前
	writeString(mesh->getName());
	// 有効、無効
	writer_->writeBool(mesh->isEnabled());
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// メッシュデータ
//------------------------------------------------------------------------------
// メッシュデータリストの書き出し
void BinarySceneSaver::writeMeshDataList(){
	int startAddress = startBlock("MeshData");
	int meshDataCount = meshDataManager_->getCount();
	for(int i = 0; i < meshDataCount; i++){
		writeMeshData(meshDataManager_->get(i));
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// メッシュデータの書き出し
void BinarySceneSaver::writeMeshData(MeshData* meshData){
	// 名前
	writeString(meshData->getName());
	// バウンディングボックス
	writeAxisAlignedBox(meshData->getBoundingBox());
	// バウンディングスフィア
	writeSphere(meshData->getBoundingSphere());
	// プリミティブタイプ
	writer_->writeInt(meshData->getPrimitiveType());
	// インデックス出力
	int vertexIndexCount = meshData->getVertexIndexCount();
	writer_->writeInt(vertexIndexCount);
	if(vertexIndexCount > 0){
		writer_->writeBytes(meshData->getVertexIndexArray(),
			sizeof(u_short) * vertexIndexCount);
	}
	// 法線を持っているか
	bool hasNormal = meshData->hasNormal();
	writer_->writeBool(hasNormal);
	// 頂点カラーを持っているか
	bool hasColor = meshData->hasColor();
	writer_->writeBool(hasColor);
	// アライメント
	align();
	// 頂点数
	int vertexCount = meshData->getVertexCount();
	writer_->writeInt(vertexCount);
	// テクスチャ座標セット数
	int texCoordSetCount = meshData->getTexCoordSetCount();
	writer_->writeInt(texCoordSetCount);
	// テクスチャ座標タイプ
	for(int i = 0; i < texCoordSetCount; i++){
		int texCoordType = meshData->getTexCoordType(i);
		writer_->writeInt(texCoordType);
	}
	// 位置
	writer_->writeBytes(meshData->getPositionArray(),
		sizeof(Vector3) * vertexCount);
	// 法線
	if(hasNormal){
		writer_->writeBytes(meshData->getNormalArray(),
			sizeof(Vector3) * vertexCount);
	}
	// 頂点カラー
	if(hasColor){
		writer_->writeBytes(meshData->getColorArray(),
			sizeof(Color4c) * vertexCount);
	}
	// テクスチャ座標
	for(int i = 0; i < texCoordSetCount; i++){
		writer_->writeBytes(meshData->getTexCoordArray(i),
			meshData->getTexCoordArraySize(i));
	}
	// 頂点あたりボーン数
	int bonesPerVertex = meshData->getBonesPerVertex();
	writer_->writeInt(bonesPerVertex);
	if(bonesPerVertex != 0){
		// ボーンインデックス
		writer_->writeBytes(meshData->getBoneIndexArray(),
			sizeof(u_char) * vertexCount * bonesPerVertex);
	}
	// 頂点あたりウェイト数
	int weightsPerVertex = meshData->getWeightsPerVertex();
	if(weightsPerVertex != 0){
		// ウェイト
		writer_->writeBytes(meshData->getWeightArray(),
			sizeof(float) * vertexCount * weightsPerVertex);
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// マテリアル
//------------------------------------------------------------------------------
// マテリアルリストの書き出し
void BinarySceneSaver::writeMaterialList(){
	int startAddress = startBlock("Material");
	int materialCount = materialManager_->getCount();
	for(int i = 0; i < materialCount; i++){
		Material* material = materialManager_->get(i);
		if(material->isBasicMaterial()){
			writeBasicMaterial(material->castBasicMaterial());
		}else{
			ErrorOut("BinarySceneSaver::writeMaterialList() "
				"unsupported material %s", material->getName().getBytes());
		}
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// マテリアルの書き出し
void BinarySceneSaver::writeMaterial(const Material* material){
	// 名前
	writeString(material->getName());
	// 優先度
	writer_->writeInt(material->getPriority());
	// ブレンドモード
	writer_->writeInt(material->getBlendMode());
	// アルファ値
	writer_->writeFloat(material->getAlpha());
	// ブレンドソース
	writer_->writeInt(material->getBlendSource());
	// ブレンドデスティネーション
	writer_->writeInt(material->getBlendDestination());
	// フォグオプション
	writer_->writeInt(material->getFogOption());
	// ライトマスク
	writer_->writeUInt(material->getLightMask());
	// Z書き込み
	writer_->writeBool(material->useZWrite());
	// Zテスト
	writer_->writeBool(material->useZTest());
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// 基本マテリアルの書き出し
void BinarySceneSaver::writeBasicMaterial(const BasicMaterial* material){
	int startAddress = startBlock("Basic");
	// マテリアルの書き出し
	writeMaterial(material);
	// ベースUVインデックス
	writer_->writeInt(material->getBaseUVIndex());
	// 光沢UVインデックス
	writer_->writeInt(material->getGlossUVIndex());
	// ライトUVインデックス
	writer_->writeInt(material->getLightUVIndex());
	// 汚れUVインデックス
	writer_->writeInt(material->getStainUVIndex());
	// ディフューズ色
	writeColor3f(material->getDiffuseColor());
	// スペキュラ色
	writeColor3f(material->getSpecularColor());
	// スペキュラパワー
	writer_->writeFloat(material->getSpecularPower());
	// アンビエント色
	writeColor3f(material->getAmbientColor());
	// エミッシブ
	writeColor3f(material->getEmissiveColor());
	// アライメント
	align();
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// テクスチャ
//------------------------------------------------------------------------------
// テクスチャリストの書き出し
void BinarySceneSaver::writeTextureList(){
	int startAddress = startBlock("Texture");
	int textureCount = textureManager_->getCount();
	for(int i = 0; i < textureCount; i++){
		Texture* texture = textureManager_->get(i);
		if(texture->isSurfaceTexture()){
			writeSurfaceTexture(texture->castSurfaceTexture());
		}else{
			ErrorOut("BinarySceneSaver::writeTextureList() "
				"unsupported texture %s", texture->getName().getBytes());
		}
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// サーフェーステクスチャの書き出し
void BinarySceneSaver::writeSurfaceTexture(const SurfaceTexture* texture){
	int startAddress = startBlock("Surface");
	// 名前
	writeString(texture->getName());
	// アドレスモードU
	writer_->writeInt(texture->getAddressModeU());
	// アドレスモードV
	writer_->writeInt(texture->getAddressModeV());
	// リピートUV
	writeTexCoord2(texture->getRepeatUV());
	// オフセットUV
	writeTexCoord2(texture->getOffsetUV());
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// ピクチャ
//------------------------------------------------------------------------------
// ピクチャの書き出し
void BinarySceneSaver::writePicture(const Picture* picture){
	// 名前
	writeString(picture->getName());
	// パス
	String path = picture->getPath();
	writeString(path);
	// ピクチャ出力ディレクトリの作成
	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("BinarySceneSaver::writePictureList() "
			"unsupported picture %s", picture->getName().getBytes());
	}
}
//------------------------------------------------------------------------------
// リンク
//------------------------------------------------------------------------------
// シーンノードリンクの書き出し
void BinarySceneSaver::writeSceneNodeLink(SceneNode* sceneNode){
	// リンクが0かどうかチェック
	int sceneNodeCount = sceneNode->getSceneNodeCount();
	int sceneLeafCount = sceneNode->getSceneLeafCount();
	if(sceneNodeCount + sceneLeafCount == 0){ return; }
	// 名前
	writeString(sceneNode->getName());
	// シーンノードリンク数
	writer_->writeInt(sceneNodeCount);
	// シーンノードリンク
	for(int i = 0; i < sceneNodeCount; i++){
		writeString(sceneNode->getSceneNode(i)->getName());
	}
	// シーンリーフリンク数
	writer_->writeInt(sceneLeafCount);
	// シーンリーフリンク
	for(int i = 0; i < sceneLeafCount; i++){
		SceneLeaf* sceneLeaf = sceneNode->getSceneLeaf(i);
		if(sceneLeaf->isModel()){
			writer_->writeInt(0);
		}else if(sceneLeaf->isLight()){
			writer_->writeInt(1);
		}else{
			Assert(false);
		}
		writeString(sceneLeaf->getName());
	}
}
//------------------------------------------------------------------------------
// モデルリンクの書き出し
void BinarySceneSaver::writeModelLink(const Model* model){
	int meshCount = model->getMeshCount();
	if(meshCount == 0){ return; }
	// 名前
	writeString(model->getName());
	// メッシュリンク数
	writer_->writeInt(meshCount);
	// メッシュリンク
	for(int i = 0; i < meshCount; i++){
		writeString(model->getMesh(i)->getName());
	}
}
//------------------------------------------------------------------------------
// メッシュリンクの書き出し
void BinarySceneSaver::writeMeshLink(const Mesh* mesh){
	bool hasMeshData = (mesh->getMeshData() != NULL);
	bool hasMaterial = (mesh->getMaterial() != NULL);
	if((!hasMeshData) && (!hasMaterial)){ return; }
	// 名前
	writeString(mesh->getName());
	// メッシュデータを持つか
	writer_->writeBool(hasMeshData);
	// マテリアルを持つか
	writer_->writeBool(hasMaterial);
	// アライメント
	align();
	// メッシュデータ
	if(hasMeshData){ writeString(mesh->getMeshData()->getName()); }
	// マテリアル
	if(hasMaterial){ writeString(mesh->getMaterial()->getName()); }
}
//------------------------------------------------------------------------------
// マテリアルリンクリストの書き出し
void BinarySceneSaver::writeMaterialLinkList(){
	int startAddress = startBlock("MaterialLink");
	int materialCount = materialManager_->getCount();
	for(int i = 0; i < materialCount; i++){
		Material* material = materialManager_->get(i);
		if(material->isBasicMaterial()){
			writeBasicMaterialLink(material->castBasicMaterial());
		}else{
			ErrorOut("BinarySceneSaver::writeMaterialLinkList() "
				"unsupported material %s", material->getName().getBytes());
		}
	}
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// 基本マテリアルリンクの書き出し
void BinarySceneSaver::writeBasicMaterialLink(const BasicMaterial* material){
	Texture* baseTexture = material->getBaseTexture();
	Texture* glossTexture = material->getGlossTexture();
	Texture* lightTexture = material->getLightTexture();
	Texture* stainTexture = material->getStainTexture();
	bool hasBaseTexture = (baseTexture != NULL);
	bool hasGlossTexture = (glossTexture != NULL);
	bool hasLightTexture = (lightTexture != NULL);
	bool hasStainTexture = (stainTexture != NULL);
	// テクスチャの有無をチェック
	if((!hasBaseTexture) && (!hasGlossTexture) &&
		(!hasLightTexture) && (!hasStainTexture)){ return; }
	int startAddress = startBlock("Basic");
	// 名前
	writeString(material->getName());
	// テクスチャの有無
	writer_->writeBool(hasBaseTexture);
	writer_->writeBool(hasGlossTexture);
	writer_->writeBool(hasLightTexture);
	writer_->writeBool(hasStainTexture);
	// アライメント
	align();
	// テクスチャ名
	if(hasBaseTexture){ writeString(baseTexture->getName()); }
	if(hasGlossTexture){ writeString(glossTexture->getName()); }
	if(hasLightTexture){ writeString(lightTexture->getName()); }
	if(hasStainTexture){ writeString(stainTexture->getName()); }
	endBlock(startAddress);
}
//------------------------------------------------------------------------------
// テクスチャリンクの書き出し
void BinarySceneSaver::writeTextureLink(const Texture* texture){
	int pictureCount = texture->getPictureCount();
	if(pictureCount == 0){ return; }
	// 名前
	writeString(texture->getName());
	// ピクチャ数
	writer_->writeInt(pictureCount);
	// ピクチャリンク
	for(int i = 0; i < pictureCount; i++){
		writeString(texture->getPicture(i)->getName());
	}
}
//------------------------------------------------------------------------------
// 値の書き出し
//------------------------------------------------------------------------------
// 文字列の書き出し
void BinarySceneSaver::writeString(const String& string){
	int writeSize = string.getSize() + 1;
	writer_->writeInt(writeSize);
	writer_->writeBytes(string.getBytes(), writeSize);
	align();
}
//------------------------------------------------------------------------------
// 三次元ベクトルの書き出し
void BinarySceneSaver::writeVector3(const Vector3& vector){
	writer_->writeBytes(vector.array, sizeof(Vector3));
}
//------------------------------------------------------------------------------
// 3×4行列の書き出し
void BinarySceneSaver::writeMatrix34(const Matrix34& matrix){
	writer_->writeBytes(matrix.array, sizeof(Matrix34));
}
//------------------------------------------------------------------------------
// 四要素整数カラー値の書き出し
void BinarySceneSaver::writeColor4c(const Color4c& color){
	writer_->writeBytes(color.array, sizeof(Color4c));
}
//------------------------------------------------------------------------------
// 三要素実数カラー値の書き出し
void BinarySceneSaver::writeColor3f(const Color3f& color){
	writer_->writeBytes(color.array, sizeof(Color3f));
}
//------------------------------------------------------------------------------
// 四要素実数カラー値の書き出し
void BinarySceneSaver::writeColor4f(const Color4f& color){
	writer_->writeBytes(color.array, sizeof(Color4f));
}
//------------------------------------------------------------------------------
// 二次元テクスチャ座標値の書き出し
void BinarySceneSaver::writeTexCoord2(const TexCoord2& uv){
	writer_->writeBytes(uv.array, sizeof(TexCoord2));
}
//------------------------------------------------------------------------------
// 軸沿いボックスの書き出し
void BinarySceneSaver::writeAxisAlignedBox(const AxisAlignedBox& box){
	writer_->writeBytes(&box, sizeof(AxisAlignedBox));
}
//------------------------------------------------------------------------------
// 球の書き出し
void BinarySceneSaver::writeSphere(const Sphere& sphere){
	writer_->writeBytes(&sphere, sizeof(Sphere));
}
//------------------------------------------------------------------------------
// ユーティリティ
//------------------------------------------------------------------------------
// アライメントを取る
void BinarySceneSaver::align(){
	writer_->align(16);
}
//------------------------------------------------------------------------------
// IDの書き出し
void BinarySceneSaver::writeID(const String& id){
	u_char buffer[12];
	int size = id.getSize();
	Assert(size <= 12);
	for(int i = 0; i < size; i++){ buffer[i] = id.charAt(i); }
	for(int i = size; i < 12; i++){ buffer[i] = 0; }
	writer_->writeBytes(buffer, 12);
}
//------------------------------------------------------------------------------
// ブロックの開始
int BinarySceneSaver::startBlock(const String& blockName){
	writeID(blockName);
	u_int blockAddress = writer_->getPosition();
	// サイズの予約
	writer_->writeInt(0);
	align();
	return blockAddress;
}
//------------------------------------------------------------------------------
// ブロックの終了
void BinarySceneSaver::endBlock(int blockStartAddress){
	align();
	int nowPosition = writer_->getPosition();
	// サイズ分をブロックサイズから引く
	int blockSize = nowPosition - blockStartAddress - 4;// アライメント依存
	writer_->setPosition(blockStartAddress);
	writer_->writeInt(blockSize);
	writer_->setPosition(nowPosition);
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
