// Copyright 2009 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#ifdef OSPRAY_ENABLE_VOLUMES

#pragma once

#include "render/pathtracer/Scattering.ih"

#include "math/sampling.ih"
#include "rkcommon/math/LinearSpace.ih"

OSPRAY_BEGIN_ISPC_NAMESPACE

inline float hg(float cosTheta, float g)
{
  float denom = 1.f + g * g - 2.f * g * cosTheta;
  return rcp(4.f * (float)pi) * (1.f - g * g) * rcp(denom * sqrt(denom));
}

inline bool HenyeyGreenstein_isSmooth(float anisotropy)
{
  if (abs(anisotropy) > 1.f - 1e-3f) {
    return false;
  }
  return true;
}

inline Scattering_EvalRes HenyeyGreenstein_eval(
    float anisotropy, const vec3f &wo, const vec3f &wi)
{
  Scattering_EvalRes res;
  if (!HenyeyGreenstein_isSmooth(anisotropy)) {
    res.pdf = 0.f;
    res.value = make_vec3f(res.pdf);
  }
  res.pdf = hg(dot(neg(wo), wi), anisotropy);
  res.value = make_vec3f(res.pdf);
  return res;
}

inline Scattering_SampleRes HenyeyGreenstein_sample(
    float anisotropy, const vec3f wo, const vec2f s, float)
{
  Scattering_SampleRes res;

  res.weight = make_vec3f(1.f);

  const float g = anisotropy;
  float cosTheta;
  if (!HenyeyGreenstein_isSmooth(anisotropy)) {
    // special case for delta function
    res.wi = g > 0 ? neg(wo) : wo;
    res.pdf = inf;
    res.type = g > 0 ? SCATTERING_SPECULAR_TRANSMISSION
                     : SCATTERING_SPECULAR_REFLECTION;
    return res;
  } else if (abs(g) < 1e-3f) {
    // special case for isotropic scattering
    cosTheta = 1.f - 2.f * s.x;
  } else {
    // general case
    float sqrTerm = (1.f - g * g) * rcp(1.f - g + 2.f * g * s.x);
    cosTheta = (1.f + g * g - sqrTerm * sqrTerm) * rcp(2.f * g);
  }

  res.type = SCATTERING_SMOOTH;
  float sinTheta = sqrt(max(0.f, 1.f - cosTheta * cosTheta));
  float phi = 2.f * M_PI * s.y;
  const vec3f localDir = cartesian(phi, sinTheta, cosTheta);

  res.wi = frame(neg(wo)) * localDir;
  res.pdf = hg(cosTheta, g);
  return res;
}

OSPRAY_END_ISPC_NAMESPACE
#endif
