#pragma once

#include "Mix/Geometry/AABB.h"
#include "Mix/Geometry/Sphere.h"
#include "Mix/Private/Scene/Common/RendererTypes.h"

namespace Mix{ namespace Scene{ namespace Common{

	// ウィジェット : 各種値
	static const UInt32 WIDGET_POS_SIZE = 12;
	static const UInt32 WIDGET_COLOR_SIZE = sizeof( Float32[4] );
	static const UInt32 WIDGET_NORMAL_SIZE = sizeof( Float32[3] );
	static const UInt32 WIDGET_TEXTURE_SIZE = sizeof( Float32[2] );
	static const UInt32 WIDGET_VERTEX_STRIDE = 48; // WIDGET_POS_SIZE + WIDGET_COLOR_SIZE + WIDGET_NORMAL_SIZE + WIDGET_TEXTURE_SIZE
	static const UInt32 WIDGET_QUAD_STRIDE = 288; // WIDGET_VERTEX_STRIDE * 6
	static const UInt32 WIDGET_QUAD_POINT_NUM = 6;

	// ウィジェット : カラー、法線、接線空間
	static const UInt32 WIDGET_DATA_OFFSET = 12;
	static const UInt32 WIDGET_DATA_SIZE = 28; // WIDGET_COLOR_SIZE + WIDGET_NORMAL_SIZE

	// ウィジェット : クワッド構造体
	struct WIDGET_QUAD
	{
		/*
			中心座標
		*/

		Mix::Vector3 pos;

		/*
			頂点座標
			  localPoints は ビルボードの作業用のため IParticleProcessor::FACE::localPoints のポインタになる
		*/

		const Mix::Vector3* localPoints;
		Mix::Vector3 points[4];

		/*
			データ
			  color normal は頂点バッファに一括でコピーするため、data の各位置のアドレスになる
			  また normal はビルボードでは使用しない
		*/

		UInt8 data[WIDGET_DATA_SIZE];
		UInt32 dataSize;

		Mix::Vector4& color;
		Mix::Vector3& normal;

		/*
			テクスチャ座標
			  texCoords は変換作業がないため、IParticleRenderer::FACE::texCoords のポインタ になる
			  texWriteOffset は上のデータのサイズが可変長のため、1頂点の書き込みオフセットになる( 座標( sizeof( MixVector3 ) ) + dataSize )
		*/

		const Mix::Vector2* texCoords;
		UInt32 texWriteOffset;

		WIDGET_QUAD( void ) :
		color( *reinterpret_cast<Mix::Vector4*>( &data[0] ) ),
		normal( *reinterpret_cast<Mix::Vector3*>( &data[16] ) )
		{
		}
	};

	// ウィジェット : サブセット構造体
	struct WIDGET_SUBSET
	{
		// レンダラーで設定されます //

		UInt32 refractClass;

		Float32 minZ;
		Float32 maxZ;

		UInt32 localLightID;
		UInt32 localLightCount;

		//////////////////////////////

		UInt32 priority;

		UInt32 quadCount;
		Mix::Scene::Common::WIDGET_QUAD** quads;

		Mix::Scene::IMaterial* pMaterial;

		//////////////////////////////

		virtual void Update( const Mix::Vector3& normal, Float32 d ) = 0;
		virtual void AppendBounds( Mix::Geometry::AABB& out ) = 0;
	};

	// ウィジェット : AABBサブセット
	struct WIDGET_AABB_SUBSET : public WIDGET_SUBSET
	{
		Mix::Geometry::AABB bounds;

		virtual void Update( const Mix::Vector3& normal, Float32 d )
		{
			const Mix::Vector3* pPoint = &( bounds.points[0] );
			const Mix::Vector3* pPointEnd = pPoint + 8;
			Float32 z;

			//最小、最大深度

			minZ = +MIX_FLOAT_MAX;
			maxZ = -MIX_FLOAT_MAX;

			while( pPoint != pPointEnd )
			{
				z = ( pPoint->x * normal.x ) + ( pPoint->y * normal.y ) + ( pPoint->z * normal.z ) + d;

				if( minZ > z ) { minZ = z; }
				if( maxZ < z ) { maxZ = z; }

				pPoint++;
			}

			// ローカルライトのクリア

			localLightID = 0xFFFFFFFF;
			localLightCount = 0;
		}

		virtual void AppendBounds( Mix::Geometry::AABB& out )
		{
			out += bounds;
		}
	};

	// ウィジェット : Sphereサブセット
	struct WIDGET_SPHERE_SUBSET : public WIDGET_SUBSET
	{
		Mix::Geometry::Sphere bounds;

		virtual void Update( const Mix::Vector3& normal, Float32 d )
		{
			const Mix::Vector3& center = bounds.center;
			Float32 radius = bounds.radius;

			Float32 z = ( center.x * normal.x ) + ( center.y * normal.y ) + ( center.z * normal.z ) + d;

			//最小、最大深度

			minZ = z - radius;
			maxZ = z + radius;

			// ローカルライトのクリア

			localLightID = 0xFFFFFFFF;
			localLightCount = 0;
		}

		virtual void AppendBounds( Mix::Geometry::AABB& out )
		{
			out += bounds;
		}
	};

	// ウィジェット : オブジェクト
	//
	// ローカルライトとの判定用に使用しています
	struct WIDGET_OBJECT
	{
		Float32 minZ;
		Float32 maxZ;

		Mix::Geometry::AABB bounds;

		UInt32 subsetStart;
		UInt32 subsetNum;
	};

}}}
