///////////////////////////////////////////////////////////////////////////////
//  CHEOOverwriter.cpp

#include <stdio.h>
#include "../Independent/FileImage/CFileImageAnalyser.h"
#include "../Independent/FormatString/LFormat.h"
#include "../Independent/Math3D/S2D.h"
#include "../Independent/Math3D/S3D.h"
#include "../Independent/Math3D/SColor.h"
#include "../Independent/Math3D/SColor32.h"
#include "../Independent/Math3D/SQuaternion.h"
#include "../Independent/Math3D/SUV.h"
#include "../Specific/Debug/LMsg.h"
#include "../Specific/FileSystem/CFile.h"
#include "../Specific/FileSystem/LFileName.h"
#include "../Specific/FileSystem/CFindFile.h"
#include "CHEOBoneWeight.h"
#include "CHEOMorph.h"
#include "CHEOOverwriter.h"
#include "CHEOPrimitive.h"
#include "EHEOBlendMode.h"
#include "EHEOColliderShape.h"
#include "EHEOColliderType.h"
#include "EHEOShaderType.h"

namespace heo {

CHEOOverwriter::CHEOOverwriter() :
	m_ReflectionProbeNum(0)
{
}

CHEOOverwriter::~CHEOOverwriter()
{
}

bool CHEOOverwriter::Overwrite(const std::string& FileName)
{
	std::vector<unsigned char> Data;
	if (!filesystem::CFile::ReadImage(Data, FileName)) return false;

	fileimage::CFileImageAnalyser Analyser(&Data[0], &Data[0] + Data.size());

	// ヘッダ
	std::string ID;
	if (!Analyser.GetZeroTerminatedString(ID)) return false;
	if (ID != "HEO") return false;

	// バージョン
	int Version;
	if (!Analyser.GetInt(Version)) return false;
	if (Version < 7) return false;

	// HEOTexCompを通したかのフラグ
	if (Version >= 21) {
		const unsigned char* HEOTexCompFlagPointer = Analyser.GetReadPointer();

		int HEOTexCompFlag;
		if (!Analyser.GetInt(HEOTexCompFlag)) return false;

		*const_cast<unsigned char*>(HEOTexCompFlagPointer) = 1;
	}

	// テクスチャリスト
	if (Version >= 26) {
		// Ver.26以降はファイル先頭部分にあるこのテクスチャ情報のみ読み込むだけで構わない

		// テクスチャリストバージョン
		// Ver.26以降はこのバージョンをチェックする
		int TextureListVersion;
		if (!Analyser.GetInt(TextureListVersion)) return false;

		if (TextureListVersion != 0) return false;

		//
		if (!AnalyseTextureList(Analyser, Version)) return false;
		if (!AnalyseReflectionProbe(Analyser, Version))return false;
		if (!AnalyseLightmapList(Analyser, Version)) return false;
	}
	else {
		// 各種リスト
		// Ver.26以前は以下の全情報を読み込まないとテクスチャ情報の正しい位置を判別できない
		if (!AnalyseNodeList(Analyser, Version)) return false;
		if (!AnalyseMeshList(Analyser, Version)) return false;
		if (!AnalyseMaterialList(Analyser, Version)) return false;
		if (!AnalyseTextureList(Analyser, Version)) return false;
		if (!AnalyseBoneTable(Analyser)) return false;
		if (!AnalyseLightmapList(Analyser, Version)) return false;
	}

	// 圧縮テクスチャファイルの存在をチェックし指定のヘッダ位置のフラグを書き替える
	int NumofTexComp[4] = { 0, 0 ,0 ,0 };

	for (int TextureIndex = 0; TextureIndex < static_cast<int>(m_TextureCompressionInfoPointerList.size()); TextureIndex++) {
		auto& TextureCompressionInfoPointer = m_TextureCompressionInfoPointerList[TextureIndex];

		for (int n = 0; n < 4; n++) {
			std::string SubFolderName;
			std::string Extension = "pvr";

			switch (static_cast<ETextureCompressionType>(n)) {
			case ETextureCompressionType::PVRTC:
				SubFolderName = "tex_pvrtc";
				break;

			case ETextureCompressionType::ETC2:
				SubFolderName = "tex_etc";
				break;
			
			case ETextureCompressionType::ASTC:
				SubFolderName = "tex_astc";
				break;

			case ETextureCompressionType::DXT:
				SubFolderName = "tex_dxt";
				Extension = "dds";
				break;

			default:
				return false;
			}

			const std::string TexFileName = LFileName::DeleteFileName(FileName) + LFileName::AddPunct(SubFolderName) +
				LFormat::Make("%03d.%s", TextureIndex, Extension.c_str());

			if (!filesystem::CFindFile::IsExistFile(TexFileName)) {
//				printf("no exist %s\n", TexFileName.c_str());
				*const_cast<unsigned char*>(TextureCompressionInfoPointer[n]) = 0;
				continue;
			}

			*const_cast<unsigned char*>(TextureCompressionInfoPointer[n]) = 1;

//			printf("exist %s\n", TexFileName.c_str());
			NumofTexComp[n]++;
		}
	}

	// リフレクションプローブキューブマップの圧縮フラグを確認する
	if (!AnalyseReflectionProbeCubemap(Version, FileName))return false;

	//
	if (!filesystem::CFile::WriteImage(Data, FileName)) return false;

	printf("ExistTextureCompression %d %d %d %d\n", NumofTexComp[0], NumofTexComp[1], NumofTexComp[2], NumofTexComp[3]);

	return true;
}

bool CHEOOverwriter::AnalyseNodeList(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	// 個数
	int Numof;
	if (!Analyser.GetInt(Numof)) return false;

	// ノードリスト
//	m_NodeList.reserve(static_cast<size_t>(Numof));

	for (int n = 0; n < Numof; n++) {
		if (!AnalyseNode(Analyser, Version)) return false;
	}

	return true;
}

bool CHEOOverwriter::AnalyseNode(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	// ノード名
	std::string NodeName;
	if (!Analyser.GetZeroTerminatedString(NodeName)) return false;

	//
	if (!Analyser.IsCanRead(4 * 3 + 4 * 4 + 4 * 3 + 4 * 3)) return false;

	// トランスフォーム
	S3D LocalPos;
	LocalPos.fX = Analyser.GetFloatNoCheck();
	LocalPos.fY = Analyser.GetFloatNoCheck();
	LocalPos.fZ = Analyser.GetFloatNoCheck();

	SQuaternion LocalRotate;
	LocalRotate.fX = Analyser.GetFloatNoCheck();
	LocalRotate.fY = Analyser.GetFloatNoCheck();
	LocalRotate.fZ = Analyser.GetFloatNoCheck();
	LocalRotate.fW = Analyser.GetFloatNoCheck();

	S3D LocalScale;
	LocalScale.fX = Analyser.GetFloatNoCheck();
	LocalScale.fY = Analyser.GetFloatNoCheck();
	LocalScale.fZ = Analyser.GetFloatNoCheck();

	// 親ノードインデックス
	const int ParentNodeIndex = Analyser.GetIntNoCheck();

	// メッシュインデックス
	const int MeshIndex = Analyser.GetIntNoCheck();

	// コライダー
	const EHEOColliderShape ColliderShape = static_cast<EHEOColliderShape>(Analyser.GetIntNoCheck());
	EHEOColliderType ColliderType = EHEOColliderType::Collider;

	S3D ColliderCenter;
	S3D ColliderSize;
	bool HasMesh = false;

	switch (ColliderShape) {
	case EHEOColliderShape::None:
		break;

	case EHEOColliderShape::Box:
		if (!Analyser.IsCanRead(4 * 2 + 4 * 3 * 2)) return false;

		if (Version >= 6) {
			ColliderType = static_cast<EHEOColliderType>(Analyser.GetIntNoCheck());
		}
		else {
			ColliderType = EHEOColliderType::Collider;
		}

		if (Version >= 23) {
			int ColliderTarget = Analyser.GetIntNoCheck();
		}

		ColliderCenter.fX = Analyser.GetFloatNoCheck();
		ColliderCenter.fY = Analyser.GetFloatNoCheck();
		ColliderCenter.fZ = Analyser.GetFloatNoCheck();

		ColliderSize.fX = Analyser.GetFloatNoCheck();
		ColliderSize.fY = Analyser.GetFloatNoCheck();
		ColliderSize.fZ = Analyser.GetFloatNoCheck();
		break;

	case EHEOColliderShape::Sphere:
		if (!Analyser.IsCanRead(4 * 2 + 4 * 3 * 2)) return false;

		if (Version >= 6) {
			ColliderType = static_cast<EHEOColliderType>(Analyser.GetIntNoCheck());
		}
		else {
			ColliderType = EHEOColliderType::Clickable;
		}

		if (Version >= 23) {
			int ColliderTarget = Analyser.GetIntNoCheck();
		}

		ColliderCenter.fX = Analyser.GetFloatNoCheck();
		ColliderCenter.fY = Analyser.GetFloatNoCheck();
		ColliderCenter.fZ = Analyser.GetFloatNoCheck();

		ColliderSize.fX = Analyser.GetFloatNoCheck();
		ColliderSize.fY = ColliderSize.fX;
		ColliderSize.fZ = ColliderSize.fX;
		break;

	case EHEOColliderShape::Mesh:
		if (!Analyser.IsCanRead(4 * 2 + 4 * 3 * 2)) return false;

		if (Version >= 6) {
			ColliderType = static_cast<EHEOColliderType>(Analyser.GetIntNoCheck());
		}
		else {
			ColliderType = EHEOColliderType::Collider;
		}

		if (Version >= 23) {
			int ColliderTarget = Analyser.GetIntNoCheck();
		}

		ColliderCenter.fX = Analyser.GetFloatNoCheck();
		ColliderCenter.fY = Analyser.GetFloatNoCheck();
		ColliderCenter.fZ = Analyser.GetFloatNoCheck();

		ColliderSize.fX = Analyser.GetFloatNoCheck();
		ColliderSize.fY = Analyser.GetFloatNoCheck();
		ColliderSize.fZ = Analyser.GetFloatNoCheck();

		if (Version >= 20) {
			// Meshを設定しているかのフラグ
			int UseMeshFlag = 0;
			if (!Analyser.GetInt(UseMeshFlag))return false;

			switch (UseMeshFlag)
			{
			case 1:
				HasMesh = true;
				break;

			case 0:
				HasMesh = false;
				break;

			default:
				break;
			}
		}

		break;

	default:
		return false;
	}

	// もしメッシュコライダーそのものがメッシュを持っているのなら取得する
	if (HasMesh) {
		//std::shared_ptr<CHEOMesh> HEOMesh = nullptr;
		if (!AnalyseMeshSimple(Analyser, Version))return false;

		//
		//HEOCollider.SetMesh(HEOMesh);
	}

	// アニメーション
	bool UseAnimation = false;
	S3D AnimationRotatePerSec;

	if (Version >= 8) {
		int UseAnimationFlag = 0;
		if (!Analyser.GetInt(UseAnimationFlag)) return false;

		switch (UseAnimationFlag) {
		case 0:
			break;

		case 1:
			if (!Analyser.IsCanRead(3 * 4)) return false;

			AnimationRotatePerSec.fX = Analyser.GetFloatNoCheck();
			AnimationRotatePerSec.fY = Analyser.GetFloatNoCheck();
			AnimationRotatePerSec.fZ = Analyser.GetFloatNoCheck();

			UseAnimation = true;
			break;

		default:
			return false;
		}
	}

	// リフレクションプローブ
	bool HasReflectionProbe = false;
	// ゲームオブジェクトが持っているリフレクションプローブコンポーネントのインデックス
	int HasReflectionProbeIndex = -1;
	// ゲームオブジェクトが使用するリフレクションプローブのインデックス
	int UseReflectionProbeIndex = -1;

	if (Version >= 12) {
		// リフレクションプローブコンポーネントそのものを持つかどうかのフラグ
		int HasReflectionProbeFlag = 0;
		if (!Analyser.GetInt(HasReflectionProbeFlag)) return false;

		switch (HasReflectionProbeFlag)
		{
		case 0:
			if (Version >= 16) {
				if (!Analyser.GetInt(UseReflectionProbeIndex)) return false;
			}
			break;
		case 1:
			HasReflectionProbe = true;
			// リフレクションプローブインデックスを読む
			if (!Analyser.GetInt(HasReflectionProbeIndex)) return false;
			break;
		default:
			return false;
		}
	}

	// ライトマップ
	if (Version >= 15) {
		if (!Analyser.Skip(4 + 4 * 2 + 4 * 2)) return false;
	}

	// オブジェクトがHeliodor上でStaticかDynamicかのフラグ
	if (Version >= 17) {
		if (!Analyser.Skip(4)) return false;
	}

	// 登録
//	m_NodeList.push_back(CHEONode(NodeName, LocalPos, LocalRotate, LocalScale, ParentNodeIndex, MeshIndex,
//		CHEOCollider(ColliderShape, ColliderType, ColliderCenter, ColliderSize)));

	return true;
}

bool CHEOOverwriter::AnalyseMeshList(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	// 個数
	int Numof;
	if (!Analyser.GetInt(Numof)) return false;

	// メッシュリスト
//	m_MeshList.reserve(static_cast<size_t>(Numof));

	for (int n = 0; n < Numof; n++) {
		if (!AnalyseMesh(Analyser, Version)) return false;
	}

	return true;
}

bool CHEOOverwriter::AnalyseMesh(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	if (!Analyser.IsCanRead(
		4 +
		1 * 6 +
		((Version >= 15) ? 0 : (4 * 5))))	// ライトマップ
	{
		return false;
	}

	// 頂点数
	const int NumofVertex = Analyser.GetIntNoCheck();

	// フラグ
	const bool ExistNormal = (Analyser.GetByteNoCheck() != 0);
	const bool ExistTangent = (Analyser.GetByteNoCheck() != 0);
	const bool ExistUV = (Analyser.GetByteNoCheck() != 0);
	const bool ExistUV2 = (Analyser.GetByteNoCheck() != 0);
	const bool ExistColor = (Analyser.GetByteNoCheck() != 0);
	const bool ExistBoneWeight = (Analyser.GetByteNoCheck() != 0);

	// ライトマップ
	// Version15以前には存在した

	// 頂点リスト
	if (!Analyser.IsCanRead((4 * 3 +
		(ExistNormal ? (4 * 3) : 0) +
		(ExistTangent ? (4 * 3) : 0) +
		(ExistUV ? (4 * 2) : 0) +
		(ExistUV2 ? (4 * 2) : 0) +
		(ExistColor ? 4 : 0) +
		(ExistBoneWeight ? (2 * 4 + 4 * 4) : 0)) * NumofVertex))
	{
		return false;
	}

	std::vector<S3D> PosList(NumofVertex);
	std::vector<S3D> NormalList(ExistNormal ? NumofVertex : 0);
	std::vector<S3D> TangentList(ExistTangent ? NumofVertex : 0);
	std::vector<SUV> UVList(ExistUV ? NumofVertex : 0);
	std::vector<SUV> UV2List(ExistUV2 ? NumofVertex : 0);
	std::vector<math3d::SColor32> ColorList(ExistColor ? NumofVertex : 0);
	std::vector<CHEOBoneWeight> HEOBoneWeightList;

	for (int n = 0; n < NumofVertex; n++) {
		// 位置
		PosList[n].fX = Analyser.GetFloatNoCheck();
		PosList[n].fY = Analyser.GetFloatNoCheck();
		PosList[n].fZ = Analyser.GetFloatNoCheck();

		// 法線
		if (ExistNormal) {
			NormalList[n].fX = Analyser.GetFloatNoCheck();
			NormalList[n].fY = Analyser.GetFloatNoCheck();
			NormalList[n].fZ = Analyser.GetFloatNoCheck();
		}

		// Tangent
		if (ExistTangent) {
			TangentList[n].fX = Analyser.GetFloatNoCheck();
			TangentList[n].fY = Analyser.GetFloatNoCheck();
			TangentList[n].fZ = Analyser.GetFloatNoCheck();
		}

		// UV
		if (ExistUV) {
			UVList[n].fU = Analyser.GetFloatNoCheck();
			UVList[n].fV = Analyser.GetFloatNoCheck();
		}

		// UV2
		if (ExistUV2) {
			UV2List[n].fU = Analyser.GetFloatNoCheck();
			UV2List[n].fV = Analyser.GetFloatNoCheck();
		}

		// カラー
		if (ExistColor) {
			ColorList[n].r = Analyser.GetByteNoCheck();
			ColorList[n].g = Analyser.GetByteNoCheck();
			ColorList[n].b = Analyser.GetByteNoCheck();
			ColorList[n].a = Analyser.GetByteNoCheck();
		}

		// ボーンウェイト
		if (ExistBoneWeight) {
			std::array<short, 4> BoneIndexList;
			BoneIndexList[0] = Analyser.GetShortNoCheck();
			BoneIndexList[1] = Analyser.GetShortNoCheck();
			BoneIndexList[2] = Analyser.GetShortNoCheck();
			BoneIndexList[3] = Analyser.GetShortNoCheck();

			std::array<float, 4> BoneWeightList;
			BoneWeightList[0] = Analyser.GetFloatNoCheck();
			BoneWeightList[1] = Analyser.GetFloatNoCheck();
			BoneWeightList[2] = Analyser.GetFloatNoCheck();
			BoneWeightList[3] = Analyser.GetFloatNoCheck();

			HEOBoneWeightList.push_back(CHEOBoneWeight(BoneIndexList, BoneWeightList));
		}
	}

	// バウンディングボックス
	if (!Analyser.IsCanRead(4 * 6)) return false;

	S3D BoundingBoxMinPos;
	BoundingBoxMinPos.fX = Analyser.GetFloatNoCheck();
	BoundingBoxMinPos.fY = Analyser.GetFloatNoCheck();
	BoundingBoxMinPos.fZ = Analyser.GetFloatNoCheck();

	S3D BoundingBoxMaxPos;
	BoundingBoxMaxPos.fX = Analyser.GetFloatNoCheck();
	BoundingBoxMaxPos.fY = Analyser.GetFloatNoCheck();
	BoundingBoxMaxPos.fZ = Analyser.GetFloatNoCheck();

	// プリミティブリスト
	int NumofPrimitive;
	if (!Analyser.GetInt(NumofPrimitive)) return false;

	std::vector<CHEOPrimitive> HEOPrimitiveList;

	const bool IndexTypeUSHORT = (NumofVertex <= 65536);

	for (int n = 0; n < NumofPrimitive; n++) {
		// マテリアルインデックス
		int MaterialIndex;
		if (!Analyser.GetInt(MaterialIndex)) return false;

		// インデックス数
		int NumofIndex;
		if (!Analyser.GetInt(NumofIndex)) return false;

		// インデックスリスト
		std::vector<unsigned short> IndexListUSHORT;
		std::vector<int> IndexListINT;

		if (!Analyser.IsCanRead((IndexTypeUSHORT ? 2 : 4) * NumofIndex)) return false;

		if (IndexTypeUSHORT) {
			IndexListUSHORT.resize(NumofIndex);

			for (int m = 0; m < NumofIndex; m++) {
				IndexListUSHORT[m] = Analyser.GetWordNoCheck();
			}
		}
		else {
			IndexListINT.resize(NumofIndex);

			for (int m = 0; m < NumofIndex; m++) {
				IndexListINT[m] = Analyser.GetIntNoCheck();
			}
		}

		// 登録
		HEOPrimitiveList.push_back(CHEOPrimitive(MaterialIndex, IndexListUSHORT, IndexListINT));
	}

	// モーフリスト
	int NumofMorph;
	if (!Analyser.GetInt(NumofMorph)) return false;

	std::vector<CHEOMorph> MorphList;

	for (int MorphIndex = 0; MorphIndex < NumofMorph; MorphIndex++) {
		// 名前
		std::string Name;
		if (!Analyser.GetZeroTerminatedString(Name)) return false;

		// 相対位置リスト
		if (!Analyser.IsCanRead(3 * sizeof(float) * NumofVertex)) return false;

		std::vector<S3D> OffsetPosList(NumofVertex);

		for (int n = 0; n < NumofVertex; n++) {
			OffsetPosList[n].fX = Analyser.GetFloatNoCheck();
			OffsetPosList[n].fY = Analyser.GetFloatNoCheck();
			OffsetPosList[n].fZ = Analyser.GetFloatNoCheck();
		}

		//
		MorphList.push_back(CHEOMorph(Name, OffsetPosList));
	}

	// 登録
//	m_MeshList.push_back(CHEOMesh(PosList, NormalList, TangentList, UVList, UV2List, ColorList, HEOBoneWeightList, HEOPrimitiveList, MorphList,
//		BoundingBoxMinPos, BoundingBoxMaxPos, LightmapIndex, LightmapScale, LightmapOffset));

	return true;
}

bool CHEOOverwriter::AnalyseMeshSimple(fileimage::CFileImageAnalyser& Analyser, int Version) {
	if (!Analyser.IsCanRead(4 + 1 * 6))
	{
		return false;
	}

	// 頂点数
	const int NumofVertex = Analyser.GetIntNoCheck();

	// フラグ
	const bool ExistNormal = (Analyser.GetByteNoCheck() != 0);
	const bool ExistTangent = (Analyser.GetByteNoCheck() != 0);
	const bool ExistUV = (Analyser.GetByteNoCheck() != 0);
	const bool ExistUV2 = (Analyser.GetByteNoCheck() != 0);
	const bool ExistColor = (Analyser.GetByteNoCheck() != 0);
	const bool ExistBoneWeight = (Analyser.GetByteNoCheck() != 0);

//	int LightmapIndex;
	S2D LightmapScale;
	S2D LightmapOffset;

	// 頂点リスト
	if (!Analyser.IsCanRead(4 * 3 + (ExistNormal ? (4 * 3) : 0)))
	{
		return false;
	}

	std::vector<S3D> PosList(NumofVertex);
	std::vector<S3D> NormalList(ExistNormal ? NumofVertex : 0);
	std::vector<S3D> TangentList(ExistTangent ? NumofVertex : 0);
	std::vector<SUV> UVList(ExistUV ? NumofVertex : 0);
	std::vector<SUV> UV2List(0);
	std::vector<math3d::SColor32> ColorList(ExistColor ? NumofVertex : 0);
	std::vector<CHEOBoneWeight> HEOBoneWeightList;

	for (int n = 0; n < NumofVertex; n++) {
		// 位置
		PosList[n].fX = Analyser.GetFloatNoCheck();
		PosList[n].fY = Analyser.GetFloatNoCheck();
		PosList[n].fZ = Analyser.GetFloatNoCheck();

		// 法線
		if (ExistNormal) {
			NormalList[n].fX = Analyser.GetFloatNoCheck();
			NormalList[n].fY = Analyser.GetFloatNoCheck();
			NormalList[n].fZ = Analyser.GetFloatNoCheck();
		}
	}

	S3D BoundingBoxMinPos;
	S3D BoundingBoxMaxPos;

	// プリミティブリスト
	int NumofPrimitive;
	if (!Analyser.GetInt(NumofPrimitive)) return false;

	std::vector<CHEOPrimitive> HEOPrimitiveList;

	const bool IndexTypeUSHORT = (NumofVertex <= 65536);

	for (int n = 0; n < NumofPrimitive; n++) {
		// インデックス数
		int NumofIndex;
		if (!Analyser.GetInt(NumofIndex)) return false;

		// インデックスリスト
		std::vector<unsigned short> IndexListUSHORT;
		std::vector<int> IndexListINT;

		if (!Analyser.IsCanRead((IndexTypeUSHORT ? 2 : 4) * NumofIndex)) return false;

		if (IndexTypeUSHORT) {
			IndexListUSHORT.resize(NumofIndex);

			for (int m = 0; m < NumofIndex; m++) {
				IndexListUSHORT[m] = Analyser.GetWordNoCheck();
			}
		}
		else {
			IndexListINT.resize(NumofIndex);

			for (int m = 0; m < NumofIndex; m++) {
				IndexListINT[m] = Analyser.GetIntNoCheck();
			}
		}

		// 登録
		HEOPrimitiveList.push_back(CHEOPrimitive(-1, IndexListUSHORT, IndexListINT));
	}

	std::vector<CHEOMorph> MorphList;

	// 登録
	//HEOMesh = std::make_shared<CHEOMesh>(PosList, NormalList, TangentList, UVList, UV2List, ColorList, HEOBoneWeightList, HEOPrimitiveList, MorphList,
	//	BoundingBoxMinPos, BoundingBoxMaxPos, LightmapIndex, LightmapScale, LightmapOffset);

	return true;
}

bool CHEOOverwriter::AnalyseMaterialList(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	// 個数
	int Numof;
	if (!Analyser.GetInt(Numof)) return false;

	// リフレクションプローブ
	// Ver.26以降はヘッダ先頭付近で処理される
	if (Version >= 11 && Version < 26) {
		if(!AnalyseReflectionProbe(Analyser, Version))return false;
	}
	
	// マテリアルリスト
	for (int n = 0; n < Numof; n++) {
		// マテリアル名
		std::string Name;
		if (!Analyser.GetZeroTerminatedString(Name)) return false;

		//
		if (!Analyser.IsCanRead(
			4 +										// シェーダータイプ
			4 +										// ブレンドモード
			4 +										// カットオフ
			((Version >= 3) ? 1 : 0) +				// 両面
			((Version >= 13) ? 1 : 0) +				// ライトスキャタリング使用フラグ
			1 +										// 頂点カラー使用フラグ
			4 * 4 +									// カラー
			4 * 4 +									// エミッションカラー
			4 * 4 +									// テクスチャインデックス（ShaderTypeによってRoughness用のサイズが変わるが多めに計算する）
			((Version >= 4) ? (4 * 4) : 0) +		// テクスチャスケール
			((Version >= 7) ? (4 * 4) : 0))) 		// テクスチャスケール1
		{
			return false;
		}

		// シェーダータイプ
		const EHEOShaderType ShaderType = static_cast<EHEOShaderType>(Analyser.GetIntNoCheck());

		// ブレンドモード
		const EHEOBlendMode BlendMode = static_cast<EHEOBlendMode>(Analyser.GetIntNoCheck());

		// カットオフ
		const float Cutoff = Analyser.GetFloatNoCheck();

		// 両面
		bool DoubleSided = false;

		if (Version >= 3) {
			DoubleSided = (Analyser.GetByteNoCheck() != 0);
		}

		// ライトスキャタリング使用フラグ
		bool UseLightScattering = true;

		if (Version >= 13) {
			UseLightScattering = (Analyser.GetByteNoCheck() != 0);
		}

		// 頂点カラー使用フラグ
		const bool UseVertexColor = (Analyser.GetByteNoCheck() != 0);

		// カラー
		const SColor Color = AnalyseColor(Analyser);

		// エミッションカラー
		SColor EmissionColor = AnalyseColor(Analyser);

		// テクスチャインデックス
		const int Texture0Index = Analyser.GetIntNoCheck();
		const int Texture1Index = Analyser.GetIntNoCheck();
		const int Texture2Index = Analyser.GetIntNoCheck();

		// tex3
		int Tex3Index = -1;
		if (Version>= 14) {
			Tex3Index= (
				(ShaderType == EHEOShaderType::AutodeskInteractive) ? Analyser.GetIntNoCheck() :
				((ShaderType == EHEOShaderType::Standard) ? Analyser.GetIntNoCheck() : -1)
			);	//PBR用
		}
		else {
			Tex3Index = ((ShaderType == EHEOShaderType::AutodeskInteractive) ? Analyser.GetIntNoCheck() : -1);	//PBR用
		}
		const int Texture3Index = Tex3Index;

		// tex4
		int Tex4Index = -1;
		if (Version >= 24 && ShaderType == EHEOShaderType::MToon) {
			Tex4Index = Analyser.GetIntNoCheck();
		}
		const int Texture4Index = Tex4Index;

		// テクスチャスケール
		SUV TextureScaleMain(1.0f, 1.0f);
		SUV TextureOffsetMain(0.0f, 0.0f);

		if (Version >= 4) {
			TextureScaleMain.fU = Analyser.GetFloatNoCheck();
			TextureScaleMain.fV = Analyser.GetFloatNoCheck();
			TextureOffsetMain.fU = Analyser.GetFloatNoCheck();
			TextureOffsetMain.fV = Analyser.GetFloatNoCheck();
			//なぜかUnityのテクスチャ座標系が┏ではなく┗のため特殊対応
			if (Version >= 19) {
				TextureOffsetMain.fV = 1.0f - TextureOffsetMain.fV;
				TextureOffsetMain.fV -= TextureScaleMain.fV;
			}
			else {
				if (TextureScaleMain.fV < 1.0f) {
					TextureOffsetMain.fV = 1.0f - TextureOffsetMain.fV;
					TextureOffsetMain.fV -= TextureScaleMain.fV;
				}
			}
		}

		// テクスチャスケール1
		SUV Texture1ScaleMain(1.0f, 1.0f);
		SUV Texture1OffsetMain(0.0f, 0.0f);

		if (Version >= 7) {
			Texture1ScaleMain.fU = Analyser.GetFloatNoCheck();
			Texture1ScaleMain.fV = Analyser.GetFloatNoCheck();
			Texture1OffsetMain.fU = Analyser.GetFloatNoCheck();
			Texture1OffsetMain.fV = Analyser.GetFloatNoCheck();
			//なぜかUnityのテクスチャ座標系が┏ではなく┗のため特殊対応
			if (Version >= 19) {
				Texture1OffsetMain.fV = 1.0f - Texture1OffsetMain.fV;
				Texture1OffsetMain.fV -= Texture1ScaleMain.fV;
			}
			else {
				if (Texture1ScaleMain.fV < 1.0f) {
					Texture1OffsetMain.fV = 1.0f - Texture1OffsetMain.fV;
					Texture1OffsetMain.fV -= Texture1ScaleMain.fV;
				}
			}
		}

		// UVスクローラ
		if (Version >= 10) {
			int UseUVScroller = 0;
			if (!Analyser.GetInt(UseUVScroller)) return false;

			if (UseUVScroller != 0) {
				if (!Analyser.IsCanRead(4 * 3)) return false;

				const float WaitTime = Analyser.GetFloatNoCheck();
				const float ScrollTime = Analyser.GetFloatNoCheck();
				const int NumofStepUV = Analyser.GetIntNoCheck();

				if (!Analyser.IsCanRead(4 * 2 * NumofStepUV)) return false;

				std::vector<SUV> StepUVList;

				for (int StepUVIndex = 0; StepUVIndex < NumofStepUV; StepUVIndex++) {
					const float U = Analyser.GetFloatNoCheck();
					const float V = Analyser.GetFloatNoCheck();

					StepUVList.push_back(SUV(U, V));
				}
			}
		}

		//リフレクションプローブ(最新版v16以上のエクスポーターでは使われていない変数なため非推奨)
		if (Version >= 11 && Version < 24) {
			if (!Analyser.IsCanRead(4)) return false;
			const int ReflectionProbeIndex = Analyser.GetIntNoCheck();
		}

		// シェーダパラメータ
/*		gcommon::CPBRParam PBRParam;
		gcommon::CUTSParam UTSParam;
		gcommon::CWaterPlaneParam WaterPlaneParam;
		gcommon::CFurParam FurParam;
*/
		switch (ShaderType) {
		case EHEOShaderType::Standard:
		case EHEOShaderType::AutodeskInteractive:
			if (Version >= 2) {
				if (!Analyser.IsCanRead(4 * 2)) return false;

				const float Metallic = Analyser.GetFloatNoCheck();
				const float Smoothness = Analyser.GetFloatNoCheck();

				// SmoothnessとRoughnessは反転したパラメータである

//				PBRParam = gcommon::CPBRParam(Metallic, 1.0f - Smoothness);
			}
			break;

		case EHEOShaderType::MToon:
			if (Version >= 24) {
				if (!Analyser.IsCanRead(4 * 7 + 4 * 4 * 2))return false;

				// トゥーン
				const float ShadeShift = Analyser.GetFloatNoCheck();
				const float ShadeToony = Analyser.GetFloatNoCheck();

				// Rim
				const SColor RimColor = AnalyseColor(Analyser);
				const float RimLightingMix = Analyser.GetFloatNoCheck();
				const float RimFresnelPower = Analyser.GetFloatNoCheck();
				const float RimLift = Analyser.GetFloatNoCheck();

				// アウトライン
				const int OutlineType = Analyser.GetIntNoCheck();
				const SColor OutlineColor = AnalyseColor(Analyser);
				const float OutlineWidth = Analyser.GetFloatNoCheck();

				// UVスクロール
				if (Version >= 25) {
					if (!Analyser.IsCanRead(4))return false;

					const int UseUVScroller_MToon = Analyser.GetIntNoCheck();
					if (UseUVScroller_MToon == 1) {
						if (!Analyser.IsCanRead(4 * 5))return false;

						const float MToonScrollWaitTime = Analyser.GetFloatNoCheck();
						const float MToonScrollScrollTime = Analyser.GetFloatNoCheck();

						const int MToonScrollCount = Analyser.GetIntNoCheck();
						const float MToonUvAnimScrollX = Analyser.GetFloatNoCheck();
						const float MToon_UvAnimScrollY = Analyser.GetFloatNoCheck();

						std::vector<SUV> StepUVList;
						StepUVList.push_back(SUV(MToonUvAnimScrollX, MToon_UvAnimScrollY));

						//UVScroller = CHEOUVScroller(true, MToonScrollWaitTime, MToonScrollScrollTime, StepUVList);
					}
				}
			}

			break;

		case EHEOShaderType::UTS:
			{
				if (!Analyser.IsCanRead(4 * 4 + 4 * 2)) return false;

				const SColor ShadeColor = AnalyseColor(Analyser);
				const float BaseColorStep = Analyser.GetFloatNoCheck();
				const float BaseShadeFeather = Analyser.GetFloatNoCheck();

				SColor _2nd_ShadeColor = SColor::Zero;
				float ShadeColor_Step = 0.0f;
				float _1st2nd_Shades_Feather = 0.0f;
				float Outline_Width = 0.0f;
				SColor Outline_Color = SColor::Zero;

				if (Version >= 9) {
					if (!Analyser.IsCanRead(4 * 4 * 2 + 4 * 3)) return false;

					_2nd_ShadeColor = AnalyseColor(Analyser);
					ShadeColor_Step = Analyser.GetFloatNoCheck();
					_1st2nd_Shades_Feather = Analyser.GetFloatNoCheck();
					Outline_Width = Analyser.GetFloatNoCheck();
					Outline_Color = AnalyseColor(Analyser);
				}

//				UTSParam = gcommon::CUTSParam(ShadeColor, BaseColorStep, BaseShadeFeather);
			}
			break;

		case EHEOShaderType::WaterPlane:
			{
				if (!Analyser.IsCanRead(4 * 4 * 2 + 4 * 5)) return false;

				const SColor AddColor = AnalyseColor(Analyser);
				const SColor SpecColor = AnalyseColor(Analyser);

				const float SpecPower = Analyser.GetFloatNoCheck();
				const float WaveMagX = Analyser.GetFloatNoCheck();
				const float WaveMagY = Analyser.GetFloatNoCheck();
				const float WaveSpeed = Analyser.GetFloatNoCheck();
				const float WaveSize = Analyser.GetFloatNoCheck();

//				WaterPlaneParam = gcommon::CWaterPlaneParam(AddColor, SpecColor, SpecPower, WaveMagX, WaveMagY, WaveSpeed, WaveSize);
			}
			break;

		case EHEOShaderType::Fur:
			{
				if (!Analyser.IsCanRead(4 * 2)) return false;

				const float FurLength = Analyser.GetFloatNoCheck();
				const int NumofLayer = Analyser.GetIntNoCheck();

//				FurParam = gcommon::CFurParam(FurLength, FurLength, NumofLayer);
			}
			break;

		default:
			break;
		}

		
		// 登録
/*		m_MaterialList.push_back(CHEOMaterial(Name, ShaderType, BlendMode, Cutoff, DoubleSided, UseVertexColor, Color, EmissionColor, Texture0Index,
			Texture1Index, Texture2Index, Texture3Index, TextureScaleMain, TextureOffsetMain, Texture1ScaleMain, Texture1OffsetMain,
			PBRParam, UTSParam, WaterPlaneParam, FurParam));
*/	}

	return true;
}

bool CHEOOverwriter::AnalyseTextureList(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	// 個数
	int Numof;
	if (!Analyser.GetInt(Numof)) return false;

	// テクスチャリスト
	for (int n = 0; n < Numof; n++) {
		// ファイル名
		std::string FileName;
		if (!Analyser.GetZeroTerminatedString(FileName)) return false;

		// クランプ
		bool Clamp = false;

		if (Version >= 1) {
			int ClampType = 0;
			if (!Analyser.GetInt(ClampType)) return false;

			Clamp = (ClampType == 1);
		}

		// 圧縮テクスチャフラグ
		std::vector<int> TextureCompressionSupportedList(4, 0);

		std::vector<const unsigned char*> TextureCompressionSupportedPointerList(4, nullptr);

		if (Version >= 5) {
			if (!Analyser.IsCanRead(4)) return false;

			for (int m = 0; m < 4; m++) {
				// ここに圧縮テクスチャフラグがBYTE型で存在する
				TextureCompressionSupportedPointerList[m] = Analyser.GetReadPointer();

				TextureCompressionSupportedList[m] = static_cast<int>(Analyser.GetByteNoCheck());
			}
		}

		// 登録
		m_TextureCompressionInfoPointerList.push_back(TextureCompressionSupportedPointerList);
//		m_TextureList.push_back(CHEOTexture(FileName, Clamp, TextureCompressionSupportedList));
	}

	return true;
}

bool CHEOOverwriter::AnalyseBoneTable(fileimage::CFileImageAnalyser& Analyser)
{
	if (!Analyser.IsCanRead(4)) return true;	// 古いHEOモデルはこの情報が無いのでひとまず成功とみなす

	// 個数
	int Numof;
	if (!Analyser.GetInt(Numof)) return false;

	// リスト
	for (int n = 0; n < Numof; n++) {
		// ボーン名
		std::string BoneName;
		if (!Analyser.GetZeroTerminatedString(BoneName)) return false;

		// ノードインデックス
		int NodeIndex;
		if (!Analyser.GetInt(NodeIndex)) return false;

		// 登録
//		m_BoneTable[NodeIndex] = BoneName;
	}

	return true;
}

bool CHEOOverwriter::AnalyseLightmapList(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	int Numof = 0;
	if (!Analyser.GetInt(Numof)) return false;

	//
	if (Version >= 26) {
		for (int n = 0; n < Numof; n++) {
			// ファイル名
			std::string FileName;
			if (!Analyser.GetZeroTerminatedString(FileName)) return false;

			// 圧縮テクスチャフラグ
			// 将来的に使用するために確保している
			std::vector<int> TextureCompressionSupportedList(4, 0);

			if (!Analyser.IsCanRead(4)) return false;

			for (int m = 0; m < 4; m++) {
				TextureCompressionSupportedList[m] = static_cast<int>(Analyser.GetByteNoCheck());
			}

			//
			const bool Clamp = true;

//			m_LightmapTextureList.push_back(CHEOTexture(FileName, Clamp, TextureCompressionSupportedList));
		}
	}
	else {
		// 旧バージョンとの互換性を保つためにここでファイル名等を設定する
		for (int n = 0; n < Numof; n++) {
			const std::string FileName = LFormat::Make("LightMap%03d.png", n);
			std::vector<int> TextureCompressionSupportedList(4, 0);
			const bool Clamp = true;

//			m_LightmapTextureList.push_back(CHEOTexture(FileName, Clamp, TextureCompressionSupportedList));
		}
	}

	// シーンにリアルタイムのDirectionalLightを使用しているか
	// 使用している場合、LightMapによるライティングとPBRによるライティングが合成される
	bool UseDirectionlLight = false;
	int UseDirectionlLightFlag = 0;
	if (Version >= 18) {
		if (!Analyser.GetInt(UseDirectionlLightFlag)) return false;
		if (UseDirectionlLightFlag == 1)UseDirectionlLight = true;
	}

	// LightMapのエンコードタイプ
	if (Version >= 22) {
		if (!Analyser.IsCanRead(4)) return false;
		int LightMapEncodeType = Analyser.GetIntNoCheck();
	}

	return true;
}

SColor CHEOOverwriter::AnalyseColor(fileimage::CFileImageAnalyser& Analyser)
{
	SColor Color;
	Color.fR = Analyser.GetFloatNoCheck();
	Color.fG = Analyser.GetFloatNoCheck();
	Color.fB = Analyser.GetFloatNoCheck();
	Color.fA = Analyser.GetFloatNoCheck();

	return Color;
}

bool CHEOOverwriter::AnalyseReflectionProbe(fileimage::CFileImageAnalyser& Analyser, int Version)
{
	// 使用するリフレクションプローブの総数を読み取る
	int ReflectionProbeNum = 0;

	if (Version >= 11) {
		if (!Analyser.IsCanRead(4)) return false;
		ReflectionProbeNum = Analyser.GetIntNoCheck();
	}

	// リフレクションプローブの情報をさらに読み込む
	if (Version >= 12) {
		for (int i = 0; i < ReflectionProbeNum; i++) {
			// Box Projection を使用するかどうか
			if (!Analyser.IsCanRead(4)) return false;
			const int UseBoxProjection = Analyser.GetIntNoCheck();

			// リフレクションプローブの情報をさらに読む
			if (!Analyser.IsCanRead(4 * 6)) return false;
			const float ReflectionProbeCenter_X = Analyser.GetFloatNoCheck();
			const float ReflectionProbeCenter_Y = Analyser.GetFloatNoCheck();
			const float ReflectionProbeCenter_Z = Analyser.GetFloatNoCheck();
			const float ReflectionProbeSize_X = Analyser.GetFloatNoCheck();
			const float ReflectionProbeSize_Y = Analyser.GetFloatNoCheck();
			const float ReflectionProbeSize_Z = Analyser.GetFloatNoCheck();

			if (Version >= 16) {
				// リフレクションプローブのMipmapCountを読み込む
				if (!Analyser.IsCanRead(4)) return false;
				int MipMapCount = Analyser.GetIntNoCheck();

				// 圧縮テクスチャフラグ
				std::vector<int> TextureCompressionSupportedList(4, 0);
				std::vector<const unsigned char*> TextureCompressionSupportedPointerList(4, nullptr);
				if (!Analyser.IsCanRead(4)) return false;

				for (int m = 0; m < 4; m++) {
					TextureCompressionSupportedPointerList[m] = Analyser.GetReadPointer();

					TextureCompressionSupportedList[m] = static_cast<int>(Analyser.GetByteNoCheck());
				}

				m_CubemapTextureCompressionInfoPointerList.push_back(TextureCompressionSupportedPointerList);
			}

			// フォルダ名
			if (Version >= 26) {
				std::string FolderName;
				if (!Analyser.GetZeroTerminatedString(FolderName)) return false;

				m_ReflectionProbeFolderNameList.push_back(FolderName);
			}
			else {
				m_ReflectionProbeFolderNameList.push_back(LFormat::Make("%d", i));
			}
		}
	}

	m_ReflectionProbeNum = ReflectionProbeNum;

	return true;
}

bool CHEOOverwriter::AnalyseReflectionProbeCubemap(int Version, const std::string& FileName)
{
	if (Version < 16) return true;

	int NumofCubemapComp[4] = { 0, 0 ,0 ,0 };

	for (int ReflectionProbeIndex = 0; ReflectionProbeIndex < m_ReflectionProbeNum; ReflectionProbeIndex++) {
		auto& TextureCompressionInfoPointer = m_CubemapTextureCompressionInfoPointerList[ReflectionProbeIndex];
		std::vector<bool> IsCompressList(4, true);

		for (int TextureIndex = 0; TextureIndex < 6; TextureIndex++) {
			for (int n = 0; n < 4; n++) {
				std::string SubFolderName;
				std::string Extension = "pvr";

				switch (static_cast<ETextureCompressionType>(n)) {
				case ETextureCompressionType::PVRTC:
					SubFolderName = "tex_reflection_cube_pvrtc";
					break;

				case ETextureCompressionType::ETC2:
					SubFolderName = "tex_reflection_cube_etc";
					break;

				case ETextureCompressionType::ASTC:
					SubFolderName = "tex_reflection_cube_astc";
					break;

				case ETextureCompressionType::DXT:
					SubFolderName = "tex_reflection_cube_dxt";
					Extension = "dds";
					break;

				default:
					return false;
				}

				const std::string TexFileName = LFileName::DeleteFileName(FileName) + SubFolderName + "\\" +
					m_ReflectionProbeFolderNameList[ReflectionProbeIndex] +
					LFormat::Make("\\%s_%d.%s","reflection_cube", TextureIndex, Extension.c_str());

				if (!filesystem::CFindFile::IsExistFile(TexFileName)) {
					//				printf("no exist %s\n", TexFileName.c_str());
					IsCompressList[n] = false;
					continue;
				}
			}
		}

		for (int n = 0; n < IsCompressList.size();n++) {
			const auto& IsCompress = IsCompressList[n];
			if (IsCompress) {
				// 圧縮フラグを書き換える
				*const_cast<unsigned char*>(TextureCompressionInfoPointer[n]) = 1;

				//			printf("exist %s\n", TexFileName.c_str());
				NumofCubemapComp[n]++;
			}
			else {
				// 圧縮フラグを書き換える
				*const_cast<unsigned char*>(TextureCompressionInfoPointer[n]) = 0;
			}
		}
	}

	printf("ExistCubemapTextureCompression %d %d %d %d\n", NumofCubemapComp[0], NumofCubemapComp[1], NumofCubemapComp[2], NumofCubemapComp[3]);

	return true;
}

}

