// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "light.h"
#include <sampling.hpp>
#include <math/linearspace3.h>

namespace embree {
    struct DirectionalLight {
        Light super; //!< inherited light fields

        LinearSpace3fa frame; //!< coordinate frame, with vz == direction *towards* the light source
        Vec3fa radiance; //!< RGB color and intensity of light
        float cosAngle;
        //!< Angular limit of the cone light in an easier to use form: cosine of the half angle in radians
        float pdf; //!< Probability to sample a direction to the light
    };

    // for very small cones treat as singular light, because float precision is not good enough
#define COS_ANGLE_MAX 0.99999988f


    // Implementation
    //////////////////////////////////////////////////////////////////////////////

    Light_SampleRes DirectionalLight_sample(const Light* super,
                                            const Sample& dg,
                                            const Vec2f& s) {
        const DirectionalLight* self = (DirectionalLight *) super;
        Light_SampleRes res;

        res.dir = self->frame.vz;
        res.dist = inf;
        res.pdf = self->pdf;

        if (self->cosAngle < COS_ANGLE_MAX)
            res.dir = self->frame * uniformSampleCone(self->cosAngle, s);

        res.weight = self->radiance; // *pdf/pdf cancel

        return res;
    }

    Light_EvalRes DirectionalLight_eval(const Light* super,
                                        const Sample&,
                                        const Vec3fa& dir) {
        DirectionalLight* self = (DirectionalLight *) super;
        Light_EvalRes res;
        res.dist = inf;

        if (self->cosAngle < COS_ANGLE_MAX && dot(self->frame.vz, dir) > self->cosAngle) {
            res.value = self->radiance * self->pdf;
            res.pdf = self->pdf;
        } else {
            res.value = Vec3fa(0.f);
            res.pdf = 0.f;
        }

        return res;
    }


    // Exports (called from C++)
    //////////////////////////////////////////////////////////////////////////////

    //! Set the parameters of an ispc-side DirectionalLight object
    extern "C" void DirectionalLight_set(void* super,
                                         const Vec3fa& direction,
                                         const Vec3fa& radiance,
                                         float cosAngle) {
        DirectionalLight* self = (DirectionalLight *) super;
        self->frame = frame(direction);
        self->radiance = radiance;
        self->cosAngle = cosAngle;
        self->pdf = cosAngle < COS_ANGLE_MAX ? uniformSampleConePDF(cosAngle) : inf;
    }

    //! Create an ispc-side DirectionalLight object
    extern "C" void* DirectionalLight_create() {
        DirectionalLight* self = (DirectionalLight *) alignedUSMMalloc(sizeof(DirectionalLight), 16);
        Light_Constructor(&self->super);
        //self->super.sample = GET_FUNCTION_POINTER(DirectionalLight_sample);
        //self->super.eval = GET_FUNCTION_POINTER(DirectionalLight_eval);
        self->super.type = LIGHT_DIRECTIONAL;

        DirectionalLight_set(self, Vec3fa(0.f, 0.f, 1.f), Vec3fa(1.f), 1.f);
        return self;
    }
} // namespace embree
