//
// Copyright 2017-2023 Valve Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#pragma once

#include <random>

#include "coordinate_space.h"
#include "sphere.h"

namespace ipl {

// --------------------------------------------------------------------------------------------------------------------
// RandomNumberGenerator
// --------------------------------------------------------------------------------------------------------------------

// Random number generator. Create one per thread for generating random numbers in a thread-safe way.
class RandomNumberGenerator
{
public:
    RandomNumberGenerator();

    // Returns a random number sampled from the uniform distribution over the domain [0, 1].
    float uniformRandomNormalized();

    // Returns a random number sampled from the uniform distribution over the domain [0, INT_MAX].
    int uniformRandom();

private:
    std::default_random_engine mGenerator;
    std::uniform_int_distribution<int> mUniformDistribution;
    std::uniform_real_distribution<float> mUniformDistributionNormalized;
};


// --------------------------------------------------------------------------------------------------------------------
// Sampling
// --------------------------------------------------------------------------------------------------------------------

// Randomly sampled directions, generated by sampling a canonical space of directions, such as the unit sphere or
// a unit hemisphere.
namespace Sampling
{
    // Sample directions from a uniform distribution over the surface of the unit sphere.
    void generateSphereSamples(int numSamples,
                               Vector3f* samples);

    // Sample directions from a uniform distribution over the surface of a unit hemisphere with its normal in
    // the +y direction.
    void generateHemisphereSamples(int numSamples,
                                   Vector3f* samples);

    // Transform hemisphere samples by rotating them so that their normal is along the specified direction.
    Vector3f transformHemisphereSample(const Vector3f& sample,
                                       const Vector3f& normal);

    // Sample points from a uniform distribution over the volume of a unit sphere.
    void generateSphereVolumeSamples(int numSamples,
                                     Vector3f* samples);

    // Transform sphere volume samples to a sphere with a given center and radius.
    Vector3f transformSphereVolumeSample(const Vector3f& sample,
                                         const Sphere& sphere);
}

}
