// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

shader ParticleUtilities
{

    // -------------------------------------
    // uniforms
    // -------------------------------------

    // !When a bigger structure (float4) follow a smaller structure (float) the binding seems off
    // Declare the uniforms in the order float4x4 > float4 > float > uint
    cbuffer PerView
    {
        stage float4x4 ViewMatrix;
        stage float4x4 ProjectionMatrix;
        stage float4x4 ViewProjectionMatrix;

        // .x - Width, .y - Height, .z - Near, .w - Far
        stage float4   ViewFrustum;

        stage float4 Viewport;
    }

    stage float GetLinearDepth(float z)
    {
    	float fastA = -ProjectionMatrix._33;    // = zFar / (zFar - zNear);
	    float fastB = ProjectionMatrix._43;     // = (-zFar * zNear) / (zFar - zNear);
	    return fastB / (z - fastA);
    }

    // -------------------------------------
    // Randomness
    // -------------------------------------

    // Some notes on randomness
    //  The algorithm below is uses unsigned integer as input and generates deterministic random values with good distribution.
    //  Because we can't pass uint as vertex input, we use a float and cast it twice to prevent interpolation errors.
    //  Also, casting a huge uint value to float causes underflow, so we limit the input value to 0 .. 0xFFFF (the masking is done on the CPU side)

    static const float  GelfondConst = 23.1406926327792690; // e to the power of Pi = (-1) to the power of -i
    static const float  GelfondSchneiderConst = 2.6651441426902251; // 2 to the power of sqrt(2)
    static const float2 Gelfond = float2(GelfondConst, GelfondSchneiderConst);
    static const float  Numerator = 123456789;

    float GetRandom(float fSeed)
    {
        // Cast to int once to prevent interpolation errors
        int uSeed = (int) (fSeed);
        fSeed = (float) uSeed;

        float2 rand2 = float2(cos(fSeed), sin(fSeed));

        float dotProduct = dot(rand2, Gelfond);

        return frac(fmod(Numerator, 1e-7 + 256.f * dotProduct));
    }
};

