//==============================================================================
//
// Balloon for MikuMikuMoving
// ビームマンPさんのBalloonエフェクトを改変させていただきました。
//
// 2012 Mogg
//==============================================================================

////////////////////////////////////////////////////////////////////////////////////////////////
// パラメータ宣言

int index = 0; //ループ用変数

//パーティクル数最大値
#define CLONE_NUM 1024

//色用変数
float3 balloon_col[5]=
{
	{1,0,0},
	{0,1,0},
	{0,0.5,1},
	{1,1,0},
	{1,0,1},
};

int count = CLONE_NUM;
int count_ss = CLONE_NUM*2;

float Height= 80;

float WidthX = 100;

float WidthZ = 100;

float Speed = -10;

float ParticleSize = 1;

float NoizeLevel = 2;

float RotationSpeed = 0.5;

//拡散力
float dispersion = 10;

// 座法変換行列
float4x4 WorldViewProjMatrix      : WORLDVIEWPROJECTION;
float4x4 WorldMatrix              : WORLD;
float4x4 ViewMatrix               : VIEW;
float4x4 LightWorldViewProjMatrix : WORLDVIEWPROJECTION < string Object = "Light"; >;

bool	 LightEnables[MMM_LightCount]		: LIGHTENABLES;		// ライト有効フラグ
float4x4 LightWVPMatrices[MMM_LightCount]	: LIGHTWVPMATRICES;	// ライト座標変換行列
float3   LightDirection[MMM_LightCount]		: LIGHTDIRECTIONS;	// ライト方向

float    ShadowDeep		: SHADOWDEEP;
float3   CameraPosition		: POSITION  < string Object = "Camera"; >;

// マテリアル色
float4   MaterialDiffuse   : DIFFUSE  < string Object = "Geometry"; >;
float3   MaterialAmbient   : AMBIENT  < string Object = "Geometry"; >;
float3   MaterialEmmisive  : EMISSIVE < string Object = "Geometry"; >;
float3   MaterialSpecular  : SPECULAR < string Object = "Geometry"; >;
float    SpecularPower     : SPECULARPOWER < string Object = "Geometry"; >;
float3   MaterialToon      : TOONCOLOR;
// ライト色
float3   LightDiffuses[MMM_LightCount]      : LIGHTDIFFUSECOLORS;
float3   LightAmbients[MMM_LightCount]      : LIGHTAMBIENTCOLORS;
float3   LightSpeculars[MMM_LightCount]     : LIGHTSPECULARCOLORS;
static float4 DiffuseColor[3]  = { MaterialDiffuse * float4(LightDiffuses[0], 1.0f)
				 , MaterialDiffuse * float4(LightDiffuses[1], 1.0f)
				 , MaterialDiffuse * float4(LightDiffuses[2], 1.0f)};
static float3 SpecularColor[3] = { MaterialSpecular * LightSpeculars[0]
				 , MaterialSpecular * LightSpeculars[1]
				 , MaterialSpecular * LightSpeculars[2]};

bool     parthf;   // パースペクティブフラグ
bool     transp;   // 半透明フラグ
bool	 spadd;    // スフィアマップ加算合成フラグ
#define SKII1    1500
#define SKII2    8000
#define Toon     3

// オブジェクトのテクスチャ
texture ObjectTexture: MATERIALTEXTURE;
sampler ObjTexSampler = sampler_state {
    texture = <ObjectTexture>;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

// スフィアマップのテクスチャ
texture ObjectSphereMap: MATERIALSPHEREMAP;
sampler ObjSphareSampler = sampler_state {
    texture = <ObjectSphereMap>;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

float ftime : TIME;

float3 ControllerPos : CONTROLOBJECT < string name = "(self)"; >;
float morph_spd
<
   string UIName = "速度調節";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;
float morph_width_x
<
   string UIName = "範囲X";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;
float morph_width_z
<
   string UIName = "範囲Z";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;
float morph_height
<
   string UIName = "範囲Y";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;
float morph_num
<
   string UIName = "個数調整";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;
float morph_rand
<
   string UIName = "ゆらぎ";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;
float morph_dis_s
<
   string UIName = "始拡散";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;
float morph_dis_e
<
   string UIName = "終拡散";
   string UIWidget = "Slider";
   bool UIVisible =  true;
   float UIMin = 0.0;
   float UIMax = 1.0;
> = 0.0;


//回転行列
static float rot_x = ftime * RotationSpeed + index * 12;
static float rot_y = ftime * RotationSpeed + index * 34;
static float rot_z = ftime * RotationSpeed + index * 56;

static float3x3 RotationX = {
    {1,	0,	0},
    {0, cos(rot_x), sin(rot_x)},
    {0, -sin(rot_x), cos(rot_x)},
};
static float3x3 RotationY = {
    {cos(rot_y), 0, -sin(rot_y)},
    {0, 1, 0},
	{sin(rot_y), 0,cos(rot_y)},
    };
static float3x3 RotationZ = {
    {cos(rot_z), sin(rot_z), 0},
    {-sin(rot_z), cos(rot_z), 0},
    {0, 0, 1},
};
float4 ClonePos(float4 Pos : POSITION) : POSITION 
{
	//表示数上限設定に引っ掛かったら消し飛ばす
	if(index >= (1-morph_num)*(float)count)
	{
		Pos.xyzw = 0;
		return Pos;
	}


	float findex = index;
    
    //回転・サイズ変更
    //Pos.xyz = mul( Pos.xyz, RotationX );
    Pos.xyz = mul( Pos.xyz, RotationY );
    //Pos.xyz = mul( Pos.xyz, RotationZ );
    Pos.xyz *= ParticleSize;
    
    // ランダム配置
    float4 base_pos;
    float rand = findex;
    
    float w_rad = frac(cos(rand*0.123))*3.1415*2;
    float w_len = frac(tan(rand*0.456));
    
    base_pos.x = cos(w_rad)*w_len;
    base_pos.y = frac(sin(rand*456));
    base_pos.z = sin(w_rad)*w_len;
    base_pos.w = 1;

    base_pos.xz *= (1-morph_dis_s);
    //上昇
    base_pos.y = frac(base_pos.y - ((Speed * (1-morph_spd)) * ftime / Height));
    //拡散
    dispersion *= morph_dis_e;
    float up_pow = pow(base_pos.y,2);
    base_pos.x += ((frac(cos(findex * 11))-0.5) * dispersion ) * up_pow;
    base_pos.z += ((frac(sin(findex * 22))-0.5) * dispersion ) * up_pow;
       
    //領域変更
    WidthX *= 1.0+morph_width_x*10.0;
    WidthZ *= 1.0+morph_width_z*10.0;
    Height *= 1.0+morph_height*10.0;
    
    base_pos.xyz *= float3(WidthX, Height, WidthZ);
    base_pos.xyz *= 0.1;
    
    //斜め
    float2 vec = ControllerPos.xz*0.1;
    vec *= base_pos.y;
    base_pos.xz += vec;
    
    //ノイズ付加
    base_pos.x += noise(float2(findex * 0.1 + ftime * 0.2, findex * 12)) * NoizeLevel*morph_rand;
    //base_pos.y += noise(float2(findex * 0.1 + ftime * 0.2, findex * 34)) * NoizeLevel*morph_rand;
    base_pos.z += noise(float2(findex * 0.1 + ftime * 0.2, findex * 56)) * NoizeLevel*morph_rand;
    
    Pos.xyz += base_pos;
    return Pos;
}


///////////////////////////////////////////////////////////////////////////////////////////////
// オブジェクト(balloon.x)描画
// その他はデフォルト動作

struct VS_OUTPUT {
    float4 Pos        : POSITION;    // 射影変換座標
    float2 Tex        : TEXCOORD1;   // テクスチャ
    float3 Normal     : TEXCOORD2;   // 法線
    float3 Eye        : TEXCOORD3;   // カメラとの相対位置
    float2 SpTex      : TEXCOORD4;   // スフィアマップテクスチャ座標
    float4 SS_UV1     : TEXCOORD5;   // セルフシャドウテクスチャ座標
    float4 SS_UV2     : TEXCOORD6;   // セルフシャドウテクスチャ座標
    float4 SS_UV3     : TEXCOORD7;   // セルフシャドウテクスチャ座標
    float4 Color      : COLOR0;      // ディフューズ色
};

// 頂点シェーダ
VS_OUTPUT Basic_VS(float4 Pos : POSITION, float3 Normal : NORMAL, float2 Tex : TEXCOORD0, uniform bool useTexture, uniform bool useSphereMap, uniform bool useSelfShadow, uniform bool useToon)
{
	VS_OUTPUT Out = (VS_OUTPUT)0;

	Pos = ClonePos(Pos);

	// カメラ視点のワールドビュー射影変換
	Out.Pos = mul(Pos, WorldViewProjMatrix );
	Out.Normal = normalize(mul(Normal, WorldViewProjMatrix));

	// カメラとの相対位置
	Out.Eye = normalize(CameraPosition - mul( Pos, WorldMatrix ));

	// 色
	float3 basecolor = balloon_col[index%5]*0.5;
	float3 normal = normalize( mul( Normal, (float3x3)WorldMatrix ));

	float3 color = float3(0, 0, 0);
	float count = 0;
	for (int i = 0; i < MMM_LightCount; i++) {
		if (LightEnables[i]) {
			color += basecolor + dot(normal, -LightDirection[i]) * balloon_col[index%5];
			count += 1.0;
		}
	}

	Out.Color.rgb = saturate(color / count);
	Out.Color.a = DiffuseColor[0].a;

	// テクスチャ座標
	Out.Tex = Tex;

	if ( useSphereMap ) {
		// スフィアマップテクスチャ座標
		float2 NormalWV = mul( Normal, (float3x3)ViewMatrix );
		Out.SpTex.x = NormalWV.x * 0.5f + 0.5f;
		Out.SpTex.y = NormalWV.y * -0.5f + 0.5f;
	}
	if (useSelfShadow)
	{
		//セルフシャドウデプスマップテクスチャ座標を計算
		float4 dpos = mul(Pos, WorldMatrix);
		Out.SS_UV1 = mul(dpos, LightWVPMatrices[0]);
		Out.SS_UV2 = mul(dpos, LightWVPMatrices[1]);
		Out.SS_UV3 = mul(dpos, LightWVPMatrices[2]);
	}
	return Out;
}

// ピクセルシェーダ
float4 Basic_PS(VS_OUTPUT IN, uniform bool useTexture, uniform bool useSphereMap, uniform bool useSelfShadow, uniform bool useToon) : COLOR0
{
	float4 Color = IN.Color;

	// スペキュラ色計算
	float3 HalfVector;
	float3 Specular = float3(0, 0, 0);

	for (int i = 0; i < MMM_LightCount; i++)
	{
		if (LightEnables[i]) {
			HalfVector = normalize(IN.Eye + -LightDirection[i]);
			Specular += pow( max(0,dot( HalfVector, normalize(IN.Normal) )), SpecularPower ) * SpecularColor[i];
		}
	}

	if ( useTexture ) {
		// テクスチャ適用
		Color *= tex2D( ObjTexSampler, IN.Tex );
	}
	if ( useSphereMap ) {
		// スフィアマップ適用
		if(spadd) Color.rgb += tex2D(ObjSphareSampler,IN.SpTex).rgb;
		else      Color.rgb *= tex2D(ObjSphareSampler,IN.SpTex).rgb;
	}

	// セルフシャドウ
	if (useSelfShadow)
	{
		float smz, ttv;
		float2 texcoord;
		float3 tt;
		float4 d;
	
		float4 uv[3];
		uv[0] = IN.SS_UV1;
		uv[1] = IN.SS_UV2;
		uv[2] = IN.SS_UV3;

		for (int i = 0; i < 3; i++)
		{
			tt = float3(uv[i].xyz) / uv[i].w;
			texcoord = (1.0f + tt.xy) * 0.5f;
			tt.xy = 1.0f - saturate((tt.xy * tt.xy - 0.8f) / 0.2f);
			
			d = tex2D(MMM_SelfShadowSampler[i], texcoord);
			smz = MMM_UnpackDepth(d) + 0.00008;

			if (saturate(tt.z) > smz)
			{
				ttv = tt.x * tt.y;
				Color.rgb *= 1.0f - (ShadowDeep * ttv);
			}
		}
	}
    
	// スペキュラ適用
	Color.rgb += Specular;

	return Color;
}


// オブジェクト描画用テクニック（balloon.x用）
// セルフシャドウなし
technique MainTec0 < string MMDPass = "object"; bool UseTexture = false; bool UseSphereMap = false; bool UseSelfShadow = false; bool UseToon = false;
	string Script =
		"LoopByCount=count;"
        "LoopGetIndex=index;"
        "Pass=DrawObject;"
        "LoopEnd=;"
	;
> {
    pass DrawObject {
        VertexShader = compile vs_3_0 Basic_VS(false, false, false, false);
        PixelShader  = compile ps_3_0 Basic_PS(false, false, false, false);
    }
}
// セルフシャドウあり
technique MainTec1 < string MMDPass = "object"; bool UseTexture = false; bool UseSphereMap = false; bool UseSelfShadow = true; bool UseToon = false;
	string Script =
		"LoopByCount=count;"
        "LoopGetIndex=index;"
        "Pass=DrawObject;"
        "LoopEnd=;"
	;
> {
    pass DrawObject {
        VertexShader = compile vs_3_0 Basic_VS(false, false, true, false);
        PixelShader  = compile ps_3_0 Basic_PS(false, false, true, false);
    }
}

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