//-----------------------------------------------------------------------------
// PostprocessEffect.fx
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------

// This source is based on following sample.
// http://xbox.create.msdn.com/ja-JP/education/catalog/sample/nonrealistic_rendering

// エッジ検出フィルターを制御する設定。

// エッジ検出での入力データの微小な変化に対する感度はどの程度にしますか。
// 設定を小さくすればするほど、より微妙なエッジが検出されるようになり、値を大きくすると、
// 不要なノイズは除外されます。
// ４方向別の感度　right, left, top, bottom
float4 DepthThreshold = 0.02;

// 入力データの変化に対応して、どの程度エッジを暗くしますか。
float DepthMultiplyer = 25;
// ４方向別の強度　right,left, top, bottom
float4 EdgeStrength = 0.4;

// 現在の画面の解像度を渡します。
float2 ScreenResolution;

float4x4 MatrixTransform;


// このテクスチャには、メインのシーンのイメージが含まれます。この上に、エッジ検出
// およびスケッチ フィルターまたはそのいずれかが適用されます。
texture SceneTexture;

sampler SceneSampler : register(s0) = sampler_state
{
    Texture = (SceneTexture);
    
    MinFilter = Linear;
    MagFilter = Linear;
    
    AddressU = Clamp;
    AddressV = Clamp;
};


// このテクスチャには、メインのシーンのイメージの法線 (カラー チャンネルに) および
// 深度 (アルファに)が含まれます。法線データと深度データの差異を使用して、
// モデルのエッジの位置が検出されます。
texture NormalDepthTexture;

sampler NormalDepthSampler : register(s1) = sampler_state
{
    Texture = (NormalDepthTexture);
    
    MinFilter = Linear;
    MagFilter = Linear;
    
    AddressU = Clamp;
    AddressV = Clamp;
};

// エッジ検出PixelShader
// 深度に応じて1pxの輝度低下ラインをつけます
float4 PSEdgeDetect(float2 texCoord : TEXCOORD0) : COLOR0
{
    // メインのシーンから元の色を検索します。
    float3 scene = tex2D(SceneSampler, texCoord);
        
    // 当該ピクセルおよび、 4 つの隣接ピクセルとの深度差を取得。
    float2 edgeOffset = 1 / ScreenResolution;
    float n0 = tex2D(NormalDepthSampler, texCoord).a;
    float n1 = tex2D(NormalDepthSampler, texCoord + float2( 1, 0) * edgeOffset).a;
    float n2 = tex2D(NormalDepthSampler, texCoord + float2(-1, 0) * edgeOffset).a;
    float n3 = tex2D(NormalDepthSampler, texCoord + float2( 0, 1) * edgeOffset).a;
    float n4 = tex2D(NormalDepthSampler, texCoord + float2( 0,-1) * edgeOffset).a;
    // 深度の値がどれだけ変化したかを割り出します。微小な変化をフィルターで除外します。
    float d1 = saturate((n0-n1-DepthThreshold.x)*DepthMultiplyer)*EdgeStrength.x;
	float d2 = saturate((n0-n2-DepthThreshold.y)*DepthMultiplyer)*EdgeStrength.y;
	float d3 = saturate((n0-n3-DepthThreshold.z)*DepthMultiplyer)*EdgeStrength.z;
	float d4 = saturate((n0-n4-DepthThreshold.w)*DepthMultiplyer)*EdgeStrength.w;
    float delta = max(max(d1,d2),max(d3,d4));
    // エッジ検出の結果をメインのシーンの色に適用します。
    scene *= (1 - delta);
	
    return float4(scene, 1);
}

//SrcAlphaをGrayscaleに変換するPixelShader
float4 PSAlphaToGS(float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 depth = tex2D(NormalDepthSampler, texCoord);
	float4 gs = depth.a;
	gs.a = 1.0;
	return gs;
}

void SpriteVertexShader(inout float4 color    : COLOR0,
                        inout float2 texCoord : TEXCOORD0,
                        inout float4 position : SV_Position)
{
    position = mul(position, MatrixTransform);
}

// エッジ検出：深度に応じて1pxの輝度低下ラインをつけます
technique EdgeDetect
{
    pass P0
    {
        VertexShader = compile vs_2_0 SpriteVertexShader();
        PixelShader = compile ps_2_0 PSEdgeDetect();
    }
}

// ソースのAlphaをグレースケール化してレンダリング（Debug use）
technique AlphaToGS
{
    pass P0
    {
        VertexShader = compile vs_2_0 SpriteVertexShader();
        PixelShader = compile ps_2_0 PSAlphaToGS();
    }
}