/***************************************************************************
 *                         Zanoza Modeler v3.3.x                           *
 *     This is unpublished proprietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                 Copyright (c) 2002-2024 Zanoza Software.                *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler 3.3.x Compute shader for Blur and Glow effects
 *--------------------------------------------------------------------------
 * @history: 12.05.2024. Created
 * @Description:
   Computer Shader for Gaussian blur and Glow effects.
   Computation is performed in one direction every pass, so two
   invocations (horizontal and vertical) required.
   Insipred by blur shader implementation by @aaronscherzinger 
      [www.github.com/aaronscherzinger/directx11_bloom/]
<[[
UserName = "Blur"
Entry = Blur OuterGlow
Version  = 1.0.0
Options  = COMPUTE
Engine = 11
]]>
*/

#define MAX_GAUSSIAN_RADIUS 31

Texture2D<float4> inputTexture : register(t0);
RWTexture2D<float4> outputTexture : register(u0);

cbuffer BlurParams : register(b0)
{
    float4 coefficients[(MAX_GAUSSIAN_RADIUS + 1) / 4];
    // .x : radius <= MAX_GAUSSIAN_RADIUS, 
    // .y : direction. 0 = horizontal, 1 = vertical
    // .zw: reserved/padding;
    int4   radiusAndDirection;
}

#ifdef COMPUTE_SHADER
[numthreads(8, 8, 1)]
void Blur(uint3 groupID : SV_GroupID, 
          uint3 groupThreadID : SV_GroupThreadID, 
          uint groupIndex : SV_GroupIndex, 
          uint3 dispatchID : SV_DispatchThreadID)
{
    int2 pixel = int2(dispatchID.x, dispatchID.y);

    int radius = radiusAndDirection.x;
    //texture direction access {1, 0} for horiz; {0, 1} for vertical;
    int2 dir = int2(1 - radiusAndDirection.y, radiusAndDirection.y);

    float4 accumulatedValue = float4(0.0, 0.0, 0.0, 0.0);
    for (int i = -radius; i <= radius; i++)
    {
        uint cIndex = (uint)abs(i);
        accumulatedValue += coefficients[cIndex >> 2][cIndex & 3] * 
                            inputTexture[mad(i, dir, pixel)];
    }

    outputTexture[pixel] = accumulatedValue;
}


//-----------------------------------------
// outer glow blur (horizontal or vertical)
// assumes non-transparent source pixels are an object shape
// and retain them unchanged. Affects transparent pixels only.
//-----------------------------------------
[numthreads(8, 8, 1)]
void OuterGlow(	uint3 groupID : SV_GroupID, 
          	uint3 groupThreadID : SV_GroupThreadID, 
          	uint groupIndex : SV_GroupIndex, 
          	uint3 dispatchID : SV_DispatchThreadID)
{
    int2 pixel = int2(dispatchID.x, dispatchID.y);

    int radius = radiusAndDirection.x;
    int2 dir = int2(1 - radiusAndDirection.y, radiusAndDirection.y);

    float4 maxValue = float4(0.0, 0.0, 0.0, 0.0);
    for (int i = -radius; i <= radius; i++)
    {
        uint cIndex = (uint)abs(i);
        float4 srcPixel = inputTexture[mad(i, dir, pixel)];
	float coef = coefficients[cIndex>>2][cIndex&3];
        maxValue = srcPixel.a*coef > maxValue.a ? float4(srcPixel.rgb, srcPixel.a*coef) : maxValue;
    }
    outputTexture[pixel] = maxValue;
}

#endif //COMPUTE_SHADER

