//------------------------------------------------------------------------------
// 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/BinarySceneLoader.h"
#include "Core/InputOutput/BinaryFileReader.h"
#include "Core/InputOutput/FilePath.h"
#include "Core/Codec/Tga/TargaLoader.h"
#include "Graphics/Scene/Scene.h"
#include "Graphics/Fog/Fog.h"
#include "Graphics/SceneNode/SceneNodeManager.h"
#include "Graphics/Light/LightManager.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{

//------------------------------------------------------------------------------
// コンストラクタ
BinarySceneLoader::BinarySceneLoader(){
}
//------------------------------------------------------------------------------
// デストラクタ
BinarySceneLoader::~BinarySceneLoader(){
}
//------------------------------------------------------------------------------
// ロード
void BinarySceneLoader::load(const String& filePath, Scene* scene){
	load(filePath, scene, scene->getRootNode());
}
//------------------------------------------------------------------------------
void BinarySceneLoader::load(const String& filePath, Scene* scene,
	SceneNode* rootNode){
	FilePath path(filePath);
	Assert(path.existFile());
	BinaryFileReader* binaryFileReader = new BinaryFileReader(filePath);
	load(binaryFileReader, scene, rootNode, path.getFolderPath());
	delete binaryFileReader;
}
//------------------------------------------------------------------------------
// ロード
void BinarySceneLoader::load(BinaryReader* binaryReader, Scene* scene,
	const String& basePath){
	load(binaryReader, scene, scene->getRootNode(), basePath);
}
//------------------------------------------------------------------------------
// ロード
void BinarySceneLoader::load(BinaryReader* binaryReader, Scene* scene,
	SceneNode* rootNode, const String& basePath){
	// 初期化
	reader_ = binaryReader;
	basePath_ = basePath;
	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(reader_->isEnd()){ break; }
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Fog"){
			readFog();
		}else if(blockName == "SceneNode"){
			readSceneNodeList(blockSize);
		}else if(blockName == "Light"){
			readLightList(blockSize);
		}else if(blockName == "Model"){
			readModelList(blockSize);
		}else if(blockName == "Mesh"){
			readMeshList(blockSize);
		}else if(blockName == "MeshData"){
			readMeshDataList(blockSize);
		}else if(blockName == "Material"){
			readMaterialList(blockSize);
		}else if(blockName == "Texture"){
			readTextureList(blockSize);
		}else if(blockName == "Picture"){
			readPictureList(blockSize);
		}else if(blockName == "SceneNodeLin"){
			readSceneNodeLinkList(blockSize);
		}else if(blockName == "ModelLink"){
			readModelLinkList(blockSize);
		}else if(blockName == "MeshLink"){
			readMeshLinkList(blockSize);
		}else if(blockName == "MaterialLink"){
			readMaterialLinkList(blockSize);
		}else if(blockName == "TextureLink"){
			readTextureLinkList(blockSize);
		}else{
// ブロック開始アライメントが0なので大丈夫だけど、ちょっとまずい
// Writerではアライメント前のサイズがブロックサイズになってる
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::load() "
				"Skip unknown block %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}

	Assert(reader_->getPosition() == reader_->getSize());
	rootNode_->setEnabled(rootNodeEnabled);
}
//------------------------------------------------------------------------------
// ヘッダの読み込み
void BinarySceneLoader::readHeader(){
	// フォーマットIDの読み込み
	if(readID() != "LBScene"){
		ErrorOut("BinarySceneLoader::readHeader() "
			"Invalid formatID (%d)", reader_->getPosition());
	}
	// バージョン番号の読み込み
	u_int binaryVersion = 0x00000900;
	u_int version = reader_->readUInt();
	if(binaryVersion != version){
		ErrorOut("BinarySceneLoader::readHeader() "
			"Invalid version (%d)", reader_->getPosition());
	}
	align();
}
//------------------------------------------------------------------------------
// フォグ
//------------------------------------------------------------------------------
// フォグの読み込み
void BinarySceneLoader::readFog(){
	Fog* fog = scene_->getFog();
	// カラー
	fog->setColor(readColor4c());
	// モード
	fog->setMode((Fog::Mode)reader_->readInt());
	// 濃度
	fog->setDensity(reader_->readFloat());
	// ニア
	fog->setNear(reader_->readFloat());
	// ファー
	fog->setFar(reader_->readFloat());
	// 有効、無効
	fog->setEnabled(reader_->readBool());
}
//------------------------------------------------------------------------------
// シーンノード
//------------------------------------------------------------------------------
// シーンノードリストの読み込み
void BinarySceneLoader::readSceneNodeList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Standard"){
			readSceneNode();
		}else if(blockName == "LOD"){
			readLODSceneNode();
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::readSceneNodeList() "
				"Skip unknown sceneNode %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}
}
//------------------------------------------------------------------------------
// シーンノードの読み込み
void BinarySceneLoader::readSceneNode(){
	SceneNode* sceneNode = sceneNodeManager_->createSceneNode(readString());
	// スケール
	sceneNode->setScale(readVector3());
	// 回転
	sceneNode->setRotationXYZ(readVector3());
	// 移動
	sceneNode->setTranslation(readVector3());
	// 有効、無効フラグ
	sceneNode->setEnabled(reader_->readBool());
}
//------------------------------------------------------------------------------
// レベルオブディティールシーンノードの読み込み
void BinarySceneLoader::readLODSceneNode(){
	LODSceneNode* sceneNode =
		sceneNodeManager_->createLODSceneNode(readString());
	// スケール
	sceneNode->setScale(readVector3());
	// 回転
	sceneNode->setRotationXYZ(readVector3());
	// 移動
	sceneNode->setTranslation(readVector3());
	// LOD分割数
	int lodThresholdCount = reader_->readInt();
	sceneNode->setLODThresholdCount(lodThresholdCount);
	// LOD分割値
	for(int i = 0; i < lodThresholdCount; i++){
		sceneNode->setLODThreshold(i, reader_->readFloat());
	}
	// 有効、無効フラグ
	sceneNode->setEnabled(reader_->readBool());
}
//------------------------------------------------------------------------------
// ライト
//------------------------------------------------------------------------------
// ライトリストの読み込み
void BinarySceneLoader::readLightList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Ambient"){
			readAmbientLight();
		}else if(blockName == "Directional"){
			readDirectionalLight();
		}else if(blockName == "Point"){
			readPointLight();
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::readLightList() "
				"Skip unknown light %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}
}
//------------------------------------------------------------------------------
// ライトの読み込み
void BinarySceneLoader::readLight(Light* light){
	// ライトマスク
	light->setLightMask(reader_->readUInt());
	// 有効、無効フラグ
	light->setEnabled(reader_->readBool());
}
//------------------------------------------------------------------------------
// アンビエントライトの読み込み
void BinarySceneLoader::readAmbientLight(){
	AmbientLight* light = lightManager_->createAmbientLight(readString());
	// ライトカラー
	light->setColor(readColor3f());
	// ライトの読み込み
	readLight(light);
}
//------------------------------------------------------------------------------
// ディレクショナルライトの読み込み
void BinarySceneLoader::readDirectionalLight(){
	DirectionalLight* light =
		lightManager_->createDirectionalLight(readString());
	// ディフューズカラー
	light->setDiffuseColor(readColor3f());
	// スペキュラカラー
	light->setSpecularColor(readColor3f());
	// 方向
	light->setDirection(readVector3());
	// ライトの読み込み
	readLight(light);
}
//------------------------------------------------------------------------------
// ポイントライトの読み込み
void BinarySceneLoader::readPointLight(){
	PointLight* light = lightManager_->createPointLight(readString());
	// ディフューズカラー
	light->setDiffuseColor(readColor3f());
	// スペキュラカラー
	light->setSpecularColor(readColor3f());
	// 位置
	light->setPosition(readVector3());
	// レンジ
	light->setRange(reader_->readFloat());
	// 減衰係数
	float attenuation0 = reader_->readFloat();
	float attenuation1 = reader_->readFloat();
	float attenuation2 = reader_->readFloat();
	light->setAttenuation(attenuation0, attenuation1, attenuation2);
	// ライトの読み込み
	readLight(light);
}
//------------------------------------------------------------------------------
// モデル
//------------------------------------------------------------------------------
// モデルリストの読み込み
void BinarySceneLoader::readModelList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Standard"){
			readStandardModel();
		}else if(blockName == "Character"){
			readCharacterModel();
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::readModelList() "
				"Skip unknown model %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}
}
//------------------------------------------------------------------------------
// 標準モデルの読み込み
void BinarySceneLoader::readStandardModel(){
	StandardModel* model = modelManager_->createStandardModel(readString());
	// 有効、無効フラグ
	model->setEnabled(reader_->readBool());
}
//------------------------------------------------------------------------------
// キャラクタモデルの読み込み
void BinarySceneLoader::readCharacterModel(){
	CharacterModel* model = modelManager_->createCharacterModel(readString());
	// 有効、無効フラグ
	model->setEnabled(reader_->readBool());
	// アライメント
	align();
	// ボーン数
	int boneCount = reader_->readInt();
	// ボーンの読み込み
	for(int i = 0; i < boneCount; i++){ readBone(model); }
	// ボーンリンク
	for(int i = 0; i < boneCount; i++){
		Bone* parent = model->getBone(i);
		int childCount = reader_->readInt();
		for(int j = 0; j < childCount; j++){
			parent->addBone(model->getBone(reader_->readInt()));
		}
	}
}
//------------------------------------------------------------------------------
// ボーンの読み込み
void BinarySceneLoader::readBone(CharacterModel* model){
	Bone* bone = model->createBone(readString());
	// ポーズ逆行列
	bone->setInversePoseMatrix(readMatrix34());
	// スケール
	bone->setScale(readVector3());
	// 回転
	bone->setRotationXYZ(readVector3());
	// 移動
	bone->setTranslation(readVector3());
}
//------------------------------------------------------------------------------
// メッシュ
//------------------------------------------------------------------------------
// メッシュリストの読み込み
void BinarySceneLoader::readMeshList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Rigid"){
			readRigidMesh();
		}else if(blockName == "Character"){
			readCharacterMesh();
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::readMeshList() "
				"Skip unknown mesh %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}
}
//------------------------------------------------------------------------------
// 剛体メッシュの読み込み
void BinarySceneLoader::readRigidMesh(){
	RigidMesh* mesh = meshManager_->createRigidMesh(readString());
	// 有効、無効フラグ
	mesh->setEnabled(reader_->readBool());
}
//------------------------------------------------------------------------------
// キャラクタメッシュの読み込み
void BinarySceneLoader::readCharacterMesh(){
	CharacterMesh* mesh = meshManager_->createCharacterMesh(readString());
	// 有効、無効フラグ
	mesh->setEnabled(reader_->readBool());
}
//------------------------------------------------------------------------------
// メッシュデータ
//------------------------------------------------------------------------------
// メッシュデータリストの読み込み
void BinarySceneLoader::readMeshDataList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		readMeshData();
	}
}
//------------------------------------------------------------------------------
// メッシュデータの読み込み
void BinarySceneLoader::readMeshData(){
	MeshData* meshData = meshDataManager_->createMeshData(readString());
	// バウンディングボックス
	meshData->setBoundingBox(readAxisAlignedBox());
	// バウンディングスフィア
	meshData->setBoundingSphere(readSphere());
	// プリミティブタイプ
	meshData->setPrimitiveType((Mesh::PrimitiveType)reader_->readInt());
	// 頂点インデックス数
	int vertexIndexCount = reader_->readInt();
	if(vertexIndexCount > 0){
		meshData->setVertexIndexCount(vertexIndexCount);
		for(int i = 0; i < vertexIndexCount; i++){
			meshData->setVertexIndex(i, reader_->readUShort());
		}
	}
	// 法線を持っているか
	bool hasNormal = reader_->readBool();
	meshData->enableNormal(hasNormal);
	// 頂点カラーを持っているか
	bool hasColor = reader_->readBool();
	meshData->enableColor(hasColor);
	// アライメント
	align();
	// 頂点数
	int vertexCount = reader_->readInt();
	meshData->setVertexCount(vertexCount);
	// テクスチャ座標セット数
	int texCoordSetCount = reader_->readInt();
	meshData->setTexCoordSetCount(texCoordSetCount);
	// テクスチャ座標タイプ
	int texCoordType[TexCoord::maxSetCount];
	for(int i = 0; i < texCoordSetCount; i++){
		texCoordType[i] = reader_->readInt();
		meshData->setTexCoordType(i, (TexCoord::Type)texCoordType[i]);
	}
	// 位置
	for(int i = 0; i < vertexCount; i++){
		meshData->setPosition(i, readVector3());
	}
	// 法線
	if(hasNormal){
		for(int i = 0; i < vertexCount; i++){
			meshData->setNormal(i, readVector3());
		}
	}
	// 頂点カラー
	if(hasColor){
		for(int i = 0; i < vertexCount; i++){
			meshData->setColor(i, readColor4c());
		}
	}
	// テクスチャ座標
	float texCoord[4];
	for(int i = 0; i < texCoordSetCount; i++){
		int texCoordSize = sizeof(float) * texCoordType[i];
		for(int j = 0; j < vertexCount; j++){
			reader_->readBytes(texCoord, texCoordSize);
			meshData->setTexCoord(j, i, texCoord, texCoordType[i]);
		}
	}
	// 頂点当たりボーン数
	int bonesPerVertex = reader_->readInt();
	meshData->setBonesPerVertex(bonesPerVertex);
	if(bonesPerVertex > 0){
		for(int i = 0; i < vertexCount; i++){
			for(int j = 0; j < bonesPerVertex; j++){
				meshData->setBoneIndex(i, j, reader_->readUChar());
			}
		}
	}
	// 頂点あたりウェイト数
	int weightsPerVertex = meshData->getWeightsPerVertex();
	if(weightsPerVertex > 0){
		for(int i = 0; i < vertexCount; i++){
			for(int j = 0; j < weightsPerVertex; j++){
				meshData->setWeight(i, j, reader_->readFloat());
			}
		}
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// マテリアル
//------------------------------------------------------------------------------
// マテリアルリストの読み込み
void BinarySceneLoader::readMaterialList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Basic"){
			readBasicMaterial();
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::readMaterialList() "
				"Skip unknown material %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}
}
//------------------------------------------------------------------------------
// マテリアルの読み込み
void BinarySceneLoader::readMaterial(Material* material){
	// 優先度
	material->setPriority(reader_->readInt());
	// ブレンドモード
	material->setBlendMode((Material::BlendMode)reader_->readInt());
	// アルファ値
	material->setAlpha(reader_->readFloat());
	// ブレンドソース
	material->setBlendSource((Material::BlendState)reader_->readInt());
	// ブレンドデスティネーション
	material->setBlendDestination((Material::BlendState)reader_->readInt());
	// フォグオプション
	material->setFogOption((Material::FogOption)reader_->readInt());
	// ライトマスク
	material->setLightMask(reader_->readUInt());
	// Z書き込み
	material->setZWrite(reader_->readBool());
	// Zテスト
	material->setZTest(reader_->readBool());
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// 基本マテリアルの読み込み
void BinarySceneLoader::readBasicMaterial(){
	BasicMaterial* material =
		materialManager_->createBasicMaterial(readString());
	// マテリアル読み込み
	readMaterial(material);
	// ベースUVインデックス
	material->setBaseUVIndex(reader_->readInt());
	// 光沢UVインデックス
	material->setGlossUVIndex(reader_->readInt());
	// ライトUVインデックス
	material->setLightUVIndex(reader_->readInt());
	// 汚れUVインデックス
	material->setStainUVIndex(reader_->readInt());
	// ディフューズカラー
	material->setDiffuseColor(readColor3f());
	// スペキュラカラー
	material->setSpecularColor(readColor3f());
	// スペキュラパワー
	material->setSpecularPower(reader_->readFloat());
	// アンビエントカラー
	material->setAmbientColor(readColor3f());
	// エミッシブカラー
	material->setEmissiveColor(readColor3f());
}
//------------------------------------------------------------------------------
// テクスチャ
//------------------------------------------------------------------------------
// テクスチャリストの読み込み
void BinarySceneLoader::readTextureList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Surface"){
			readSurfaceTexture();
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::readTextureList() "
				"Skip unknown texture %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}
}
//------------------------------------------------------------------------------
// サーフェーステクスチャの読み込み
void BinarySceneLoader::readSurfaceTexture(){
	SurfaceTexture* texture =
		textureManager_->createSurfaceTexture(readString());
	// アドレスモードU
	texture->setAddressModeU((Texture::AddressMode)reader_->readInt());
	// アドレスモードV
	texture->setAddressModeV((Texture::AddressMode)reader_->readInt());
	// リピートUV
	texture->setRepeatUV(readTexCoord2());
	// オフセットUV
	texture->setOffsetUV(readTexCoord2());
}
//------------------------------------------------------------------------------
// ピクチャ
//------------------------------------------------------------------------------
// ピクチャリストの読み込み
void BinarySceneLoader::readPictureList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String name = readString();
		String path = readString();
		// 拡張子を取得
		FilePath filePath(path);
		String extension = filePath.getExtension();
		// 拡張子にあわせてピクチャを読み分ける
		Picture* picture;
		if(extension == "tga"){
			TargaLoader loader(basePath_ + path);
			loader.loadHeader();
			// アルファの有無
			if(loader.hasAlpha()){
				picture = readPictureRGBA8(name, loader);
			}else{
				picture = readPictureRGB8(name, loader);
			}
		}else{
			ErrorOut("BinarySceneLoader::readPictureList() "
				"Unsupported picture format %s (%d)",
				path.getBytes(), reader_->getPosition());
			return;
		}
		// パスを設定する
		picture->setPath(path);
	}
}
//------------------------------------------------------------------------------
// RGB8ビットピクチャの読み込み
Picture* BinarySceneLoader::readPictureRGB8(
	const String& name, TargaLoader& loader){
	PictureRGB8* picture = pictureManager_->createPictureRGB8(name);
	picture->setSize(loader.getSize());
	loader.loadImage(picture->getImageBuffer());
	return picture;
}
//------------------------------------------------------------------------------
// RGBA8ビットピクチャの読み込み
Picture* BinarySceneLoader::readPictureRGBA8(
	const String& name, TargaLoader& loader){
	PictureRGBA8* picture = pictureManager_->createPictureRGBA8(name);
	picture->setSize(loader.getSize());
	loader.loadImage(picture->getImageBuffer());
	return picture;
}
//------------------------------------------------------------------------------
// シーンノードリンク
//------------------------------------------------------------------------------
// シーンノードリンクリストの読み込み
void BinarySceneLoader::readSceneNodeLinkList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		readSceneNodeLink();
	}
}
//------------------------------------------------------------------------------
// シーンノードリンクの読み込み
void BinarySceneLoader::readSceneNodeLink(){
	String name = readString();
	SceneNode* sceneNode;
	if(name.equals("RootNode")){
		sceneNode = rootNode_;
	}else{
		sceneNode = sceneNodeManager_->search(name);
		if(sceneNode == NULL){
			ErrorOut("BinarySceneLoader::readSceneNodeLink() "
				"not found source sceneNode %s (%d)",
				name.getBytes(), reader_->getPosition());
		}
	}
	// シーンノードリンク
	int sceneNodeCount = reader_->readInt();
	for(int i = 0; i < sceneNodeCount; i++){
		String targetName = readString();
		SceneNode* target = sceneNodeManager_->search(targetName);
		if(target == NULL){
			ErrorOut("BinarySceneLoader::readSceneNodeLink() "
				"not found target sceneNode %s (%d)",
				targetName.getBytes(), reader_->getPosition());
		}
		sceneNode->addSceneNode(target);
	}
	// シーンリーフリンク
	int sceneLeafCount = reader_->readInt();
	for(int i = 0; i < sceneLeafCount; i++){
		int type = reader_->readInt();
		String targetName = readString();
		SceneLeaf* sceneLeaf = NULL;
		if(type == 0){
			sceneLeaf = modelManager_->search(targetName);
		}else if(type == 1){
			sceneLeaf = lightManager_->search(targetName);
		}else{
			ErrorOut("BinarySceneLoader::readSceneNodeLink() "
				"unsupported SceneLeafType %s %d (%d)",
				targetName.getBytes(), type, reader_->getPosition());
		}
		if(sceneLeaf == NULL){
			ErrorOut("BinarySceneLoader::readSceneNodeLink() "
				"not found target SceneLeaf %s (%d)",
				targetName.getBytes(), reader_->getPosition());
		}
		sceneNode->addSceneLeaf(sceneLeaf);
	}
}
//------------------------------------------------------------------------------
// モデルリンク
//------------------------------------------------------------------------------
// モデルリンクリストの読み込み
void BinarySceneLoader::readModelLinkList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		readModelLink();
	}
}
//------------------------------------------------------------------------------
// モデルリンクの読み込み
void BinarySceneLoader::readModelLink(){
	String name = readString();
	Model* model = modelManager_->search(name);
	if(model == NULL){
		ErrorOut("BinarySceneLoader::readModelLink() "
			"not found source model %s (%d)",
			name.getBytes(), reader_->getPosition());
	}
	// メッシュリンク
	int meshCount = reader_->readInt();
	for(int i = 0; i < meshCount; i++){
		String targetName = readString();
		Mesh* target = meshManager_->search(targetName);
		if(target == NULL){
			ErrorOut("BinarySceneLoader::readModelLink() "
				"not found target mesh %s (%d)",
				targetName.getBytes(), reader_->getPosition());
		}
		model->addMesh(target);
	}
}
//------------------------------------------------------------------------------
// メッシュリンク
//------------------------------------------------------------------------------
// メッシュリンクリストの読み込み
void BinarySceneLoader::readMeshLinkList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		readMeshLink();
	}
}
//------------------------------------------------------------------------------
// メッシュリンクの読み込み
void BinarySceneLoader::readMeshLink(){
	String name = readString();
	Mesh* mesh = meshManager_->search(name);
	if(mesh == NULL){
		ErrorOut("BinarySceneLoader::readMeshLink() "
			"not found source mesh %s (%d)",
			name.getBytes(), reader_->getPosition());
	}
	// メッシュデータを持つか
	bool hasMeshData = reader_->readBool();
	// マテリアルを持つか
	bool hasMaterial = reader_->readBool();
	Assert(hasMeshData || hasMaterial);
	// アライメント
	align();
	// メッシュデータリンク
	if(hasMeshData){
		String targetName = readString();
		MeshData* target = meshDataManager_->search(targetName);
		if(target == NULL){
			ErrorOut("BinarySceneLoader::readMeshLink() "
				"not found target meshData %s (%d)",
				targetName.getBytes(), reader_->getPosition());
		}
		mesh->setMeshData(target);
	}
	// マテリアルリンク
	if(hasMaterial){
		String targetName = readString();
		Material* target = materialManager_->search(targetName);
		if(target == NULL){
			ErrorOut("BinarySceneLoader::readMeshLink() "
				"not found target material %s (%d)",
				targetName.getBytes(), reader_->getPosition());
		}
		mesh->setMaterial(target);
	}
}
//------------------------------------------------------------------------------
// マテリアルリンク
//------------------------------------------------------------------------------
// マテリアルリンクリストの読み込み
void BinarySceneLoader::readMaterialLinkList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		String blockName = readID();
		int blockSize = reader_->readInt();
		// ブロック開始時にアライメントをとる
		align();
		int blockAddress = reader_->getPosition();
		if(blockName == "Basic"){
			readBasicMaterialLink();
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinarySceneLoader::readMaterialList() "
				"Skip unknown material %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}

}
//------------------------------------------------------------------------------
// 基本マテリアルリンクの読み込み
void BinarySceneLoader::readBasicMaterialLink(){
	String name = readString();
	Material* material = materialManager_->search(name);
	if(material == NULL){
		ErrorOut("BinarySceneLoader::readBasicMaterialLink() "
			"Not found material %s (%d)",
			name.getBytes(), reader_->getPosition());
	}
	BasicMaterial* basicMaterial = material->castBasicMaterial();
	if(basicMaterial == NULL){
		ErrorOut("BinarySceneLoader::readBasicMaterialLink() "
			"Invalid type material %s (%d)",
			name.getBytes(), reader_->getPosition());
	}
	bool hasBaseTexture = reader_->readBool();
	bool hasGlossTexture = reader_->readBool();
	bool hasLightTexture = reader_->readBool();
	bool hasStainTexture = reader_->readBool();
	align();
	if(hasBaseTexture){
		String textureName = readString();
		Texture* texture = textureManager_->search(textureName);
		if(texture == NULL){
			ErrorOut("BinarySceneLoader::readBasicMaterialLink() "
				"Not found texture %s (%d)",
				textureName.getBytes(), reader_->getPosition());
		}
		basicMaterial->setBaseTexture(texture);
	}
	if(hasGlossTexture){
		String textureName = readString();
		Texture* texture = textureManager_->search(textureName);
		if(texture == NULL){
			ErrorOut("BinarySceneLoader::readBasicMaterialLink() "
				"Not found texture %s (%d)",
				textureName.getBytes(), reader_->getPosition());
		}
		basicMaterial->setGlossTexture(texture);
	}
	if(hasLightTexture){
		String textureName = readString();
		Texture* texture = textureManager_->search(textureName);
		if(texture == NULL){
			ErrorOut("BinarySceneLoader::readBasicMaterialLink() "
				"Not found texture %s (%d)",
				textureName.getBytes(), reader_->getPosition());
		}
		basicMaterial->setLightTexture(texture);
	}
	if(hasStainTexture){
		String textureName = readString();
		Texture* texture = textureManager_->search(textureName);
		if(texture == NULL){
			ErrorOut("BinarySceneLoader::readBasicMaterialLink() "
				"Not found texture %s (%d)",
				textureName.getBytes(), reader_->getPosition());
		}
		basicMaterial->setStainTexture(texture);
	}
}
//------------------------------------------------------------------------------
// テクスチャリンク
//------------------------------------------------------------------------------
// テクスチャリンクリストの読み込み
void BinarySceneLoader::readTextureLinkList(int listSize){
	int endAddress = reader_->getPosition() + listSize;
	while(true){
		if(endAddress == reader_->getPosition()){ break; }
		Assert(!reader_->isEnd());
		readTextureLink();
	}
}
//------------------------------------------------------------------------------
// テクスチャリンクの読み込み
void BinarySceneLoader::readTextureLink(){
	String name = readString();
	Texture* texture = textureManager_->search(name);
	if(texture == NULL){
		ErrorOut("BinarySceneLoader::readTextureLink() "
			"not found source texture %s (%d)",
			name.getBytes(), reader_->getPosition());
	}
	// ピクチャリンク
	int pictureCount = reader_->readInt();
	for(int i = 0; i < pictureCount; i++){
		String targetName = readString();
		Picture* target = pictureManager_->search(targetName);
		if(target == NULL){
			ErrorOut("BinarySceneLoader::readTextureLink() "
				"not found target picture %s (%d)",
				targetName.getBytes(), reader_->getPosition());
		}
		texture->addPicture(target);
	}
}
//------------------------------------------------------------------------------
// 値の読み込み
//------------------------------------------------------------------------------
// 文字列の読み込み
String BinarySceneLoader::readString(){
	String result;
	int size = reader_->readInt();
	if(size > stringBufferSize_){
		char* allocateBuffer = new char[size];
		reader_->readBytes(allocateBuffer, size);
		result = allocateBuffer;
		delete allocateBuffer;
	}else{
		reader_->readBytes(stringBuffer_, size);
		result = stringBuffer_;
	}
	align();
	return result;
}
//------------------------------------------------------------------------------
// 三次元ベクトルの読み込み
Vector3 BinarySceneLoader::readVector3(){
	Vector3 result;
	reader_->readBytes(result.array, sizeof(Vector3));
	return result;
}
//------------------------------------------------------------------------------
// Matrix34値の読み込み
Matrix34 BinarySceneLoader::readMatrix34(){
	Matrix34 result;
	reader_->readBytes(result.array, sizeof(Matrix34));
	return result;
}
//------------------------------------------------------------------------------
// 三要素整数カラー値の読み込み
Color3c BinarySceneLoader::readColor3c(){
	Color3c result;
	reader_->readBytes(result.array, sizeof(Color3c));
	return result;
}
//------------------------------------------------------------------------------
// 四要素整数カラー値の読み込み
Color4c BinarySceneLoader::readColor4c(){
	Color4c result;
	reader_->readBytes(result.array, sizeof(Color4c));
	return result;
}
//------------------------------------------------------------------------------
// 三要素実数カラー値の読み込み
Color3f BinarySceneLoader::readColor3f(){
	Color3f result;
	reader_->readBytes(result.array, sizeof(Color3f));
	return result;
}
//------------------------------------------------------------------------------
// 四要素実数カラー値の読み込み
Color4f BinarySceneLoader::readColor4f(){
	Color4f result;
	reader_->readBytes(result.array, sizeof(Color4f));
	return result;
}
//------------------------------------------------------------------------------
// 二次元テクスチャ座標値の読み込み
TexCoord2 BinarySceneLoader::readTexCoord2(){
	TexCoord2 result;
	reader_->readBytes(result.array, sizeof(TexCoord2));
	return result;
}
//------------------------------------------------------------------------------
// 軸沿いボックスの読み込み
AxisAlignedBox BinarySceneLoader::readAxisAlignedBox(){
	AxisAlignedBox result;
	reader_->readBytes(&result, sizeof(AxisAlignedBox));
	return result;
}
//------------------------------------------------------------------------------
// 球の読み込み
Sphere BinarySceneLoader::readSphere(){
	Sphere result;
	reader_->readBytes(&result, sizeof(Sphere));
	return result;
}
//------------------------------------------------------------------------------
// ユーティリティ
//------------------------------------------------------------------------------
// アライメントを取る
void BinarySceneLoader::align(){
	reader_->align(16);
}
//------------------------------------------------------------------------------
// IDの読み込み
String BinarySceneLoader::readID(){
	char buffer[13];
	buffer[12] = 0;
	reader_->readBytes(buffer, 12);
	return String(buffer);
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
